• 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.GameObject.ActionType;
20 import com.replica.replicaisland.HotSpotSystem.HotSpotType;
21 
22 /**
23  * This component implements the "patrolling" behavior for AI characters.  Patrolling characters
24  * will walk forward on the map until they hit a direction hot spot or a wall, in which case they
25  * may change direction.  Patrollers can also be configured via this component to attack the player
26  * if appropriate conditions are met.
27  */
28 public class PatrolComponent extends GameComponent {
29     private float mMaxSpeed;
30     private float mAcceleration;
31     private boolean mAttack;
32     private float mAttackAtDistance;
33     private boolean mAttackStopsMovement;
34     private float mAttackDuration;
35     private float mAttackDelay;
36     private boolean mTurnToFacePlayer;
37     private boolean mFlying;
38 
39     private float mLastAttackTime;
40     Vector2 mWorkingVector;
41     Vector2 mWorkingVector2;
42 
43 
PatrolComponent()44     public PatrolComponent() {
45         super();
46         mWorkingVector = new Vector2();
47         mWorkingVector2 = new Vector2();
48 
49         reset();
50         setPhase(GameComponent.ComponentPhases.THINK.ordinal());
51     }
52 
53     @Override
reset()54     public void reset() {
55         mTurnToFacePlayer = false;
56         mMaxSpeed = 0.0f;
57         mAcceleration = 0.0f;
58         mAttack = false;
59         mAttackAtDistance = 0.0f;
60         mAttackStopsMovement = false;
61         mAttackDuration = 0.0f;
62         mAttackDelay = 0.0f;
63         mWorkingVector.zero();
64         mWorkingVector2.zero();
65         mFlying = false;
66     }
67 
68     @Override
update(float timeDelta, BaseObject parent)69     public void update(float timeDelta, BaseObject parent) {
70         GameObject parentObject = (GameObject) parent;
71 
72         if (parentObject.getCurrentAction() == ActionType.INVALID
73         	|| parentObject.getCurrentAction() == ActionType.HIT_REACT) {
74             parentObject.setCurrentAction(GameObject.ActionType.MOVE);
75         }
76 
77         if ((mFlying || parentObject.touchingGround()) && parentObject.life > 0) {
78             GameObjectManager manager = sSystemRegistry.gameObjectManager;
79             GameObject player = null;
80             if (manager != null) {
81                 player = manager.getPlayer();
82             }
83 
84             if (mAttack) {
85                 updateAttack(player, parentObject);
86             }
87 
88 
89             if (parentObject.getCurrentAction() == GameObject.ActionType.MOVE
90                     && mMaxSpeed > 0.0f) {
91                 int hotSpot = HotSpotSystem.HotSpotType.NONE;
92                 HotSpotSystem hotSpotSystem = sSystemRegistry.hotSpotSystem;
93                 if (hotSpotSystem != null) {
94                     // TODO: ack, magic number
95                     hotSpot = hotSpotSystem.getHotSpot(parentObject.getCenteredPositionX(),
96                             parentObject.getPosition().y + 10.0f);
97                 }
98                 final float targetVelocityX = parentObject.getTargetVelocity().x;
99                 final float targetVelocityY = parentObject.getTargetVelocity().y;
100 
101                 boolean goLeft = (parentObject.touchingRightWall()
102                         || hotSpot == HotSpotType.GO_LEFT) && targetVelocityX >= 0.0f;
103 
104                 boolean goRight = (parentObject.touchingLeftWall()
105                         || hotSpot == HotSpotType.GO_RIGHT) && targetVelocityX <= 0.0f;
106 
107                 boolean pause = (mMaxSpeed == 0.0f) || hotSpot == HotSpotType.GO_DOWN;
108 
109                 if (mTurnToFacePlayer && player != null && player.life > 0) {
110                     final float horizontalDelta = player.getCenteredPositionX()
111                         - parentObject.getCenteredPositionX();
112                     final int targetFacingDirection = Utils.sign(horizontalDelta);
113                     final float closestDistance = player.width / 2.0f;
114 
115                     if (targetFacingDirection < 0.0f) { // we want to turn to the left
116                         if (goRight) {
117                             goRight = false;
118                             pause = true;
119                         } else if (targetFacingDirection
120                                 != Utils.sign(parentObject.facingDirection.x)) {
121                             goLeft = true;
122                         }
123                     } else if (targetFacingDirection > 0.0f) { // we want to turn to the right
124                         if (goLeft) {
125                             goLeft = false;
126                             pause = true;
127                         } else if (targetFacingDirection
128                                 != Utils.sign(parentObject.facingDirection.x)) {
129                             goRight = true;
130                         }
131                     }
132 
133                     if (Math.abs(horizontalDelta) < closestDistance) {
134                         goRight = false;
135                         goLeft = false;
136                         pause = true;
137                     }
138                 }
139 
140                 if (!mFlying) {
141                     if (!pause && !goLeft && !goRight && targetVelocityX == 0.0f) {
142                         if (parentObject.facingDirection.x < 0.0f) {
143                             goLeft = true;
144                         } else {
145                             goRight = true;
146                         }
147                     }
148 
149 
150                     if (goRight) {
151                         parentObject.getTargetVelocity().x = mMaxSpeed;
152                         parentObject.getAcceleration().x = mAcceleration;
153                     } else if (goLeft) {
154                         parentObject.getTargetVelocity().x = -mMaxSpeed;
155                         parentObject.getAcceleration().x = mAcceleration;
156                     } else if (pause) {
157                         parentObject.getTargetVelocity().x = 0;
158                         parentObject.getAcceleration().x = mAcceleration;
159                     }
160                 } else {
161                     final boolean goUp = (parentObject.touchingGround() && targetVelocityY < 0.0f)
162                     	|| hotSpot == HotSpotType.GO_UP;
163 
164                     final boolean goDown = (parentObject.touchingCeiling() && targetVelocityY > 0.0f)
165                             || hotSpot == HotSpotType.GO_DOWN;
166 
167                     if (goUp) {
168                         parentObject.getTargetVelocity().x = 0.0f;
169                         parentObject.getTargetVelocity().y = mMaxSpeed;
170                         parentObject.getAcceleration().y = mAcceleration;
171                         parentObject.getAcceleration().x = mAcceleration;
172 
173                     } else if (goDown) {
174                         parentObject.getTargetVelocity().x = 0.0f;
175                         parentObject.getTargetVelocity().y = -mMaxSpeed;
176                         parentObject.getAcceleration().y = mAcceleration;
177                         parentObject.getAcceleration().x = mAcceleration;
178 
179                     } else if (goRight) {
180                         parentObject.getTargetVelocity().x = mMaxSpeed;
181                         parentObject.getAcceleration().x = mAcceleration;
182                         parentObject.getAcceleration().y = mAcceleration;
183                         parentObject.getTargetVelocity().y = 0.0f;
184                     } else if (goLeft) {
185                         parentObject.getTargetVelocity().x = -mMaxSpeed;
186                         parentObject.getAcceleration().x = mAcceleration;
187                         parentObject.getAcceleration().y = mAcceleration;
188                         parentObject.getTargetVelocity().y = 0.0f;
189                     }
190                 }
191             }
192         } else if (!mFlying && !parentObject.touchingGround() && parentObject.life > 0) {
193         	// A non-flying unit is in the air.  In this case, just watch for bounces off walls.
194         	if (Utils.sign(parentObject.getTargetVelocity().x) != Utils.sign(parentObject.getVelocity().x)) {
195         		// Todo: maybe the physics code should adjust target velocity instead in this case?
196         		parentObject.getTargetVelocity().x *= -1.0f;
197         	}
198         }
199     }
200 
updateAttack(GameObject player, GameObject parentObject)201     private void updateAttack(GameObject player, GameObject parentObject) {
202         TimeSystem time = sSystemRegistry.timeSystem;
203         final float gameTime = time.getGameTime();
204 
205         boolean visible = true;
206         CameraSystem camera = sSystemRegistry.cameraSystem;
207         ContextParameters context = sSystemRegistry.contextParameters;
208         final float dx =
209             Math.abs(parentObject.getCenteredPositionX() - camera.getFocusPositionX());
210         final float dy =
211             Math.abs(parentObject.getCenteredPositionY() - camera.getFocusPositionY());
212         if (dx > context.gameWidth / 2.0f || dy > context.gameHeight / 2.0f) {
213             visible = false;
214         }
215         if (visible && parentObject.getCurrentAction() == GameObject.ActionType.MOVE) {
216             boolean closeEnough = false;
217             boolean timeToAttack = (gameTime - mLastAttackTime) > mAttackDelay;
218             if (mAttackAtDistance > 0 && player != null && player.life > 0
219                     && timeToAttack) {
220                 // only attack if we are facing the player
221                 if (Utils.sign(player.getPosition().x - parentObject.getPosition().x)
222                         == Utils.sign(parentObject.facingDirection.x)) {
223                     mWorkingVector.set(parentObject.getPosition());
224                     mWorkingVector.x = parentObject.getCenteredPositionX();
225                     mWorkingVector2.set(player.getPosition());
226                     mWorkingVector2.x = player.getCenteredPositionX();
227                     if (mWorkingVector2.distance2(mWorkingVector) <
228                         mAttackAtDistance * mAttackAtDistance) {
229                         closeEnough = true;
230                     }
231                 }
232             } else {
233                 closeEnough = true;  // If no distance has been set, don't worry about
234                                      // the player's position.
235             }
236 
237             if (timeToAttack && closeEnough) {
238                 // Time to attack.
239                 parentObject.setCurrentAction(GameObject.ActionType.ATTACK);
240                 mLastAttackTime = gameTime;
241                 if (mAttackStopsMovement) {
242                     parentObject.getVelocity().zero();
243                     parentObject.getTargetVelocity().zero();
244                 }
245             }
246         } else if (parentObject.getCurrentAction() == GameObject.ActionType.ATTACK) {
247             if (gameTime - mLastAttackTime > mAttackDuration) {
248                 parentObject.setCurrentAction(GameObject.ActionType.MOVE);
249                 if (mAttackStopsMovement) {
250                     parentObject.getTargetVelocity().x =
251                         mMaxSpeed * Utils.sign(parentObject.facingDirection.x);
252                     parentObject.getAcceleration().x = mAcceleration;
253                 }
254             }
255         }
256     }
257 
setMovementSpeed(float speed, float acceleration)258     public void setMovementSpeed(float speed, float acceleration) {
259         mMaxSpeed = speed;
260         mAcceleration = acceleration;
261     }
262 
setupAttack(float distance, float duration, float delay, boolean stopMovement)263     public void setupAttack(float distance, float duration, float delay, boolean stopMovement) {
264         mAttack = true;
265         mAttackAtDistance = distance;
266         mAttackStopsMovement = stopMovement;
267         mAttackDuration = duration;
268         mAttackDelay = delay;
269     }
270 
setTurnToFacePlayer(boolean turn)271     public void setTurnToFacePlayer(boolean turn) {
272         mTurnToFacePlayer = turn;
273     }
274 
setFlying(boolean flying)275     public void setFlying(boolean flying) {
276         mFlying = flying;
277     }
278 }
279