• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.replica.replicaisland;
18 
19 import com.replica.replicaisland.CollisionParameters.HitType;
20 import com.replica.replicaisland.GameObject.ActionType;
21 
22 public class PlayerComponent extends GameComponent {
23 
24     private static final float GROUND_IMPULSE_SPEED = 5000.0f;
25     private static final float AIR_HORIZONTAL_IMPULSE_SPEED = 4000.0f;
26     private static final float AIR_VERTICAL_IMPULSE_SPEED = 1200.0f;
27     private static final float AIR_VERTICAL_IMPULSE_SPEED_FROM_GROUND = 250.0f;
28     private static final float AIR_DRAG_SPEED = 4000.0f;
29     private static final float MAX_GROUND_HORIZONTAL_SPEED = 500.0f;
30     private static final float MAX_AIR_HORIZONTAL_SPEED = 150.0f;
31     private static final float MAX_UPWARD_SPEED = 250.0f;
32     private static final float VERTICAL_IMPULSE_TOLERANCE = 50.0f;
33     private static final float FUEL_AMOUNT = 1.0f;
34 
35     private static final float JUMP_TO_JETS_DELAY = 0.5f;
36 
37     private static final float STOMP_VELOCITY = -1000.0f;
38     private static final float STOMP_DELAY_TIME = 0.15f;
39     private static final float STOMP_AIR_HANG_TIME = 0.0f; //0.25f;
40     private static final float STOMP_SHAKE_MAGNITUDE = 15.0f;
41     private static final float STOMP_VIBRATE_TIME = 0.05f;
42     private static final float HIT_REACT_TIME = 0.5f;
43 
44     private static final float GHOST_REACTIVATION_DELAY = 0.3f;
45     private static final float GHOST_CHARGE_TIME = 0.75f;
46 
47     private static final int MAX_GEMS_PER_LEVEL = 3;
48 
49     private static final float NO_GEMS_GHOST_TIME = 3.0f;
50     private static final float ONE_GEM_GHOST_TIME = 8.0f;
51     private static final float TWO_GEMS_GHOST_TIME = 0.0f; // no limit.
52 
53 
54     public enum State {
55         MOVE,
56         STOMP,
57         HIT_REACT,
58         DEAD,
59         WIN,
60         FROZEN,
61         POST_GHOST_DELAY
62     }
63 
64     private boolean mTouchingGround;
65     private State mState;
66     private float mTimer;
67     private float mTimer2;
68     private float mFuel;
69     private float mJumpTime;
70     private boolean mGhostActive;
71     private float mGhostDeactivatedTime;
72     private float mGhostChargeTime;
73     private InventoryComponent mInventory;
74     private Vector2 mHotSpotTestPoint;
75     private ChangeComponentsComponent mInvincibleSwap;
76     private float mInvincibleEndTime;
77     private HitReactionComponent mHitReaction;
78     private float mFuelAirRefillSpeed;
79     private DifficultyConstants mDifficultyConstants;
80     private final static DifficultyConstants sDifficultyArray[] = {
81     	new BabyDifficultyConstants(),
82     	new KidsDifficultyConstants(),
83     	new AdultsDifficultyConstants()
84     };
85     private FadeDrawableComponent mInvincibleFader;	// HACK!
86 
87     // Variables recorded for animation decisions.
88     private boolean mRocketsOn;
89 
PlayerComponent()90     public PlayerComponent() {
91         super();
92         mHotSpotTestPoint = new Vector2();
93         reset();
94         setPhase(ComponentPhases.THINK.ordinal());
95     }
96 
97     @Override
reset()98     public void reset() {
99         mTouchingGround = false;
100         mState = State.MOVE;
101         mTimer = 0.0f;
102         mTimer2 = 0.0f;
103         mFuel = 0.0f;
104         mJumpTime = 0.0f;
105         mGhostActive = false;
106         mGhostDeactivatedTime = 0.0f;
107         mInventory = null;
108         mGhostChargeTime = 0.0f;
109         mHotSpotTestPoint.zero();
110         mInvincibleSwap = null;
111         mInvincibleEndTime = 0.0f;
112         mHitReaction = null;
113         mDifficultyConstants = getDifficultyConstants();
114         mFuelAirRefillSpeed = mDifficultyConstants.getFuelAirRefillSpeed();
115         mInvincibleFader = null;
116     }
117 
move(float time, float timeDelta, GameObject parentObject)118     protected void move(float time, float timeDelta, GameObject parentObject) {
119         VectorPool pool = sSystemRegistry.vectorPool;
120         InputGameInterface input = sSystemRegistry.inputGameInterface;
121 
122         if (pool != null && input != null) {
123 
124             if (mFuel < FUEL_AMOUNT) {
125                 if (mTouchingGround) {
126                     mFuel += mDifficultyConstants.getFuelGroundRefillSpeed() * timeDelta;
127                 } else {
128                     mFuel += mFuelAirRefillSpeed * timeDelta;
129                 }
130 
131                 if (mFuel > FUEL_AMOUNT) {
132                     mFuel = FUEL_AMOUNT;
133                 }
134             }
135 
136             final InputXY dpad = input.getDirectionalPad();
137             final InputButton jumpButton = input.getJumpButton();
138 
139             if (dpad.getPressed() || jumpButton.getPressed()) {
140                 Vector2 impulse = pool.allocate();
141 
142                 if (dpad.getPressed()) {
143                     impulse.set(dpad.getX(), 0.0f);
144                 }
145 
146                 if (jumpButton.getPressed()) {
147                     if (jumpButton.getTriggered(time) && mTouchingGround) {
148                     	// In this case, velocity is instant so we don't need to scale
149                     	// it by time.
150                         impulse.y = AIR_VERTICAL_IMPULSE_SPEED_FROM_GROUND;
151                         mJumpTime = time;
152                     } else if (time > mJumpTime + JUMP_TO_JETS_DELAY) {
153                         if (mFuel > 0.0f) {
154                             mFuel -= timeDelta;
155                             impulse.y = AIR_VERTICAL_IMPULSE_SPEED * timeDelta;
156                             mRocketsOn = true;
157                         }
158 
159                     }
160                 }
161 
162                 float horziontalSpeed = GROUND_IMPULSE_SPEED;
163                 float maxHorizontalSpeed = MAX_GROUND_HORIZONTAL_SPEED;
164                 final boolean inTheAir = !mTouchingGround
165                     || impulse.y > VERTICAL_IMPULSE_TOLERANCE;
166                 if (inTheAir) {
167                     horziontalSpeed = AIR_HORIZONTAL_IMPULSE_SPEED;
168                     maxHorizontalSpeed = MAX_AIR_HORIZONTAL_SPEED;
169                 }
170 
171                 impulse.x = (impulse.x * horziontalSpeed * timeDelta);
172 
173                 // Don't let our jets move us past specific speed thresholds.
174                 float currentSpeed = parentObject.getVelocity().x;
175                 final float newSpeed = Math.abs(currentSpeed + impulse.x);
176                 if (newSpeed > maxHorizontalSpeed) {
177                     if (Math.abs(currentSpeed) < maxHorizontalSpeed) {
178                         currentSpeed = maxHorizontalSpeed * Utils.sign(impulse.x);
179                         parentObject.getVelocity().x = (currentSpeed);
180                     }
181                     impulse.x = (0.0f);
182                 }
183 
184                 if (parentObject.getVelocity().y + impulse.y > MAX_UPWARD_SPEED
185                         && Utils.sign(impulse.y) > 0) {
186                     impulse.y = (0.0f);
187                     if (parentObject.getVelocity().y < MAX_UPWARD_SPEED) {
188                         parentObject.getVelocity().y = (MAX_UPWARD_SPEED);
189                     }
190                 }
191 
192                 if (inTheAir) {
193                     // Apply drag while in the air.
194                     if (Math.abs(currentSpeed) > maxHorizontalSpeed) {
195                         float postDragSpeed = currentSpeed -
196                             (AIR_DRAG_SPEED * timeDelta * Utils.sign(currentSpeed));
197                         if (Utils.sign(currentSpeed) != Utils.sign(postDragSpeed)) {
198                             postDragSpeed = 0.0f;
199                         } else if (Math.abs(postDragSpeed) < maxHorizontalSpeed) {
200                             postDragSpeed = maxHorizontalSpeed * Utils.sign(postDragSpeed);
201                         }
202                         parentObject.getVelocity().x = (postDragSpeed);
203                     }
204                 }
205 
206                 parentObject.getImpulse().add(impulse);
207                 pool.release(impulse);
208             }
209 
210         }
211     }
212 
update(float timeDelta, BaseObject parent)213     public void update(float timeDelta, BaseObject parent) {
214 
215         TimeSystem time = sSystemRegistry.timeSystem;
216         GameObject parentObject = (GameObject)parent;
217 
218         final float gameTime = time.getGameTime();
219         mTouchingGround = parentObject.touchingGround();
220 
221         mRocketsOn = false;
222 
223 
224         if (parentObject.getCurrentAction() == ActionType.INVALID) {
225             gotoMove(parentObject);
226         }
227 
228         if (mInventory != null && mState != State.WIN) {
229             InventoryComponent.UpdateRecord inventory = mInventory.getRecord();
230             if (inventory.coinCount >= mDifficultyConstants.getCoinsPerPowerup()) {
231                 inventory.coinCount = 0;
232                 mInventory.setChanged();
233                 parentObject.life = mDifficultyConstants.getMaxPlayerLife();
234                 if (mInvincibleEndTime < gameTime) {
235 	                mInvincibleSwap.activate(parentObject);
236 	                mInvincibleEndTime = gameTime + mDifficultyConstants.getGlowDuration();
237 	                if (mHitReaction != null) {
238 	                    mHitReaction.setForceInvincible(true);
239 	                }
240                 } else {
241                 	// invincibility is already active, extend it.
242                 	mInvincibleEndTime = gameTime + mDifficultyConstants.getGlowDuration();
243                 	// HACK HACK HACK.  This really doesn't go here.
244                 	// To extend the invincible time we need to increment the value above (easy)
245                 	// and also tell the component managing the glow sprite to reset its
246                 	// timer (not easy).  Next time, make a shared value system for this
247                 	// kind of case!!
248                 	if (mInvincibleFader != null) {
249                 		mInvincibleFader.resetPhase();
250                 	}
251                 }
252             }
253             if (inventory.rubyCount >= MAX_GEMS_PER_LEVEL) {
254                 gotoWin(gameTime);
255             }
256         }
257 
258         if (mInvincibleEndTime > 0.0f && (mInvincibleEndTime < gameTime || mState == State.DEAD)) {
259             mInvincibleSwap.activate(parentObject);
260             mInvincibleEndTime = 0.0f;
261             if (mHitReaction != null) {
262                 mHitReaction.setForceInvincible(false);
263             }
264         }
265 
266 
267      // Watch for hit reactions or death interrupting the state machine.
268         if (mState != State.DEAD && mState != State.WIN ) {
269             if (parentObject.life <= 0) {
270                 gotoDead(gameTime);
271             } else if (parentObject.getPosition().y < -parentObject.height) {
272                 // we fell off the bottom of the screen, die.
273                 parentObject.life = 0;
274                 gotoDead(gameTime);
275             } else if (mState != State.HIT_REACT
276             		&& parentObject.lastReceivedHitType != HitType.INVALID
277                     && parentObject.getCurrentAction() == ActionType.HIT_REACT) {
278                 gotoHitReact(parentObject, gameTime);
279             } else {
280                 HotSpotSystem hotSpot = sSystemRegistry.hotSpotSystem;
281                 if (hotSpot != null) {
282                     // TODO: HACK!  Unify all this code.
283                     if (hotSpot.getHotSpot(parentObject.getCenteredPositionX(),
284                             parentObject.getPosition().y + 10.0f) == HotSpotSystem.HotSpotType.DIE) {
285                         parentObject.life = 0;
286                         gotoDead(gameTime);
287                     }
288                 }
289             }
290         }
291 
292         switch(mState) {
293             case MOVE:
294                 stateMove(gameTime, timeDelta, parentObject);
295                 break;
296             case STOMP:
297                 stateStomp(gameTime, timeDelta, parentObject);
298                 break;
299             case HIT_REACT:
300                 stateHitReact(gameTime, timeDelta, parentObject);
301                 break;
302             case DEAD:
303                 stateDead(gameTime, timeDelta, parentObject);
304                 break;
305             case WIN:
306                 stateWin(gameTime, timeDelta, parentObject);
307                 break;
308             case FROZEN:
309                 stateFrozen(gameTime, timeDelta, parentObject);
310                 break;
311             case POST_GHOST_DELAY:
312                 statePostGhostDelay(gameTime, timeDelta, parentObject);
313                 break;
314             default:
315                 break;
316         }
317 
318         final HudSystem hud = sSystemRegistry.hudSystem;
319         final InputGameInterface input = sSystemRegistry.inputGameInterface;
320         if (hud != null) {
321             hud.setFuelPercent(mFuel / FUEL_AMOUNT);
322         }
323 
324     }
325 
gotoMove(GameObject parentObject)326     protected void gotoMove(GameObject parentObject) {
327         parentObject.setCurrentAction(GameObject.ActionType.MOVE);
328         mState = State.MOVE;
329     }
330 
stateMove(float time, float timeDelta, GameObject parentObject)331     protected void stateMove(float time, float timeDelta, GameObject parentObject) {
332         if (!mGhostActive) {
333             move(time, timeDelta, parentObject);
334 
335             final InputGameInterface input = sSystemRegistry.inputGameInterface;
336             final InputButton attackButton = input.getAttackButton();
337 
338             if (attackButton.getTriggered(time) && !mTouchingGround) {
339                 gotoStomp(parentObject);
340             } else if (attackButton.getPressed() && mTouchingGround
341                     && mGhostDeactivatedTime + GHOST_REACTIVATION_DELAY < time) {
342                 mGhostChargeTime += timeDelta;
343                 if (mGhostChargeTime > GHOST_CHARGE_TIME) {
344                     GameObjectFactory factory = sSystemRegistry.gameObjectFactory;
345                     GameObjectManager manager = sSystemRegistry.gameObjectManager;
346                     if (factory != null && manager != null) {
347                         final float x = parentObject.getPosition().x;
348                         final float y = parentObject.getPosition().y;
349                         float ghostTime = NO_GEMS_GHOST_TIME;
350                         if (mInventory != null) {
351                             InventoryComponent.UpdateRecord inventory = mInventory.getRecord();
352                             if (inventory.rubyCount == 1) {
353                                 ghostTime = ONE_GEM_GHOST_TIME;
354                             } else if (inventory.rubyCount == 2) {
355                                 ghostTime = TWO_GEMS_GHOST_TIME;
356                             }
357                         }
358                         GameObject ghost = factory.spawnPlayerGhost(x, y, parentObject, ghostTime);
359 
360                         manager.add(ghost);
361                         mGhostActive = true;
362                         CameraSystem camera = sSystemRegistry.cameraSystem;
363                         if (camera != null) {
364                             camera.setTarget(ghost);
365                         }
366                                             }
367                 }
368             } else if (!attackButton.getPressed()) {
369                 mGhostChargeTime = 0.0f;
370             }
371         }
372 
373     }
374 
gotoStomp(GameObject parentObject)375     protected void gotoStomp(GameObject parentObject) {
376         parentObject.setCurrentAction(GameObject.ActionType.ATTACK);
377         mState = State.STOMP;
378         mTimer = -1.0f;
379         mTimer2 = -1.0f;
380         parentObject.getImpulse().zero();
381         parentObject.getVelocity().set(0.0f, 0.0f);
382         parentObject.positionLocked = true;
383     }
384 
stateStomp(float time, float timeDelta, GameObject parentObject)385     protected void stateStomp(float time, float timeDelta, GameObject parentObject) {
386         if (mTimer < 0.0f) {
387             // first frame
388             mTimer = time;
389         } else if (time - mTimer > STOMP_AIR_HANG_TIME) {
390             // hang time complete
391             parentObject.getVelocity().set(0.0f, STOMP_VELOCITY);
392             parentObject.positionLocked = false;
393         }
394 
395         if (mTouchingGround && mTimer2 < 0.0f) {
396             mTimer2 = time;
397             CameraSystem camera = sSystemRegistry.cameraSystem;
398             if (camera != null) {
399                 camera.shake(STOMP_DELAY_TIME, STOMP_SHAKE_MAGNITUDE);
400             }
401             VibrationSystem vibrator = sSystemRegistry.vibrationSystem;
402 
403             if (vibrator != null) {
404                 vibrator.vibrate(STOMP_VIBRATE_TIME);
405             }
406 
407             GameObjectFactory factory = sSystemRegistry.gameObjectFactory;
408             GameObjectManager manager = sSystemRegistry.gameObjectManager;
409             if (factory != null && manager != null) {
410                 final float x = parentObject.getPosition().x;
411                 final float y = parentObject.getPosition().y;
412                 GameObject smoke1 = factory.spawnDust(x, y - 16, true);
413                 GameObject smoke2 = factory.spawnDust(x + 32, y - 16, false);
414                 manager.add(smoke1);
415                 manager.add(smoke2);
416             }
417         }
418 
419         if (mTimer2 > 0.0f && time - mTimer2 > STOMP_DELAY_TIME) {
420             parentObject.positionLocked = false;
421             gotoMove(parentObject);
422         }
423     }
424 
gotoHitReact(GameObject parentObject, float time)425     protected void gotoHitReact(GameObject parentObject, float time) {
426     	if (parentObject.lastReceivedHitType == CollisionParameters.HitType.LAUNCH) {
427             if (mState != State.FROZEN) {
428                 gotoFrozen(parentObject);
429             }
430     	} else {
431             mState = State.HIT_REACT;
432             mTimer = time;
433 
434         }
435     }
436 
stateHitReact(float time, float timeDelta, GameObject parentObject)437     protected void stateHitReact(float time, float timeDelta, GameObject parentObject) {
438         // This state just waits until the timer is expired.
439         if (time - mTimer > HIT_REACT_TIME) {
440             gotoMove(parentObject);
441         }
442     }
443 
gotoDead(float time)444     protected void gotoDead(float time) {
445         mState = State.DEAD;
446         mTimer = time;
447     }
448 
stateDead(float time, float timeDelta, GameObject parentObject)449     protected void stateDead(float time, float timeDelta, GameObject parentObject) {
450         if (mTouchingGround && parentObject.getCurrentAction() != ActionType.DEATH) {
451             parentObject.setCurrentAction(ActionType.DEATH);
452             parentObject.getVelocity().zero();
453             parentObject.getTargetVelocity().zero();
454         }
455 
456         if (parentObject.getPosition().y < -parentObject.height) {
457             // fell off the bottom of the screen.
458             parentObject.setCurrentAction(ActionType.DEATH);
459             parentObject.getVelocity().zero();
460             parentObject.getTargetVelocity().zero();
461         }
462 
463         if (parentObject.getCurrentAction() == ActionType.DEATH && mTimer > 0.0f) {
464             final float elapsed = time - mTimer;
465             HudSystem hud = sSystemRegistry.hudSystem;
466             if (hud != null && !hud.isFading()) {
467                 if (elapsed > 2.0f) {
468                     hud.startFade(false, 1.5f);
469                     hud.sendGameEventOnFadeComplete(GameFlowEvent.EVENT_RESTART_LEVEL, 0);
470                     EventRecorder recorder = sSystemRegistry.eventRecorder;
471                     if (recorder != null) {
472                     	recorder.setLastDeathPosition(parentObject.getPosition());
473                     }
474                 }
475             }
476 
477         }
478     }
479 
gotoWin(float time)480     protected void gotoWin(float time) {
481         mState = State.WIN;
482         TimeSystem timeSystem = sSystemRegistry.timeSystem;
483         mTimer = timeSystem.getRealTime();
484         timeSystem.appyScale(0.1f, 8.0f, true);
485     }
486 
stateWin(float time, float timeDelta, GameObject parentObject)487     protected void stateWin(float time, float timeDelta, GameObject parentObject) {
488        if (mTimer > 0.0f) {
489         	TimeSystem timeSystem = sSystemRegistry.timeSystem;
490             final float elapsed = timeSystem.getRealTime() - mTimer;
491             HudSystem hud = sSystemRegistry.hudSystem;
492             if (hud != null && !hud.isFading()) {
493                 if (elapsed > 2.0f) {
494                     hud.startFade(false, 1.5f);
495                     hud.sendGameEventOnFadeComplete(GameFlowEvent.EVENT_GO_TO_NEXT_LEVEL, 0);
496 
497                 }
498             }
499 
500         }
501     }
502 
gotoFrozen(GameObject parentObject)503     protected void gotoFrozen(GameObject parentObject) {
504         mState = State.FROZEN;
505         parentObject.setCurrentAction(ActionType.FROZEN);
506     }
507 
stateFrozen(float time, float timeDelta, GameObject parentObject)508     protected void stateFrozen(float time, float timeDelta, GameObject parentObject) {
509         if (parentObject.getCurrentAction() == ActionType.MOVE) {
510             gotoMove(parentObject);
511         }
512     }
513 
gotoPostGhostDelay()514     protected void gotoPostGhostDelay() {
515         mState = State.POST_GHOST_DELAY;
516     }
517 
statePostGhostDelay(float time, float timeDelta, GameObject parentObject)518     protected void statePostGhostDelay(float time, float timeDelta, GameObject parentObject) {
519         if (time > mGhostDeactivatedTime) {
520             if (!mGhostActive) { // The ghost might have activated again during this delay.
521                 CameraSystem camera = sSystemRegistry.cameraSystem;
522                 if (camera != null) {
523                     camera.setTarget(parentObject);
524                 }
525             }
526             gotoMove(parentObject);
527         }
528     }
529 
getRocketsOn()530     public final boolean getRocketsOn() {
531         return mRocketsOn;
532     }
533 
getGhostActive()534     public final boolean getGhostActive() {
535         return mGhostActive;
536     }
537 
deactivateGhost(float delay)538     public final void deactivateGhost(float delay) {
539         mGhostActive = false;
540         mGhostDeactivatedTime = sSystemRegistry.timeSystem.getGameTime() + delay;
541         gotoPostGhostDelay();
542     }
543 
setInventory(InventoryComponent inventory)544     public final void setInventory(InventoryComponent inventory) {
545         mInventory = inventory;
546     }
547 
setInvincibleSwap(ChangeComponentsComponent invincibleSwap)548     public final void setInvincibleSwap(ChangeComponentsComponent invincibleSwap) {
549         mInvincibleSwap = invincibleSwap;
550     }
551 
setHitReactionComponent(HitReactionComponent hitReact)552     public final void setHitReactionComponent(HitReactionComponent hitReact) {
553         mHitReaction = hitReact;
554     }
555 
setInvincibleFader(FadeDrawableComponent fader)556     public final void setInvincibleFader(FadeDrawableComponent fader) {
557     	mInvincibleFader = fader;
558     }
559 
adjustDifficulty(GameObject parent, int levelAttemps )560     public final void adjustDifficulty(GameObject parent, int levelAttemps ) {
561     	// Super basic DDA.
562     	// If we've tried this levels several times secretly increase our
563         // hit points so the level gets easier.
564     	// Also make fuel refill faster in the air after we've died too many times.
565 
566     	if (levelAttemps >= mDifficultyConstants.getDDAStage1Attempts()) {
567             if (levelAttemps >= mDifficultyConstants.getDDAStage2Attempts()) {
568             	parent.life += mDifficultyConstants.getDDAStage2LifeBoost();
569             	mFuelAirRefillSpeed = mDifficultyConstants.getDDAStage2FuelAirRefillSpeed();
570             } else {
571             	parent.life += mDifficultyConstants.getDDAStage1LifeBoost();
572             	mFuelAirRefillSpeed = mDifficultyConstants.getDDAStage1FuelAirRefillSpeed();
573             }
574         }
575 
576 
577     }
578 
getDifficultyConstants()579     public static DifficultyConstants getDifficultyConstants() {
580     	return sDifficultyArray[sSystemRegistry.contextParameters.difficulty];
581     }
582 
583 }