C64 "Thrust" style physics

Started by
6 comments, last by _TinOmen_ 20 years, 6 months ago
Hi, I''m working on a clone of the C64 classic game "Thrust". For those who do not know "thrust", the game features a space ship that is controlled just like in "Asteroids". The ship can pick up an orb, which then becomes connected to the ship with a tractor beam (a stick). A bit like the two-player mode in the 80:ies arcade game "Space Duel". Both the ship and the orb are subject to gravity which pulls them down toward the planet. I was wondering if anyone can help me with some pointers how to implement the physics routines for animating the ship and orb. I''ve read articles on how to make it the "correct" way in full-blown physics, but I''m needing a simpler approximation. Preferably it would be simple enough to implement in integer math because I''m targeting an 8-bit classic platform.
Advertisement
a simple Euler integration should do. It sounds bad already

what you need for your objects (spaceship or asteroid), is some physics properties.

I use a simple 2D vector class, for the sake of readability.


class CMobile{public:    Vector2 m_vForces;        // force accumulator    Vector2 m_vAcceleration;  // acceleration this frame    Vector2 m_vVelocity;    Vector2 m_vPosition;    float   m_fAngle;    float   m_fMass;    virtual void Update (float dt);    void AddForce(Vector2 vForce) { m_vForces += vForce; }    void AddAcceleration(Vector2 vAcc) { m_vAcceleration += vAcc; }};//you update the position of your physical objects like thisvoid CMobile::Update (float dt){    m_vAcceleration += m_vForces / m_fMass;    m_vPosition     += m_vVelocity * dt + m_vAcceleration * (dt*dt);    m_vVelocity     += m_vAcceleration * dt;    m_vAcceleration  = Vector2::Zero();    m_vForces        = Vector2::Zero();}


The update function will make your spaceship and asteroids turn accelerations and forces into movement.



Now, for your spaceship, you can derive a class like this

class CSpaceShip: public CMobile{public:    float m_fEnginePower;    Vector2 m_vDirection; // direction the ship is pointing towards    virtual void Update(float dt);};void CSpaceShip::Udpate(float dt){    m_fAngle += m_xInputs.KeyRotateLeftValue() * dt;    m_fAngle -= m_xInputs.KeyRotateLeftValue() * dt;    m_vDirection = Vector2(cos(m_fAngle), sin(m_fAngle));    float fThrust = m_xInputs.KeyThrottleValue() * m_fEnginePower;    AddForce(m_vDirection * fThrust);    AddAcceleration(Vector2(0.0f, -9.81f, 0.0f)); // gravity    CMobile::Update(dt);};


the spaceship will rotate around with keypresses, and its engine will push it towards where the spaceship is pointing. Gravity is also added.

You can also add air friction to your spaceship (something like (-m_vVelocity * fAirFriction) , and all sorts of other forces.

For your asteroids, you need another class, with even simpler physics, since they have no engines.



for your spaceship tracting beam, it''s a bit more complicated.

first, you need to be able to tell if an asteroid is in the beam. The function returns the distance of the point to the beam generator, and the angle between the beam core, the point, and the beam generator.

void PointBeamDeviation(Vector2 vPoint, Vector2 vBeamPos, Vector2 vBeamDir, float& fPointDistance, float &fPointAngularDeviation){    fPointDistance = (vPoint - vBeamPos).Magnitude();    fPointAngularDeviation = acos((vPoint - vBeamPos).Dot(vBeamDir) / fPointDistance);} 

Given the distance of the point to the generator, and its angle from the beam, you can apply a force to the asteroid that would push it towards the spaceship.


float fMaxAngleDev = (30.0f / 180.0f * PI);float fDist;float fAngularDev;PointBeamDeviation(Asteroid.m_vPosition, SpaceShip.m_vPosition, SpaceShip.m_vDirection, fDist, fAngularDev);if (fAngularDev < fMaxAngleDev){    Vector vTractingDirection = (SpaceShip.m_vPosition - Asteroid.m_vPosition).UnitVector();    float fDistTractingForce = fMaxDistTractingForce / fDist;    float fAngularTractingForce = cos(fAngularDev);    if (fDistTractingForce > 10.0f)       fDistTractingForce = 10.0f;        float fTractingForce = fAngularTractingForce * fDistTractingForce;    Vector2 vTractingForce = vTractingDirection * fTractingForce;    Asteroid.AddForce(vTractingForce);}


you can add loads of different forces, some force fields, some collision impacts, ect...

Everything is better with Metal.

no integer maths there I''m afraid, even some cos/acos functions, but you''ll need to do some clever tricks to get the integer maths working.

Everything is better with Metal.

Many thanks for the examples Oliii, I will look into them.
I''m still hoping there exists a simpler non-generic technique
I got a grip of all the thrust/velocity part for ship movement, it''s only the link between the ship and pod which is the problem.
The distance between the ship and pod is fixed.
See this link for a screen shot from another thrust-clone:
http://www.lysator.liu.se/~peda/thrust/
OK, so the pod swings about like a pendulum?

In this case, you may want to look at a verlet integration. It's quite simple

struct CParticle{    Vector m_pos;    Vector m_oldpos;    Vector m_vAccel;    float  m_invmass; // 1.0f / mass of particle    void Update(void)    {                float dt2   = (1.0f / 60.0f) * (1.0f / 60.0f); // 60 fps        Vector Temp = m_pos;        m_vAccel    = Vector(0, -10); // gravity        m_pos      += (m_pos - m_oldpos) + m_vAccel * dt2;        m_oldpos    = Temp;    }};struct CLink_Orb_Ship{   CParticle* m_pxShip;   CParticle* m_pxOrb;   float      m_fRestLength;   void Update(void)   {       m_pxOrb ->Update();       m_pxShip->Update();       UpdateLink();       while (FindAndProcessCollision())           UpdateLink();   }   void UpdateLink(void)   {       float  m_l2      = m_fRestLength * m_fRestLength;       Vector delta     = m_pxShip->m_pos - m_pxOrb->m_pos;       float  delta2    = delta*delta;       float  invmass0  = m_pxOrb->m_invmass;       float  invmass1  = m_pxShip->m_invmass;       float  invmass   = (invmass0 + invmass1);       float  diff      = m_l2 / (delta2 + m_l2) - 0.5f;       diff            *= -2.0f / invmass;       delta           *= diff;       m_pxOrb->m_pos  += delta*invmass0;       m_pxShip->m_pos -= delta*invmass1;   }   bool FindAndProcessCollision(void)   {       .....       .....       .....   }};



What this do, it will connect the pod to the ship, the pod will swing like a heavy pendulum (if you set its mass to larger than the ship), dragging the ship around, while the ship will be pushed by its thrusters. The UpdateLink() function will enforce the pod and the ship to be at a fixed distance, while the heavier of the two (the pod) will move a little and the lighter one will do most of the movement, thus the pod will drag the ship. The verlet integration has the advantage of being more stable when you constrain the particle like this. The euler will be too unstable. Plus, it's simpler. All you need is to record the previous position of the particle in oldpos, calculate the accelerations, and presto. When you first set the ship position at initialisation, set both pos and oldpos to that position, which basically sets the initial velocity to 0.

You can plug in the collision detection for the orb and the ship routine. All you have to do in there, is move the ship and the orb by the collision response, and re-update the link. Of course, when the ship or the orb collides, the link constrain will be broken (the distance between them will be shorten or increased), so you need to re-update the link constrain, and by doing so, it might introduce more collisions, ect...

[edited by - oliii on October 5, 2003 7:59:06 PM]

Everything is better with Metal.

btw, this system is taken from that article

http://www.gamasutra.com/resource_guide/20030121/jacobson_01.shtml

and that collision loop is not fuly necessary, I got carried away. All you need is

void Update(void)   {           m_pxOrb ->Update();    m_pxShip->Update();           FindAndProcessCollision();    UpdateLink();   }   



[edited by - oliii on October 5, 2003 8:00:58 PM]

Everything is better with Metal.

This looks like some very good advice Oliii.

I read that gamasutra article just the other day and thought it
interesting, but I was not sure how I would use that information
in my game.

Now I think you have sent me in a good direction

This is a great and friendly forum.

[edited by - _TinOmen_ on October 6, 2003 7:06:12 AM]
NP

Everything is better with Metal.

This topic is closed to new replies.

Advertisement