Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

DarkBASIC Professional Discussion / Tutorial : Decouple the Display Loop for Better Performance.

Author
Message
KISTech
16
Years of Service
User Offline
Joined: 8th Feb 2008
Location: Aloha, Oregon
Posted: 7th Sep 2010 23:41 Edited at: 8th Sep 2010 04:51
We have all done it. Hacked out a simple program or demo without any timer based movement code, and with little regard to how fast or slow the user's computer will run it. Which is ok, because it accomplished whatever we were attempting to show to those people.

When we move on to making an actual game for release, it becomes more important to consider the speed of the user's computer.

This is not a discussion on Timer Based Movement. I think we've already covered that well enough, and if not I'll be happy to write an in-depth tutorial for it.

This is a discussion on how to get more performance out of your main loop, while maintaining a good framerate.

What we typically see in the forums is something like this.


There's no Timer Based Movement, sync rate is set to 60, and it does it's thing at an inconsistent rate from computer to computer. Setting VSYNC ON instead of setting sync rate has basically the same effect, but with the benefit of not taking up all of the CPU's cycles.

Another approach is to turn VSYNC OFF and set sync rate to 0 and just let it fly as fast as it can, but again that is going to run at different speeds on different computers, and eats up all available CPU cycles.

This example shows this with Timer Based Movement included just to keep things running at an even pace. Take notice of the FPS that DBPro reports. This isn't just how many times the screen is drawn, but also how many times your main loop runs.


On a fast computer you can get quite high framerates with that, but again, it eats up all the available CPU cycles.


The solution I've come up with, although I'm sure I'm not the first, is to Separate the Game Loop and Display Loop and let them run independently.

The main objective here is to put in the Display Loop only those things that need to be drawn, created, modified, grabbed, or pasted to the screen right before the sync, which is the only time they are needed. Everything in the Game Loop should be the rest of the game that needs constant updating, such as object movement, calculations, collision detection, networking, etc..

The following example aims for an FPS of 30. So every 33 milliseconds it executes the Display Loop. The Game Loop is set to run at 4 times that rate. If the computer is fast enough, it will achieve this, and the Overall Loop Count will be quite high. If it's not, then the Game Loop slows to match up with the Display Loop, but no matter how fast the Game Loop runs, the Display Loop will always run at the desired framerate if it can. If things slow down to where they are at the same rate, even if the Display Loop rate drops below 30, the Game Loop rate will stay with it because it's trying to run faster, but can't. Timer Based Movement keeps the objects moving at the same speed no matter what the FPS or LPS.



Remember the FPS shown in the second example? That was your code running flat out. What we've done is made better use of that processing power by only requiring the display to be updated when it's needed, and giving the power over to the real meat of the program, where the more important stuff happens.

Using this method on the server app for Worlds Apart Online, it runs the Game Loop at around 23,000 loops per second with a Display Loop rate of 5 FPS. Perfect for a server that needs to handle lots of network traffic but doesn't need much of a display.

The client for Worlds Apart Online is able to maintain 40 FPS with a Game Loop rate of 80-90 loops per second.

I'm sharing this to help others who are pushing DBPro to it's limits and need more performance out of it while still achieving a good framerate.

I hope it helps.

Questions? Ask away...

[edit]
I've updated the code to use the HITIMER() function from IanM's Matrix1Utils plugin, since it is more accurate and reliable than the Windows TIMER() function.
[/edit]

Sixty Squares
17
Years of Service
User Offline
Joined: 7th Jun 2006
Location: Somewhere in the world
Posted: 7th Sep 2010 23:52
Nice tutorial! I'm going to try something like this in my game, the FPS is quite low at this point . The demo froze my computer for a while though, not sure why.

Would this result in "jerky" movement though? Wouldn't running the display loop at 30fps make the game look like it's running at 30 fps even if could actually run at 60? Sure everything would be moving at the same speed, but why force the game to run at 30fps if it doesn't have to? I guess it's a sacrifice though... sacrificing smoothness for game loop cycles.


Guns, cinematics, stealth, items and more!
Fatal Berserker
13
Years of Service
User Offline
Joined: 2nd Jul 2010
Location:
Posted: 7th Sep 2010 23:53
Looks really detailed and indepth, but what benefit does this have from timer based movement?
And i see your basing it on average loops per second, what if suddenly their AV stops scanning, wont it become really quick for a second?

Smoke me a kipper, ill be back for breakfast.
KISTech
16
Years of Service
User Offline
Joined: 8th Feb 2008
Location: Aloha, Oregon
Posted: 8th Sep 2010 00:37 Edited at: 8th Sep 2010 00:42
@Sixty Squares : 30 FPS isn't really a sacrifice. The difference between 30 FPS and 60 FPS (at least with this method) is indistinguishable. If timer based movement is implemented properly, there shouldn't see a decrease in smoothness.

What you set your desired framerate at is up to you and depends largely on the contents of the game loop. If you are attempting to get 60 FPS and your main loop takes more than 16.667 milliseconds to run, then you'll never achieve it, but if you take the Display items out of your main loop and the resulting Game Loop is able to run within 16.667 milliseconds or less, then you may be able to reach 60 FPS. So it's not really sacrificing smoothness for anything, but sacrificing a few frames for better performance.

It's a matter of finding a balance between what is an acceptable framerate, and how much time your game loop is taking to run.

[edit]
The biggest performance boost this gave me was with networking and moving the objects associated with networked players, because the main loop was taking so long to process before, the movement packets for players I had waiting to be processed were being overwritten by the new movement packets, making the amount they were moving much larger. Now I don't miss any of those packets.
[/edit]

@Fatal Berserker : In my previous posts about Timer Based Movement I did include averaging of the TBM factors to allow for some movement smoothing, so that in the event of an AV scan ending (or some other event) the movement doesn't suddenly jump ahead, but catches up over a very short amount of time.

There is no averaging of the TBM factors in this tutorial, mainly because I didn't want this to turn into another discussion about it with Mage.

Dr Tank
15
Years of Service
User Offline
Joined: 1st Apr 2009
Location: Southampton, UK
Posted: 8th Sep 2010 00:45 Edited at: 8th Sep 2010 00:53
This the kind of system I use in Super Badass Spaceship X. The standard idea of "timer based movement" really bugs me too.

Another cool thing about a system like this is that the game mechanics are deterministic, allowing the use of a simple player input recorder to record gameplay.

I strongly recommend people give this a read.

Also, I haven't read all your code yet, and maybe I've missed it, but you could try putting in interpolation between game mechanics frames for the the display update.

Edit: It seems game loops per second varies. Perhaps it doesn't work on my machine. I'll check out your code now.
Diggsey
17
Years of Service
User Offline
Joined: 24th Apr 2006
Location: On this web page.
Posted: 8th Sep 2010 01:18
Quote: "It seems game loops per second varies."


That's the point

[b]
KISTech
16
Years of Service
User Offline
Joined: 8th Feb 2008
Location: Aloha, Oregon
Posted: 8th Sep 2010 02:57
Quote: "That's the point"


Yup. The Game Loops per second varies, so the Display Loops per second is unaffected. (to a point at least..)

Dr Tank
15
Years of Service
User Offline
Joined: 1st Apr 2009
Location: Southampton, UK
Posted: 8th Sep 2010 03:20
Quote: "Yup. The Game Loops per second varies, so the Display Loops per second is unaffected. (to a point at least..)"

OK. I do things the other way around! Not sure what the point of doing things your way is. Maybe i'm being dim though.

I thought the point was that game logic should continue at some fixed framerate so that it behaves predictably and the game runs at a fixed speed regardless of FPS.
KISTech
16
Years of Service
User Offline
Joined: 8th Feb 2008
Location: Aloha, Oregon
Posted: 8th Sep 2010 03:51
I can actually see how one might think that, but with Timer Based Movement you don't have to worry about the consistency of the game loop.

With this you'll get better performance from a game loop with lots of heavy calculations, movements, collision detections, etc, because it's not having to deal with all that time consuming display code that's only needed right before a sync.

tiresius
21
Years of Service
User Offline
Joined: 13th Nov 2002
Location: MA USA
Posted: 8th Sep 2010 04:03
If you're going to be counting milliseconds and checking against low numbers, I highly recommend using IanM's Matrix1 function hitimer(). The timer() function is notoriously low resolution so you'll see it jump in spurts of 8, 15, 0, 8, 16, 0 milliseconds, and not exactly what you'd expect.


A 3D marble platformer using Newton physics.
KISTech
16
Years of Service
User Offline
Joined: 8th Feb 2008
Location: Aloha, Oregon
Posted: 8th Sep 2010 04:29
I usually do. For the sake of the tutorial I left that out.

I should probably amend the first post to bring that to light.

Thanks.

tiresius
21
Years of Service
User Offline
Joined: 13th Nov 2002
Location: MA USA
Posted: 8th Sep 2010 05:34
Nice! Decoupling game logic with the display is important for consistent physics simulations as well. Well done. I hope you put this in the Code Snippets area too.


A 3D marble platformer using Newton physics.
KISTech
16
Years of Service
User Offline
Joined: 8th Feb 2008
Location: Aloha, Oregon
Posted: 8th Sep 2010 06:20
Thanks. The Code Snippets is probably a good idea.

baxslash
Valued Member
Bronze Codemaster
17
Years of Service
User Offline
Joined: 26th Dec 2006
Location: Duffield
Posted: 8th Sep 2010 12:32
Great work KISTech, again I'm learning more from you!

Sixty Squares
17
Years of Service
User Offline
Joined: 7th Jun 2006
Location: Somewhere in the world
Posted: 9th Sep 2010 00:58 Edited at: 9th Sep 2010 00:59
@KISTech: Ah, I just tried it out in my game. I had already separated the two loops so it wasn't difficult to do. You're right. Great tutorial, the game is actually running more smoothly now


Guns, cinematics, stealth, items and more!
KISTech
16
Years of Service
User Offline
Joined: 8th Feb 2008
Location: Aloha, Oregon
Posted: 9th Sep 2010 01:36
Nice. Glad it helped.

baxslash
Valued Member
Bronze Codemaster
17
Years of Service
User Offline
Joined: 26th Dec 2006
Location: Duffield
Posted: 9th Sep 2010 12:30
I just implimented this in my game "Soma" and it's running very smoothly!!

Nice work dude!!

Quel
15
Years of Service
User Offline
Joined: 13th Mar 2009
Location:
Posted: 24th Sep 2010 20:21
Correct me if i'm wrong, but TBM is mainly (if not competely) for avoiding TOO FAST movement of units/characters or any dinamics in the game, running on an unexpectedly FAST machine...

The point KISTech presents seems a little extreme to me, to say the least, so you say it is okay to have let's say 8 FPS, because TBM will take care of the correct placing of an object? What if i desperately wanted to select that object and it just keeps jumping (at the right speed alright, but have you actually seen it how it looks and feels?)

Any thoughts on that? I'm not being offensive or anything don't misunderstand (i have already experienced the effect of text not being able to interpret what/HOW i wanna say things a few times before...), i'm just asking questions. And this really has been building up in me, i mean i have always thought TBM is for handling faster FPS than needed, and everybody here is talking about the complete opposite...

...which seems to be the stupidest thing ever for me... no offense...
Daniel wright 2311
User Banned
Posted: 24th Sep 2010 20:31
ok, but here is my problem, displaying bolth in a difrent loop cant be done, well at least by me with in a main loop, like do loop.If it can show me and ill do it with in my game. You have each set with in a return, and my game runs with in a do loop. thanks

my signature keeps being erased by a mod So this is my new signature.
Quel
15
Years of Service
User Offline
Joined: 13th Mar 2009
Location:
Posted: 24th Sep 2010 20:36
What loop values are you getting running this sample program? (first post, third snippet!)

I'm getting 17fps on all four in stand by, and 7-8 varies when clicking. Is my laptop really this piece of cr*p?
Daniel wright 2311
User Banned
Posted: 24th Sep 2010 20:40
Im getting 30 for the main loop and well,to many for my display loop.My laptop is not real old but not that great either.

my signature keeps being erased by a mod So this is my new signature.
KISTech
16
Years of Service
User Offline
Joined: 8th Feb 2008
Location: Aloha, Oregon
Posted: 24th Sep 2010 22:30 Edited at: 24th Sep 2010 22:45
@Quel,
Timer Based Movement is universal in it's application. It gives you the proper offset for movement based on how much time has passed since the last movement. So it doesn't matter if your framerate is 1 or 1000.

@All,
After reading back through all the posts in this thread, I think there was some confusion for some. This isn't a replacement for Timer Based Movement. It uses Timer Based Movement because it should, just like all of our programs should.

This has more to do with maintaining a more steady framerate, and getting better performance out of your game's main loop.

@Quel,
As for the low performance on your laptop.

This bit of code from that snippet is where you adjust your speeds.



If you increase the value in the second IF statement, you will reduce the number of times the GameLoop runs per second. This will give the DisplayLoop more time to run, and increase your FPS. DO NOT set your GameLoop rate higher than your DisplayLoop. Otherwise your DisplayLoop will run more than once without the GameLoop having updated anything.

On my machine the Overall Loops Per Second is over 4,000,000 so I can't simulate the conditions of your laptop, but here is another full example that "should" even out the GameLoop and DisplayLoop so that your framerate will improve.

If your DisplayLoop Rate and GameLoop Rate displayed in the program were already just about even, then this wont help, and in that case yes, your system is apparently quite old and slow.



This will dynamically alter the GameLoop rate based on the framerate achieved. If your system is fast enough to run the demo at it's intended 30 FPS, you wont see a change.

Dr Tank
15
Years of Service
User Offline
Joined: 1st Apr 2009
Location: Southampton, UK
Posted: 24th Sep 2010 22:48
I've given this a proper read though and now "get" it. This system seems good for a game with networking. For a game without I still think having a fixed timestep and interpolating stuff for the display is better, because you're not doing more collision detection or whatever than you need to, but I guess it does avoid writing interpolation code.
KISTech
16
Years of Service
User Offline
Joined: 8th Feb 2008
Location: Aloha, Oregon
Posted: 24th Sep 2010 23:06
You can also play around with the GLV variable to "tune" the GameLoop to an appropriate speed.

The next version of this demo will have something that will.

- Run a quick test of the machine's capabilities to determine how many loops per second it can do
- Set some initial variables based on that value
- Adjust the loop variables dynamically in the main loop to allow the GameLoop to run faster or slower as needed
- Adjust another variable that will be used in the NICE WAIT command to give processing time back to Windows

I ran a test using the NICE WAIT idea, and the program still ran at 30 FPS, but CPU usage dropped to 3%.


Quote: "but I guess it does avoid writing interpolation code. "


Can you elaborate? I'm not getting exactly what you mean.

Latch
17
Years of Service
User Offline
Joined: 23rd Jul 2006
Location:
Posted: 24th Sep 2010 23:37
I think this is a very interesting and informative tutorial! The methods presented are clever and helpful.

However, the comments that follow are not meant to take away any of the validity of KISTech's tutorial. It has more to do with what I think is a mistake in approach to program control through the method of timer based movement that is reiterated again and again on these forums.

In general, I think timer based movement as it seems to be implemented on the forums really isn't a proper way to do it. Maybe I've missed something in what I've read, but the way it's approached seems to be by adjusting how much an object is moved based on how much time has passed. It ends up not being an interpolated movement - i.e. there isn't a smooth progression from one point to the next if the loop iteration time has changed. It's just a jump. If an object moved 10 units at 60 fps per iteration, it's going to jump to 20 units per iteration. If it's a 10 unit wide object, that destroys most chances for collision detection.

Actual timer based functioning, should be the control of the loop iterations themselves. This is actually what SYNC(hronization) is supposed to accomplish. In a game, movements, angle changes, speeds, etc., should be consistent to how they are programmed. A car moving at 20 units an iteration should always move at 20 units an iteration. If the iterations slow, the car should still move at 20 units. The problem here is that the iteration has slowed and is what needs to be controlled.

FPS in it's true sense is the measure of how many frames (we could say screen redraws) happen in a second. This is not the same as the synchronization rate. The synchronization rate is how many loops (iterations) occur per second. FPS and sync keep being used interchangeably and are not the same thing.

The real FPS is based on your graphics adapter and your monitor. DBPro and DirectX are smart enough in their defaults to never attempt to actually redraw the screen faster than the monitor can VSYNC it (redraw it). The FPS displayed when you run your programs is the synchronization rate - how many loops run per second.

As the lowest common denominator for most monitors vsync is 60 FPS, the newer windows and direct x releases automatically force the sync rate to match. So you may see DB programs running at 60 FPS as a cap unless you mess around with vsync and sync.

Now, if you can set a DB Programs sync rate to 0 and query the fps and it reads something like 500, there's no way your monitor is redrawing the screen that fast in most cases. And if you monitor's maximum refresh is less than that (say 120 hz) you would see what is called tearing if your screen was actually redrawing that fast. Tearing is where part of a previous image is still on screen while a new image is being drawn - or your monitor could actually get damaged. Since this isn't the case, FPS and sync rate are NOT the same thing. Therefore, a bad precedent is already set if the approach to control game speed is based on the idea of sync rate as if it is screen redraw time.

Relating this to timer based movement, the control should be in the synchronization. One should find ways to control the loop's iterations (perhaps beyond just setting a SYNC rate if that isn't sufficient).

I know this tutorial isn't on timer based movement, it's on the logic of using a method to separate the background processing from the display. I whole heartedly agree that the drawing should only be handled when drawing needs to be done. That's going to give your program lot's of playing room to do other things. But I have to disagree with the implementation of timer based movement as it is presented.

It's impractical to multiply a factor times an object's potential movement. Multiplication is quite expensive, and the more objects you have, the more multiplication you have to do. A particle system, for example, might be a function that uses thousands of objects. Multiplying a speed factor times each one of these, can really eat up performance in and of itself. And let's say there are 6 parameters to control - x,y, and z direction, x,y and z angle - that ends up being 6 X 1000 X factor...

Enjoy your day.
Sven B
19
Years of Service
User Offline
Joined: 5th Jan 2005
Location: Belgium
Posted: 25th Sep 2010 00:52 Edited at: 25th Sep 2010 00:52
Hi Latch,

Doesn't Direct3D render to a buffer before sending it to the monitor? I always thought that "FPS" was the number of frames rendered to the buffer per second instead of to the monitor when talking about this stuff. Of course, the screen refresh rate is also measured in FPS ~Hz. I've also read multiple articles about not setting your frame rate higher than your screen refresh rate, because it won't do a thing (it will heat up your computer more quickly )

And also, I would like to disagree with your vision on TBM. I think it is a really good way to cope with unexpected changes in your frame rate where it is not desired (like a moving character), and it is not really necessary for FX like particles. The frame rate can for example drop if the player decides to open a few other programs, if your anti-virus starts scanning, etc. It's hard to imagine that I would ever get to a point where I would have so much multiplications that it would start to be noticeable, but I'm sure you can find ways to get rid of the problem if necessary.

Cheers!
Sven B

KISTech
16
Years of Service
User Offline
Joined: 8th Feb 2008
Location: Aloha, Oregon
Posted: 25th Sep 2010 01:21 Edited at: 25th Sep 2010 01:23
Ok. I actually understand everything you said.

Quote: "
Maybe I've missed something in what I've read, but the way it's approached seems to be by adjusting how much an object is moved based on how much time has passed. It ends up not being an interpolated movement - i.e. there isn't a smooth progression from one point to the next if the loop iteration time has changed. It's just a jump. If an object moved 10 units at 60 fps per iteration, it's going to jump to 20 units per iteration.
"


If I'm interpreting this correctly, you meant to say something like, "If an object moved at 10 units at 30 fps then at 60 fps it would move 20 units.". This would not be the case, and is actually what the TBM code is meant to prevent. In fact, movement using TBM is true interpolation. (isn't it?) (I can show an example with the math if needed.)

Understanding this one point will probably clear up some of the other issues in your post.


Quote: "
If it's a 10 unit wide object, that destroys most chances for collision detection.
"


If you are checking collision from the object's old/current position to it's proposed new position before you move it, then there is no problem.

Latch
17
Years of Service
User Offline
Joined: 23rd Jul 2006
Location:
Posted: 25th Sep 2010 02:42 Edited at: 25th Sep 2010 02:51
Hi KISTech,

Quote: "If an object moved 10 units at 60 fps per iteration, it's going to jump to 20 units per iteration."


OOps! That should actually read: "If an object moves at 10 units when the rate is 60 fps per iteration, it's going to jump up to moving 20 units at 30 fps per iteration."

I mean that the logic of speeding up an object as determined by how much time passes between iterations, is going to cause the position of the object to increase the lower the FPS, and to decrease the higher the fps. In the case of an object that is in front of a wall that is say, 6 units wide, a 10 unit wide object will have collision detected with the wall if it moves 10 units or less.
Quote: "If you are checking collision from the object's old/current position to it's proposed new position before you move it, then there is no problem."

In the case of it being forced to move 20 units in an iteration, it would pass to the other side of the wall without a collision even occurring.

Hi Sven B,
Quote: "Doesn't Direct3D render to a buffer before sending it to the monitor? I always thought that "FPS" was the number of frames rendered to the buffer per second instead of to the monitor when talking about this stuff. Of course, the screen refresh rate is also measured in FPS ~Hz. I've also read multiple articles about not setting your frame rate higher than your screen refresh rate, because it won't do a thing (it will heat up your computer more quickly )"

I'd already written so much, I didn't want to put everyone completely to sleep!

My point with mentioning the redraw FPS is that it is not the same as the sync rate. The sync rate only controls how fast loops run in DB. Monitor refresh is different.

It is true that a backbuffer is used to store stuff to be sent to the main screen. That is part of the "smartness" I was talking about with DBPro and Direct X. The rendering to the buffer is basically just writing to a memory area in the computer. The fastest you can write to a memory area either in system memory or video memory depending on how things are set up in direct x, is as fast as your computer can do it - and that has to be as fast as the hardware allows - there's no way to go faster. If DBPro is managed properly behind the scenes, then it never writes to the actual display until the backbuffer is filled. Since the filling of the backbuffer should be based on hardware capabilities and speed, it should be filled and waiting in most cases before you are ready to do your next step. Any slowdown is in calculating what to fill the backbuffer with. Even if you draw nothing to the back buffer, it is still swapped with the front buffer - and this happens as fast as it can happen - no faster. So I'm not sure about the heating up thing you mentioned.

If I were to speculate on the content of the articles you mentioned, it would be that you can directly manage the redraw rate to the screen at a hardware level in directx and you have to be very careful on how to approach this. In this case I'm calling FPS the actual frame redraws to the monitor. If you decide to overtax the graphics adapter and send an FPS to the monitor that isn't supported (too fast), you can possibly damage the monitor or the graphics adapter, or at the very least get a display I was mentioning called tearing - where previous and current frames blend causing a mess.

And in regards to TBM, if you disagree with my vision of it that's fine. If it's implementation works for you then that's good. I think managing the overall cycle (loop iterations) of the game makes more sense. The movements, rotations, etc. should be fixed values based on the size and dynamics of the world. The speed at which the world steps through time should be consistent to maintain the physical dynamics. It is this time that should be managed in Timer based movement, not the movements themselves.

Again, KISTech, this is a very good tutorial. You've put some effort and some thought into and it makes sense. I just don't think the type of timer based movement presented here, and in most threads on the forum, is the best practice.

Enjoy your day.
KISTech
16
Years of Service
User Offline
Joined: 8th Feb 2008
Location: Aloha, Oregon
Posted: 25th Sep 2010 04:00
I think you still missed the point I was making. Timer Based Movement, as it's presented here, does ensure that an object that's supposed to move at 20 units per second does just that.

I'll elaborate.

Let's say your program is happily running along at a perfect 30 FPS.

- The speed of your object is 10 units per second.
- Each loop occurs every 33.33 milliseconds.
- The TBM function is going to return 0.03333 every loop.
- Speed * TBM Factor = 10 * 0.03333 = 0.3333
- So each loop the object will move 0.3333 units.
- 0.3333 * 30 FPS = 9.999 units per second that your object has moved.

Not changing anything but the FPS, here's how that plays out at 60.

- Each loop occurs every 16.66 milliseconds.
- The TBM function will return 0.01666 every loop.
- Speed * TBM Factor = 10 * 0.01666 = 0.1666
- 0.1666 * 60 FPS = 9.996. units per second.

So no matter the frame rate, or loop rate, you'll get the same movement from the object no matter what.

It's not that I disagree with your vision of TBM, I think you may have misinterpreted mine.

Latch
17
Years of Service
User Offline
Joined: 23rd Jul 2006
Location:
Posted: 25th Sep 2010 05:13
@KISTech
I think I understand your approach, and that's why I think it's great. You're goal is to control the game loop, so the game always runs at the same rate. The "background stuff" looping can be let to run wild if it wants to. It'll perform any calculations or updates - but the game loop is meant to remain consistant. Am I following your plan?

I was answering Sven Bs comments and yours, so maybe the answers got a bit jumbled together. I was trying to say that mutiplying an object's movement by a time factor is not, in my opinon, the best approach; especially considering that there may be thousands of objects to have to update in this way. And looking at your program, if it actually limits the game loop, then you shouldn't need to regulate the position updates with a time factor times movement. The speed of the game loop should control that. In your example above, you are starting out with 10 speed units and ending up with close to 10 speed units after your calculations. It would seem that your speed adjustment calculations shouldn't be necessary. If you already have 10 units, and are going to end up with 10, why recalculate?

I probably am just misinterpretting you. Sometimes it takes a drill to get through the old coconut!

Enjoy your day.
KISTech
16
Years of Service
User Offline
Joined: 8th Feb 2008
Location: Aloha, Oregon
Posted: 25th Sep 2010 05:29
Quote: "
It would seem that your speed adjustment calculations shouldn't be necessary. If you already have 10 units, and are going to end up with 10, why recalculate?
"


You have to recalculate each and every loop because the time between loops is always changing. You'll never get a perfect 16.667 ms per loop. It will vary.

Quote: "
You're goal is to control the game loop, so the game always runs at the same rate. The "background stuff" looping can be let to run wild if it wants to. It'll perform any calculations or updates - but the game loop is meant to remain consistant. Am I following your plan?
"


More specifically, the idea is to control the Display loop, which takes a lot of processing to manipulate images, text, and draw it all to the screen. By controlling that you have more processing power to hand over to the Game loop, which gives your overall program better performance and smoother feel. The Timer Based Movement just makes sure that everything moves at the right speed, no matter how fast the Game loop is running.

The Slayer
Forum Vice President
14
Years of Service
User Offline
Joined: 9th Nov 2009
Playing: (Hide and) Seek and Destroy on my guitar!
Posted: 25th Sep 2010 13:32
Here's something I found in one of the newsletters. It's an example of perfect 60 FPS, made by Lee Bamber. So, credits go entirely to him. It's a simple clock that ticks every second, and runs at a perfect 60 frames per second, even if you lower the screen refresh rate. As can be expected, the animation becomes unsmooth while at a low (below 20 or 15 FPS!), but the clock keeps ticking at the same 60 FPS.



Slayer rules!!! Yeaaah, man!
KISTech
16
Years of Service
User Offline
Joined: 8th Feb 2008
Location: Aloha, Oregon
Posted: 25th Sep 2010 20:15
Interesting. Not quite as flexible as the way I wrote mine, but still it's a nice piece of code.

Dr Tank
15
Years of Service
User Offline
Joined: 1st Apr 2009
Location: Southampton, UK
Posted: 26th Sep 2010 20:36
A lot to read here. The system I use is similar to Lee's. I'll post a snippet soon.

In the meantime, I'll try to explain about the interpolation. In Lee's code, you can see that logic loops are done until the logic time "catches up with" the real time. This means that the times (logic time and display time) can differ by as much as the logic timestep. This means motion is not always smooth - if you position objects at the time of the latest timestep for display, movement may be stuttery, with a "beats" effect.

The latest timestep is ahead of the real time. The previous timestep is behind. By interpolating between these you can obtain positions, rotations of objects at the "exact" time you update the display.

More on this when I post the code.
KISTech
16
Years of Service
User Offline
Joined: 8th Feb 2008
Location: Aloha, Oregon
Posted: 27th Sep 2010 19:19
Ah. I see what you mean.

Dr Tank
15
Years of Service
User Offline
Joined: 1st Apr 2009
Location: Southampton, UK
Posted: 28th Sep 2010 02:11
I'm glad. This whole thing really bakes my head. Here's my example. I'm pretty sure it's possible to do much better. This version does look "glitchy" at times. I think this is due to dropped frames.

You can try 3 different modes by pressing 1-3. Not sure which is best. Toggle interpolation with the spacekey.

KISTech
16
Years of Service
User Offline
Joined: 8th Feb 2008
Location: Aloha, Oregon
Posted: 28th Sep 2010 04:08
You're right. It makes my head hurt too.

Kira Vakaan
15
Years of Service
User Offline
Joined: 1st Dec 2008
Location: MI, United States
Posted: 28th Sep 2010 11:14 Edited at: 28th Sep 2010 11:17
@Latch: You just completely blew my mind. It makes so much sense. Control the number of logic frames per second instead of the logic increments each frame. However an obvious problem arises when a program that strives for 60fps runs on a computer that can only give it 30.

This is a very interesting approach to TBM, although I can't really see a downside to the "tradition" TBM approach (Edit: Although I just did. Read below the quote. ), excluding the problem you mentioned about collision. When KISTech said:
Quote: "If you are checking collision from the object's old/current position to it's proposed new position before you move it, then there is no problem."

I'm pretty sure he assumed the use of sliding collision detection, in which an object is mathematically slid along a ray, as opposed to simple intersections, which is what I figured you were talking about.
Assuming KISTech was talking about sliding collision and you were talking about intersections, there is no problem with either one when dealing with linear paths. However, when dealing with erratic paths, traditional TBM fails to preserve the same resolution of movement that is captured by yours (a wobbly path from A to B can't really be approximated by a straight line from A to B).

There appear to be issues with both methods. Anyhoo, as KISTech stated in his first post, this is not to be a discussion about TBM. At any rate, thank you very much for your ideas. I hadn't thought like that before.

@KISTech: This decoupling of logic and display is great! I can't believe it never really occurred to me before. But what's the real benefit of controlling the frequency of each individual loop? Why not just control the frequency of the slower loop from the faster one (make the fastest loop the top level loop)? I suppose on the off-chance that the processing time of the fast loop causes the slow loop to miss its desired frequency would make controlling both loops from a nearly empty one more accurate... I think I just answered my own question.

KISTech
16
Years of Service
User Offline
Joined: 8th Feb 2008
Location: Aloha, Oregon
Posted: 28th Sep 2010 18:23
Right. This attempts to maintain a steady framerate because that's the loop that will show whats going on to the player. That part of it is all about the visual experience to the player.

Controlling the rest of the program, which I've called the GameLoop, you can do a lot more with it.

For example, on my machine the Overall Loops per Second runs at just over 4,000,000. If I dynamically change the GameLoop interval so it runs faster, I can get even more processing out of it. If there is a point where it doesn't need that much processing, say it's not a Networked game, then I can dynamically add in a NICE WAIT command from IanM's Matrix1Utils with a value that will allow the GameLoop to process as many times as is needed and give the rest of the processing time back to the system.

I did a quick test with the above example using a NICE WAIT that dynamically adjusted, and when it settled in to a value the program ran just as you see it now, but it was only using 3% of the CPU.

I'll post a demo of that shortly.

Hawkblood
14
Years of Service
User Offline
Joined: 5th Dec 2009
Location:
Posted: 28th Sep 2010 18:52
@KISTech
Dude, you've inspired me! This is almost like multi-threading. I've never thought of doing it like that before. The conventional way of doing the game loop does all the calculations and then waits for v-sync before proceeding (with v-sync on)-- that's wasted processor time. And for those that think 30fps is slow, your eye can't see faster than that anyway... Most people can't see faster that 20fps.

So with this method, you do some calculation.... do some movement.... do some collisions........ Oh! it's time to render so do it now.

I LIKE IT! Thanks.

The fastest code is the code never written.
KISTech
16
Years of Service
User Offline
Joined: 8th Feb 2008
Location: Aloha, Oregon
Posted: 28th Sep 2010 19:17
@Hawkblood, you bet. Glad you like it.

@All, here is a quick and dirty example of dynamically changing the GameLoop interval based on FPS performance, and adding a WAIT value that gives processing time back to the system so DBP doesn't peg the CPU at full throttle.

(NOTE: This is a quick and dirty example for illustration purposes only.)



Every 1/4 of a second it checks the value of the Overall Loops counter and if it's over 100,000 then it increments the Wait Value. (since that counter resets every second it's going to be "off" but the example still works to illustrate the point) Then the NICE WAIT command runs after each DisplayLoop. This does drop the framerate a bit on my machine, but like I said this is quick and dirty to show what can be done. I would do it differently in a production game. Possibly a 1 or 2 ms wait if the GameLoop was running to fast.

If your Overall Loop count running the previous example wasn't over 100,000 then you wont see a difference.

Dr Tank
15
Years of Service
User Offline
Joined: 1st Apr 2009
Location: Southampton, UK
Posted: 28th Sep 2010 20:30
Tried to run the new one but don't have hitimer(). How can i change the code for it to work with timer()?

Is hitimer() just higher resolution than timer(), or is it true that it's somehow "more reliable"?
KISTech
16
Years of Service
User Offline
Joined: 8th Feb 2008
Location: Aloha, Oregon
Posted: 28th Sep 2010 20:56
It's very true. Install IanM's Matrix1Utils found here. They are indispensable utilities anyway.

The TIMER() function tends to jump around and has a meaningful resolution of about 10 milliseconds. If you were to observe values taken from the TIMER() you would see values like 0, 5, 15, 6, 8, 0, 10, 12, where under the same conditions HITIMER() might give 10, 10, 8, 10, 10, 10, 10.

HITIMER() accesses the hardware high performance timer, which is much more accurate and reliable.

Someone correct me if I'm wrong, but I think TIMER() is software based as part of the operating system, and would be susceptible to hardware and software interrupts, which is what would make the values jump around.

Kira Vakaan
15
Years of Service
User Offline
Joined: 1st Dec 2008
Location: MI, United States
Posted: 28th Sep 2010 21:36 Edited at: 28th Sep 2010 21:40
@KISTech: I've been playing around with your example and the nice wait command, and I came up with this:

Instead of attempting to change the frequency at which the Game Loop fires, I try to keep it firing at its desired frequency. My idea was to attempt to calculate the amount of "free" time the program has when it's not running the Game or Display Loops and wait for that long. It's not exactly stable right now, and the reported FPS's seems to mellow out over time, but on my computer the overall FPS tends to 78, the Game Loop FPS tends to 65, and the Display Loop FPS tends to 26. The fact that the overall FPS tends to 78 is actually a good thing. That mean the program is making very efficient use of downtime by using the nice wait command when it can. I'll probably keep tinkering, but I thought I'd share my progress.

Edit: Oh, and my CPU usage stayed around 0-1% with my example while it stayed at 3% with yours. Interesting, although I need to come up with more accurate FPS control. Neither the Game nor Display seems to meet its goal.

KISTech
16
Years of Service
User Offline
Joined: 8th Feb 2008
Location: Aloha, Oregon
Posted: 28th Sep 2010 23:03
Nice.

Quote: "Neither the Game nor Display seems to meet its goal."


Still, it's close, and shows the basic concept.

I would tinker with it some more, but I'm exceptionally busy.

Latch
17
Years of Service
User Offline
Joined: 23rd Jul 2006
Location:
Posted: 16th Oct 2010 06:38
@Kira Vakaan

Quote: "Edit: Oh, and my CPU usage stayed around 0-1% with my example while it stayed at 3% with yours. Interesting, although I need to come up with more accurate FPS control. Neither the Game nor Display seems to meet its goal."


Though I don't know the workings of hitimer(), the reduction in CPU usage seems to be related to a processing delay. By default, a DarkBASIC game or app wants to hog all of the CPU time. Right? A game doesn't want to share resources with other programs because usually you play a game to play a game and not do other stuff at the same time. You can force an app to pause it's processing and return some of the CPU.

I'm guesing that's what hitimer() does. If that is the case, the same result can be achieved by using the windows api command
SleepEx(). The reduction in CPU usage will be directly related to how much time the system is told to let DarkBASIC sleep until control is returned. While this is good for other programs running simulataneously, it may not necessarily be good for the DarkBASIC app or game.

Try a test:



By reducing if n=10, the CPU process percentage should decrease and the FPS should decrease.

If you decrease the 100 in call dll 1,"SleepEx",100,0, the fps should increase and the cpu will increase.

So be aware that at least in this control of the CPU, there isn't any additional juice being lent to run the DarkBASIC app or game. But, hitimer() may not be using SleepEx() to control timing so this may not apply.

Enjoy your day.
Indicium
15
Years of Service
User Offline
Joined: 26th May 2008
Location:
Posted: 16th Oct 2010 18:04
I don't know if I've misunderstood, but hitimer() is just... a timer... right?

Latch
17
Years of Service
User Offline
Joined: 23rd Jul 2006
Location:
Posted: 16th Oct 2010 23:24 Edited at: 16th Oct 2010 23:30
Quote: "I don't know if I've misunderstood, but hitimer() is just... a timer... right?"


I guess it is VSYNC that is reducing the CPU cycles? What I was musing for htimer(), if it was reducing CPU cycles, was that in it's make up, it may have used SleepEx() to reduce the CPU load when DB is running - preventing DB from trying to eat up 100% of the processing time.

For example, in the scenario I was proposing, the pseudo code to make a DLL timer function might look like:



Then some DB:



When this function is called, SleepEx will pause the thread 1 millisecond, then return the windows clock time since starting, in milliseconds. The result is that the CPU cycles will be reduced because it is forcing that 1 ms rest.

EDIT:
If the ms is raised in SleepEx() in the DLL function, then you can reduce the CPU usage by DB even more, at the cost of FPS, however.

Enjoy your day.
General Jackson
User Banned
Posted: 17th Oct 2010 05:20
Bookmarked.

Thanks!

Eminent
13
Years of Service
User Offline
Joined: 15th Jul 2010
Location:
Posted: 19th Oct 2010 00:33
I tried implementing this but it just gives me a black screen. I think it has to do with the pasting of the image.


Login to post a reply

Server time is: 2024-04-16 15:18:21
Your offset time is: 2024-04-16 15:18:21