2D game math & more

I've hit a roadblock in my coding. There are a number of things that I don't know how to do:


How do I get things to follow a particular direction/path? eg. getting a bullet to follow a line or getting all enemies to follow the player (I know that direction vectors are the way to go, but I have no clue how to implement them)
__________________________________________________________________________

If I want to reload a gun, or have a particular firing rate, how do I implement this? Obviously, I need to make it impossible to fire for a time period, but how do I calculate this across game ticks?

- I have a rough idea, but no-one to discuss it with, so I don't know whether it's a good idea or not. The plan is to have a timer running from the start of the game, which I can use to compare timings across ticks. eg. If I want a gun to take 2 seconds to reload, I can check the current time (ms since start) and only allow the gun to fire when 2 seconds have passed. The same would be implemented with firing rates.

- I have also heard that limiting frame-rates is a bad idea, and that I should instead calculate how far an object would have moved in the time since the last screen update. Is this necessary for a simple 2D SDL game? And how would I do this if the direction is not just up/down/left/right, but say 80° from north. Or if the distance travelled is not an integer?
__________________________________________________________________________

In displaying and calculating position, should I use a floating point value for the actual position but convert it to an int when displaying it on the screen? This seems like the most sensible idea for displaying something that is moving at an angle, or very slowly, but is it the really the best idea?


Thanks!
Last edited on
I think I can help you with the first question

If you want the bullet to travel at a straight line, you can use the angle of the weapon angle and the speed of the bullet speed

Since you will know the hypotenuse speed and the angle angle the vector will be: (using trigonometry)
1
2
move.x = speed*(cos(angle*PI/180));
move.y = speed*(sin(angle*PI/180));


If however you want it to follow someone, you'll have to send the position of the object to a function that calculates the distance x and y between the target and the object every time the position of the target changes, find the angle using
angle = atan(diff.y/diff.x) * 180 / PI;
and then use
1
2
move.x = speed*(cos(angle*PI/180));
move.y = speed*(sin(angle*PI/180));

to move the object.

also
1
2
#include <cmath>
#define PI 3.14159265 

I hope this helped
Fantastic, thanks a bunch!

Quick question though: is the angle from North, or East? I know that in maths, it is normally clockwise from East, but is it the same in your example?

Also, do you mean += instead of just =?

(Edit: 100th post!)
Last edited on
0 degrees is normally considered facing the top of the screen. North, south, east and west are not used directly in calculating game object positions, they're simply things you can add on the top to show the player to make the game feel more "real".

Maniax is calculating the change in position, which is applied to the position itself after other physics are calculated. Because of that, he would simply use =.
I have also heard that limiting frame-rates is a bad idea, and that I should instead calculate how far an object would have moved in the time since the last screen update. Is this necessary for a simple 2D SDL game? And how would I do this if the direction is not just up/down/left/right, but say 80° from north. Or if the distance travelled is not an integer?

Updating the game physics (positions, velocities, collisions, etc.) in fixed time steps has certain advantages. It becomes more stable. If you have a varying time step the game might feel a bit different when the frame rate is very high compared to a lower frame rate. You could also get problems with collisions if the time step gets very large the objects might move through walls without collision being detected. http://gafferongames.com/game-physics/fix-your-timestep/

How do I get things to follow a particular direction/path? eg. getting a bullet to follow a line or getting all enemies to follow the player (I know that direction vectors are the way to go, but I have no clue how to implement them)
You could keep track of the velocity of the object. In a 2D game you can split the velocity into horizontal and vertical velocity. Each time you update the position of the object you add the horizontal velocity to the x coordinate and vertical velocity to the y coordinate. To make a bullet move at a speed of 5 pixels to the left each update you set the horizontal velocity to -5. If you want acceleration you just add a constant to the velocity each update (assuming acceleration is constant). So to add gravity you just add a positive constant (assuming y grows downwards) to the horizontal velocity each update. This assumes that you update with a fixed time step. Even if the time step is fixed you might want to test different time steps to see and compare. In that case you can use a delta time like they used in the article I linked above. You will then have to use the delta time when calculating how much to update the positions, velocities, etc.

There are ways to make more realistic calculations but what I have described above is fast, easy to implement and often good enough given the update rate is not too small.

If I want to reload a gun, or have a particular firing rate, how do I implement this? Obviously, I need to make it impossible to fire for a time period, but how do I calculate this across game ticks?

- I have a rough idea, but no-one to discuss it with, so I don't know whether it's a good idea or not. The plan is to have a timer running from the start of the game, which I can use to compare timings across ticks. eg. If I want a gun to take 2 seconds to reload, I can check the current time (ms since start) and only allow the gun to fire when 2 seconds have passed. The same would be implemented with firing rates.
Yes you could do that. Another way is to store how much time is left on the reloading and subtract each update. When it reaches 0 the reloading has finished. I don't know if this method is any better than yours.


In displaying and calculating position, should I use a floating point value for the actual position but convert it to an int when displaying it on the screen? This seems like the most sensible idea for displaying something that is moving at an angle, or very slowly, but is it the really the best idea?
Using floating point numbers sounds like a good idea. Of course it depends on the game and I can think of a few situations when I would prefer to use integers.
Well
1
2
move.x = speed*(cos(angle*PI/180));
move.y = speed*(sin(angle*PI/180));

but
1
2
position.x += speed*(cos(angle*PI/180));
position.y += speed*(sin(angle*PI/180));
Last edited on
Eh, stuff's gonna go here just to check I didn't get anything wrong:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<cmath>
#define PI 3.14159265

struct rect
{
    float x, y;
};

float angle(Player* p, Enemy* e)
{
    rect diff;

    diff.x = ((p.x > e.x) ? p.x - e.x : e.x - p.x);
    diff.y = ((p.y > e.y) ? p.y - e.y : e.y - p.y);

    return atan(diff.y / diff.x) * 180 / PI;  
}
Last edited on
Peter, thanks for the response.

___________________________________________________________

What I'm thinking about framerates, is that I want the game to run as though it's at 60 fps. However, I don't want to physically limit the framerate to 60 by using a short delay every loop, since there's nothing I can do when the fps drops below 60.

What I'd rather do is say, for example, that at 60fps, the player moves at 1 pixel per frame. Then I can use a float for the distance travelled each frame, and calculate this by multiplying the speed by the time taken / (1/60).

This would mean that if the game is running at 120fps (and so the game is looping every 1/120 of a second) then the distance the player moves in that frame is halved. Over two frames (and, in this case, the time at 60fps for 1 frame), the player will move exactly the same distance as 1 frame at 60fps. Using a float for position is the only way of doing this, if the speed is 1 (for example). Otherwise the player would never move.

________________________________________________________

I should note that this game would be a top-down game, so gravity doesn't matter.

I could split a bullet's velocity into horizontal and vertical (and calculate it's new position as above), but if, say, the gun is being aimed by the mouse, then I would have to calculate these velocities based on the angle. This would be harder for me than simply drawing the angle and calculating new positions based on it (including total velocity).

_______________________________________________________

In terms of reloading, (and also timing for everything) this seems easier. Would you mean beginning a timer at the start of every loop and checking how long has passed at the end (before passing the time on to some variable, for the next loop through)? Do you think this would make more sense than having a timer running constantly and setting it to 0 at the start of every loop? I don't know why this was my original idea, maybe I just didn't like the though of lots of different timer initializations.

__________________________________________________________

Thanks for the advice!

Maniax, my mistake. I thought that move was just an example object, not the distance moved in each axis.
When making a 2D or 3D game it can be very helpful to have your own vector class. Take for instance shooting a gun where ever your mouse is:

1
2
3
4
5
6
7
8
9
10
11
12
13
int speed = 10;

//get the line between the two points
vector2 direction = player->position - mouse->position;

//normalize that line
direction.normalize()

//create new bullet
Bullet bullet = new Bullet(player->position);

//apply the direction scaled by speed
bullet->setVelocity(direction * speed); 


Some of the accompanying code for the vector class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Other code...
vector2 vector2::operator- (const vector2 &rhs)
{
    x -= rhs.x;
    y -= rhs.y;
    return vector2(*this);
}

vector2 vector2::operator* (const double &rhs)
{
    x *= rhs;
    y *= rhs;

    return vector2(*this);
}

void vector2::normalize()
{
    //normalizing a line makes the x, y, (z)
    //components < 1 making their magnitude (a^2 + b^2 = c^2)
    //equal 1
    double length = sqrt(x*x+y*y);
    x = x/length;
    y = y/length;
}
// More code...   


since the normalized direction has a length of 1 multiplying it by a scalar(speed) it will scale the x and y axis to achieve the speed and direction desired for your bullet.

I'm sure you can find larger examples of vector2/3 somewhere. If you'd like more code snippets or examples let me know.
Last edited on
Just out of interest, why are you using a pointer to player and mouse?

I use dynamic memory for everything in my framework. The only time I ever use something as an object is when I'm using something for temporary storage. It helps to speed up vector iteration.

To help put it in perspective my mouse would be accessed by my input singleton: gDirectInput->getMouseX(); / gDirectInput->getMouseX();

and then for game objects I have a singleton world manager, WMI, that's in charge of adding elements.

1
2
//in main loop or any other function
Player *player1 = WMI->add(new Player(vector3(x, y, z));


1
2
3
4
5
6
7
8
//in WMI
BaseEntity* WorldManager::add(BaseEntity* newEntity)
{
    //vector<BaseEntity*> m_entityVec
    m_entityVec.pushBack(newEntity);

    return newEntity;
}


So in my main code I now have a pointer to my player and a pointer in a vector of entities so I can loop through them and update their physics / graphics / etc by just calling WMI->update(); AND use my player1 pointer in main however I want and still be accessing the same data that the vector is pointing to.

Words cannot express how much I love pointers. Just be sure to delete them; when you're done.

By the way BaseEntity is the object all of my game entities inherit off of. That way I can store them in the same arrays.
Last edited on
That's basically my idea with enemies. I can store them all in a vector and iterate through them every game loop to check for collision etc.

Then I can delete them if they die.

However, my vector only stored objects of enemy type, and instead of using new and then delete I would simply erase the dead enemy.
Last edited on
Seems solid to me man.

Try looking into making a baseEntity class that has all of your game entities inheriting off of it. Make pure virtual functions like render, and update. I usually have my game system running off of unique IDs.

Like so:
1
2
3
4
5
BaseGameEntity::BaseGameEntity(){
    static int nextID = 0;
    this->m_ID = nextID;
    nextID++;
}


example Base Entity header:
1
2
3
4
5
6
7
8
9
10
11
12
class BaseGameEntity{
private:
    int m_ID;
public:
    BaseGameEntity();
    ~BaseGameEntity();

    virtual void render() = 0;
    virtual void update() = 0;

    int getID();
};


example enemy header:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Enemy : BaseGameEntity(){
private:
    int m_health;
    vector3 m_position;

public:
    Enemy(vector3 position, int health);

    void render(); //render function defined in enemy
    void update(); //update physics here

    vector3 getPosition();
    int getHealth();
};


WIth a common BaseGameEntity you can have one vector to loop through:

1
2
3
4
5
6
7
8
9
10
11
12
vector<BaseGameEntity*> m_entityList;

m_entityList.push_back(new Player(...));
m_entityList.push_back(new Enemty(...));

for(vector<BaseGameEntity*>::iterator i = m_entityList.begin(); i != m_entityList.end(); i++)
{
    (*i)->update();
    (*i)->render();
}



So when I create an enemy, player or any other object that needs to be iterated through they will now have a unique ID associated with them. This ID is also assigned to the accompanying DirectX graphic so the physics object, graphics object and game object are now linked through a common ID.

The IDs come in real handy if you start building an EntityManager which utilizes a map. the mapped values would be ID and a pointer IE: map<int, BaseEntity*>;

I normally have a RigidBody class in between the BGE and enemy / player stuff. It's up to you how you'd break up your physics object information and game / render information.

I like that you're moving towards pointers. Keep it up man :)

Sorry if a lot of this is not new to you and I'm preaching to the choir. This topic gets me excited since I'm going to school for it.
Topic archived. No new replies allowed.