Slick Forums

Discuss the Slick 2D Library
It is currently Tue Jun 18, 2013 10:37 pm

All times are UTC




Post new topic Reply to topic  [ 20 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Smooth Movement Demo
PostPosted: Sun Nov 21, 2010 6:30 pm 
Offline

Joined: Thu Sep 24, 2009 8:14 pm
Posts: 50
Following my "Sprite Preview" project, I've created a simple prototype where game entities (creatures) are moving around the screen.

Creating smooth movement was more difficult than I expected. You want your game to be able to run as fast as possible, but be able to deal with slow downs of any magnitude. So how does one deal with arbitrary fluctuations in game speed? How does your update(int delta) method behave when the delta is 300,000 milliseconds? I ended up implementing something very similar to this, except without alpha blending as described in that article (I don't think it makes sense to do that in a game).

I've also learned to deal with synchronizing different types of actions. In this prototype, I implemented a SmoothMove action and a Speak action and worked out a way to synchronize them so that it always takes the same time to speak and move 1 step. This part seems strange in retrospect because the solution seems so simple and obvious once it came to me, but was felt damn near impossible when I was struggling to figure it out.

You can check out my web start demo and source code here.

*Edit - This prototype deals with my experience in timing and synchronizing game entities and effects in a well-defined fashion. If you are reading the source, you should disregard designs of behavior objects, organization of tasks and the render queue (amongst other things), I will study and redesign those elements, and document them in a future update.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 22, 2010 3:40 am 
Offline
Oldbie
User avatar

Joined: Fri Jul 20, 2007 9:25 am
Posts: 410
Location: Croatia
I've missed something earlier because I don't know what you are talking about. Smooth movement?? .. what is a big deal about it?

And delta of 30 seconds?? huh? When does that happen?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 22, 2010 5:15 am 
Offline

Joined: Thu Sep 24, 2009 8:14 pm
Posts: 50
It (smooth movement) is not that obvious and trivial really. I share my code and experience because there will always be someone who might be able to learn from it.

Regarding fixed time steps, I can't recommend it enough. Without putting in some sort of upper and lower bounds on your deltas, how do you know your code will handle things gracefully when the user's system slows down? Don't just assume a 30 second delta is impossible, but guard against the potential of it happening.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 22, 2010 8:47 am 
Offline
Game Developer

Joined: Sun Nov 12, 2006 11:18 pm
Posts: 890
Location: Germany
jlcheng, I would bet if "something" blocks the delta based update() routine for 30 seconds it would also block your fixed time step routine :wink:

I've tried both approaches, delta based updating using Slick and the fixed time step approach using BlitzMax.

Both have their advantages and disadvantages. And you can do easy workarounds to combine both with each other.

In my opinion the fixed time step approach simplifies implementing the game logic because you can assume a guaranteed timing behavior on every update call. But the render code gets complicated because you need to render the "in between" steps of your limited update rate to get smooth movement (the tweening code).

The Slick approach complicates the update logic a bit more because you have to measure the time on your own and you need to consider the delta value for each and every calculation (like motion, jumping, etc).
But the render code is dead simple.

In the end both approaches get the job done and IMHO it's more the personal preference of the game developer that's important.

But thanks for sharing your code and offering a possible alternative!

I will have a look at the code in the next few days - too busy ATM...

_________________
Right Angle Games | Marte Engine
Back to the past | Star Cleaner | SpiderTrap


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 22, 2010 10:54 am 
Offline
Site Admin
User avatar

Joined: Thu Jan 01, 1970 12:00 am
Posts: 3143
I like delta based updates as a framework, because you can easily turn it into fixed step - but not vice vesa.

I tend to use fixed step in my games.

Kev


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 22, 2010 12:36 pm 
Offline
Game Developer

Joined: Sun Nov 12, 2006 11:18 pm
Posts: 890
Location: Germany
kevglass wrote:
I tend to use fixed step in my games.
Kev

Looking up your WarpStone source code it seems that you avoid dealing with the tweening stuff in your render code. Or did I just miss that?

So you simply render as fast as the system runs and update every fixed time step (25ms).

Did I get this right?

_________________
Right Angle Games | Marte Engine
Back to the past | Star Cleaner | SpiderTrap


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 22, 2010 12:37 pm 
Offline
Site Admin
User avatar

Joined: Thu Jan 01, 1970 12:00 am
Posts: 3143
Yep, rendering as fast as I can gives me chance for some interesting effects that look lovely - data model updates are fixed time step.

Kev


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 22, 2010 6:20 pm 
Offline

Joined: Thu Sep 24, 2009 8:14 pm
Posts: 50
Tommy,

I'm not sure what you mean by rendering the "in between" steps. Do you mind explaining? In the way my game is written, there is absolutely no state change between one update() call to the next(). Therefore, even if I call render() more than once between two update() calls, all render() calls will draw exactly the same thing to the screen - The way it is designed, it only makes sense to call render exactly once per update, and the render method draw exactly what the game state is at the time.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 22, 2010 6:29 pm 
Offline

Joined: Thu Sep 24, 2009 8:14 pm
Posts: 50
Kevin, do you mind pointing me to the source code for WarpStone? I'd like to see what you are doing between data model updates for special effects.

I think of effects as part of the data model myself, so they are also constrained by a maximum value when their update(int delta) methods are called.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 22, 2010 8:50 pm 
Offline
Game Developer

Joined: Sun Nov 12, 2006 11:18 pm
Posts: 890
Location: Germany
@jlcheng: Oops! I mean - you were linking to Gaffer's "Fix your timestep" article.
At the end of his article named the "The final touch" he explains how to interpolate the differences between update and render times.
This is called tweening and he explains how to deal with it by calculating a "state" value which is passed to the render() call and affects the placement of all objects rendered. That's the complicated part when using fixed time steps I meant in my post above.

I also tried to explain it in my own tutorial over here:
http://www.rightanglegames.com/topdownshootertu/index.html
Just look for the paragraph titled "Some thoughts about the main game loop".

The code is in BlitzMax (some OO Basic game language) but the explanation of the fixed time step loop including tweening is in pseudo language so it should fit any language.

Hope that helps,
Tommy

_________________
Right Angle Games | Marte Engine
Back to the past | Star Cleaner | SpiderTrap


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 22, 2010 9:17 pm 
Offline
Oldbie
User avatar

Joined: Fri Jul 20, 2007 9:25 am
Posts: 410
Location: Croatia
Just want to add that I love the delta that slick has... except things already mentioned, you can do really cool game speedup or slowdown effects (like matrix :) ). Don't know how non-delta engines handle it but her you just modify delta before passing it, really cool.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 23, 2010 12:30 am 
Offline

Joined: Thu Sep 24, 2009 8:14 pm
Posts: 50
Tommy, thanks for the link. I spent some time to read through it and I have better idea of what you mean. The "tween" logic and what Glenn Fiedler* does with alpha blending is something that I'm intentionally leaving out of my game.

Both you and Glenn use an accumulator + a nested loop where multiple update() calls consumes the time in the accumulator. To be concise, I will call this the accumulator approach.

The accumulator approach has this advantage: If your game has a brief slow down, your logic update can catch up to where it should be by doing multiple update() calls inside the nested loop. It will be accurate and demonstrate repeatable behavior.

In my game. I do not use an accumulator. If the delta is greater than 16ms (targeting 60fps), then I simply treat it as 16ms and do my update/render and restart the loop. The result is that the game slows down (fps drops) when there is a spike in load. There is no catch up code. However, it also means I do not have to implement some sort of "tween" logic to deal with remainders in the accumulator (or "temporal aliasing", as Glenn calls it).

In addition to dealing with temporal aliasing, there is also a potential problem with visual effects. I'm going to use an exaggerated example again.

Let's say you have a game with a fixed step of 16ms (~60fps). In this game, you have a bullet that moves across your screen at ~1cm per second. Let's say that there is a sudden slowdown and your delta is precisely 960ms. Now your nested loop will run update() 60 times to consume all the values in the accumulator. Now this bullet will suddenly jump 1cm after that 960ms pause. Now this is nice in the sense that this is where the bullet should be after a 960ms delay. But visually, it appears as a jump of ~1 cm.

Another reason I am avoiding using an accumulator is stable behavior under consistent heavy load. The game I hope to write is somewhat similar to SimCity/Sims. I expect the update() to consistently be above 16ms when there are too many objects in the game. In this case, using an accumulator may end up going into a "spiral of death" and skip around a lot since each render() call is always separated by multiple update() calls. So I ultimately decided to avoid using an accumulator and just let the FPS drop.

After all this, I'm not saying the approach in your tutorial is wrong or mine is better or what not. I simply enjoy discussing trade-offs of each approach. As designers, the decision will ultimately based on the games we want to make and how we expect it to behave.

* Glenn Fiedler, the author of the "Fix your Timestep!" article.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 23, 2010 7:52 am 
Offline
Game Developer

Joined: Sun Nov 12, 2006 11:18 pm
Posts: 890
Location: Germany
jlcheng,
I agree: there is no "right" or "wrong" way.
Currently I prefer a fixed step approach too - it simplifies so many things.

Another nice approach which Caspian Prince of www.puppygames.net uses for his games (or at least he once wrote that he does it like this) is also a fixed step solution. He aims at a target rate of 60 FPS. But he measures the real FPS and if the drop rate is too high he just halfs his target frame rate to 30 FPS. This is simple to code and doesn't affect the code too much.

Finally I also love those discussions: if it helps to simplify my game coding or to learn something or get a better understanding - then let's have some :lol:

Cheers,
Tommy

_________________
Right Angle Games | Marte Engine
Back to the past | Star Cleaner | SpiderTrap


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 23, 2010 9:53 am 
Offline
Game Developer
User avatar

Joined: Wed Feb 17, 2010 12:24 am
Posts: 594
kevglass wrote:
I like delta based updates as a framework, because you can easily turn it into fixed step - but not vice vesa.

I tend to use fixed step in my games.

Kev



What's a delta based update versus a fixed step?

Fixed step is just doing X every Y updates()?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 23, 2010 11:37 am 
Offline
Site Admin
User avatar

Joined: Thu Jan 01, 1970 12:00 am
Posts: 3143
To me:

Delta based updates - you update your logic based on the passing of real time, however much might have passed since your last update.

Fixed based update - you segment you updates so that the only change in time you account for in your update logic is one value. So every data model update you do is say for 30ms. If the real world has moved on 90ms then you update 3 times each for 30ms.

Kev


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 20 posts ]  Go to page 1, 2  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 2 guests


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
You cannot post attachments in this forum

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