views:

113

answers:

4

This may be the wrong approach, but as I dig deeper into developing my game engine I have ran into a timing issue.

So lets say I have a set of statements like:

for(int i = 0; i < 400; i++)
{
     engine->get2DObject("bullet")->Move(1, 0);
}

The bullet will move, however, on the screen there won't be any animation. It will basically "warp" from one part of the screen to the next.

So, I am thinking...create a vector of function pointers for each base object (which the user inherits from) and when they call "Move" I actually don't move the object until the next iteration of the game loop. So something like:

while(game.running())
{
     game.go();
}

go()
{
     for(...)
          2dobjs.at(i)->action.pop_back();
}

Or something like that, and this way it runs only a single action of each object during each iteration (of course I'll add in a check to see if there is actually "actions" to be ran).

And if that is a good idea, my question is how do I store the parameters. Since each object can do more than a single type of "action" rather than move (rotateby is one example), I think it would be nonsensical to create a struct similar in fashion to:

struct MoveAction {
     MovePTR...;
     int para1;
     int para2;
};

Thoughts? Or is this the completely wrong direction?

A: 

So where does 400 come from? Why not just do it this way:

go()
{
    engine->get2DObject("bullet")->Move(1, 0);
}
Beta
The 400 comes from the programmer who wants to move the bullet 400 pixels after, lets say for example, the user hits the space bar to "fire" a bullet. ie to "fire" it up the screen.
Nathan Adams
+1  A: 

I don't think this is the right direction. After you store 400 moves in a vector of function pointers, you'll still need to pop and perform a move, redraw the screen, and repeat. Isn't it easier just to move(), redraw, and repeat?

I'd say your bullet is warping because it's moving 400 pixels/frame, not because you need to delay the move calculations.

But if this is the correct solution for your architecture, in C++ you should use classes rather than function pointers. For example:

class Action // an abstract interface for Actions
{
public:
    virtual void execute() = 0; // pure virtual function
}

class MoveAction: public Action
{
public:
    MoveAction(Point vel) : velocity(vel) {}
    virtual void execute();
    Point velocity;
    ...
}

std::vector<Action*> todo;

gameloop
{
    ...
    todo.push_back(new MoveAction(Point(1,0))
    ...
}
Lee Reeves
A: 

I think the general approach could be different to get what you want. I personally would prefer a setup where each go loop called functions to set the position for all objects including the bullet, then draw the scene. So each loop it would put the bullet where it should be right then.

If you do decide to go your route, you will likely have to do your struct idea. It's not pleasant, but until we get closures, you'll have to do.

JoshD
+3  A: 

Thoughts? Or is this the completely wrong direction?

It's the wrong direction.

Actually, the idea of being able to queue actions or orders has some merit. But usually this applies to things like AI and to more general tasks (like "proceed to location X", "attack anything you see", etc). So it usually doesn't cover the frame-by-frame movement issue that you're dealing with here.

For very simply entities like bullets, queuing tasks is rather overkill. After all, what else is a bullet going to do except move forward each time? It's also an awkward way to implement such simple motion. It brings up issues like, why only 400 steps forward? What if the area in front is longer? What if its shorter? What if some other object gets in the way after only say 50 steps? (Then 350 queued move actions were a waste.)

Another problem with this idea (at least in the simplistic way you've presented it) is that your bullets are going to move a fixed amount per each iteration of your game loop. But not all iterations are going to take the same amount of time. Some people's computers will obviously be able to run the code faster than others. And even disregarding that, sometimes the game loop may be doing considerably more work than other times (such as when many more entities are active in the game). So you would really want a way to factor in the time that each iteration is taking to adjust the movement and such so that the everything appears to move at a consistent speed to the user, regardless of how fast the game loop is running.

So instead of each movement action being "move X amount" they would be "move at X speed" and would then be multiplied by something like the time elapsed since the last iteration. And then you would really never know how many move actions to queue, because it would depend on how fast your game loop is running in that scenario. But again, this is another indication that queuing movement actions is an awkward solution to frame-by-frame movement.

The way most game engines do it is to simply call some sort of function on the each object each frame which evaluates its movement. Maybe a function like void ApplyMovement(float timeElapsedSinceLastFrame);. In the case of a bullet, it would multiply the speed at which a bullet should move per second by the passed in time since the last frame to determine the amount that the bullet should move this frame. For more complex objects you might want to do math with rotations, accelerations, decelerations, target-seeking, etc. But the general idea is the same: call a function each iteration of the game loop to evaluate what should happen for that iteration.

TheUndeadFish
I think both Lee Reeves said essentially the same thing (using a velocity vs an array of "actions"), but his was a lot smaller to digest (thus easier to understand imo) so I accepted his but I still uped yours.
Nathan Adams