GPWiki.org
GPWiki.org
It is currently Thu May 23, 2013 11:17 pm

All times are UTC




Post new topic Reply to topic  [ 20 posts ] 
Author Message
PostPosted: Thu Mar 15, 2012 6:19 am 
Bytewise

Joined: Sun Oct 16, 2011 3:09 pm
Posts: 277
Location: Here (where else?)
My first new topic :p

I am attempting to make my game a bit more alive, with animated people walking around.
That lead to the problem of managing many animations, each needing an update after some ticks (potentially different for each animation).
Currently, I am deciding on the central structure to use. (Which is sort of an ad-hoc decision, is this sane?)

As a first solution, I thought of using a cyclic buffer, and a callback structure.
Code:
/** Abstract base class of a callback when a tick count has been reached. */
class TickCallback {
public:
   TickCallback();
   virtual ~TickCallback();
   void TickReached() = 0;
   TickCallback *next; ///< Next callback in the chain (managed by #TickManager).
};
Derived versions of this class receives the callback when the time has passed.

The manager itself:
Code:
class TickManager {
public:
   TickManager();
   ~TickManager();

   void Tick();
   void Add(TickCallback *cb, int num_ticks);

private:
   TickCallback *ticks[TICK_BUFFERSIZE]; ///< Tick buffer.
   uint16 head;                               ///< Index in #anims to current tick.
};
Where '(head + x) % TICK_BUFFERSIZE' is called at x ticks from now.

The Tick() and Add() code is fairly trivial:
Code:
void TickManager::Tick()
{
   this->head = (this->head + 1) % TICK_BUFFERSIZE;
   TickCallback *cb = this->ticks[this->head];
   if (cb != NULL) {
      this->ticks[this->head] = NULL; // New callbacks may get added on TickCallback::TickReached calls.
      do {
         TickCallback *next = cb->next;
         cb->TickReached();
         cb = next;
      } while (cb != NULL);
   }
}

void TickManager::Add(TickCallback *cb, int num_ticks)
{
   assert(num_ticks > 0 && num_ticks <= TICK_BUFFERSIZE);
   uint16 idx = (this->head + num_ticks) % TICK_BUFFERSIZE;

   cb->next = this->ticks[idx];
   this->ticks[idx] = cb;
}
Code has not been compiled yet, but I hope the idea is clear.
You register a callback, and after from x ticks, TickReached() gets called, since at each tick, Tick() gets called.

One nice thing I noticed is that this is more generic than just animations. Basically anything that needs ticks passed can be done in this way.

Is this a useful solution?
Are there better ones, and/or are there things I should watch out for?
(An obvious alternative is to have a list of persons, and iterate over them each tick, but how would that compare with this solution, where the TickManager calls each person after some x ticks?)

_________________
My project: Messing about in FreeRCT, dev blog, and IRC #freerct at oftc.net


Top
 Profile  
 
PostPosted: Thu Mar 15, 2012 1:04 pm 
Funky Monkey

Joined: Thu Sep 09, 2004 1:17 pm
Posts: 1552
Location: burrowed
Interesting solution. This is more of a timer, as you already realized, a very basic thing a game framework should have.
When you are talking about ticks however it appears as if you are currently managing your animations by mainloop cycles as opposed to time based.
This can work on restricted or closed systems like consoles or if you force and clamp your max cycles per second to a certain amount, but even then you will run into problems.
In fact there's no ultimate solution for timers, but there are better approximations for a more stable simulation.
The main problem is as soon as you have more or less frames, say by running it on another pc, the animation gets either slower or faster. This is what some old dos games did.

(further read: http://gafferongames.com/game-physics/fix-your-timestep/)

How you set your timing up however is intirely up to you. If you are comfortable with a callback you can sign in with each object, thats fine.
The regular way to solve this is that each object has an update method which is periodically called by the game engine, and the time passed is identified by either a deltaTime (time passed from last tick to current tick) or totalTime.

Code:
if((counter += deltaTime) >= animationframetime)
{
  newAnimationFrame();
  animationframetime += animationframeduration;
  counter = 0;
}

_________________
Long pork is people!

wzl's burrow


Top
 Profile  
 
PostPosted: Thu Mar 15, 2012 2:47 pm 
Harmlessness does no harm
User avatar

Joined: Tue Sep 14, 2004 8:37 pm
Posts: 3809
Location: Ferriday, LA, US
weezl wrote:
The regular way to solve this is that each object has an update method which is periodically called by the game engine, and the time passed is identified by either a deltaTime (time passed from last tick to current tick) or totalTime.

Code:
if((counter += deltaTime) >= animationframetime)
{
  newAnimationFrame();
  animationframetime += animationframeduration;
  counter = 0;
}

This is typically the way it is done (though the code above would be better-implemented with at least some way to make up for missed frames, rather than strictly incrementing the frame).

One method I've found neat is to use a percentage-based time mechanism. This might be a useful approach for animations that may need to be sped up or slowed down (either in the game, or to make previewing your animations easier). Basic idea is that instead of using milliseconds (or similar) as the frame delta, you only use milliseconds to specify the animation duration. You divide the current time (as in time between when the animation was started, and this update) by total animation time to get your delta (between 0 and 1 -- min/max would help ensure this).

Using this method, you can do a lot of tricks. If you want to use an entire sprite sheet to specify all the frames of an animation, just count the total number of frames, and multiply it by the time delta fed to your animation update -- and, assuming your animation runs at a constant frame-rate (i.e. the animation is designed so that each frame can use the same time delay and look as it is intended), that's pretty much all the setup required. You could also very easily use it for handling transitions (i.e. a glowing highlight) -- specify a "start" color and a "highlight" color, then interpolate between the two by multiplying the difference by the delta (which, if you will remember, is between 0 and 1).

I have yet to find anything animation-wise that cannot be accomplished by this method -- and it has really cool benefits.

_________________
What most people don't understand about "enlightenment" is that it is not an end-goal; but where you find yourself just before taking a new "first step."


Top
 Profile  
 
PostPosted: Thu Mar 15, 2012 3:42 pm 
Funky Monkey

Joined: Thu Sep 09, 2004 1:17 pm
Posts: 1552
Location: burrowed
rotInMilc wrote:
(though the code above would be better-implemented with at least some way to make up for missed frames, rather than strictly incrementing the frame).



Yep, i wanted to keep it as simple as possible, but i guess it wouldn't hurt to also show a method that is regarding frameskipping or other wise hiccups

Code:
if(counter >= totalTime)
{
  NewFrameAnimation();
  counter += animationframeduration;
}


Though, i guess this is simpler after all :P

_________________
Long pork is people!

wzl's burrow


Top
 Profile  
 
PostPosted: Thu Mar 15, 2012 6:07 pm 
Source Code Swashbuckler
User avatar

Joined: Wed Nov 09, 2011 3:58 am
Posts: 199
Location: Brazil
weezl wrote:
The regular way to solve this is that each object has an update method which is periodically called by the game engine, and the time passed is identified by either a deltaTime (time passed from last tick to current tick) or totalTime.

Code:
if((counter += deltaTime) >= animationframetime)
{
  newAnimationFrame();
  animationframetime += animationframeduration;
  counter = 0;
}

I agree with you, furthermore, Alberth will need to call the Timer Function(in Windows, SetTimer) inside the main loop. But timer functions gauge by milliseconds, does anyone knows how to, instead of use milliseconds, use frame/second?

_________________
"Life finds a way." - Ian Malcolm
My WebBlog: PixelDeveloper
English is not my native language, so excuse me for any writing mistakes.


Top
 Profile  
 
PostPosted: Thu Mar 15, 2012 8:22 pm 
Bytewise

Joined: Sun Oct 16, 2011 3:09 pm
Posts: 277
Location: Here (where else?)
Thanks all for the replies!

weezl wrote:
Interesting solution. This is more of a timer, as you already realized, a very basic thing a game framework should have.
Yeah, it surprised me a bit. I started with an animation delay manager, but after I coded it, I realized I could hook other timing stuff in it as well, such as passage of game-time, and blinking of cursors, so I removed all animation-specific stuff from it again :)
The only thing that still indicates its origin, is the name of the file (animations.cpp :) ).

What worries me a bit about the cyclic buffer is that you have distributed state now, namely the person (that knows what to display), and a callback (that manages time-delays).
On the other hand, you don't have to do anything for all the animations that have more ticks to wait, which could be a huge advantage.
(But is this a significant saving? I probably will have to measure it once it is running with a filled park before I know.)

weezl wrote:
When you are talking about ticks however it appears as if you are currently managing your animations by mainloop cycles as opposed to time based.
This can work on restricted or closed systems like consoles or if you force and clamp your max cycles per second to a certain amount, but even then you will run into problems.
In fact there's no ultimate solution for timers, but there are better approximations for a more stable simulation.
The main problem is as soon as you have more or less frames, say by running it on another pc, the animation gets either slower or faster. This is what some old dos games did.
I do have a timer that injects a user-event in a quite simplistic SDL event-loop every 30msecs. Each user-event triggers a Tick(). 33.3Hz is a very weird tick-rate, which is basically a combination of me wanting something around 30 frames/second, and SDL needing multiples of 10msecs for the timer (in the simplistic setup that I use at the moment).
I will do some experiments (probably with a better setup) once the game has some more shape.

Due to the timer, more frames on a faster PC are not likely to happen. (In fact, the game currently is mostly idle at my system, waiting for input from the keyboard/mouse.) Less frames is indeed still possible, as you mention.

weezl wrote:
Ooh, nice article. Just what I needed, I was wondering about that! Thanks, /me bookmarked it until it is time to consider coaster physics in more detail.

weezl wrote:
The regular way to solve this is that each object has an update method which is periodically called by the game engine, and the time passed is identified by either a deltaTime (time passed from last tick to current tick) or totalTime.

Code:
if((counter += deltaTime) >= animationframetime)
{
  newAnimationFrame();
  animationframetime += animationframeduration;
  counter = 0;
}
The nice thing about this solution (or a more fine-grained variant of it) is that you can very precisely define how much time should progress, something which is much more difficult with my solution, as you have fixed slots.

Something to ponder about.... :)

rotInMilc wrote:
One method I've found neat is to use a percentage-based time mechanism. This might be a useful approach for animations that may need to be sped up or slowed down (either in the game, or to make previewing your animations easier). Basic idea is that instead of using milliseconds (or similar) as the frame delta, you only use milliseconds to specify the animation duration. You divide the current time (as in time between when the animation was started, and this update) by total animation time to get your delta (between 0 and 1 -- min/max would help ensure this).
Cool idea, each time you compute the fraction of the animation (in time), and use that as index in the animation frames.

The only case where this may become tricky is when you have frames with unequal display times, but I agree that is a pretty unlikely edge-case. (And even then, it can easily be solved with a bisection on the summed fractions (ie frame n gets the summed fractions of frames 1 .. n as value).

FelipeFS wrote:
I agree with you, furthermore, Alberth will need to call the Timer Function(in Windows, SetTimer) inside the main loop. But timer functions gauge by milliseconds, does anyone knows how to, instead of use milliseconds, use frame/second?
No Windows here ("look ma, I have windows without Windows!" :p ), but SDL also provides a timer. However, at multiples of 10msec, it lacks fine control on tick-rate. I have seen other SDL methods where you process all inputs, and then delay for the remaining time. That may work better, I will need to experiment when I have some more game running.

The conversion from frames/second to milliseconds is actually very simple, it's 1000 / f (where f is frames/second).
The reasoning is as follows: If you have f frames each second, you have f frames each 1000 milliseconds. 1 frame then takes 1000 / f milliseconds (assuming each is equally long.

_________________
My project: Messing about in FreeRCT, dev blog, and IRC #freerct at oftc.net


Top
 Profile  
 
PostPosted: Thu Mar 15, 2012 9:47 pm 
Harmlessness does no harm
User avatar

Joined: Tue Sep 14, 2004 8:37 pm
Posts: 3809
Location: Ferriday, LA, US
Alberth wrote:
rotInMilc wrote:
One method I've found neat is to use a percentage-based time mechanism. This might be a useful approach for animations that may need to be sped up or slowed down (either in the game, or to make previewing your animations easier). Basic idea is that instead of using milliseconds (or similar) as the frame delta, you only use milliseconds to specify the animation duration. You divide the current time (as in time between when the animation was started, and this update) by total animation time to get your delta (between 0 and 1 -- min/max would help ensure this).

Cool idea, each time you compute the fraction of the animation (in time), and use that as index in the animation frames.

The only case where this may become tricky is when you have frames with unequal display times, but I agree that is a pretty unlikely edge-case. (And even then, it can easily be solved with a bisection on the summed fractions (ie frame n gets the summed fractions of frames 1 .. n as value).


Exactly -- and it helps that, once you have that bisection, you can increase/reduce the duration of the sequence -- and the animation still plays "correctly." No need to fiddle with the delay times for each individual case should you decide to have an animation that runs at varying speeds. :)

Alberth wrote:
FelipeFS wrote:
I agree with you, furthermore, Alberth will need to call the Timer Function(in Windows, SetTimer) inside the main loop. But timer functions gauge by milliseconds, does anyone knows how to, instead of use milliseconds, use frame/second?
No Windows here ("look ma, I have windows without Windows!" :p ), but SDL also provides a timer. However, at multiples of 10msec, it lacks fine control on tick-rate. I have seen other SDL methods where you process all inputs, and then delay for the remaining time. That may work better, I will need to experiment when I have some more game running.

The conversion from frames/second to milliseconds is actually very simple, it's 1000 / f (where f is frames/second).
The reasoning is as follows: If you have f frames each second, you have f frames each 1000 milliseconds. 1 frame then takes 1000 / f milliseconds (assuming each is equally long.

I don't understand why one would want to use the FPS count to time animations... It just doesn't seem like a very accurate method for tracking/managing animations. Am I missing something?

_________________
What most people don't understand about "enlightenment" is that it is not an end-goal; but where you find yourself just before taking a new "first step."


Top
 Profile  
 
PostPosted: Fri Mar 16, 2012 4:50 pm 
Source Code Swashbuckler
User avatar

Joined: Wed Nov 09, 2011 3:58 am
Posts: 199
Location: Brazil
rotInMilc wrote:
I don't understand why one would want to use the FPS count to time animations... It just doesn't seem like a very accurate method for tracking/managing animations. Am I missing something?

Sometimes it is good, when you want a fixed framerate.
Alberth wrote:
The conversion from frames/second to milliseconds is actually very simple, it's 1000 / f (where f is frames/second).
The reasoning is as follows: If you have f frames each second, you have f frames each 1000 milliseconds. 1 frame then takes 1000 / f milliseconds (assuming each is equally long.

As far I know, there is a variable(the computer processing speed) that you must put in this equation, I just don't remember where.

_________________
"Life finds a way." - Ian Malcolm
My WebBlog: PixelDeveloper
English is not my native language, so excuse me for any writing mistakes.


Top
 Profile  
 
PostPosted: Fri Mar 16, 2012 6:02 pm 
Dexterous Droid
User avatar

Joined: Wed Aug 18, 2004 7:40 pm
Posts: 3735
Location: South Africa
weezl wrote:

This article is gold, ingest its deep wisdom! You don't need to be running physics to benefit from using a fixed timestep, just chuck out the bit about integrating between states and keep everything else that fixes the timestep of updates. I would recommend you abandon the callbacks and use a fixed timestep to keep your animations running smoothly. It should be left up to each individual object to update its state based on information available to it. So supply it with the fixed deltaTime value via an update function. Let everything inherit from Updatable with a void update(float deltaTime). In your game loop you check if stuff must be updated yet and call update on everything if it does.

A general comment I have regarding "BlahManager" classes is that they've often got bad design. This arises from one of two reasons, as far as I can tell, either:
1) the programmer is not thinking in OO and has blobs of data called Blah that he is manipulating with BlahManager (instead of letting each object do it's own thing via methods) [see TickCallback *next; ///< Next callback in the chain (managed by #TickManager).]
or,
2) the programmer didn't have a clear enough idea of what the class was trying to achieve and it ended up with the highly generic Manager title. I think this is maybe applicable to what you've created.

The code you've outlined is highly general purpose, even though you set out to create something for animation timing. Now if and when you start doing more things with your class, you will end up widening the class's responsibility. Making any changes to it becomes harder and harder. Say you want to start running AI logic with this class. Now a GameObject which has inherited TickCallback for animation purposes has to hack the method to add in stuff to check whether the callback is getting called because of an AI reason or an animation reason.

That leads onto another issue: abusing inheritance. Inheritance should only be used in is-a relationships. You're abusing it because you're wanting access to private information of the various objects in order to execute the callback. Only you're hiding the fact that you're breaking encapsulation by forcing the classes to inherit from TickCallback. What's actually happening is that TickManager is manipulating objects' private data that it shouldn't know anything about, albeit in a dynamic and extensible way.

Minor gripe: using this-> is making your code harder to read. It's unnecessary given the scope and lack of name conflicts.

Another minor gripe: your TickCallback is an abstract class, which means everything that wants to make use of timing functions is going to end up with a VTABLE lookup hit every time Tick() is called. This is probably going to make no difference to performance, but it feels wrong and unnecessary.

I think your solution is overly complex. "Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." ~ Brian Kerrighan. You set TickCallback *cb = this->ticks[this->head] but then don't use cb on the next line where you set the head to NULL. Then you say TickCallback *next = cb->next; which would segfault.

C++ is very complicated and some of the stuff I've said might be wrong. I've tried to double check it as much as possible though.


FelipeFS wrote:
As far I know, there is a variable(the computer processing speed) that you must put in this equation, I just don't remember where.

I think you're thinking about QueryPerformanceCounter, which is used in conjunction with QueryPerformanceFrequency from what I can remember. The conversion between time per frame and frames per second is exactly as mentioned before.

PS: here's my gameloop, simple but works
Code:
void Game::run(){
    float gametime = 0.0;
    while (window->IsOpened()){
        // Process events
        sf::Event Event;
        while (window->GetEvent(Event)){
            if (Event.Type == sf::Event::Closed) // Close window : exit
                window->Close();
        }
      // Run as many game frames according to how much time has passed
      gametime += window->GetFrameTime();
      if (gametime > 0.5) gametime = 0.5; //we put a cap incase of alt-tab or other lock-up (e.g. debug)
      while (gametime > 0){
         gametime -= tickLength;
         update();
      }
      // Render the frame once all updating is complete
      draw();
    }
}

_________________
Whatever the mind can conceive and believe, it can achieve


Top
 Profile  
 
PostPosted: Fri Mar 16, 2012 7:15 pm 
Funky Monkey

Joined: Thu Sep 09, 2004 1:17 pm
Posts: 1552
Location: burrowed
I have actually experimented quite a lot with game timing and still have not found a solution that gives 100% stable results yet. It is after all a highly complex topic where the outcome is influenced by the duration of your update cycles, render cycles and maybe your idle/sleep times;

The way i currently run my loop (which so far seems stable) is

Code:
while(run)
{
  updateCount += deltaTime; // deltatime will be capped internally to 0.25s

  while(updateCount > updateTime) // Loop to make up for missed frames
  {
    updateCount -= updateTime; // decrease by the fixed update frametime (nothing to do with the actual render times)
    Update(); //Updates everything

    if(!rendered)
    {
      Render(); // Render everything to the buffer only once
      rendered = true;
    }
  }

  if(rendered) // I experimented with manually checking for static frame times but it currently runs as VSync
  {
    SwapBuffers(); // Actually swapping the backbuffer to the front
    rendered = false;
  }
}


The main reason the actual rendering happens in the update is so the swapping that actually waits for vsync doesn't drop if a frame render takes longer than it can actually fit it into the current vsync rate. It's kinda odd and i'm likely to change it (as soon as someone hits me with a bat :P) when i know a better alternative. But it produces stable physics and a solid framerate from what i can tell.

_________________
Long pork is people!

wzl's burrow


Top
 Profile  
 
PostPosted: Sat Mar 17, 2012 2:32 pm 
Bytewise

Joined: Sun Oct 16, 2011 3:09 pm
Posts: 277
Location: Here (where else?)
More discussions! Great!

rotInMilc wrote:
I don't understand why one would want to use the FPS count to time animations... It just doesn't seem like a very accurate method for tracking/managing animations. Am I missing something?
It is entirely possible that my ideas are totally wrong.

You (and others here as well) seem to link animations to the real time, in one way or another.
That is a very good idea, it seems better than my idea of slowing down the entire game if the cycle time becomes too long.


FelipeFS wrote:
As far I know, there is a variable(the computer processing speed) that you must put in this equation, I just don't remember where.
That sounds like the next problem you have after deciding that you have x milli seconds for each frame. How do you divide those x milli seconds between input processing, updating game state, rendering, and (possibly) idling?
For idling, you need to know much time is taken for the other activities. Perhaps that is what you were aiming at?


IGTHORN wrote:
weezl wrote:

This article is gold, ingest its deep wisdom! You don't need to be running physics to benefit from using a fixed timestep, just chuck out the bit about integrating between states and keep everything else that fixes the timestep of updates.
I read it, and it is indeed very clear. I definitely want to use it for my physics (including the interpolation, it sounds like fun to build it :) ).
For animations, a similar system would be useful I think. I just need to wrap my head around it.


IGTHORN wrote:
I would recommend you abandon the callbacks and use a fixed timestep to keep your animations running smoothly. It should be left up to each individual object to update its state based on information available to it. So supply it with the fixed deltaTime value via an update function.
This is simpler, and you don't distribute state, which is good.
My callback system is mostly about avoiding update of some internal timer of each object, which you very quickly do in more than 50% of the cases. That is a lot of mostly useless memory access if you have a 1000+ game objects wandering around.


IGTHORN wrote:
Let everything inherit from Updatable with a void update(float deltaTime). In your game loop you check if stuff must be updated yet and call update on everything if it does.
Haha, and then you continue with how bad it is to abuse inheritance :D

IGTHORN wrote:
1) the programmer is not thinking in OO and has blobs of data called Blah that he is manipulating with BlahManager (instead of letting each object do it's own thing via methods) [see TickCallback *next; ///< Next callback in the chain (managed by #TickManager).]
I am well aware of sneaking in foreign data here, but to me this really means "don't you dare touch it, object!". It exists so I can make a poor man's list out of the objects, without having to create a full-blown list<TickCallback *> at every point in the array.
(ie it is piggy-backing some inter-object management data onto the object, the object is not touching 'next, and the manager is not touching data of the object).

'Manager' for me is strictly inter-object business, as well as storage/retrieval of collections of objects, and dispatching calls from the environment to the right object. Like you say, it is not doing the job of the objects.


IGTHORN wrote:
2) the programmer didn't have a clear enough idea of what the class was trying to achieve and it ended up with the highly generic Manager title. I think this is maybe applicable to what you've created.
To some extent that is certainly true. The whole point of this thread is to figure out a good way to handle many animated objects at the same time.
(Which is working very nicely, I must say. Thanks guys for all the feedback you are providing. It's very useful and much appreciated.)

The class is indeed very generic, which came as surprise to me. It caused me to reconsider the structure of the classes. Not by extending the responsibilities, but by shifting animation more to the objects themselves, so this tick-manager gets room to do just tick-handling (and nothing more).

I have been playing the OO game long enough to know that you should keep responsibilities at the right place, and that you cannot simply 'add' responsibilities.


IGTHORN wrote:
The code you've outlined is highly general purpose, even though you set out to create something for animation timing.
Yeah, at which point I concluded I created something else than my objective, and I started wondering how others do this. I had a quick peek at the GPWiki, but could not find a discussion quickly, so I ended up posting here :)

Now if and when you start doing more things with your class, you will end up widening the class's responsibility. Making any changes to it becomes harder and harder. Say you want to start running AI logic with this class. Now a GameObject which has inherited TickCallback for animation purposes has to hack the method to add in stuff to check whether the callback is getting called because of an AI reason or an animation reason.

IGTHORN wrote:
That leads onto another issue: abusing inheritance. Inheritance should only be used in is-a relationships. You're abusing it because you're wanting access to private information of the various objects in order to execute the callback. Only you're hiding the fact that you're breaking encapsulation by forcing the classes to inherit from TickCallback. What's actually happening is that TickManager is manipulating objects' private data that it shouldn't know anything about, albeit in a dynamic and extensible way.
I assume this is about 'next', right?
I explained that above already.

I thought about 'abuse of inheritance' this morning before getting up, and I think the issue is somewhat different.
In Java, you'd write an interface for this (not sure whether you can add data in an interface, but let's assume you can), and implement that interface for all objects (much like you propose with 'Updatable'). In C++ however, inheritance is not only pure inheritance (as it is in newer languages), it may also be used for the notion of 'interface'. Stroustrup already sees abstract base classes as interfaces or contracts.
So technically, my base class is a proper solution. However, I fully agree with you that it is not one I should be proud of. Multiple inheritance gets very complicated very quickly, so you want to avoid it as much as possible.


IGTHORN wrote:
Minor gripe: using this-> is making your code harder to read. It's unnecessary given the scope and lack of name conflicts.
True, but I have to come to like explicitness where things are coming from. Blame it on programming Python for too long, as well as other C++ projects :p

IGTHORN wrote:
Another minor gripe: your TickCallback is an abstract class, which means everything that wants to make use of timing functions is going to end up with a VTABLE lookup hit every time Tick() is called. This is probably going to make no difference to performance, but it feels wrong and unnecessary.
And doing your own administration is faster, is less error prone, and feels better???

For a generic class, it is the right solution, I think.


The question is whether the solution is the right answer to the problem. The answer seems to be mostly 'no'. The only thing stopping it from dropping out of sight completely is the fact that I don't like updating several hundred timer counters each update cycle just because I didn't organize my animated objects in a saner way.

IGTHORN wrote:
I think your solution is overly complex.
It is certainly more complex. What I find difficult to decide is whether it is worth the gain in CPU time.

Perhaps I should stop worrying, and just what you suggest. At least as initial version it will work, and perhaps even longer :p

IGTHORN wrote:
You set TickCallback *cb = this->ticks[this->head] but then don't use cb on the next line where you set the head to NULL. Then you say TickCallback *next = cb->next; which would segfault.
I would hope not. Note that 'ticks' is an array of pointers, so I should be clearing a pointer, not the object itself.

IGTHORN wrote:
C++ is very complicated and some of the stuff I've said might be wrong. I've tried to double check it as much as possible though.
And your efforts are appreciated (just like your entire post btw).


Also, thank both you and weezl for posting the game-loop. They will come in handy when hooking the animations into the main loop.
(It looks like it's time to ditch the fixed rate game loop :D )

Albert

_________________
My project: Messing about in FreeRCT, dev blog, and IRC #freerct at oftc.net


Top
 Profile  
 
PostPosted: Sat Mar 17, 2012 2:44 pm 
Funky Monkey

Joined: Thu Sep 09, 2004 1:17 pm
Posts: 1552
Location: burrowed
Just a quick mention:
You don't need to manage your time on a per-object base. Just have them stored once in your game class or as a seperate Timer class that is updated every game cycle. How you actually implement the access to those objects would be up to you.
One way is to pass delta and totaltime as arguments in your Update() procedure.
I use a static class Time {} for it, so it can be accessed from anywhere so if i need the time at anypoint in the game i just ask for Time.Delta or Time.Total.
You can come up with something entirely different though. Just use what feels intuitive :)

_________________
Long pork is people!

wzl's burrow


Top
 Profile  
 
PostPosted: Sat Mar 17, 2012 2:54 pm 
Bytewise

Joined: Sun Oct 16, 2011 3:09 pm
Posts: 277
Location: Here (where else?)
Good idea!

The problem with 'inutitive' is that thinking outside the box is so difficult.
That is why I like this discussion so much; different people have so many nice ideas that I would never invent :D

Thanks, Albert

_________________
My project: Messing about in FreeRCT, dev blog, and IRC #freerct at oftc.net


Top
 Profile  
 
PostPosted: Sat Mar 17, 2012 3:17 pm 
Harmlessness does no harm
User avatar

Joined: Tue Sep 14, 2004 8:37 pm
Posts: 3809
Location: Ferriday, LA, US
Alberth wrote:
FelipeFS wrote:
As far I know, there is a variable(the computer processing speed) that you must put in this equation, I just don't remember where.
That sounds like the next problem you have after deciding that you have x milli seconds for each frame. How do you divide those x milli seconds between input processing, updating game state, rendering, and (possibly) idling?
For idling, you need to know much time is taken for the other activities. Perhaps that is what you were aiming at?

Basically, the way things are typically done, you measure time between frames, rather than the time between each function that is executed between frames.

When you run a loop iteration, you start off by getting the time at the end of the previous iteration (after all processing/rendering). Then you use that as an argument to your processing functions. When everything is processed and rendered, you simply go to the next iteration (which will update based on the time elapsed in processing this iteration).

It isn't perfect accuracy, but is adequate. Computers are more complex than they used to be, where one could simply not factor timing in at all, and still be able to expect a game to run at a predictable framerate. We have a world of differing instruction-processing speeds/bandwidths, not to mention environments that run hundreds of background services that, at any time, may request CPU cycles. This makes it much more difficult -- if not impossible -- to get a "perfect" timing method for games.

_________________
What most people don't understand about "enlightenment" is that it is not an end-goal; but where you find yourself just before taking a new "first step."


Top
 Profile  
 
PostPosted: Sun Mar 18, 2012 6:23 am 
Dexterous Droid
User avatar

Joined: Wed Aug 18, 2004 7:40 pm
Posts: 3735
Location: South Africa
Alberth wrote:
IGTHORN wrote:
You set TickCallback *cb = this->ticks[this->head] but then don't use cb on the next line where you set the head to NULL. Then you say TickCallback *next = cb->next; which would segfault.
I would hope not. Note that 'ticks' is an array of pointers, so I should be clearing a pointer, not the object itself.

Ah yeah, you're right :) Should have had a more careful look at the code.

_________________
Whatever the mind can conceive and believe, it can achieve


Top
 Profile  
 
PostPosted: Mon Dec 24, 2012 12:48 am 
Lord of Cheesecakes

Joined: Sun Jun 24, 2012 12:49 am
Posts: 341
Sorry, I think I'm late to the party.

gafferongames.com is pretty good. Thanks for the link. I'm enjoying this introduction to integration for game physics:

http://gafferongames.com/game-physics/i ... on-basics/

I guess this makes my post extremely off-topic, but I don't have anything else to say. I'll try a stab then:

Quote:
Is this a useful solution?

I'd say your approach to this looks a bit strange to me. I don't really understand the purpose of it. So... Why can't you just cycle through an array of frame images? Sumtin regarding performance? I have no clue.

Code:
struct AnimatedSprite
{
   void Draw(float x, float y, float startTime);

   Image* imageSet;
   uint imageQ; // 'Q' in my identifiers always = 'quantity'

   float frameDuration;
};

void AnimatedSprite::Draw(float x, float y, float startTime)
{
   imageSet[FastFloatToInt(fmod((Time::GetTime() - startTime) / frameDuration, imageQ))]->Draw(x, y);
}


If it has something to do with performance regarding instances, then I recommend you create a rendering job utility which renders in batches and provides controllable depth by employing the Z-buffer in an orthographic view.

This is relevant: http://http.developer.nvidia.com/GPUGem ... ter03.html

One more thing, if you're wondering what "FastFloatToInt" is all about, I guess you can check this out too: http://www.mega-nerd.com/FPcast/

_________________
What most people don't understand is what I like to explain as a thing that I understand.


Top
 Profile  
 
PostPosted: Mon Dec 24, 2012 9:43 am 
Bytewise

Joined: Sun Oct 16, 2011 3:09 pm
Posts: 277
Location: Here (where else?)
Pieman wrote:
Sorry, I think I'm late to the party.
You are, but that's not a problem :)

Pieman wrote:
gafferongames.com is pretty good. Thanks for the link. I'm enjoying this introduction to integration for game physics:

http://gafferongames.com/game-physics/i ... on-basics/

I guess this makes my post extremely off-topic, but I don't have anything else to say.
Link is pretty good indeed. Until I have coasters programmed, I have no need for integrators, but I will re-read those blogs once I get to that point.

If you want to know all the details of integration in a computer, I can recommend the Numerical Recipes book. There are several versions (for different different languages). It covers much numerical stuff though, probably more than you ever want to know.

Pieman wrote:
Quote:
Is this a useful solution?

I'd say your approach to this looks a bit strange to me. I don't really understand the purpose of it. So... Why can't you just cycle through an array of frame images? Sumtin regarding performance? I have no clue.
I had to re-read the topic to understand what it was all about.

It's basically about trying to avoid redrawing animations where its frame-time has not passed yet. One obvious way is to have a timer local to each animation, and update the timer of each object (and return without redrawing when the timer is still running).
My first post takes it one step further, and centralizes the frame-time administration, so you can find out which animations need to be updated efficiently.

The discussion was very useful. I got a lot of good advice on frame rates and approaches on animation. The subject appears to be more complicated than I thought. I dropped the generic centralized approach and went for the simpler distributed animation approach, which works fine for now (I have very few objects moving around currently, so of course there is no problem :p ).

When I have to get my coaster cars moving, no doubt I will have to reconsider my approach.

Pieman wrote:
Code:
struct AnimatedSprite
{
   void Draw(float x, float y, float startTime);

   Image* imageSet;
   uint imageQ; // 'Q' in my identifiers always = 'quantity'

   float frameDuration;
};

void AnimatedSprite::Draw(float x, float y, float startTime)
{
   imageSet[FastFloatToInt(fmod((Time::GetTime() - startTime) / frameDuration, imageQ))]->Draw(x, y);
}
I am always amazed at how much code you can execute in time-critical parts of the code; perhaps I am too scared about that :p

The subject was however the level above this; that is, how to decide what "sprite.Draw()" to call (btw, shouldn't the x, y be part of the AnimatedSprite structure?)

Pieman wrote:
If it has something to do with performance regarding instances, then I recommend you create a rendering job utility which renders in batches and provides controllable depth by employing the Z-buffer in an orthographic view.
Not sure what you mean with 'controllable depth' here (maybe cut off rendering at some Z depth?). For rendering, I do create a set of sprites to draw, ordered by Z (mostly, sprites are very much in and over each other, making assigning an order a nice challenge :) ). I blit to a SDL canvas, ie no GPU stuff. (It does seem like a nice alternative way, so I will definitely play with it one day though.)
For now, I just draw everything. I also always draw the entire screen, so I do have room for improvement :p

Pieman wrote:
Hmm, not much of a fan of nvidia, the company doesn't release specs of its hardware, making it impossible to build good open source drivers for the video cards :(
The link could be useful, but I have yet to program my first OpenGL experiment, so this is a few steps above my expertise currently :)

Pieman wrote:
One more thing, if you're wondering what "FastFloatToInt" is all about, I guess you can check this out too: http://www.mega-nerd.com/FPcast/
In the interest of keeping the option of network multi-player games, I stay away from floating point as much as possible. Perhaps with OpenGL this will change.

_________________
My project: Messing about in FreeRCT, dev blog, and IRC #freerct at oftc.net


Top
 Profile  
 
PostPosted: Mon Dec 24, 2012 5:36 pm 
Lord of Cheesecakes

Joined: Sun Jun 24, 2012 12:49 am
Posts: 341
Quote:
It's basically about trying to avoid redrawing animations where its frame-time has not passed yet.

What do you mean? Don't you overwrite what you've previously drawn anyway? Don't you clear your buffers? I'm not sure what the bananas you're doing, but it sounds like a fishy and misguided approach lured by Satan Directed Media Layer. I'm not sure how you are hoping to accomplish a performance benefit from this evil approach.

xD

But really, how's that supposed to work ?

Quote:
I am always amazed at how much code you can execute in time-critical parts of the code; perhaps I am too scared about that :p

I bet you mine will run faster, unless SDL is succeeding in its goal of taking a dump on common sense. :P

Quote:
(btw, shouldn't the x, y be part of the AnimatedSprite structure?)

No, coordinates are part of instance information. AnimatedSprite keeps a set of images which comprise each frame in an animation. It also stores the frame duration. AnimatedSprite = Sprite information (i.e. image, positional offset etc.) which is animated. Whenever you want to make use of a certain animation, you may simply call

cuteDancingPrincess.Draw(where shes doing the moves on the x axis, where shes doing the moves on the y axis, the time she started dancing);

If you want more dancing princesses, then you can call it multiple times. :rock

Quote:
Hmm, not much of a fan of nvidia, the company doesn't release specs of its hardware, making it impossible to build good open source drivers for the video cards :(
The link could be useful, but I have yet to program my first OpenGL experiment, so this is a few steps above my expertise currently :)

Neither am I a fan of Nvidia. AMD everything! Btw, thats what crap like SDL does to you. And if I remember correctly, I think the example is more Direct3D oriented. Yet, neither the facts that this excellent resource is provided by Nvidia or that it is Direct3D oriented are relevant to the information's usefulness to you. SDL's reign upon your soul is the only god damn factor you need to consider. :D

Quote:
In the interest of keeping the option of network multi-player games, I stay away from floating point as much as possible. Perhaps with OpenGL this will change.

wtf you're being naive. The floating point is within a single function scope and it doesn't affect the gameplay anyway. The people who are afraid of floating point in networked programs are trying to make compactions that break the synchronicity anyway. Do they even understand the nature of UDP? Idiotic.

_________________
What most people don't understand is what I like to explain as a thing that I understand.


Top
 Profile  
 
PostPosted: Tue Dec 25, 2012 10:38 am 
Bytewise

Joined: Sun Oct 16, 2011 3:09 pm
Posts: 277
Location: Here (where else?)
Pieman wrote:
Don't you overwrite what you've previously drawn anyway? Don't you clear your buffers?
I try to redraw only those parts that should actually be changed.

Pieman wrote:
But really, how's that supposed to work ?
The central list can tell me very fast which animations need to be updated. Using dirty rectangles, I mark those areas as modified, then I redraw the areas covered by the dirty rectangles.
Note that in game play of FreeRCT, your screen is normally filled with lots of windows, which cointain mostly static information.

Pieman wrote:
Quote:
(btw, shouldn't the x, y be part of the AnimatedSprite structure?)


No, coordinates are part of instance information.
Good point, makes sense.

Pieman wrote:
Quote:
In the interest of keeping the option of network multi-player games, I stay away from floating point as much as possible. Perhaps with OpenGL this will change.


wtf you're being naive. The floating point is within a single function scope and it doesn't affect the gameplay anyway.
In case you haven't noticed, the formal parameters of the draw function are also floating point numbers, which feels to me like you are storing object positions in floating point. That will affect collision detection, and thus give different results at different machines.

Even use of floating point in drawing will have different results at different machines, but only in the UI. I use the sprite Z buffer also to decide what you click at. Use of floating point in the sprite position will thus give different results in clicking, but it is luckily still a local difference, not propagated to other parts of the game.

And last but not least:
Pieman wrote:
... it sounds like a fishy and misguided approach lured by Satan Directed Media Layer
... unless SDL is succeeding in its goal of taking a dump on common sense.
... thats what crap like SDL does to you.
... SDL's reign upon your soul is the only god damn factor you need to consider
Are you trying to tell me something?
The only message I get is that you have a blind hate about SDL. That's ok, but you don't need to tell me that four times, nor do you need to add religion into the equation, imho.

If you are trying to tell me I should not use SDL, you are failing. I pick libraries on perceived technical advantages, not on religion. I may be making a bad choice, but then tell me why my choice is not going to work.

If you are trying to tell me I should use another library instead, give me alternatives, and explain in what way they are better.

In general, throwing mud is not very convincing. We tried it with Microsoft in the 80's and 90's, Microsoft tried it with Linux (search for 'FUD'). It's just not working. A better strategy is to provide an alternative, take away the reason why people make (in your view) bad choices, gently point out the existence of such an alternative, then let them make up their mind.

_________________
My project: Messing about in FreeRCT, dev blog, and IRC #freerct at oftc.net


Top
 Profile  
 
PostPosted: Wed Dec 26, 2012 5:27 pm 
Lord of Cheesecakes

Joined: Sun Jun 24, 2012 12:49 am
Posts: 341
Quote:
Using dirty rectangles, I mark those areas as modified, then I redraw the areas covered by the dirty rectangles.

Oh yes, that dirty scum. (haha, yes, I know of dirty rectangles though I haven't done anything with them in my own experience) I still think mine will be faster.

Quote:
In case you haven't noticed, the formal parameters of the draw function are also floating point numbers,

Hmm, you have draw functions that don't use floating point parameters? Parameters don't say anything about external code, though you may need casting (unless you have a chain of overloads for every/most function called within the overloaded scope). Yet still. Striving for such consistency implies that you are trying to make compactions that will break the synchronicity anyway... assuming any player can interact with these "float cursed" objects during gameplay, then they could be affected by one player and a few packets describing this client-local interaction may miss, thereby breaking the syncronicity (unless this interaction recurs and new packets succeed to fix it). Actually, there's a lot that can happen which can completely defeat this odd strafe to either eliminate FPA or resolve its small platform-dependant inconsistencies. Yet the packets will surely describe a state including all of the object's new properties, which are usually the basis of interaction. Without this, then the syncronicity can break much, much faster... and otherwise I don't see the point (but hey, you have loads of unoptimized FPA which at least behaves consistently). Almost all of the same packet information will be sent. For anything that is critical and noticible in the gameplay, you should synchronize regularly... because otherwise it's simply impossible to ensure consistence.

Though of course, a lot of it depends on the genre of your game and requires tradeoffs to be made. It's just like buying an expensive car because it has been proven to be extremely safe, if not the safest in its class...

One more note: You're making a RCT game. I think you're nuts for worrying about a few floats. And the behavior of floats matters most. This floating-point behavior that I've introduced merely occurs within a single function's scope. It won't disturb the synchronicity at all. You should be talking about FPA and not about floating point numbers themselves. There is absolutely no reason to worry about it in your case.

Quote:
In general, throwing mud is not very convincing.

That's why half of it is just a joke. Actually, I probably wouldn't have written any of it if it weren't for my idea to call SDL satanic. It's sarcastic blatence. :spin

Quote:
not on religion

From my experience, you seem to pick or discard technical advantages on "religion," as do I. Don't even try to make that argument. Every programmer makes technical decisions, and they're usually consistent about their reasons...

This seems a bit hot. Not my intention. Good luck with your game.

_________________
What most people don't understand is what I like to explain as a thing that I understand.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 20 posts ] 

All times are UTC


Who is online

Users browsing this forum: Google [Bot] and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group