¿Por qué la física no se comporta de manera consistente en Unity?

Estoy haciendo un juego en el que los jugadores AI lanzan una pelota.

Captura de pantalla

En la captura de pantalla, puede ver la arena que está separada por una networking en el medio. Cada lado de la arena tiene 6 jugadores que pertenecen a uno de 2 equipos. En este momento, uno de los jugadores del lado derecho tiene el balón (el jugador de la parte superior derecha). Él va a lanzar la pelota hacia el lado izquierdo.

De acuerdo con mi código, la pelota siempre debe aterrizar en el mismo lugar, porque el jugador siempre aplica la misma fuerza a la pelota. Sin embargo, he notado que la pelota no siempre aterriza en el mismo lugar. He marcado donde he visto aterrizar la bola con varios círculos rojos.

Curiosamente, en mi PC principal, la pelota casi siempre aterriza en el círculo más a la derecha. Raramente cae en los otros círculos, aunque eso sucede. En otras 3 PCs probé este juego, sin embargo, la pelota aterriza con mayor frecuencia en las piernas del jugador de arriba a la izquierda, a veces en la cabeza o detrás de él, pero nunca en el círculo de la derecha (frente a él )

Mi juego depende en gran medida de la física. Se supone que la IA debe calcular cómo lanzar la pelota para que aterrice en un lugar muy específico, así como también adivinar dónde aterrizará dependiendo de la position y los movimientos de la pelota. Si la física no se comporta de manera consistente en todas las máquinas todo el time, ¿cómo se supone que la IA debe calcular todo esto con precisión?

Aquí está el código a cargo de arrojar:

private IEnumerator Serve() { var ball = GameObject.Find("Ball").GetComponent<BallController>(); if (ball.ServingPlayer != this) yield break; yield return new WaitForSeconds(3); Vector3 shootDirection = transform.forward.normalized; var q = Quaternion.AngleAxis(-45, transform.right); ball.RigidBody.AddForce(q * shootDirection * 20f, ForceMode.VelocityChange); } 

Como puede ver, la pelota siempre se lanza "hacia adelante" (hacia la networking) en un ángulo ascendente de 45 °, usando un vector normalizado y una velocidad constante ( 20f ).

Antes de cada lanzamiento, la position de los jugadores se restablece a la misma location exacta (y rotation) que se ven en la captura de pantalla.

 player.transform.localEulerAngles = new Vector3(0, playerRotation, 0); player.transform.position = startingposition + posOffset; 

En este caso, la -90f del jugador es -90f o -90f dependiendo de qué lado esté el jugador, la position startingposition es su position "horizontal" (relativa a la networking), y posOffset es su position "vertical".

La bola tiene su restablecimiento de velocidad y velocidad angular, pero no su rotation (ya que es una esfera, su rotation no debe influir en nada). Su position también se establece en una location fija en relación con el jugador que tiene que servir la pelota.

 rb.velocity = Vector3.zero; rb.angularVelocity = Vector3.zero; transform.position = ServingPlayer.ServingPosition; 

Aquí, rb es el RigidBody la pelota.

Finalmente, no estoy influyendo en el movimiento de la pelota de ninguna manera. Simplemente le aplico una fuerza cuando sirvo, lo cual ocurre solo una vez. 3 segundos después de que la pelota cae, la partida se reinicia y todo se repite.

El flujo es básicamente así (pseudocódigo):

 Start() ResetCourt() StartCoroutine(Players[0].Serve()) event BallLanded() wait for 3 seconds // repeat starting with ResetCourt() 

Realmente necesito que la trayectoria de la bola sea reproducible cada vez en cada máquina posible. Obviamente estoy haciendo algo mal aquí, ¿pero qué?

No creo que esté haciendo algo mal, la razón por la que el resultado es diferente es porque el motor de física de Unity está llamando a FixedUpdate a una velocidad diferente dependiendo del hardware y la carga del sistema. Muchos cálculos de física usan el paso de time en cada llamada para suavizar el resultado. Vea la respuesta aquí: http://answers.unity3d.com/questions/11839/making-fixedupdate-fixed-timestep-independent.html