Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » A5 - Proper Allegro event structure

This thread is locked; no one can reply to it. rss feed Print
 1   2 
A5 - Proper Allegro event structure
RPG Hacker
Member #12,492
January 2011
avatar

Yeah, that summed up the general principles behind my idea quite well. As I said, I don't know if, in reality, this could actually work out as itended, but basically, since none of the currently spread timing variants is perfect in all situations, I've always thought about ways to improve them by taking "the best from both worlds". Ultimately, a time step like this still wouldn't be as accurate as a fixed time step, but it should at least avoid errors based on floating point imprecision.

Chris Katko
Member #1,881
January 2002
avatar

One of the things that Mike Acton of Insomniac Games said that has really hit home with me is that no matter WHAT you develop, there is ALWAYS a subset of hardware platforms you're going to run on.

NOBODY is writing code that runs on a z80 and Google data center. Nobody.

So, I'm seeing hints of that when you say "demand frame rate be between 20 and 80 FPS." That's a reasonable constraint.

Moreso, anybody getting a mere 20 FPS (sustained, or in OFTEN hard negative spikes, but not once or twice every 60 seconds of gameplay), it really doesn't matter what happens. I mean YES, it does. We all care about our potential audiences. But if their computer cannot sustain say, 15 FPS, then they can't run the game. The game shouldn't explode or anything, but if the physics start to warp and mess up at that rate? "Such is life."

So among all this writing, the key point I'm illustrating is, if someone can't run above an absolute minimum FPS, then you shouldn't worry too much about what happens to the simulation. The only thing I'd worry about is making it really easy to quit the game! I hate games where the keyboard/mouse input becomes super hard to actually navigate to the exit button when the frame rate drops to zero.

And if you make a game that makes it hard to ALT-TAB, ALT-F4, or control-alt-delete to kill? You deserve to be beaten with an ugly stick.

But that's getting off-topic.

This has been a really interesting civil discussion, so thank you to everyone for contributing so far!

-----sig:
“Programs should be written for people to read, and only incidentally for machines to execute.” - Structure and Interpretation of Computer Programs

RPG Hacker
Member #12,492
January 2011
avatar

Well said! And true. As someone who develops games for many different systems and who has had quite a lot of different PCs in his life (currently a high-end PC, but before that, a rather low-end one), having games that are able to potentially run on as many different systems as possible is always a concern to me. Right now, for example, I'm working on an engine with a Direct3D 12 renderer and probably a Vulkan renderer, mainly to get warm with the technology. However, even now, I still consider trying out Visual Studio's XP toolset and adding a legacy renderer (like Open GL) to see if the game engine could potentially run on many different systems, even out-dated ones (as someone who has had to bear with just a Direct3D 10-compatible graphics card for many years, I know what it feels like not to be able to play certain games or use certain features because they were only implemented for Direct3D 11/12).

The only thing I'd worry about is making it really easy to quit the game! I hate games where the keyboard/mouse input becomes super hard to actually navigate to the exit button when the frame rate drops to zero.

Know what you mean. When programming a game on Windows, for example, I always make sure the close (X) button works properly, because that is indeed annoying. I have seen a couple of frameworks where the close button on a window is disabled by default (I think Allegro 4 and probably 5 are among them). I never understood why. I personally consider not supporting the close button bad practice, unless you have a really, really good reason, so I always felt like having the close button enabled should be the default behavior. Oh well, I guess due to how Allegro is structured, this would be kinda hard to have as a default feature (in Allegro 5 it IS technically enabled by default, but unless you check your window for events, it won't do anything). My own engine is written in C++ and you need to inherit from an abstract application class to implement your game code, that makes it a lot easier to implement the close button by default.

Quote:

This has been a really interesting civil discussion, so thank you to everyone for contributing so far!

Thanks go back to all of you! ;)

Peter Hull
Member #1,136
March 2001

It's strange, I was just thinking about this very issue on Saturday and was going to ask you guys about it. Now I've just got to read this whole thread...

My particular problem came about when messing with JS/HTML canvas. I had heard performance is pretty good these days yet I was struggling to get 60fps. I reduced the amount of work per frame several times until I was actually doing nothing at all in the rendering loop and still only getting about 39.9fps. It was then I discovered the vsync on the laptop was set to 40fps. ::)

So this seems to cause difficulties because (as I understand it) vsync and frame-rate is in the hands of the user rather than the developer - if you'd figured on getting 60fps and were pegged to 40 that's going to make an awkward 3:2 skip. Is there a way to cope with that?

pete

Elias
Member #358
May 2000

One idea is to increase the logic frame rate. If we run logic at 60 FPS and vsync is 40 Hz we will have 3 timer events for 2 screen updates. If you have a game character which moves 10 pixel each timer tick - it will move very unsmooth now:

|     |     |     |     |     |     |     |     | vsyncs
*   *   o   *   *   o   *   *   o   *   *   o   * timer events (o = not drawn)
0     10    30    40    60    70    90    100    (drawn pixel position)

So the character will sometimes move 10 pixel and sometimes jump 20 pixel. An easy fix here is of course to change FPS to 120 or 200 - now everything will be 100% smooth. For the sake of being general, let's assume we use 180 FPS. It means for 2 screen updates there will be 9 timer events.

|        |        |        |        |        |        |
* o o o * o o o o * o o o * o o o o * o o o * o o o o *     
0        13       30       43       60       73

The variation and error for when one game state gets drawn (40 times a second) is much smaller now and it will appear smooth.

A second idea you can combine with this is interpolation. Observe the mistake we still make, for example when drawing the frame "13" above. We move 3.33 pixel for each timer tick (at 180 FPS). So at one timer event the character is at position 13.33, at the next it is at 16.66. The vsync happens in between. If we look at the clock in our render function, we can linearly interpolate the position to draw to. (Extrapolation may also work, but not sure if that's a good idea.)

--
"Either help out or stop whining" - Evert

RPG Hacker
Member #12,492
January 2011
avatar

Or, of course, you could also just use delta time. (I do have to at least mention it, don't I?) ;)
With delta time, V-Sync interval really doesn't matter, since the game will always appear smooth as long as it just runs at the same interval as V-Sync (or as long as the FPS are divisible by the V-Sync interval). Of course, as discussed in this thread, this isn't the perfect solution for every game, so we really need to know what kind of game you're working on.

Elias said:

One idea is to increase the logic frame rate.

The problem with this is that it's hard to find a frequency that works on every monitor, though, and this method also probably won't work with G-Sync or F-Sync too well (which, admittedly, is still a rather new technology not many people use yet, but since it greatly improves game visuals and will probably catch on eventually, it's always a good idea to support it). Aside from that, in your example, you're of course tripling the number of updates for "just" some improved smoothness. IMO, the cost greatly outweighs the benefits in this case.

Quote:

A second idea you can combine with this is interpolation.

I personally tried implementing an interpolation game loop once and came to the conclusion that it's way too impractical for almost any kind of game. Basically, whenever any kind of collision happens, you'll get flickering sprites, and even though dewitter claims that this isn't that bad (see the article I linked earlier in this thread), it's actually quite horrible. It makes the game look like a broken, glitchy mess. The only way this could probably be fixed would be to always calculate a logic frame in advance and then use that data to check if any collision was going to happen in the next frame to prevent objects from being rendered inside walls. Not only would this greatly increase the complexity of the code, it would also introduce an input lag of at least 1 frame (which, I guess, wouldn't matter that much if the game was actually running at 180 FPS, but see my last paragraph for that). While interpolation sounds like the best game loop possible for a game, I've personally found it to be the least usable. Correct me if you've actually managed to make a game that looks and feels great using interpolation.

Elias
Member #358
May 2000

Yeah, that's what I meant with "extrapolation may also work". In most games it probably does not. And yes, interpolation means you will lag behind one frame. But note that if you use 40 Hz vsync, you will always have a lag of about 1/40th second anyway. So this probably won't matter.

--
"Either help out or stop whining" - Evert

RPG Hacker
Member #12,492
January 2011
avatar

Elias said:

But note that if you use 40 Hz vsync, you will always have a lag of about 1/40th second anyway.

How so? And wouldn't the update lag add on top of that, technically doubling the lag?

EDIT:
This whole discussion really got me thinking. Before this, I was really more on the "when do you ever need fixed time steps?" side, but now I kinda see that there are a couple of situations where fixed time stamps might be favorable. Especially that last bit from Elias about interpolation and extrapolation was really useful for me. All this time, I always thought I WERE using interpolation when I was really using extrapolation, I guess that's why I had so much trouble (jittery graphics) with this special kind of game loop (although interpolation still has one or two problems, just smaller ones). In fact, after this discussion, I'm now considering adding both time step variants to my WIP game engine. My engine already supports two different game loops. One, where the rendering happens on the main thread, and one, where the rendering happens on a secondary thread. Both of them use delta time. I have no problem adding one or two more game loops to this mess to support fixed time steps. The game loop would then always pass a fixed delta time to the update() function, but the user would be free to ignore this delta time altogether. This could be a bit tough to get working with multi-threaded rendering, since update() and render() wouldn't sync to each other anymore, but I'll see what I can do.

In that regard, thanks for igniting a spark! ;)

 1   2 


Go to: