Я пытаюсь реализовать какую-то физику искусственного пространства в моей 2D игре. У меня есть вид сверху на мой космический корабль. Вы можете изменить направление и установить максимальную скорость, которая затем ускоряет корабль в этом направлении в зависимости от величины ускорения двигателя.
У меня есть код, который работает нормально, заставляя корабль медленно начинать движение в этом направлении и увеличивать скорость до достижения максимальной скорости.
Обновить
Хотя ответы были немного полезны, я не могу прийти к окончательному решению. Я не могу преобразовать теории в рабочий код. Вот еще несколько параметров:
- Мы работаем с 2D сеткой
- Корабль имеет один двигатель, где вы можете установить мощность от 0 до 1, чтобы указать полную мощность.
- Двигатель имеет максимальную скорость
- Существует фальшивое космическое трение, где, если вы больше не применяете силу к кораблю, он в конечном итоге остановится.
проблема
У меня проблема, когда я меняю направление. Если я еду в одном направлении на скорости 300, а затем меняю направление на противоположное, я теперь сразу же двигаюсь на заданной скорости вместо того, чтобы замедляться и возвращаюсь к этой скорости в этом направлении.
Желаемое состояние
Текущий код
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
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);
}
}