Re: Modal event processing
Re: Modal event processing
- Subject: Re: Modal event processing
- From: Graham Cox <email@hidden>
- Date: Sat, 07 Jul 2012 09:08:47 +1000
On 07/07/2012, at 6:02 AM, Charlie Dickman wrote:
> In my view's drawRect method I use a global state variable that defines the next function to perform. When drawRect gets called I do what is necessary for the current state, set up for the next state, set the value for the next state and then return from drawRect. So the primary driving force is the periodic view update requirement (which is guaranteed by actions invoking [self setNeedsDisplay: YES]).
Hmmm, don't do that.
-drawRect: is going to be called for all sorts of reasons, not just because your timer refreshed the view. It's quickly going to get out of step if your state machine (which is what it is) is advanced on every -drawRect:
Abstract the state machine so its state can be changed by some explicit message rather than -drawRect:, then you can control when it changes state according to the logic of your game. Again this sounds upside-down, in that you're using the drawing to control the state instead of using the state to control the drawing.
A naïve way to implement animation is to try to run a timer at, say 30 fps, which refreshes a view. When the view draws, it updates the animation state, for example by moving a graphic object some fixed distance. If things run smoothly, it "works", in that the speed and position of the object are apparently correct. Then sometimes they aren't, because for whatever reason the 30fps can't be maintained, the motion slows down and the position is less than what was predicted. The right way to do this is to model the physics in a simple way, remembering that speed is distance / time. So when your timer fires, you measure the elapsed time and use that to calculate the correct position of the object. You set its position there and you refresh the view. Then when it is drawn, it is in the right place. It does not matter how slow or fast the view refresh manages to be, it will animate correctly - the object speed is now independent of the view update rate. This is a subtle difference but crucial to success.
You have to design your game and all its animation as if it were totally invisible. In other words, it has a data model that models the game in all its states, including transitional animations that has nothing to do with screens or views or pixels. Then you get your view to render that data model as a sort of 'snapshot' of what it's doing at any particular moment. It should not matter how quickly or slowly you take that snapshot - what you see is what the game is doing at that moment. If you take snapshots fast enough (30fps) you will see the game animated smoothly.
If on the other hand you use the taking of the snapshot to drive the game, it will be terrible. Effectively your game is in a static state until someone looks at it, at which point you're trying to hurriedly rearrange it into the expected state for display. If that were real life, you can see the absurdity of it.
You can use a timer to keep the state of the game updated, but at each moment, calculate the full state of the game and schedule a view update. Don't schedule a view update and use that to update the game state. If the logic is factored in a reasonable way, you can see that this amounts to swapping two lines of code. It makes all the difference.
--Graham
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden