Ich versuche, in meinem 2D-Spiel eine Art Faux-Space-Physik zu implementieren. Ich habe eine Ansicht von oben nach unten von meinem Raumschiff. Sie können die Richtung ändern und eine Geschwindigkeit bis zu einem Maximum einstellen, die das Schiff dann entsprechend dem Motorbeschleunigungsbetrag des Schiffes in diese Richtung beschleunigt.
Ich habe einen Code, der gut funktioniert, damit sich das Schiff langsam in diese Richtung bewegt und die Geschwindigkeit erhöht, bis die Höchstgeschwindigkeit erreicht ist.
Aktualisieren
Die Antworten waren zwar etwas hilfreich, bringen mich aber nicht zu meiner endgültigen Lösung. Ich kann die Theorien nicht in Arbeitscode umwandeln. Hier sind einige weitere Parameter:
- Wir arbeiten mit einem 2D-Raster
- Das Schiff verfügt über einen einzelnen Motor, in dem Sie die Leistung von 0 bis 1 einstellen können, um die volle Leistung anzuzeigen.
- Der Motor hat eine Höchstdrehzahl
- Es gibt eine gefälschte Raumreibung, bei der das Schiff irgendwann aufhört, wenn Sie es nicht mehr mit Strom versorgen.
Problem
Das Problem, das ich habe, ist, wenn ich die Richtung ändere. Wenn ich mit 300 Geschwindigkeit in einer Richtung fahre und dann die Richtung in die entgegengesetzte Richtung ändere, fahre ich jetzt sofort mit der eingestellten Geschwindigkeit, anstatt langsamer zu werden, und komme in dieser Richtung wieder auf diese Geschwindigkeit.
Wunschzustand
Aktueller Code
public void Update(Consoles.Space space)
{
var GameTimeElapsedUpdate = (float)SadConsole.Engine.GameTimeElapsedUpdate;
Graphic.PositionOffset = viewPortMaster.Position;
// Update the engine
ShipDetails.Engine.Update();
// Degrade the current velocity with friction??
if (velocity.Length() < 0f)
{
var accelerationFrame = ShipDetails.Engine.GetAccelerationFrame();
if (velocity.X > 0)
velocity.X -= accelerationFrame;
else if (velocity.X < 0)
velocity.X += accelerationFrame;
if (velocity.Y > 0)
velocity.Y -= accelerationFrame;
else if (velocity.Y < 0)
velocity.Y += accelerationFrame;
}
// Handle any new course adjustments
if (IsTurnRightOn)
SetHeading(heading + (ShipDetails.TurningSpeedRight * GameTimeElapsedUpdate));
if (IsTurnLeftOn)
SetHeading(heading - (ShipDetails.TurningSpeedLeft * GameTimeElapsedUpdate));
// Handle any power changes
if (IsPowerIncreasing)
{
SetPower(ShipDetails.Engine.DesiredPower + (GameTimeElapsedUpdate * ((ShipDetails.Engine.MaxSpeed / Settings.SecondsForFullPowerAdjustment) / ShipDetails.Engine.MaxSpeed)));
if (ShipDetails.Engine.DesiredPower > 1.0d)
ShipDetails.Engine.DesiredPower = 1.0d;
}
if (IsPowerDecreasing)
{
SetPower(ShipDetails.Engine.DesiredPower - (GameTimeElapsedUpdate * ((ShipDetails.Engine.MaxSpeed / Settings.SecondsForFullPowerAdjustment) / ShipDetails.Engine.MaxSpeed)));
if (ShipDetails.Engine.DesiredPower < 0.0d)
ShipDetails.Engine.DesiredPower = 0.0d;
}
// Calculate new velocity based on heading and engine
// Are we changing direction?
if (vectorDirectionDesired != vectorDirection)
{
// I think this is wrong, I don't think this is how I'm supposed to do this. I don't really want to
// animate the heading change, which is what I think this is actually doing..
if (vectorDirectionDesired.X < vectorDirection.X)
vectorDirection.X = Math.Min(vectorDirection.X + (vectorDirectionDesired.X * Settings.SpeedSquareSecond * GameTimeElapsedUpdate), vectorDirectionDesired.X);
else if (vectorDirectionDesired.X > vectorDirection.X)
vectorDirection.X = Math.Max(vectorDirection.X + (vectorDirectionDesired.X * Settings.SpeedSquareSecond * GameTimeElapsedUpdate), vectorDirectionDesired.X);
if (vectorDirectionDesired.Y < vectorDirection.Y)
vectorDirection.Y = Math.Min(vectorDirection.Y + (vectorDirectionDesired.Y * Settings.SpeedSquareSecond * GameTimeElapsedUpdate), vectorDirectionDesired.Y);
else if (vectorDirectionDesired.Y > vectorDirection.Y)
vectorDirection.Y = Math.Max(vectorDirection.Y + (vectorDirectionDesired.Y * Settings.SpeedSquareSecond * GameTimeElapsedUpdate), vectorDirectionDesired.Y);
}
vectorDirection = vectorDirectionDesired;
if (ShipDetails.Engine.Power != 0)
{
var force = new Vector2(vectorDirection.X * (float)ShipDetails.Engine.Speed, vectorDirection.Y * (float)ShipDetails.Engine.Speed);
var acceleration = new Vector2(force.X / ShipDetails.Engine.Acceleration, force.Y / ShipDetails.Engine.Acceleration) * GameTimeElapsedUpdate;
velocity = new Vector2(velocity.X + acceleration.X, velocity.Y + acceleration.Y);
Point endingLocation;
endingLocation.X = (int)velocity.X;
endingLocation.Y = (int)velocity.Y;
velocity.X -= endingLocation.X;
velocity.Y -= endingLocation.Y;
MapPosition += endingLocation;
}
if (this == Settings.GameWorld.CurrentShip)
{
var debug = space.GetDebugLayer();
debug.Clear();
debug.Print(0 + space.ViewArea.X, 0 + space.ViewArea.Y, $"Ship: {MapPosition}");
debug.Print(0 + space.ViewArea.X, 1 + space.ViewArea.Y, $"Speed: {ShipDetails.Engine.Speed} Desired: {ShipDetails.Engine.DesiredPower}");
debug.Print(0 + space.ViewArea.X, 2 + space.ViewArea.Y, $"Heading: {heading} Adjusted: {adjustedHeading}");
debug.Print(0 + space.ViewArea.X, 3 + space.ViewArea.Y, $"Dir: {vectorDirection.X.ToString("0.00")}, {vectorDirection.Y.ToString("0.00")} DirDes: {vectorDirectionDesired.X.ToString("0.00")}, {vectorDirectionDesired.Y.ToString("0.00")}");
}
}
ShipEngine Code
class ShipEngine
{
public int Acceleration;
public int AccelerationBonus;
public int MaxSpeed;
public int MaxAfterburner;
public int Speed { get { return (int)(Power * MaxSpeed); } }
// This is a 0-1 no power to full power rating where MaxSpeed is full power
public double DesiredPower { get { return desiredPower; } set { desiredPower = value; if (value != Power) isDesiredTriggered = true; } }
public double Power;
public bool IsAdjusting { get { return Speed != 0; } }
private double desiredPower;
private bool isDesiredTriggered;
public void Update()
{
if (DesiredPower != Power)
{
var GameTimeElapsedUpdate = (float)SadConsole.Engine.GameTimeElapsedUpdate;
var accelerationFrame = (((float)(Acceleration + AccelerationBonus) / Settings.SpeedSquareSecond) * GameTimeElapsedUpdate);
if (DesiredPower > Power)
{
Power += accelerationFrame;
if (Power > DesiredPower)
Power = DesiredPower;
}
else if (DesiredPower < Power)
{
Power -= accelerationFrame;
if (Power < DesiredPower)
Power = DesiredPower;
}
}
}
public float GetAccelerationFrame()
{
return (((float)Acceleration / Settings.SpeedSquareSecond) * (float)SadConsole.Engine.GameTimeElapsedUpdate);
}
}
Antworten:
Ich bin nicht vertraut mit
xna
... aber ich kenne Mathe. Und Physik zu implementieren, ohne die Mathematik dahinter zu verstehen, ist wie in die Politik zu gehen, ohne zu wissen, wie man lügt. Also lasst uns anfangen!Erstens ist Ihre Art, das Schiff zu bewegen, nicht wirklich physikbasiert. Sie möchten nicht, dass der Spieler die Position des Schiffes direkt ändert. Was Sie tun möchten, ist, den Spieler auf das Schiff beschleunigen zu lassen, dann die Physik die Schiffsgeschwindigkeit berechnen zu lassen und dann die Welt die Schiffsposition um diese neu berechnete Geschwindigkeit ändern zu lassen . Die Geschwindigkeit ist der zeitliche Unterschied in der Position des Schiffes. Wenn es 5 Einheiten nach rechts und 1 Einheit nach oben bewegte, bewegte es sich mit einer Geschwindigkeit von
(5,-1)
. Die Beschleunigung ist der Geschwindigkeitsunterschied des Schiffes - sie beeinflusst die Position des Schiffes nur durch Änderung seiner Geschwindigkeit. Wenn Ihr Schiff 2 Einheiten nach links und 1 Einheit nach unten fuhr, was die Geschwindigkeit von bedeutet(2,1)
und der Spieler beschleunigt es in die entgegengesetzte Richtung (dh(-2,-1)
), es stoppt mit der nächsten Zeiteinheit (sei es Frame oder Tick oder was auch immer). Mit anderen Worten, Sie müssen dem Geschwindigkeitsvektor einen Beschleunigungsvektor hinzufügen und dann berechnen, wo das Schiff als nächstes sein wird.Vektoren
Stellen Sie sich einen Pfeil vor, der irgendwo beginnt (Ursprung), irgendwo zeigt (Richtung) und eine bestimmte Länge (Größe) hat. Beschreiben Sie es nun mit zwei Werten - wie viel X und wie viel Y ist sein Ende von Anfang an. Zur Vereinfachung werde ich nur über die X-Achse sprechen, was bedeutet, dass Ihre Vektoren auf etwas zeigen, das "so viel X" rechts (positiv) oder links (negativ) ist.
Geschwindigkeit
Wie sollte sich nun die Position des Schiffes zwischen den Frames ändern? Mit Geschwindigkeitsvektor. Nehmen wir an, Ihr Schiff startet am Ort (0,0) mit der Geschwindigkeit (12,0). Dies bedeutet, dass die Position wie folgt geändert wird:
Beschleunigung
Wie ändern wir die Richtung? Sie möchten nicht nur die Geschwindigkeit auf ändern
(-12,0)
. Das würde bedeuten, dass das Schiff von 100 Parsec nach rechts auf 100 Parsec nach links in einem "Frame" fährt. Ich würde nicht auf diesem Schiff sein wollen, wenn es passiert. Wiederum wird die "Länge" des Vektors "Größe" genannt und im Falle einer Geschwindigkeit ist es zufällig Geschwindigkeit. Sie möchten also, dass die Größe der Geschwindigkeit (Schiffsgeschwindigkeit) langsam auf 0 abnimmt und dann auf negativ 12 beschleunigt (was bedeutet, dass sie sich in die entgegengesetzte Richtung bewegt). Sie können dies tun, indem Sie der Geschwindigkeit eine Beschleunigung hinzufügen, z. B. die Beschleunigung von(-4,0)
. Das Schiff bewegt sich nun wie folgt (der Spieler drückte auf einem dritten "Rahmen" nach links und ließ es dann auf einem neunten los):Sie möchten also eine Beschleunigung von anwenden
(4,0)
, damit das Schiff allmählich in einer positiven X-Richtung an Geschwindigkeit gewinnt, wenn der Spieler den rechten Pfeil drückt, und eine Beschleunigung anwenden,(-4,0)
wenn der linke Pfeil gedrückt wird. Wenn keine Tasten gedrückt werden, wenden Sie offensichtlich keine Beschleunigung an, was bedeutet, dass das Schiff seine Geschwindigkeit beibehält (sich mit konstanter Geschwindigkeit in eine bestimmte Richtung bewegt). Wenn Sie möchten, dass es sich allmählich verlangsamt, wenn keine Taste gedrückt wird, fügen Sie einen weiteren Vektor hinzu, rufen Sie ihn aufDrag
und geben Sie ihm die Richtung, die immer der Geschwindigkeit entgegengesetzt ist (dh zur Rückseite des Schiffes), bis die Geschwindigkeit 0 erreicht. Hoffentlich haben Sie die Idee .Code
Was ich tun würde (Pseudocode, Sie müssen ihn reparieren, Kapselung hinzufügen usw., außerdem werden einige Aspekte ignoriert, z. B. ist die Diagonale etwas schneller als die Gerade nach links, rechts, oben oder unten):
quelle
Dazu müssen Sie die Trägheit simulieren. So würde ich es empfehlen:
quelle
if (this.Vel.LengthSquared() > this.MaxSpeed * MaxSpeed)
Sie haben MaxSpeed dort zweimal .. AuchThrustForward
verwendet,this.Accel
aber Ihr Kommentar sagt, dies ist Max Beschleunigung ist das auch richtig?this.MaxSpeed
gibt es zweimal, um den Code zu optimieren. DieVector2.Length()
Berechnung dauert länger alsVector2.LengthSquared()
die folgende if-Anweisung macht dasselbe, ist jedoch nicht optimiert und leichter zu verstehen:if (this.Vel.Length() > this.MaxSpeed)
Ok, es ist eigentlich ganz einfach zu erreichen. Wie bereits erwähnt, beschreibt Ihre Motorrichtung zunächst den Bewegungspfad. Dies macht es angenehm, damit zu arbeiten.
Speichern Sie zunächst immer einen Vektor der Bewegungsrichtung.
Als nächstes müssen Sie einen Vektor des Aussehens Ihres Motors haben.
Wenn Sie sich also in Bewegung setzen, sagen wir mal rechts, zeigen sowohl die Richtung als auch das Aussehen des Motorvektors nach rechts. Wenn Sie jetzt drehen wollen, sagen wir nach oben (90 Grad), dann drehen Sie einfach den Lookat-Engine-Vektor.
Jetzt kommt der lustige Teil. Bestimmen Sie mit jeder Funktion, wie stark die Richtungsänderung und der Bruch beeinflusst werden sollen.
zuerst die Richtungsänderung.
Abhängig von Ihrer Geschwindigkeit und Änderung des Winkels kann u den Richtungsvektor verlangsamen und drehen.
Wenn Sie eine vollständige Richtungsänderung (180 Grad) wünschen, dann ist es einfache Mathematik. In deinem Update ändere einfach deine Geschwindigkeit langsam. Wenn die Geschwindigkeit auf Null geht, drehen Sie den Richtungsvektor um 180 Grad und fügen Sie die Geschwindigkeit erneut hinzu.
Bei einer 90-Grad-Drehung wird es etwas komplizierter. Sie müssen eine Funktion definieren, um zu berechnen, wie viel das Schiff je nach Geschwindigkeit drehen darf und ob es langsamer wird. Aber du kannst mit den Werten spielen, bis sie passen, was du willst.
quelle