Saya mencoba menerapkan semacam fisika ruang palsu dalam game 2D saya. Saya memiliki pandangan top down dari kapal ruang angkasa saya. Anda dapat mengubah arah dan mengatur kecepatan hingga maksimum yang kemudian mempercepat kapal ke arah itu sesuai dengan jumlah akselerasi mesin kapal.
Saya memiliki kode yang berfungsi dengan baik agar kapal perlahan mulai bergerak ke arah itu dan meningkatkan kecepatan hingga kecepatan maks terpenuhi.
Memperbarui
Walaupun jawabannya sedikit membantu, itu tidak membawa saya ke solusi akhir saya. Sepertinya saya tidak bisa mengubah teori menjadi kode kerja. Berikut beberapa parameter lainnya:
- Kami sedang bekerja dengan kisi 2D
- Kapal memiliki mesin tunggal di mana Anda dapat mengatur daya dari 0 hingga 1 untuk menunjukkan daya penuh.
- Mesinnya memiliki kecepatan maksimal
- Ada gesekan ruang palsu di mana jika Anda tidak lagi menerapkan daya ke kapal, pada akhirnya akan berhenti.
Masalah
Masalah yang saya alami adalah ketika saya mengubah arah. Jika saya bepergian dalam satu arah dengan kecepatan 300, kemudian mengubah arah ke arah yang berlawanan, saya sekarang langsung bepergian dengan kecepatan yang telah ditentukan alih-alih melambat, dan kembali ke kecepatan itu ke arah itu.
Keadaan yang diinginkan
Kode saat ini
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")}");
}
}
Kode Pengiriman Mesin
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);
}
}