Perubahan arah harus memperlambat objek dan mempercepat dalam tajuk baru (berbasis grid 2D)


8

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:

  1. Kami sedang bekerja dengan kisi 2D
  2. Kapal memiliki mesin tunggal di mana Anda dapat mengatur daya dari 0 hingga 1 untuk menunjukkan daya penuh.
  3. Mesinnya memiliki kecepatan maksimal
  4. 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

masukkan deskripsi gambar di sini

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

}

Apakah Anda berbicara tentang menambahkan hambatan?
Daniel Holst

Saya tidak tahu Saya telah menulis ulang judul dan beberapa uraian untuk menjadi lebih fokus "apa yang saya inginkan". :)
Thraka

1
Masih belum jelas 100% perilaku apa yang Anda inginkan dari pesawat ruang angkasa Anda miliki. Mungkin membaca beberapa pertanyaan serupa dan lihat apakah itu memberi Anda apa yang Anda butuhkan, atau membantu Anda mengisolasi perilaku spesifik apa yang Anda inginkan yang berbeda dari mereka. Membuat diagram tentang permainan demi permainan dari apa yang Anda ingin kapal lakukan di setiap bagian belokan mungkin banyak membantu.
DMGregory

Pertanyaan itu mungkin bisa membantu saya, tetapi sepertinya ia mencoba melakukan lebih dari yang saya inginkan. Terima kasih atas tips diagramnya! Saya akan melakukannya setelah bekerja hari ini.
Thraka

1
Lihatlah fisika 2d dasar. Kedengarannya seperti yang perlu Anda lakukan adalah menerapkan percepatan vektor kecepatan Anda.
ClassicThunder

Jawaban:


6

Saya tidak terbiasa dengan xna... tapi saya tahu matematika. Dan menerapkan fisika tanpa memahami matematika di baliknya seperti masuk ke politik tanpa tahu bagaimana berbohong. Jadi mari kita mulai!

Pertama-tama, cara Anda menggerakkan kapal tidak berdasarkan fisika. Anda tidak ingin pemain mengubah posisi kapal secara langsung. Yang ingin Anda lakukan adalah membiarkan pemain menerapkan akselerasi ke kapal, lalu biarkan fisika menghitung kecepatan kapal , lalu biarkan dunia mengubah posisi kapal dengan kecepatan yang baru dihitung itu. Velocity adalah perbedaan posisi kapal dalam waktu. Jika bergerak 5 unit ke kanan dan 1 unit ke atas, itu bergerak dengan kecepatan (5,-1). Akselerasi adalah perbedaan dalam kecepatan kapal - itu hanya mempengaruhi posisi kapal dengan mengubah kecepatannya. Jika kapal Anda pergi 2 unit ke kiri dan 1 unit ke bawah, berarti kecepatan(2,1), dan pemain mempercepatnya ke arah yang berlawanan, artinya (-2,-1)), itu akan berhenti di tempat dengan unit waktu berikutnya (baik itu bingkai atau centang atau apa pun). Dengan kata lain, Anda perlu menambahkan vektor percepatan ke vektor kecepatan dan kemudian menghitung di mana kapal berikutnya.

Vektor

Bayangkan panah yang dimulai di suatu tempat (asal), menunjuk ke suatu tempat (arah) dan memiliki panjang tertentu (besarnya). Sekarang gambarkan dengan dua nilai - seberapa banyak X dan seberapa banyak Y adalah akhir dari awalnya. Untuk penyederhanaan saya hanya akan berbicara tentang sumbu X yang berarti vektor Anda menunjuk pada sesuatu yang "banyak X" ke kanan (positif) atau ke kiri (negatif).

Kecepatan

Sekarang, bagaimana posisi kapal harus berubah di antara frame? Dengan vektor kecepatan. Mari kita asumsikan kapal Anda mulai dari lokasi (0,0) dengan kecepatan (12,0). Ini berarti akan mengubah posisinya sebagai berikut:

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

Percepatan

Bagaimana kita mengubah arah? Anda tidak ingin hanya mengubah kecepatan menjadi (-12,0). Itu berarti kapal bergerak dari 100 parsec ke kanan hingga 100 parsec yang tersisa dalam satu "bingkai". Saya tidak ingin berada di kapal itu ketika itu terjadi. Sekali lagi, "panjang" vektor disebut "magnitudo" dan dalam hal kecepatan terjadi pada kecepatan. Jadi Anda ingin besarnya kecepatan (kecepatan kapal) perlahan-lahan turun ke 0 dan kemudian berakselerasi ke negatif 12 (yang berarti bergerak dalam arah yang berlawanan). Anda dapat melakukannya dengan menambahkan akselerasi ke kecepatan, mis. Akselerasi dari (-4,0), jadi sekarang kapal bergerak sebagai berikut (pemain menekan ke kiri pada "bingkai" ke-3 lalu melepaskannya pada tanggal 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)

Jadi, Anda ingin menerapkan akselerasi (4,0)untuk membuat kapal secara bertahap mendapatkan kecepatan dalam arah X positif ketika pemain menekan panah kanan dan menerapkan akselerasi (-4,0)ketika panah kiri ditekan. Jelas ketika tidak ada tombol yang ditekan Anda tidak menerapkan akselerasi yang berarti kapal menjaga kecepatannya (bergerak dengan kecepatan konstan dalam arah tertentu). Jika Anda ingin memperlambat secara bertahap ketika tidak ada tombol yang ditekan, tambahkan vektor lain, panggil Dragdan berikan arah yang selalu berlawanan dengan kecepatan (yaitu menuju bagian belakang kapal) hingga besarnya kecepatan mencapai 0. Semoga Anda mendapatkan ide .

Kode

Apa yang akan saya lakukan (kode semu, Anda harus memperbaikinya, menambahkan enkapsulasi, dll., Juga mengabaikan beberapa aspek, misalnya pergi diagonal sedikit lebih cepat daripada lurus ke kiri, kanan, atas atau bawah):

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
Terima kasih atas jawaban terinci, saya akan membacanya dan kembali kepada Anda. Saya menghargai bantuannya !!
Thraka

1
Anda juga dapat menggunakan seret untuk membatasi kecepatan kapal dan memperlambat kapal jika mengurangi daya. Ini akan bermanfaat untuk menurunkan akselerasi dengan lancar karena kecepatan mendekati kecepatan maksimum (saya tahu bahwa ini di luar cakupan pertanyaan Anda, tetapi berpikir bahwa itu mungkin merupakan tambahan yang baik jika Anda menggunakan pendekatan ini)
Malrig

1
Saya ingin drag, sebenarnya itulah poin # 4 saya di pertanyaan saya. :)
Thraka

3

Untuk melakukan ini, Anda perlu mensimulasikan inersia. Ini adalah bagaimana saya akan merekomendasikan melakukannya:

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

Terima kasih sudah datang untuk melihat ini. Ini memang terlihat seperti pengambilan yang menarik. Saya mencoba menerapkannya tetapi tidak berfungsi seperti yang saya kira seharusnya. Apakah ini benar?? if (this.Vel.LengthSquared() > this.MaxSpeed * MaxSpeed)Anda memiliki MaxSpeed ​​di sana dua kali .. Juga, ThrustForwardmenggunakan this.Acceltetapi komentar Anda mengatakan ini adalah akselerasi Max apakah itu benar juga?
Thraka

Ya ini benar, saya menyalinnya langsung dari permainan yang saya kerjakan yang masih dalam tahap awal. Jangan ragu untuk menggunakan kode ini sebagai basis dan memodifikasinya sesuai kebutuhan. this.MaxSpeedada dua kali untuk mengoptimalkan kode. Vector2.Length()membutuhkan waktu lebih lama untuk dihitung daripada Vector2.LengthSquared() Pernyataan berikut jika melakukan hal yang sama tetapi tidak dioptimalkan dan lebih mudah dipahami:if (this.Vel.Length() > this.MaxSpeed)
Ramon J Denham

0

Ok itu sebenarnya sangat sederhana untuk dicapai. Pertama-tama seperti yang Anda sebutkan, arah mesin Anda menggambarkan jalur gerakan. Ini membuatnya nyaman untuk digunakan.

Pertama-tama, selalu simpan vektor dari arah Anda bergerak.

Selanjutnya Anda harus memiliki vektor tampilan mesin Anda.

Jadi untuk saat ini ketika Anda mulai bergerak, katakanlah benar, arah dan tampilan vektor mesin mengarah ke kanan. Ketika Anda sekarang ingin mengubah let.s mengatakan ke atas (90 derajat), maka Anda cukup mengubah vektor mesin pencari.

Sekarang tiba bagian menyenangkan. Tentukan dengan fungsi apa pun seberapa kuat untuk mempengaruhi perubahan arah dan istirahat.

pertama-tama perubahan arah.

Tergantung pada Kecepatan Anda dan perubahan sudut Anda bisa memperlambat dan mengubah arah vektor.

Jika Anda ingin perubahan arah lengkap (180 derajat), maka itu matematika sederhana. Dalam pembaruan Anda cukup ubah kecepatan Anda secara perlahan. Ketika kecepatan berubah menjadi nol, balikkan vektor arah 180 derajat dan mulailah menambah kecepatan lagi.

Pada putaran 90 derajat, itu menjadi sedikit lebih rumit. Anda perlu mendefinisikan fungsi untuk menghitung berapa banyak kapal diizinkan untuk berubah sesuai dengan kecepatan dan jika itu akan memperlambat berapa banyak. Tetapi Anda dapat bermain dengan nilai-nilai sampai sesuai dengan yang Anda inginkan.


Mungkin Anda memukul sesuatu yang saya lewatkan. Penundaan harus dihitung berdasarkan lintasan baru versus yang lama dan penundaan putaran ... Tidak yakin bagaimana memodelkan itu.
Thraka
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.