~eda-qa/dhlib/main

« back to all changes in this revision

Viewing changes to lib/gamex/BaseGameDriver.mhx

  • Committer: edA-qa mort-ora-y
  • Date: 2010-02-16 05:36:32 UTC
  • Revision ID: eda-qa@disemia.com-20100216053632-60lt7fndfi3fgblw
first

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* <license>
 
2
 * This file is part of the dis-Emi-A HaXe Library. Copyright (c) edA-qa mort-ora-y
 
3
 * For full copyright and license information please refer to doc/license.txt.
 
4
 * </license> 
 
5
 */
 
6
package gamex;
 
7
 
 
8
#if flash
 
9
//these classes as the target specific implementations
 
10
typedef BackingEventDispatcher = flash.events.EventDispatcher;
 
11
#end
 
12
 
 
13
/** 
 
14
 * A generic driver for a game which handles game events as well
 
15
 * as basic timing.
 
16
 *
 
17
 * A class should derive from this and override the _stepTime function
 
18
 * to hook into the basic logic.
 
19
 *
 
20
 * NOTE: The standard Animation framework is used for timing, this allows
 
21
 * more code sharing and proper placement in a display list.
 
22
 */
 
23
class BaseGameDriver<GameObjectType : GameObject> implements ui.Animation, 
 
24
        implements ui.AnimationMaster, implements TimerDispatcher
 
25
{
 
26
        /*hidden*/ var __events : BackingEventDispatcher;
 
27
 
 
28
        //this is heavily influence by the overall framerate, which has been pushed up tp 50
 
29
        //to get a better timing...
 
30
        /*hidden*/ private var __preferredInterval : Int;
 
31
        //the ratio between real time and game time
 
32
        /*hidden*/ private var __realToGameRatio : Float;
 
33
        
 
34
        public function new( ?interval : Null<Int>, ?ratio : Null<Float> )
 
35
        {
 
36
                MixinAnimationMaster(true);
 
37
                
 
38
                __preferredInterval = (interval == null) ? 50 : interval;
 
39
                __realToGameRatio = (ratio == null) ? 1.0 : ratio;
 
40
                
 
41
                __events = new BackingEventDispatcher();
 
42
                
 
43
                __halted = false;
 
44
                __timerRunning = false;
 
45
                
 
46
                __postEvents = new Array<BaseEvent>();
 
47
                
 
48
                gameObjects = new Array<GameObjectType>();
 
49
        }
 
50
        
 
51
        /**
 
52
         * @param weak [in] specifies a weak/non-weak reference. By default everything is
 
53
         *              weak so that when children are removed from the display they will stop being
 
54
         *              listeners
 
55
         */
 
56
        /*final*/ public function addEventListener( evt : String, listener : Dynamic -> Void, ?priority : Int,
 
57
                ?weak : Bool = true )
 
58
        {
 
59
                if( priority == null )
 
60
                        priority = 0;
 
61
                __events.addEventListener( evt, listener,  false, priority, weak );
 
62
        }
 
63
        
 
64
        /*final*/ public function removeEventListener( evt : String, listener : Dynamic -> Void )
 
65
        {
 
66
                __events.removeEventListener( evt, listener, false );
 
67
        }
 
68
        
 
69
        /**
 
70
         * Our events will be posted during the timer stepping, this avoids a bit of overhead
 
71
         * using the asyncEvent.post and it can better time what is going on.  Even if the
 
72
         * game is paused (timer not running) these events will be posted!
 
73
         */
 
74
        /*hidden*/ var __postEvents : Array<BaseEvent>;
 
75
        /*final*/ public function postEvent( evt : BaseEvent )
 
76
        {
 
77
                Assert.is( evt, BaseEvent );
 
78
                
 
79
                //trace( "POST: " + evt.type );
 
80
                //okay, if we aren't started then revert to AsyncEvent (so that events are always dispatched)
 
81
                if( !__timerRunning )
 
82
                        AsyncEvent.post( __events, evt );
 
83
                else
 
84
                        __postEvents.push( evt );
 
85
        }
 
86
        
 
87
        /**
 
88
         * Unlike postEvent this indicates the event is part of the running game and should not
 
89
         * be always dispatched -- if the timer is not running it will not be posted.
 
90
         */
 
91
        /*final*/ public function queueEvent( evt : BaseEvent )
 
92
        {
 
93
                __postEvents.push( evt );
 
94
        }
 
95
        
 
96
        /*hidden*/ function __dispatchPostEvents( )
 
97
        {
 
98
                while( __postEvents.length > 0 )
 
99
                {
 
100
                        var p = __postEvents.`shift'();
 
101
                        AsyncEvent.dispatch( __events, p );
 
102
                }
 
103
        }
 
104
        
 
105
        /**
 
106
         * This can be used by callers who are sure they aren't within the game timer step but
 
107
         * suspect events may have been posted that need dispatching. It is to be used only
 
108
         * in special cases where a visual synchronization needs to be forced. Alternate methods 
 
109
         * are typically preferred.
 
110
         */
 
111
        /*final*/ public function forceDispatchNow()
 
112
        {
 
113
                __dispatchPostEvents();
 
114
        }
 
115
        
 
116
        /**
 
117
         * Immediately dispatches an event.  This happens even if the timer is not running.
 
118
         */
 
119
        /*final*/ public function dispatchEvent( evt : BaseEvent )
 
120
        {
 
121
                //trace( "dispatch: " + evt );
 
122
                Assert.is( evt, BaseEvent );
 
123
                AsyncEvent.dispatch( __events, evt );
 
124
        }
 
125
        
 
126
        
 
127
        /////////////////////////////////////////////////////////////////////////////////
 
128
        // Timing
 
129
        
 
130
        /**
 
131
         * The use of the Flash timer (as opposed to haxe ) allows us to call updateAfterEvent, though
 
132
         * in practive this is no more effective than increasing the frameRate of the application.
 
133
         */
 
134
        /*hidden*/ private var __timerRunning : Bool;
 
135
        /*hidden*/ private var __lastTime : Float;
 
136
        
 
137
        /*final*/ public function startTimer()
 
138
        {
 
139
#if debug
 
140
                elapsedTotal = 0;
 
141
                elapsedSteps = 0;
 
142
                procTotal = 0;
 
143
#end
 
144
                
 
145
                __lastTime = flash.Lib.getTimer();
 
146
                
 
147
                if( __timerRunning )
 
148
                        return;
 
149
                        
 
150
                ui.AnimationManager.s_addListener( this, __preferredInterval );
 
151
                __timerRunning = true;
 
152
        }
 
153
        
 
154
#if debug
 
155
        public var elapsedTotal : Float;
 
156
        public var elapsedSteps : Int;
 
157
        public var procTotal : Float;
 
158
#end
 
159
        /*final*/ public function animate( elapsed : Float ) : Bool
 
160
        {
 
161
                __lastTime = flash.Lib.getTimer();
 
162
                
 
163
#if debug               
 
164
                elapsedTotal += elapsed;
 
165
                elapsedSteps++;
 
166
#end
 
167
                
 
168
                if( !__halted )
 
169
                {
 
170
                        var gameTime = elapsed * __realToGameRatio;
 
171
                        
 
172
                        for( go in gameObjects )
 
173
                                go.stepTime( gameTime );
 
174
                        
 
175
                        _stepTime( gameTime );
 
176
                        __animationMasterStep( gameTime );      //NOTE: animations in this holder step in GameTime, not real time
 
177
                }
 
178
                
 
179
                //always process these, even when halted, this allows debug mode to work...
 
180
                __dispatchPostEvents();
 
181
                
 
182
#if debug               
 
183
                var newTime = flash.Lib.getTimer();
 
184
                procTotal += (newTime - __lastTime) / 1000.0;
 
185
#end
 
186
 
 
187
                return true;
 
188
        }
 
189
        
 
190
        /**
 
191
         * This function must be overriden by a derived class.  It is the main hook
 
192
         * into the GameDriver, it is called each interval with the actual time that
 
193
         * has elapsed
 
194
         */
 
195
        /*abstract*/ function _stepTime( elapsed : Float )
 
196
        {
 
197
                Assert.pureVirtual();
 
198
        }
 
199
        
 
200
        /*final*/ public function stopTimer()
 
201
        {
 
202
                ui.AnimationManager.s_removeListener( this );
 
203
                __timerRunning = false;
 
204
                
 
205
                //ensure we have no pending post events
 
206
                __dispatchPostEvents();
 
207
        }
 
208
        
 
209
        /*final*/ public function pause( )
 
210
        {
 
211
                if( __timerRunning )
 
212
                        stopTimer();
 
213
                else
 
214
                        startTimer();
 
215
        }
 
216
        
 
217
        var __halted : Bool;
 
218
        /**
 
219
         * Discards timer events.  This is meant to be used temporarily, such as during
 
220
         * a popup menu when you don't really wish to alter the status of the timer, but
 
221
         * wish nonetheless for nothing to happen temporarily.
 
222
         */
 
223
        /*final*/ public function haltPause() 
 
224
        {
 
225
                __halted = !__halted;
 
226
        }
 
227
        
 
228
        //////////////////////////////////////////////////////////////////////////////////////////////////////////
 
229
        // Object Handling
 
230
 
 
231
        /*protected*/ var gameObjects : Array<GameObjectType>;
 
232
        public function addGameObject( go : GameObjectType )
 
233
        {
 
234
                gameObjects.push( go );
 
235
                postEvent( ObjectEvent.newRemoved( go ) );
 
236
        }
 
237
        
 
238
        public function removeGameObject( go : GameObjectType )
 
239
        {
 
240
                gameObjects.remove( go );
 
241
                postEvent( ObjectEvent.newRemoved( go ) );
 
242
        }
 
243
        
 
244
        include(`ui/MixinAnimationMaster.ihx')
 
245
}