Unity Engine 2D rigidbody inexacto saltando mientras que en una plataforma que se mueve hacia abajo

Actualmente estoy trabajando duro en un pequeño juego de plataforms en el motor Unity3D, utilizando sus capacidades 2D.

Ahora he tenido un problema donde, aunque un object está claramente conectado a tierra, de alguna manera no se registra como tal en cada cuadro y, por lo tanto, la function de salto, que solo se ejecuta cuando el object está conectado a tierra, no funcionará. Esto hasta ahora solo parece ocurrir mientras el jugador está en una plataforma que actualmente se mueve hacia abajo.

Ahora no soy el mejor en física 2D en Unity, así que como tal, decidí ver lo que todos piensan que podría ser el problema.

Para fines de ilustración, aquí es lo que se ve en el editor:

enter image description here

El bloque blanco es el personaje jugador, el bloque azul es la plataforma (actualmente se mueve hacia abajo) y la línea roja es un raycast que verifica si el personaje jugador está conectado a tierra.

Espero que ustedes puedan descubrir lo que está mal. Todo lo que tengo hasta ahora es que parece 50/50 ya sea que el jugador esté conectado a tierra durante un cuadro en la plataforma, mientras que dicha plataforma se está moviendo hacia abajo.

Aquí también mi código para el jugador:

using System.Collections; using System.Collections.Generic; using UnityEngine; public class CharacterMovement : MonoBehaviour { private bool left = false; private bool right = false; float velX = 0; float velY = 0; [SerializeField] private float gravity; [SerializeField] private float speed; [SerializeField] private float maxSpeed; [SerializeField] private float jumpForce; [SerializeField] private float jumpSpeed; bool isGrounded = false; float groundedTime = 0; float distanceToGround = 0; float distanceSide = 0; bool plug = false; int plugCounter = 0; void Start () { distanceToGround = this.GetComponent<Collider2D>().bounds.extents.y; distanceSide = this.GetComponent<Collider2D>().bounds.extents.x; } void Update () { Grounded(); WalkingInput(); Walking(); Jumping(); Debug.Log(isGrounded); this.GetComponent<Rigidbody2D>().velocity = new Vector2(velX, this.GetComponent<Rigidbody2D>().velocity.y); //Debug.Log(this.GetComponent<Rigidbody2D>().velocity.x + " " + this.GetComponent<Rigidbody2D>().velocity.y); } void Grounded() { LayerMask mask = (1 << 8); mask = ~mask; if (Physics2D.Raycast(new Vector3(this.transform.position.x - distanceSide, this.transform.position.y - distanceToGround - 0.04f, this.transform.position.z), Vector3.right, distanceSide * 2, mask)) { isGrounded = true; groundedTime += Time.deltaTime; } else { isGrounded = false; groundedTime = 0; } //debugging ray Debug.DrawLine(new Vector3(this.transform.position.x - distanceSide, this.transform.position.y - distanceToGround - 0.04f, this.transform.position.z), new Vector3(this.transform.position.x - distanceSide, this.transform.position.y - distanceToGround - 0.04f, this.transform.position.z) + new Vector3(distanceSide * 2, 0, 0), Color.networking); } void WalkingInput() { if (Input.GetButtonDown("Left")) { left = true; } if (Input.GetButtonUp("Left")) { left = false; } if (Input.GetButtonDown("Right")) { right = true; } if (Input.GetButtonUp("Right")) { right = false; } } void Walking() { if (left == true && velX >= -maxSpeed) { if(velX > 0) { velX = 0; } velX -= speed * Time.deltaTime; if (isGrounded) { if (velX < -maxSpeed) { velX = -maxSpeed; } } else { if (velX < -jumpSpeed) { velX = -jumpSpeed; } } } if (right == true && velX <= maxSpeed) { if (velX < 0) { velX = 0; } velX += speed * Time.deltaTime; if (isGrounded) { if (velX > maxSpeed) { velX = maxSpeed; } } else { if (velX > jumpSpeed) { velX = jumpSpeed; } } } if(left == false && right == false || left == true && right == true) { velX = 0; } } void Jumping() { if (Input.GetButtonDown("Jump") && isGrounded) { Debug.Log("ActuallyJumped"); this.GetComponent<Rigidbody2D>().AddForce(new Vector2(0, jumpForce)); } } } 

y el código para la plataforma:

 using System.Collections; using System.Collections.Generic; using UnityEngine; public class MovingPlatform : MonoBehaviour { [SerializeField] Transform pointA; [SerializeField] Transform pointB; [SerializeField] float platformSpeed; private float wayThere = 0; bool going = true; //true = going to b, false = going to a void FixedUpdate() { if (going == true) { Vector2 offset = DetermineOffset(pointA.transform.position, pointB.transform.position); this.GetComponent<Rigidbody2D>().velocity = new Vector2(offset.x * platformSpeed * Time.deltaTime, offset.y * platformSpeed * Time.fixedDeltaTime); if (Vector2.Distance(this.transform.position, pointB.transform.position) < 0.2f) { going = false; } } else { Vector2 offset = DetermineOffset(pointB.transform.position, pointA.transform.position); this.GetComponent<Rigidbody2D>().velocity = new Vector2(offset.x * platformSpeed * Time.deltaTime, offset.y * platformSpeed * Time.fixedDeltaTime); if (Vector2.Distance(this.transform.position, pointA.transform.position) < 0.2f) { going = true; } } } private Vector2 DetermineOffset(Vector2 PointA, Vector2 PointB) { int x = 0; int y = 0; if(PointB.x > PointA.x) { x = 1; } else if (PointB.x < PointA.x) { x = -1; } else { x = 0; } if(PointB.y > PointA.y) { y = 1; } else if (PointB.y < PointA.y) { y = -1; } else { y = 0; } return (new Vector2(x, y)); } } 

También las configuraciones del editor para el personaje y la plataforma en ese order:

enter image description here

Con todo, espero que una de ustedes, buena persona, pueda ayudarme en esto y ¡gracias ya!

EDITAR: Cambió el código de la plataforma para usar velocidad en lugar de rigidbody.moveposition. Esto funciona mejor El error ahora no existe a bajas velocidades, todavía es visible a altas velocidades. Creo que podría tener que ver con cómo Unity calcula la gravedad del cuerpo rígido porque se convierte en 0 cuando un cuerpo rígido está conectado a tierra, lo que significa que actualmente el cuerpo rígido está conectado a tierra, luego cae, luego se pone a tierra, luego cae lo que explicaría la relación 50/50 también. Sin embargo, me parece extraño que esto funcione bien a menor velocidad.

Si alguien de alguna manera todavía puede encontrar la manera de hacerlo a mayor velocidad, ¡estaría más que feliz!

EDIT2: Respondió mi propia pregunta al final. Verifique las respuestas para ver cómo lo arreglé.

¡Bien! ¡Así que finalmente lo descubrí! DmGregory tenía razón y era un problema con mi raycast. Sin embargo, debido a que no podía imaginar cómo se supone que se debe hacer un boxcast de la manera correcta y no parecía el tipo de cosa que necesito, y es mucho más costoso en performance que un raycast o un linecast, decidí cambiar a la siguiente pieza de código en Grounding(); function

 LayerMask mask = (1 << 8); mask = ~mask; if (Physics2D.Linecast(new Vector2(this.transform.position.x - distanceSide, this.transform.position.y - distanceToGround), new Vector2(this.transform.position.x + distanceSide, this.transform.position.y - distanceToGround - 0.1f), mask)) { isGrounded = true; groundedTime += Time.deltaTime; } else { isGrounded = false; groundedTime = 0; } //debugging ray Debug.DrawLine(new Vector3(this.transform.position.x -distanceSide, this.transform.position.y - distanceToGround, this.transform.position.z), new Vector3(this.transform.position.x + distanceSide, this.transform.position.y - distanceToGround - 0.1f, this.transform.position.z), Color.networking); 

Básicamente todo lo que es es raycast ahora es diagonal. Agregaré otra que vaya en diagonal hacia el otro lado (solo asegúrate de cubrir la mayoría de las esquinas). En general, gracias por las respuestas a todos y espero que esto ayude a alguien en el futuro.

Puede intentar llamar a los methods Grounded() y Jumping() desde FixedUpdate() , ya que utiliza el motor de física, con un time delta fijo. Quizás sucede durante la diferencia entre el time delta y el time delta fijo.

Lea más sobre el order de ejecución de Unity .