Ich mache ein Spiel, in dem KI-Spieler einen Ball werfen.
Im Screenshot sehen Sie die Arena, die in der Mitte durch ein Netz getrennt ist. Jede Seite der Arena hat 6 Spieler, die zu einem von 2 Teams gehören. Im Moment hat einer der Spieler auf der rechten Seite den Ball (der Spieler oben rechts). Er wird den Ball auf die linke Seite werfen.
Nach meinem Code sollte der Ball immer an der gleichen Stelle landen, da der Spieler immer die gleiche Kraft auf den Ball ausübt. Mir ist jedoch aufgefallen, dass der Ball nicht immer an derselben Stelle landet. Ich habe markiert, wo ich den Ball landen gesehen habe, mit mehreren roten Kreisen.
Interessanterweise landet der Ball auf meinem Haupt-PC fast immer auf dem Kreis ganz rechts. Es landet selten auf den anderen Kreisen, aber das ist nicht geschehen. Auf 3 anderen PCs, auf denen ich dieses Spiel getestet habe, landet der Ball jedoch meistens auf den Beinen des Spielers oben links, manchmal auf seinem Kopf oder hinter ihm, aber niemals auf dem Kreis ganz rechts (vor ihm) ).
Mein Spiel hängt stark von der Physik ab. Die KI soll berechnen, wie der Ball geworfen werden soll, damit er an einem bestimmten Ort landet, und je nach Position und Bewegung des Balls erraten, wo er landen wird. Wenn sich die Physik nicht immer auf allen Maschinen konsistent verhält, wie soll die KI all dies genau berechnen?
Hier ist der Code, der für das Werfen zuständig ist:
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);
}
Wie Sie sehen können, wird der Ball immer "nach vorne" (in Richtung des Netzes) in einem Winkel von 45 ° nach oben geworfen, wobei ein normalisierter Vektor und eine konstante Geschwindigkeit ( 20f
) verwendet werden.
Vor jedem Wurf wird die Position der Spieler auf genau die Position (und Drehung) zurückgesetzt, die sie auf dem Screenshot sehen.
player.transform.localEulerAngles = new Vector3(0, playerRotation, 0);
player.transform.position = startingposition + posOffset;
In diesem Fall playerRotation
ist entweder 90f
oder -90f
abhängig davon, auf welcher Seite sich der Spieler befindet, startingposition
seine "horizontale" Position (relativ zum Netz) und posOffset
seine "vertikale" Position.
Der Ball hat seine Geschwindigkeit und Winkelgeschwindigkeit zurückgesetzt, aber nicht seine Drehung (da es sich um eine Kugel handelt, sollte seine Drehung nichts beeinflussen). Seine Position ist auch auf einen festen Ort relativ zu dem Spieler eingestellt, der den Ball bedienen muss.
rb.velocity = Vector3.zero;
rb.angularVelocity = Vector3.zero;
transform.position = ServingPlayer.ServingPosition;
Hier rb
ist der Ball RigidBody
.
Schließlich beeinflusse ich die Bewegung des Balls in keiner Weise. Ich übe beim Servieren einfach eine Kraft darauf aus, was nur einmal vorkommt. 3 Sekunden nachdem der Ball gelandet ist, wird das Match zurückgesetzt und alles wiederholt sich.
Der Fluss ist im Grunde wie folgt (Pseudocode):
Start()
ResetCourt()
StartCoroutine(Players[0].Serve())
event BallLanded()
wait for 3 seconds
// repeat starting with ResetCourt()
Ich brauche wirklich die Flugbahn des Balls, um jedes Mal auf jeder möglichen Maschine reproduzierbar zu sein. Natürlich mache ich hier etwas falsch, aber was?
Antworten:
Ich glaube nicht, dass Sie etwas falsch machen. Der Grund dafür, dass das Ergebnis anders ist, ist, dass die Unity-Physik-Engine FixedUpdate je nach Hardware- und Systemlast unterschiedlich schnell aufruft. Viele physikalische Berechnungen verwenden den Zeitschritt bei jedem Aufruf, um das Ergebnis zu glätten. Die Antwort finden Sie hier: http://answers.unity3d.com/questions/11839/making-fixedupdate-fixed-timestep-independent.html
quelle