~eda-qa/dhlib/main

« back to all changes in this revision

Viewing changes to app-squix/squix/Game.hx

  • 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 squix;
 
7
 
 
8
import flash.display.BitmapData;
 
9
import flash.display.Sprite;
 
10
 
 
11
import mathx.Point2;
 
12
import mathx.Rect2;
 
13
 
 
14
import flashx.ObjectCollider;
 
15
 
 
16
/**
 
17
 * Contains all game related elements (abstract information and links
 
18
 * to other classes
 
19
 */
 
20
class Game extends gamex.BaseGameDriver<GameObject>
 
21
{
 
22
        public var global : Global;
 
23
        
 
24
        //referencable objects
 
25
        public var corePanel : CorePanel;
 
26
        public var cursor : PlayerCursor;
 
27
        public var selector : GameSelector;
 
28
        public var surface : Surface;
 
29
        public var edgeTimer : EdgeTimer;
 
30
        public var miniPuzzle : MiniPuzzle;
 
31
        public var scoring : Scoring;
 
32
                
 
33
        //game behaviour config
 
34
        public var constrainSelectorToCursor : Bool;    //constraint the selector to the cursor (requires useCursor == true)
 
35
        public var lockCursorOnSelector : Bool;
 
36
        public var innerMonsterOverlap : Bool;  //can the inner monster overlap the borders?
 
37
        public var useCursor : Bool;    //will a cursor be used/displayed
 
38
        public var useDemoIMS : Bool;   //use a demo sprite for the inner monster
 
39
        public var useCircleSelector : Bool;    //flase=use trace selector
 
40
        public var allowCursorJitter : Bool;    //improves movement, but cursor then jitters
 
41
        public var allowSelectorEscape : Bool;  //can a selection be prematurely finished?
 
42
        public var traceAllowCross : Bool;      //allow lines to cross during trace selection
 
43
        public var cursorStartOnEdge : Bool; //the cursor always starts on the nearest edge, otherwise it can float
 
44
        public var enableMouseCursor : Bool;    //use the mouse to control cursor
 
45
        public var useStickyKeys : Bool;        //use sticky cursor control
 
46
        public var useMiniPuzzle : Bool; //should the minipuzzle be used
 
47
        public var useInnerBonus : Bool;        //should inner bonuses be created
 
48
        
 
49
        //live variables
 
50
        public var cursorPhase : CursorPhase;
 
51
        
 
52
        public var numLives : Int;      //number of player remaining "lives"
 
53
        public var gamePhase : GamePhase;       //should we go to the next level
 
54
        public var score : Int;
 
55
        public var nextLifeScore : Int;
 
56
        public var curLevel : Int;      //level counter (starts at 0, to be displayed as 1)
 
57
                
 
58
        //public to allow other GameObjects to use it...
 
59
        public var goodCollider : ObjectCollider;       //use when collision would benefit player (looser collision criteria)
 
60
        public var badCollider : ObjectCollider;        //use when collision harms player (tighter collision criteria)
 
61
        public var neutralCollider : ObjectCollider;    //use when outcome has no positive or negative impact, and checking should be balanced
 
62
        
 
63
        public function new( difficulty : Int )
 
64
        {
 
65
                super();
 
66
                
 
67
                global = new Global( difficulty, 0 );
 
68
                        
 
69
                badCollider = new ObjectCollider(flash.Lib.current.stage, 0.95);
 
70
                goodCollider = new ObjectCollider(flash.Lib.current.stage, 0.05);
 
71
                neutralCollider = new ObjectCollider(flash.Lib.current.stage, 0.5);
 
72
                scoring = new Scoring( this );
 
73
                        
 
74
                //global game options
 
75
                constrainSelectorToCursor = true;
 
76
                lockCursorOnSelector = true;
 
77
                innerMonsterOverlap = false;
 
78
                useCursor = true;
 
79
                useDemoIMS = false;
 
80
                useCircleSelector = false;
 
81
                allowCursorJitter = false;
 
82
                allowSelectorEscape = false;
 
83
                traceAllowCross = false;
 
84
                cursorStartOnEdge = false;
 
85
                useMiniPuzzle = true;
 
86
                useInnerBonus = true;
 
87
        
 
88
                //non-behavioural options (loaded from global options)
 
89
                enableMouseCursor = Options.enableMouseCursor;  //if false, assume keyboard cursor, both combined has little sense...
 
90
                useStickyKeys = Options.useStickyKeys; //something feels just wrong about this mode
 
91
 
 
92
                //setup Tutorial mode
 
93
#if tutorial1
 
94
                cursorStartOnEdge = true;
 
95
                global.numInnerMonsters = 0;
 
96
                global.numEdgeMonsters = 0;
 
97
                useMiniPuzzle = false;
 
98
#end
 
99
                
 
100
                Assert.isTrue( useCursor || !constrainSelectorToCursor );
 
101
                Assert.isTrue( constrainSelectorToCursor || useCircleSelector );
 
102
                Assert.isFalse( traceAllowCross );      //unless two ambigious trace conditions are resolved..
 
103
                
 
104
                numLives = global.startingLives;
 
105
                gamePhase = GamePhase.None;
 
106
                score = 0;
 
107
                nextLifeScore = global.extraLifePointDelta;
 
108
                curLevel = 0;
 
109
        }
 
110
        
 
111
        public function start()
 
112
        {
 
113
                gamePhase = GamePhase.LevelStart;
 
114
                startTimer();
 
115
        }
 
116
        
 
117
        override function _stepTime( elapsed : Float )
 
118
        {
 
119
                //var start = flash.Lib.getTimer();
 
120
                
 
121
                scoring.checkBonusLife();
 
122
                
 
123
                //should any of these return false, it means to stop evaluating the next ones
 
124
                //thus, the order here forms a priority
 
125
                checkNewLevel()
 
126
                && checkLevelOver()
 
127
                && checkRestoreCursor()
 
128
                && checkSelectorCursorDie()     //perhaps these should be
 
129
                && checkEdgeCursorDie();        //self-checking somehow, like PuzzlePiece...?
 
130
                
 
131
                
 
132
                //var end = flash.Lib.getTimer();
 
133
                //trace( (end - start ) );
 
134
        }
 
135
        
 
136
        function checkNewLevel() : Bool
 
137
        {
 
138
                if( gamePhase == GamePhase.LevelStart )
 
139
                {
 
140
                        gamePhase = GamePhase.Action;
 
141
                        surface = new Surface( global.surfaceSize.x, global.surfaceSize.y );    //needs to come first, before others might look at it
 
142
                        
 
143
                        //start on the edge phase (though perhaps the cursor itself decides this)
 
144
                        cursorPhase = CursorPhase.Edge;
 
145
                        
 
146
                        //create the inner monster
 
147
                        for( i in 0...global.numInnerMonsters )
 
148
                        {
 
149
                                var ims : InnerMonsterSprite;
 
150
                                if( useDemoIMS )
 
151
                                        ims = new IMSSimple()
 
152
                                else
 
153
                                        ims = new IMSTrio();
 
154
                                new InnerMonster( this, ims );
 
155
                        }
 
156
                        
 
157
                        for( i in 0...global.numEdgeMonsters )
 
158
                                new EdgeMonster( this, i );
 
159
                        if( global.numEdgeMonsters > 0 )
 
160
                                new EdgeTimer( this );
 
161
                        
 
162
                        if( useMiniPuzzle )
 
163
                                new MiniPuzzle( this );
 
164
                                
 
165
                        if( useInnerBonus )
 
166
                        {
 
167
                                new InnerBonus( this, Point2.at( surface.width * 0.2, surface.height * 0.2 ) );
 
168
                                new InnerBonus( this, Point2.at( surface.width * 0.2, surface.height * 0.8 ) );
 
169
                                new InnerBonus( this, Point2.at( surface.width * 0.8, surface.height * 0.2 ) );
 
170
                                new InnerBonus( this, Point2.at( surface.width * 0.8, surface.height * 0.8 ) );
 
171
                        }
 
172
                                
 
173
                        postEvent( new GameEvent( GameEvent.NewLevel ) );
 
174
                        new LevelStart( this );
 
175
                        
 
176
                        return false;
 
177
                }
 
178
                
 
179
                return true;
 
180
        }
 
181
        
 
182
        //allows another object to indicate we should start the next level
 
183
        public function startNewLevel()
 
184
        {
 
185
                /* Note that the PostLevelOver event is done synchronously to ensure that
 
186
                 * it is finished before the new level actually starts 
 
187
                 */
 
188
                if( gamePhase == GamePhase.LevelEnd )
 
189
                {
 
190
                        dispatchEvent( new GameEvent( GameEvent.PostLevelOver ) );
 
191
                        //only do in this case since otherwise we may just be starting the first time
 
192
                        curLevel++;
 
193
                        //recreate global params
 
194
                        global = new Global( global.difficulty, curLevel );
 
195
                }
 
196
                gamePhase = GamePhase.LevelStart;
 
197
        }
 
198
        
 
199
        public function startLevelEnd()
 
200
        {
 
201
                //there is a possible (and once realized) error where two level end events could
 
202
                //trigger at the same time
 
203
                if( gamePhase != GamePhase.Action )
 
204
                        return;
 
205
                gamePhase = GamePhase.LevelEnd;
 
206
                postEvent( new GameEvent( GameEvent.LevelOver ) );
 
207
                
 
208
                //update stats
 
209
                Options.ifSetLevelStatus( curLevel, Options.statusNormal );
 
210
        }
 
211
        
 
212
        public function endLevelEnd()
 
213
        {
 
214
                Assert.isTrue( gamePhase == GamePhase.LevelEnd );
 
215
                new LevelOver( this );
 
216
        }
 
217
        
 
218
        function checkLevelOver() : Bool
 
219
        {
 
220
                if( gamePhase != GamePhase.Action )
 
221
                        return true;
 
222
                        
 
223
                //only if not already going to a newlevel...
 
224
                if( surface.cleared >= global.levelClearAt )
 
225
                {
 
226
                        startLevelEnd();
 
227
                        endLevelEnd();
 
228
                        return false;
 
229
                }
 
230
                
 
231
                return true;
 
232
        }
 
233
        
 
234
        function checkRestoreCursor() : Bool
 
235
        {
 
236
                if( gamePhase != GamePhase.Action )
 
237
                        return true;
 
238
                        
 
239
                //setup a cursor
 
240
                if( cursor == null && useCursor ) 
 
241
                {
 
242
                        if( numLives == 0 )
 
243
                        {
 
244
                                endGame();
 
245
                                return false;
 
246
                        }
 
247
                        else
 
248
                        {
 
249
                                numLives--;
 
250
                                new PlayerCursor( this );
 
251
                        }
 
252
                }
 
253
                
 
254
                return true;
 
255
        }
 
256
        
 
257
        //public so GameLayout can call (premature end)
 
258
        public function endGame()
 
259
        {
 
260
                //post the level was over (so cleanup occurs)
 
261
                postEvent( new GameEvent( GameEvent.LevelOver ) );
 
262
                new GameOver( this );
 
263
                postEvent( new GameEvent( GameEvent.GameOver ) );
 
264
                gamePhase = GamePhase.GameOver;
 
265
        }
 
266
        
 
267
        function checkSelectorCursorDie() : Bool
 
268
        {
 
269
                if( gamePhase != GamePhase.Action )
 
270
                        return true;
 
271
                        
 
272
                if( selector == null )
 
273
                        return true;
 
274
                        
 
275
                for( go in gameObjects )
 
276
                        if( Std.is( go, InnerMonster ) 
 
277
                                && go.getCorePanelCollisionObject() != null )
 
278
                        {
 
279
                                if( badCollider.doCollide( 
 
280
                                        go.getCorePanelCollisionObject(),
 
281
                                        selector.getCorePanelCollisionObject() 
 
282
                                        ) )
 
283
                                {
 
284
                                        postEvent( new GameEvent( GameEvent.CursorDie ) );
 
285
                                        return false;
 
286
                                }
 
287
                        }
 
288
                
 
289
                return true;
 
290
        }
 
291
        
 
292
        function checkEdgeCursorDie() : Bool
 
293
        {
 
294
                if( gamePhase != GamePhase.Action )
 
295
                        return true;
 
296
                        
 
297
                if( cursor == null 
 
298
                        || cursorPhase != CursorPhase.Edge 
 
299
                        || cursor.getCorePanelCollisionObject() == null )       
 
300
                        return true;
 
301
                        
 
302
                for( go in gameObjects )
 
303
                        if( Std.is( go, EdgeMonster ) 
 
304
                                && go.getCorePanelCollisionObject() != null )
 
305
                        {
 
306
                                //TODO: Check actual position on grid to prevent nearby death... (hmm, I like if the way it is)
 
307
                                if( badCollider.doCollide( 
 
308
                                        go.getCorePanelCollisionObject(),
 
309
                                        cursor.getCorePanelCollisionObject()
 
310
                                        ) )
 
311
                                {
 
312
                                        postEvent( new GameEvent( GameEvent.CursorDie ) );
 
313
                                        return false;
 
314
                                }
 
315
                        }
 
316
                        
 
317
                return true;                    
 
318
        }
 
319
        
 
320
        public function isCursorNearEdgeKiller() : Bool
 
321
        {
 
322
                if( cursor == null )
 
323
                        return false;
 
324
                        
 
325
                for( go in gameObjects )
 
326
                        if( Std.is( go, EdgeMonster ) )
 
327
                        {
 
328
                                //TODO: genarlize locating objects...
 
329
                                var em = cast( go, EdgeMonster );
 
330
                                var dist = em.getSPos().distanceTo( cursor.getSPos() );
 
331
                                if( dist < global.cursorInvincibleDist )
 
332
                                        return true;
 
333
                        }                       
 
334
                        
 
335
                return false;
 
336
        }
 
337
        
 
338
        /////////////////////////////////////////////////////////////////////////////////////////////////////////
 
339
        // UI interactions
 
340
        public function buttonEnd()
 
341
        {
 
342
                if( selector != null )
 
343
                        selector.buttonEnd();
 
344
        }
 
345
        
 
346
        public function buttonStart()
 
347
        {
 
348
                //only does something in action mode
 
349
                if( gamePhase != GamePhase.Action )
 
350
                        return;
 
351
                        
 
352
                if( selector == null )
 
353
                {
 
354
                        if( useCircleSelector )
 
355
                                new CircleSelector( this );
 
356
                        else
 
357
                                new TraceSelector( this );
 
358
                }
 
359
        }
 
360
        
 
361
        ///////////////////////////////////////////////////////////////////////////////////////////////////////
 
362
        // Common game operations with no other home
 
363
        
 
364
        /**
 
365
         * Determines if the indicated piece can be cleared from the surface.
 
366
         * The rules are:
 
367
         *              if numMonsters == 1
 
368
         *                      allowed = dc does not intersect monster
 
369
         *              otherwise
 
370
         *                      allowed = true (if there is no monster, and to allow monster killing on higher levels)
 
371
         */
 
372
        public function allowedToClear( dc : Sprite ) : Bool
 
373
        {
 
374
                //translate into local world (via intermediary as to not destroy Sprite)
 
375
                var trans = new Sprite();
 
376
                trans.addChild( dc );
 
377
                var scale = corePanel.surfaceSizeToLocal( Point2.at( 1, 1 ) );
 
378
                var tl = corePanel.surfaceToLocal( Point2.at( 0, 0 ) );
 
379
                trans.x = tl.x;
 
380
                trans.y = tl.y;
 
381
                trans.scaleX = scale.x;
 
382
                trans.scaleY = scale.y;
 
383
                corePanel.addChild( trans );
 
384
                
 
385
                var ret = true;
 
386
                var count = 0;
 
387
                for( go in gameObjects )
 
388
                        if( Std.is( go, InnerMonster ) 
 
389
                                && go.getCorePanelCollisionObject() != null )
 
390
                        {
 
391
                        count ++;
 
392
                        ret = ret && !neutralCollider.doCollide( go.getCorePanelCollisionObject(), trans        );
 
393
                        if( !ret )
 
394
                                break;
 
395
                        }
 
396
                
 
397
                //cleanup
 
398
                trans.removeChild( dc );
 
399
                corePanel.removeChild( trans );
 
400
                return count != 1 || ret;
 
401
        }
 
402
        
 
403
        public function clearSurface( dc : Sprite ) : Void
 
404
        {
 
405
                var oldCleared = surface.cleared;
 
406
                surface.clear( dc );
 
407
                var diffCleared = surface.cleared - oldCleared;
 
408
                var bounds = dc.getBounds( null );
 
409
                postEvent( GameEvent.newSegmentCleared( diffCleared, Rect2.fromFlash( bounds ) ) );
 
410
        }
 
411
        
 
412
}