• 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 NPCComponent extends GameComponent {
23     private float mPauseTime;
24     private float mTargetXVelocity;
25     private int mLastHitTileX;
26     private int mLastHitTileY;
27 
28     private int mDialogEvent;
29     private int mDialogIndex;
30 
31     private HitReactionComponent mHitReactComponent;
32 
33     private int[] mQueuedCommands;
34     private int mQueueTop;
35     private int mQueueBottom;
36     private boolean mExecutingQueue;
37 
38     private Vector2 mPreviousPosition;
39 
40     private float mUpImpulse;
41     private float mDownImpulse;
42     private float mHorizontalImpulse;
43     private float mSlowHorizontalImpulse;
44     private float mAcceleration;
45 
46     private int mGameEvent;
47     private int mGameEventIndex;
48     private boolean mSpawnGameEventOnDeath;
49 
50     private boolean mReactToHits;
51     private boolean mFlying;
52     private boolean mPauseOnAttack;
53 
54     private float mDeathTime;
55 	private float mDeathFadeDelay;
56 
57     private static final float UP_IMPULSE = 400.0f;
58     private static final float DOWN_IMPULSE = -10.0f;
59     private static final float HORIZONTAL_IMPULSE = 200.0f;
60     private static final float SLOW_HORIZONTAL_IMPULSE = 50.0f;
61     private static final float ACCELERATION = 300.0f;
62     private static final float HIT_IMPULSE = 300.0f;
63     private static final float HIT_ACCELERATION = 700.0f;
64 
65     private static final float DEATH_FADE_DELAY = 4.0f;
66 
67     private static final float PAUSE_TIME_SHORT = 1.0f;
68     private static final float PAUSE_TIME_MEDIUM = 4.0f;
69     private static final float PAUSE_TIME_LONG = 8.0f;
70     private static final float PAUSE_TIME_ATTACK = 1.0f;
71     private static final float PAUSE_TIME_HIT_REACT = 1.0f;
72 
73     private static final int COMMAND_QUEUE_SIZE = 16;
74 
NPCComponent()75     public NPCComponent() {
76         super();
77         setPhase(ComponentPhases.THINK.ordinal());
78         mQueuedCommands = new int[COMMAND_QUEUE_SIZE];
79         mPreviousPosition = new Vector2();
80         reset();
81     }
82 
83     @Override
reset()84     public void reset() {
85         mPauseTime = 0.0f;
86         mTargetXVelocity = 0.0f;
87         mLastHitTileX = 0;
88         mLastHitTileY = 0;
89         mDialogEvent = GameFlowEvent.EVENT_SHOW_DIALOG_CHARACTER1;
90         mDialogIndex = 0;
91         mHitReactComponent = null;
92         mQueueTop = 0;
93         mQueueBottom = 0;
94         mPreviousPosition.zero();
95         mExecutingQueue = false;
96         mUpImpulse = UP_IMPULSE;
97         mDownImpulse = DOWN_IMPULSE;
98         mHorizontalImpulse = HORIZONTAL_IMPULSE;
99         mSlowHorizontalImpulse = SLOW_HORIZONTAL_IMPULSE;
100         mAcceleration = ACCELERATION;
101         mGameEvent = -1;
102         mGameEventIndex = -1;
103         mSpawnGameEventOnDeath = false;
104         mReactToHits = false;
105         mFlying = false;
106         mDeathTime = 0.0f;
107         mDeathFadeDelay = DEATH_FADE_DELAY;
108         mPauseOnAttack = true;
109     }
110 
111     @Override
update(float timeDelta, BaseObject parent)112     public void update(float timeDelta, BaseObject parent) {
113 
114         GameObject parentObject = (GameObject)parent;
115 
116         if (mReactToHits &&
117         		mPauseTime <= 0.0f &&
118         		parentObject.getCurrentAction() == ActionType.HIT_REACT) {
119         	mPauseTime = PAUSE_TIME_HIT_REACT;
120             pauseMovement(parentObject);
121         	parentObject.getVelocity().x = -parentObject.facingDirection.x * HIT_IMPULSE;
122         	parentObject.getAcceleration().x = HIT_ACCELERATION;
123 
124         } else if (parentObject.getCurrentAction() == ActionType.DEATH) {
125         	if (mSpawnGameEventOnDeath && mGameEvent != -1) {
126         		if (Utils.close(parentObject.getVelocity().x, 0.0f)
127         				&& parentObject.touchingGround()) {
128 
129         			if (mDeathTime < mDeathFadeDelay && mDeathTime + timeDelta >= mDeathFadeDelay) {
130         				HudSystem hud = sSystemRegistry.hudSystem;
131 
132         	        	if (hud != null) {
133         	        		hud.startFade(false, 1.5f);
134         	        		hud.sendGameEventOnFadeComplete(mGameEvent, mGameEventIndex);
135         	        		mGameEvent = -1;
136         	        	}
137         			}
138         			mDeathTime += timeDelta;
139 
140         		}
141         	}
142         	// nothing else to do.
143         	return;
144         } else if (parentObject.life <= 0) {
145         	parentObject.setCurrentAction(ActionType.DEATH);
146         	parentObject.getTargetVelocity().x = 0;
147         	return;
148         } else if (parentObject.getCurrentAction() == ActionType.INVALID ||
149         		(!mReactToHits && parentObject.getCurrentAction() == ActionType.HIT_REACT)) {
150         	parentObject.setCurrentAction(ActionType.MOVE);
151         }
152 
153         if (mPauseTime <= 0.0f) {
154 
155             HotSpotSystem hotSpotSystem = sSystemRegistry.hotSpotSystem;
156 
157             if (hotSpotSystem != null) {
158             	final float centerX = parentObject.getCenteredPositionX();
159                 final int hitTileX = hotSpotSystem.getHitTileX(centerX);
160                 final int hitTileY = hotSpotSystem.getHitTileY(parentObject.getPosition().y + 10.0f);
161                 boolean accepted = true;
162 
163                 if (hitTileX != mLastHitTileX || hitTileY != mLastHitTileY) {
164 
165             	    final int hotSpot = hotSpotSystem.getHotSpotByTile(hitTileX, hitTileY);
166 
167                     if (hotSpot >= HotSpotSystem.HotSpotType.NPC_GO_RIGHT && hotSpot <= HotSpotSystem.HotSpotType.NPC_SLOW) {
168                     	// movement-related commands are immediate
169                         parentObject.setCurrentAction(ActionType.MOVE);
170                     	accepted = executeCommand(hotSpot, parentObject, timeDelta);
171                     } else if (hotSpot == HotSpotSystem.HotSpotType.ATTACK && !mPauseOnAttack) {
172                     	// when mPauseOnAttack is false, attacks are also immediate.
173                     	accepted = executeCommand(hotSpot, parentObject, timeDelta);
174                     } else if (hotSpot == HotSpotSystem.HotSpotType.NPC_RUN_QUEUED_COMMANDS) {
175                     	if (!mExecutingQueue && mQueueTop != mQueueBottom) {
176                     		mExecutingQueue = true;
177                         }
178                     } else if (hotSpot > HotSpotSystem.HotSpotType.NONE) {
179                     	queueCommand(hotSpot);
180                     }
181                 }
182 
183                 if (mExecutingQueue) {
184                 	if (mQueueTop != mQueueBottom) {
185                 		accepted = executeCommand(nextCommand(), parentObject, timeDelta);
186                 		if (accepted) {
187                 			advanceQueue();
188                 		}
189                 	} else {
190                 		mExecutingQueue = false;
191                 	}
192                 }
193 
194                 if (accepted) {
195                 	mLastHitTileX = hitTileX;
196                 	mLastHitTileY = hitTileY;
197                 }
198 
199             }
200         } else {
201             mPauseTime -= timeDelta;
202             if (mPauseTime < 0.0f) {
203                 resumeMovement(parentObject);
204                 mPauseTime = 0.0f;
205                 parentObject.setCurrentAction(ActionType.MOVE);
206             }
207         }
208 
209         mPreviousPosition.set(parentObject.getPosition());
210     }
211 
executeCommand(int hotSpot, GameObject parentObject, float timeDelta)212     private boolean executeCommand(int hotSpot, GameObject parentObject, float timeDelta) {
213     	boolean hitAccepted = true;
214     	final CameraSystem camera = sSystemRegistry.cameraSystem;
215 
216     	switch(hotSpot) {
217         case HotSpotSystem.HotSpotType.WAIT_SHORT:
218             if (mPauseTime == 0.0f) {
219                 mPauseTime = PAUSE_TIME_SHORT;
220                 pauseMovement(parentObject);
221             }
222             break;
223         case HotSpotSystem.HotSpotType.WAIT_MEDIUM:
224             if (mPauseTime == 0.0f) {
225                 mPauseTime = PAUSE_TIME_MEDIUM;
226                 pauseMovement(parentObject);
227             }
228             break;
229         case HotSpotSystem.HotSpotType.WAIT_LONG:
230             if (mPauseTime == 0.0f) {
231                 mPauseTime = PAUSE_TIME_LONG;
232                 pauseMovement(parentObject);
233             }
234             break;
235         case HotSpotSystem.HotSpotType.ATTACK:
236         	if (mPauseOnAttack) {
237 	            if (mPauseTime == 0.0f) {
238 	                mPauseTime = PAUSE_TIME_ATTACK;
239 	                pauseMovement(parentObject);
240 
241 	            }
242         	}
243             parentObject.setCurrentAction(ActionType.ATTACK);
244 
245             break;
246 
247         case HotSpotSystem.HotSpotType.TALK:
248         	if (mHitReactComponent != null) {
249             	if (parentObject.lastReceivedHitType != HitType.COLLECT) {
250             		mHitReactComponent.setSpawnGameEventOnHit(
251             				HitType.COLLECT, mDialogEvent, mDialogIndex);
252             		if (parentObject.getVelocity().x != 0.0f) {
253             			pauseMovement(parentObject);
254             		}
255             		hitAccepted = false;
256             	} else {
257                     parentObject.setCurrentAction(ActionType.MOVE);
258 
259             		resumeMovement(parentObject);
260             		mHitReactComponent.setSpawnGameEventOnHit(HitType.INVALID, 0, 0);
261             		parentObject.lastReceivedHitType = HitType.INVALID;
262             	}
263         	}
264         	break;
265 
266         case HotSpotSystem.HotSpotType.WALK_AND_TALK:
267         	if (mDialogEvent != GameFlowEvent.EVENT_INVALID) {
268         		LevelSystem level = sSystemRegistry.levelSystem;
269         		level.sendGameEvent(mDialogEvent, mDialogIndex, true);
270         		mDialogEvent = GameFlowEvent.EVENT_INVALID;
271         	}
272         	break;
273 
274         case HotSpotSystem.HotSpotType.TAKE_CAMERA_FOCUS:
275         	if (camera != null) {
276         		camera.setTarget(parentObject);
277         	}
278         	break;
279 
280         case HotSpotSystem.HotSpotType.RELEASE_CAMERA_FOCUS:
281 
282         	if (camera != null) {
283         		GameObjectManager gameObjectManager = sSystemRegistry.gameObjectManager;
284         		camera.setTarget(gameObjectManager.getPlayer());
285         	}
286         	break;
287 
288         case HotSpotSystem.HotSpotType.END_LEVEL:
289         	HudSystem hud = sSystemRegistry.hudSystem;
290 
291         	if (hud != null) {
292         		hud.startFade(false, 1.5f);
293         		hud.sendGameEventOnFadeComplete(GameFlowEvent.EVENT_GO_TO_NEXT_LEVEL, 0);
294         	}
295         	break;
296         case HotSpotSystem.HotSpotType.GAME_EVENT:
297         	if (mGameEvent != -1) {
298     			LevelSystem level = sSystemRegistry.levelSystem;
299     			if (level != null) {
300     				level.sendGameEvent(mGameEvent, mGameEventIndex, true);
301     				mGameEvent = -1;
302     			}
303     		}
304         	break;
305 
306         case HotSpotSystem.HotSpotType.NPC_GO_UP_FROM_GROUND:
307             if (!parentObject.touchingGround()) {
308                 hitAccepted = false;
309                 break;
310             }
311             // fall through
312         case HotSpotSystem.HotSpotType.NPC_GO_UP:
313         	parentObject.getVelocity().y = mUpImpulse;
314         	parentObject.getTargetVelocity().y = 0.0f;
315             mTargetXVelocity = 0.0f;
316 
317             break;
318         case HotSpotSystem.HotSpotType.NPC_GO_DOWN_FROM_CEILING:
319             if (!parentObject.touchingCeiling()) {
320                 hitAccepted = false;
321                 break;
322             }
323             // fall through
324         case HotSpotSystem.HotSpotType.NPC_GO_DOWN:
325         	parentObject.getVelocity().y = mDownImpulse;
326         	parentObject.getTargetVelocity().y = 0.0f;
327         	if (mFlying) {
328         		mTargetXVelocity = 0.0f;
329         	}
330             break;
331         case HotSpotSystem.HotSpotType.NPC_GO_LEFT:
332         	parentObject.getTargetVelocity().x = -mHorizontalImpulse;
333         	parentObject.getAcceleration().x = mAcceleration;
334         	if (mFlying) {
335         		parentObject.getVelocity().y = 0.0f;
336         		parentObject.getTargetVelocity().y = 0.0f;
337         	}
338             break;
339         case HotSpotSystem.HotSpotType.NPC_GO_RIGHT:
340         	parentObject.getTargetVelocity().x = mHorizontalImpulse;
341         	parentObject.getAcceleration().x = mAcceleration;
342         	if (mFlying) {
343         		parentObject.getVelocity().y = 0.0f;
344         		parentObject.getTargetVelocity().y = 0.0f;
345         	}
346 
347             break;
348         case HotSpotSystem.HotSpotType.NPC_GO_UP_RIGHT:
349         	parentObject.getVelocity().y = mUpImpulse;
350         	parentObject.getTargetVelocity().x = mHorizontalImpulse;
351         	parentObject.getAcceleration().x = mAcceleration;
352 
353 
354             break;
355         case HotSpotSystem.HotSpotType.NPC_GO_UP_LEFT:
356         	parentObject.getVelocity().y = mUpImpulse;
357         	parentObject.getTargetVelocity().x = -mHorizontalImpulse;
358         	parentObject.getAcceleration().x = mAcceleration;
359 
360 
361             break;
362         case HotSpotSystem.HotSpotType.NPC_GO_DOWN_RIGHT:
363         	parentObject.getVelocity().y = mDownImpulse;
364         	parentObject.getTargetVelocity().x = mHorizontalImpulse;
365         	parentObject.getAcceleration().x = mAcceleration;
366 
367 
368             break;
369         case HotSpotSystem.HotSpotType.NPC_GO_DOWN_LEFT:
370         	parentObject.getVelocity().y = mDownImpulse;
371         	parentObject.getTargetVelocity().x = -mHorizontalImpulse;
372         	parentObject.getAcceleration().x = mAcceleration;
373 
374 
375             break;
376         case HotSpotSystem.HotSpotType.NPC_GO_TOWARDS_PLAYER:
377             int direction = 1;
378             GameObjectManager manager = sSystemRegistry.gameObjectManager;
379             if (manager != null) {
380                 GameObject player = manager.getPlayer();
381                 if (player != null) {
382                     direction = Utils.sign(
383                             player.getCenteredPositionX() -
384                             parentObject.getCenteredPositionX());
385                 }
386             }
387             parentObject.getTargetVelocity().x = mHorizontalImpulse * direction;
388             if (mFlying) {
389             	parentObject.getVelocity().y = 0.0f;
390         		parentObject.getTargetVelocity().y = 0.0f;
391         	}
392             break;
393         case HotSpotSystem.HotSpotType.NPC_GO_RANDOM:
394         	parentObject.getTargetVelocity().x = mHorizontalImpulse * (Math.random() > 0.5f ? -1.0f : 1.0f);
395         	if (mFlying) {
396         		parentObject.getVelocity().y = 0.0f;
397         		parentObject.getTargetVelocity().y = 0.0f;
398         	}
399             break;
400 
401         case HotSpotSystem.HotSpotType.NPC_STOP:
402         	parentObject.getTargetVelocity().x = 0.0f;
403         	parentObject.getVelocity().x = 0.0f;
404             break;
405 
406         case HotSpotSystem.HotSpotType.NPC_SLOW:
407         	parentObject.getTargetVelocity().x = mSlowHorizontalImpulse * Utils.sign(parentObject.getTargetVelocity().x);
408             break;
409 
410         case HotSpotSystem.HotSpotType.NPC_SELECT_DIALOG_1_1:
411         case HotSpotSystem.HotSpotType.NPC_SELECT_DIALOG_1_2:
412         case HotSpotSystem.HotSpotType.NPC_SELECT_DIALOG_1_3:
413         case HotSpotSystem.HotSpotType.NPC_SELECT_DIALOG_1_4:
414         case HotSpotSystem.HotSpotType.NPC_SELECT_DIALOG_1_5:
415         case HotSpotSystem.HotSpotType.NPC_SELECT_DIALOG_2_1:
416         case HotSpotSystem.HotSpotType.NPC_SELECT_DIALOG_2_2:
417         case HotSpotSystem.HotSpotType.NPC_SELECT_DIALOG_2_3:
418         case HotSpotSystem.HotSpotType.NPC_SELECT_DIALOG_2_4:
419         case HotSpotSystem.HotSpotType.NPC_SELECT_DIALOG_2_5:
420         	selectDialog(hotSpot);
421         	break;
422         case HotSpotSystem.HotSpotType.NONE:
423             if (parentObject.touchingGround() && parentObject.getVelocity().y <= 0.0f) {
424                 //resumeMovement(parentObject);
425             }
426             break;
427     	}
428 
429     	return hitAccepted;
430     }
431 
pauseMovement(GameObject parentObject)432     private void pauseMovement(GameObject parentObject) {
433     	mTargetXVelocity = parentObject.getTargetVelocity().x;
434     	parentObject.getTargetVelocity().x = 0.0f;
435     	parentObject.getVelocity().x = 0.0f;
436     }
437 
resumeMovement(GameObject parentObject)438     private void resumeMovement(GameObject parentObject) {
439     	parentObject.getTargetVelocity().x = mTargetXVelocity;
440     	parentObject.getAcceleration().x = mAcceleration;
441     }
442 
selectDialog(int hitSpot)443     private void selectDialog(int hitSpot) {
444 		mDialogEvent = GameFlowEvent.EVENT_SHOW_DIALOG_CHARACTER1;
445     	mDialogIndex = hitSpot - HotSpotSystem.HotSpotType.NPC_SELECT_DIALOG_1_1;
446 
447     	if (hitSpot >= HotSpotSystem.HotSpotType.NPC_SELECT_DIALOG_2_1) {
448     		mDialogEvent = GameFlowEvent.EVENT_SHOW_DIALOG_CHARACTER2;
449     		mDialogIndex = hitSpot - HotSpotSystem.HotSpotType.NPC_SELECT_DIALOG_2_1;
450     	}
451     }
452 
nextCommand()453     private int nextCommand() {
454     	int result = HotSpotSystem.HotSpotType.NONE;
455     	if (mQueueTop != mQueueBottom) {
456     		result = mQueuedCommands[mQueueTop];
457     	}
458     	return result;
459     }
460 
advanceQueue()461     private int advanceQueue() {
462     	int result = HotSpotSystem.HotSpotType.NONE;
463     	if (mQueueTop != mQueueBottom) {
464     		result = mQueuedCommands[mQueueTop];
465     		mQueueTop = (mQueueTop + 1) % COMMAND_QUEUE_SIZE;
466     	}
467     	return result;
468     }
469 
queueCommand(int hotspot)470     private void queueCommand(int hotspot) {
471     	int nextSlot = (mQueueBottom + 1) % COMMAND_QUEUE_SIZE;
472     	if (nextSlot != mQueueTop) { // only comply if there is space left in the buffer
473     		mQueuedCommands[mQueueBottom] = hotspot;
474     		mQueueBottom = nextSlot;
475     	}
476     }
477 
setHitReactionComponent(HitReactionComponent hitReact)478     public void setHitReactionComponent(HitReactionComponent hitReact) {
479     	mHitReactComponent = hitReact;
480     }
481 
setSpeeds(float horizontalImpulse, float slowHorizontalImpulse, float upImpulse, float downImpulse, float acceleration)482     public void setSpeeds(float horizontalImpulse, float slowHorizontalImpulse, float upImpulse, float downImpulse, float acceleration) {
483     	mHorizontalImpulse = horizontalImpulse;
484     	mSlowHorizontalImpulse = slowHorizontalImpulse;
485     	mUpImpulse = upImpulse;
486     	mDownImpulse = downImpulse;
487     	mAcceleration = acceleration;
488     }
489 
setGameEvent(int event, int index, boolean spawnOnDeath)490     public void setGameEvent(int event, int index, boolean spawnOnDeath) {
491     	mGameEvent = event;
492     	mGameEventIndex = index;
493     	mSpawnGameEventOnDeath = spawnOnDeath;
494     }
495 
setReactToHits(boolean react)496     public void setReactToHits(boolean react) {
497     	mReactToHits = react;
498     }
499 
setFlying(boolean flying)500     public void setFlying(boolean flying) {
501     	mFlying = flying;
502     }
503 
setPauseOnAttack(boolean pauseOnAttack)504     public void setPauseOnAttack(boolean pauseOnAttack) {
505     	mPauseOnAttack = pauseOnAttack;
506     }
507 }
508