Thay đổi hướng sẽ làm chậm đối tượng và tăng tốc trong tiêu đề mới (dựa trên lưới 2D)


8

Tôi đang cố gắng thực hiện một số loại vật lý không gian giả trong trò chơi 2D của mình. Tôi có một cái nhìn từ trên xuống của con tàu không gian của tôi. Bạn có thể thay đổi hướng và đặt tốc độ lên tối đa, sau đó tăng tốc cho tàu theo hướng đó theo lượng tăng tốc động cơ của tàu.

Tôi có mã làm việc tốt với việc khiến con tàu từ từ bắt đầu di chuyển theo hướng đó và tăng tốc độ lên cho đến khi đạt được tốc độ tối đa.

Cập nhật

Mặc dù các câu trả lời hơi hữu ích, nhưng nó không đưa tôi đến giải pháp cuối cùng. Tôi dường như không thể chuyển đổi các lý thuyết thành mã làm việc. Dưới đây là một số thông số:

  1. Chúng tôi đang làm việc với lưới 2D
  2. Con tàu có một động cơ duy nhất trong đó bạn có thể đặt công suất từ ​​0 đến 1 để biểu thị toàn bộ sức mạnh.
  3. Động cơ có tốc độ tối đa
  4. Có một ma sát không gian giả mà nếu bạn không còn áp dụng năng lượng cho tàu, cuối cùng nó sẽ dừng lại.

Vấn đề

Vấn đề tôi gặp phải là khi tôi đổi hướng. Nếu tôi đang di chuyển trong một tiêu đề ở tốc độ 300, sau đó thay đổi tiêu đề thành ngược lại, thì bây giờ tôi ngay lập tức di chuyển ở tốc độ đã đặt thay vì giảm tốc độ và quay trở lại tốc độ đó theo hướng đó.

Trạng thái mong muốn

nhập mô tả hình ảnh ở đây

Mã hiện tại

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")}");
    }

}

Mã 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);
    }

}

Bạn đang nói về việc thêm kéo?
Daniel Holst

Tôi không biết. Tôi đã điều chỉnh lại tiêu đề và một số mô tả để tập trung hơn "những gì tôi muốn". :)
Thraka 6/07/2015

1
Vẫn chưa rõ 100% hành vi mà bạn muốn tàu vũ trụ của bạn có. Có thể đọc một số câu hỏi tương tự và xem nếu những câu hỏi đó cung cấp cho bạn những gì bạn cần, hoặc giúp bạn cách ly những hành vi cụ thể mà bạn muốn khác với họ. Vẽ sơ đồ một cách chơi theo những gì bạn muốn con tàu thực hiện ở mỗi phần của lượt có thể giúp ích rất nhiều.
DMGregory

Câu hỏi đó có thể giúp tôi ra ngoài, nhưng có vẻ như nó có thể đang cố gắng làm nhiều hơn tôi muốn. Cảm ơn những lời khuyên về sơ đồ! Tôi sẽ làm điều đó sau khi làm việc ngày hôm nay.
Thraka

1
Nhìn vào vật lý 2d cơ bản. Âm thanh như tất cả những gì bạn cần làm là áp dụng gia tốc cho vectơ vận tốc.
ClassicThunder

Câu trả lời:


6

Tôi không quen thuộc với xna... nhưng tôi biết toán học. Và thực hiện vật lý mà không hiểu toán học đằng sau nó cũng giống như đi vào chính trị mà không biết nói dối. Vậy hãy bắt đầu!

Trước hết, cách di chuyển con tàu của bạn không thực sự dựa trên vật lý. Bạn không muốn người chơi thay đổi vị trí của con tàu trực tiếp. Những gì bạn muốn làm là để người chơi áp dụng gia tốc cho con tàu, sau đó để vật lý tính toán vận tốc của con tàu , sau đó để thế giới thay đổi vị trí của con tàu bằng vận tốc mới được tính toán đó. Vận tốc là sự khác biệt về vị trí của con tàu trong thời gian. Nếu nó di chuyển 5 đơn vị sang phải và 1 đơn vị lên, nó di chuyển theo vận tốc (5,-1). Gia tốc là sự khác biệt về vận tốc của con tàu - nó chỉ ảnh hưởng đến vị trí của con tàu bằng cách thay đổi vận tốc của nó. Nếu tàu của bạn đi 2 đơn vị sang trái và 1 đơn vị xuống, nghĩa là vận tốc của(2,1)và người chơi tăng tốc theo hướng ngược lại, nghĩa là (-2,-1)), nó sẽ dừng tại chỗ với đơn vị thời gian tiếp theo (có thể là khung hoặc đánh dấu hoặc bất cứ điều gì). Nói cách khác, bạn cần thêm vectơ gia tốc vào vectơ vận tốc và sau đó tính toán nơi con tàu sẽ tiếp theo.

Vectơ

Hãy tưởng tượng một mũi tên bắt đầu từ đâu đó (gốc), chỉ đến một nơi nào đó (hướng) và có độ dài (độ lớn) nhất định. Bây giờ mô tả nó với hai giá trị - bao nhiêu X và bao nhiêu Y là kết thúc của nó kể từ khi bắt đầu. Để đơn giản hóa, tôi sẽ chỉ nói về trục X, có nghĩa là vectơ của bạn chỉ vào một cái gì đó "nhiều X" ở bên phải (dương) hoặc bên trái (âm).

Vận tốc

Bây giờ, vị trí của con tàu sẽ thay đổi như thế nào giữa các khung? Với véc tơ vận tốc. Giả sử tàu của bạn bắt đầu tại vị trí (0,0) với vận tốc (12,0). Nó có nghĩa là nó sẽ thay đổi vị trí của nó như sau:

Position:   Velocity:
(0,0)       (12,0)
(12,0)      (12,0)
(24,0)      (12,0)
(36,0)      (12,0)

Sự tăng tốc

Làm thế nào để chúng ta thay đổi hướng? Bạn không muốn thay đổi vận tốc thành (-12,0). Điều đó có nghĩa là con tàu đi từ 100 phân tích phải sang 100 phân tích còn lại trong một "khung". Tôi sẽ không muốn ở trên con tàu đó khi nó xảy ra. Một lần nữa, "chiều dài" của vectơ được gọi là "độ lớn" và trong trường hợp vận tốc, nó xảy ra là tốc độ. Vì vậy, bạn muốn cường độ của vận tốc (tốc độ của tàu) giảm dần về 0 và sau đó tăng tốc về âm 12 (có nghĩa là nó di chuyển theo hướng ngược lại). Bạn có thể làm như vậy bằng cách thêm gia tốc vào vận tốc, ví dụ như gia tốc của (-4,0), vì vậy bây giờ con tàu di chuyển như sau (người chơi nhấn trái vào "khung" thứ 3 rồi thả nó vào ngày 9):

Position:   Velocity:   Acceleration:
(0,0)       (12,0)      (0,0)     # starts in 0,0 going right
(12,0)      (12,0)      (0,0)
(24,0)      (12,0)      (-4,0)
(36,0)      (8,0)       (-4,0)    # starts to slow down
(44,0)      (4,0)       (-4,0)
(48,0)      (0,0)       (-4,0)    # stops
(48,0)      (-4,0)      (-4,0)    # changes direction
(44,0)      (-8,0)      (-4,0)    # starts to go left
(36,0)      (-12,0)     (0,0)     # goes left at steady speed
(24,0)      (-12,0)     (0,0)
(12,0)      (-12,0)     (0,0)
(0,0)       (-12,0)     (0,0)     # passes 0,0 starting point
(-12,0)     (-12,0)     (0,0)     # keeps going left with the same speed
(-24,0)     (-12,0)     (0,0)

Vì vậy, bạn muốn áp dụng gia tốc (4,0)để làm cho con tàu tăng dần tốc độ theo hướng X dương khi người chơi nhấn mũi tên phải và áp dụng gia tốc (-4,0)khi nhấn mũi tên trái. Rõ ràng khi không nhấn phím nào, bạn không áp dụng bất kỳ gia tốc nào có nghĩa là con tàu đang giữ tốc độ của nó (di chuyển với tốc độ không đổi theo hướng nhất định). Nếu bạn muốn nó chậm dần khi không nhấn phím nào, hãy thêm một vectơ khác, gọi nó Dragvà hướng nó luôn ngược với vận tốc (tức là về phía sau tàu) cho đến khi cường độ vận tốc đạt đến 0. Hy vọng bạn hiểu ý .

Những gì tôi sẽ làm (mã giả, bạn sẽ phải sửa nó, thêm đóng gói, v.v., nó cũng bỏ qua một số khía cạnh, ví dụ: đi chéo nhanh hơn một chút so với thẳng trái, phải, lên hoặc xuống):

class Vector {
    x = 0;
    y = 0;

    add(Vector v) {
        this.x += v.x;
        this.y += v.y;
    }
}

class Ship {
    position = new Vector;
    velocity = new Vector;
    maxSpeed = 12;

    accelerate(Vector acceleration) {
        this.velocity.add(acceleration);
        if (this.velocity.x > this.maxSpeed)
            this.velocity.x = this.maxSpeed);
        if (this.velocity.x < -1*this.maxSpeed)
            this.velocity.x = -1*this.maxSpeed); // do the same for y
    }
}

switch (pressedKey) {
    case 'right': Ship.accelerate(new Vector(4,0)); break;
    case 'left': Ship.accelerate(new Vector(-4,0)); break;
}

Ship.position.add(Ship.velocity); // world updates the ship's position

1
Cảm ơn câu trả lời chi tiết, tôi sẽ đọc qua nó và lấy lại cho bạn. Tôi đánh giá cao sự giúp đỡ !!
Thraka

1
Bạn cũng có thể sử dụng lực cản để hạn chế vận tốc tàu và làm chậm tàu ​​nếu chúng giảm sức mạnh. Điều này sẽ có lợi ích trong việc giảm tốc độ gia tốc một cách trơn tru khi vận tốc tiến gần đến vận tốc tối đa (tôi biết rằng điều này vượt quá phạm vi câu hỏi của bạn nhưng nghĩ rằng nó có thể là một sự bổ sung tốt nếu bạn đi theo phương pháp này)
Malrig

1
Tôi thực sự muốn kéo, thực sự đó là điểm số 4 của tôi trong câu hỏi của tôi. :)
Thraka

3

Để làm điều này, bạn cần phải mô phỏng quán tính. Đây là cách tôi khuyên bạn nên làm điều đó:

class Ship
{
    public Vector2 Pos; //Current ship position
    public Vector2 Vel; //Store current velocity as a vector
    public float Rot; //What direction the ship is facing in radians

    public float Accel; //Maximum acceleration
    public float MaxSpeed; //Maximum velocity 

    public void Update(float elapsedTime)
    {
        this.Pos += this.Vel * elapsedTime; //Update our position based on our current velocity
        this.Rot = MathHelper.WrapAngle(this.Rot); //Wrap our heading angle to always be between -Pi and Pi
        if (this.Vel.LengthSquared() > this.MaxSpeed * MaxSpeed) //Keep the velocity vector's length shorter than our max speed
        {
            this.Vel.Normalize();
            this.Vel *= this.MaxSpeed;
        }
    }

    public void ThrustForward(float elapsedTime) //Apply our acceleration to our current velocity
    {
        this.Vel += Vector2.Transform(-Vector2.UnitY * this.Accel * elapsedTime, Matrix.CreateRotationZ(this.Rot));
    }
}

Cảm ơn đã đến để xem xét điều này. Điều này không giống như một mất thú vị. Tôi đang cố gắng thực hiện nó nhưng nó không hoạt động như tôi nghĩ nó nên làm. Điều này có đúng không ?? if (this.Vel.LengthSquared() > this.MaxSpeed * MaxSpeed)bạn có MaxSpeed ​​trong đó hai lần .. Ngoài ra, ThrustForwardsử dụng this.Accelnhưng nhận xét của bạn cho biết đây là gia tốc Max có đúng không?
Thraka

Vâng, đây là chính xác, tôi đã sao chép nó trực tiếp từ một trò chơi tôi đang làm việc vẫn còn ở giai đoạn đầu. Hãy sử dụng mã này làm cơ sở và sửa đổi nó khi bạn cần. this.MaxSpeedCó hai lần để tối ưu hóa mã. Vector2.Length()mất nhiều thời gian để tính toán hơn Vector2.LengthSquared() Câu lệnh if nếu làm điều tương tự nhưng không được tối ưu hóa và dễ hiểu hơn:if (this.Vel.Length() > this.MaxSpeed)
Ramon J Denham

0

Ok nó thực sự rất đơn giản để đạt được. Trước hết như bạn đã đề cập, hướng động cơ của bạn mô tả đường di chuyển. Điều này làm cho nó thoải mái để làm việc với.

Trước hết, luôn luôn lưu trữ một vectơ của hướng ur di chuyển.

Tiếp theo bạn phải có một vectơ của cái nhìn của động cơ ur.

Vì vậy, bây giờ khi bạn bắt đầu di chuyển, hãy nói đúng, cả hướng và diện mạo của vectơ động cơ đều chỉ về bên phải. Khi bạn muốn bật let.s say lên trên (90 độ), thì bạn chỉ cần xoay vector công cụ lookat.

Bây giờ đến phần thú vị. Xác định với bất kỳ chức năng nào mạnh mẽ để ảnh hưởng đến sự thay đổi hướng và phá vỡ.

đầu tiên của sự thay đổi hướng.

Tùy thuộc vào Tốc độ của bạn và thay đổi góc u có thể làm chậm và xoay vectơ chỉ hướng.

Nếu bạn muốn thay đổi hướng hoàn toàn (180 độ), thì đó là phép toán đơn giản. Trong cập nhật của bạn chỉ cần thay đổi tốc độ của bạn từ từ. Khi tốc độ chuyển về 0, lật vectơ chỉ hướng 180 độ và bắt đầu thêm tốc độ một lần nữa.

Khi quay 90 độ, nó phức tạp hơn một chút. bạn cần xác định một hàm để tính toán con tàu được phép quay bao nhiêu theo tốc độ và nếu nó sẽ chậm lại bao nhiêu. Nhưng bạn có thể chơi với các giá trị cho đến khi nó phù hợp với những gì bạn muốn.


Có lẽ bạn đang đánh vào thứ gì đó tôi đang thiếu. Một độ trễ cần được tính toán dựa trên quỹ đạo mới so với độ trễ cũ và độ trễ ... Không chắc chắn làm thế nào để mô hình hóa điều đó.
Thraka 7/07/2015
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.