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 17package com.replica.replicaisland; 18 19import com.replica.replicaisland.ChannelSystem.Channel; 20import com.replica.replicaisland.GameObject.ActionType; 21 22public class NPCAnimationComponent extends GameComponent { 23 24 // Animations 25 public static final int IDLE = 0; 26 public static final int WALK = 1; 27 public static final int RUN_START = 2; 28 public static final int RUN = 3; 29 public static final int SHOOT = 4; 30 public static final int JUMP_START = 5; 31 public static final int JUMP_AIR = 6; 32 public static final int TAKE_HIT = 7; 33 public static final int SURPRISED = 8; 34 public static final int DEATH = 9; 35 36 37 protected static final float RUN_SPEED_THRESHOLD = 100.0f; 38 protected static final float JUMP_SPEED_THRESHOLD = 25.0f; 39 protected static final float FALL_SPEED_THRESHOLD = -25.0f; 40 protected static final float FALL_TIME_THRESHOLD = 0.2f; 41 42 private int mCurrentAnimation; 43 private SpriteComponent mSprite; 44 private ChannelSystem.Channel mChannel; 45 private int mChannelTrigger; 46 private boolean mFlying; 47 private boolean mStopAtWalls; // Controls whether or not the character will go back 48 // to idle when running into a wall 49 50 51 public NPCAnimationComponent() { 52 super(); 53 reset(); 54 setPhase(GameComponent.ComponentPhases.ANIMATION.ordinal()); 55 } 56 57 @Override 58 public void reset() { 59 mCurrentAnimation = IDLE; 60 mChannel = null; 61 mSprite = null; 62 mFlying = false; 63 mStopAtWalls = true; 64 } 65 66 @Override 67 public void update(float timeDelta, BaseObject parent) { 68 if (mSprite != null) { 69 GameObject parentObject = (GameObject)parent; 70 71 final int oldAnimation = mCurrentAnimation; 72 switch(mCurrentAnimation) { 73 case IDLE: 74 idle(parentObject); 75 break; 76 case WALK: 77 walk(parentObject); 78 break; 79 case RUN_START: 80 runStart(parentObject); 81 break; 82 case RUN: 83 run(parentObject); 84 break; 85 case SHOOT: 86 shoot(parentObject); 87 break; 88 case JUMP_START: 89 jumpStart(parentObject); 90 break; 91 case JUMP_AIR: 92 jumpAir(parentObject); 93 break; 94 case TAKE_HIT: 95 takeHit(parentObject); 96 break; 97 case SURPRISED: 98 surprised(parentObject); 99 break; 100 case DEATH: 101 death(parentObject); 102 break; 103 default: 104 assert(false); 105 } 106 107 if (mChannel != null) { 108 if (mChannel.value != null 109 && ((ChannelSystem.ChannelBooleanValue)mChannel.value).value) { 110 mCurrentAnimation = mChannelTrigger; 111 } 112 } 113 114 if (oldAnimation != mCurrentAnimation) { 115 mSprite.playAnimation(mCurrentAnimation); 116 } 117 } 118 } 119 120 protected boolean shouldFall(GameObject parentObject) { 121 boolean result = false; 122 TimeSystem time = sSystemRegistry.timeSystem; 123 final float airTime = time.getGameTime() - parentObject.getLastTouchedFloorTime(); 124 if (!mFlying && !parentObject.touchingGround() && airTime > FALL_TIME_THRESHOLD) { 125 final Vector2 velocity = parentObject.getVelocity(); 126 if (velocity.y < FALL_SPEED_THRESHOLD) { 127 result = true; 128 } 129 } 130 return result; 131 } 132 133 protected boolean shouldJump(GameObject parentObject) { 134 boolean result = false; 135 136 if (!mFlying) { 137 final Vector2 velocity = parentObject.getVelocity(); 138 if (velocity.y > JUMP_SPEED_THRESHOLD) { 139 result = true; 140 } 141 } 142 return result; 143 } 144 145 protected boolean shouldRun(GameObject parentObject) { 146 boolean result = false; 147 if (!mFlying && parentObject.touchingGround()) { 148 final Vector2 velocity = parentObject.getVelocity(); 149 if (Math.abs(velocity.x) >= RUN_SPEED_THRESHOLD) { 150 result = true; 151 } 152 } 153 return result; 154 } 155 156 protected boolean shouldMove(GameObject parentObject) { 157 boolean result = true; 158 final Vector2 velocity = parentObject.getVelocity(); 159 160 if (mStopAtWalls) { 161 if ((velocity.x < 0.0f && parentObject.touchingLeftWall()) 162 || (velocity.x > 0.0f && parentObject.touchingRightWall())) { 163 result = false; 164 } 165 } 166 return result; 167 } 168 169 protected boolean shouldTakeHit(GameObject parentObject) { 170 boolean result = false; 171 if (parentObject.getCurrentAction() == ActionType.HIT_REACT 172 && mSprite.findAnimation(TAKE_HIT) != null) { 173 result = true; 174 } 175 return result; 176 } 177 178 protected void gotoRunStart() { 179 if (mSprite.findAnimation(RUN_START) != null) { 180 mCurrentAnimation = RUN_START; 181 } else { 182 mCurrentAnimation = RUN; 183 } 184 } 185 186 protected void gotoRun() { 187 mCurrentAnimation = RUN; 188 } 189 190 protected void idle(GameObject parentObject) { 191 final GameObject.ActionType currentAction = parentObject.getCurrentAction(); 192 if (currentAction == ActionType.MOVE) { 193 final Vector2 velocity = parentObject.getVelocity(); 194 if (shouldFall(parentObject)) { 195 mCurrentAnimation = JUMP_AIR; 196 } else if (shouldJump(parentObject)) { 197 mCurrentAnimation = JUMP_START; 198 parentObject.positionLocked = true; 199 } else if (Math.abs(velocity.x) > 0.0f && shouldMove(parentObject)) { 200 if (shouldRun(parentObject)) { 201 gotoRunStart(); 202 parentObject.positionLocked = true; 203 } else { 204 mCurrentAnimation = WALK; 205 } 206 } 207 } else if (currentAction == ActionType.ATTACK) { 208 mCurrentAnimation = SHOOT; 209 } else if (shouldTakeHit(parentObject)) { 210 mCurrentAnimation = TAKE_HIT; 211 } else if (parentObject.getCurrentAction() == ActionType.DEATH) { 212 mCurrentAnimation = DEATH; 213 } 214 } 215 216 protected void walk(GameObject parentObject) { 217 final GameObject.ActionType currentAction = parentObject.getCurrentAction(); 218 if (currentAction == ActionType.MOVE) { 219 final Vector2 velocity = parentObject.getVelocity(); 220 if (shouldFall(parentObject)) { 221 mCurrentAnimation = JUMP_AIR; 222 } else if (shouldJump(parentObject)) { 223 mCurrentAnimation = JUMP_START; 224 parentObject.positionLocked = true; 225 } else if (Math.abs(velocity.x) > 0.0f) { 226 if (shouldRun(parentObject)) { 227 gotoRun(); 228 } 229 if (velocity.x > 0.0f) { 230 parentObject.facingDirection.x = 1; 231 } else { 232 parentObject.facingDirection.x = -1; 233 } 234 } else { 235 mCurrentAnimation = IDLE; 236 } 237 } else if (currentAction == ActionType.ATTACK) { 238 mCurrentAnimation = SHOOT; 239 } else if (shouldTakeHit(parentObject)) { 240 mCurrentAnimation = TAKE_HIT; 241 } else if (parentObject.getCurrentAction() == ActionType.DEATH) { 242 mCurrentAnimation = DEATH; 243 } 244 } 245 246 protected void runStart(GameObject parentObject) { 247 parentObject.positionLocked = true; 248 if (mSprite.animationFinished()) { 249 mCurrentAnimation = RUN; 250 parentObject.positionLocked = false; 251 } 252 } 253 protected void run(GameObject parentObject) { 254 final GameObject.ActionType currentAction = parentObject.getCurrentAction(); 255 if (currentAction == ActionType.MOVE) { 256 final Vector2 velocity = parentObject.getVelocity(); 257 if (shouldFall(parentObject)) { 258 mCurrentAnimation = JUMP_AIR; 259 } else if (shouldJump(parentObject)) { 260 parentObject.positionLocked = true; 261 mCurrentAnimation = JUMP_START; 262 } else if (Math.abs(velocity.x) > 0.0f) { 263 if (!shouldRun(parentObject)) { 264 mCurrentAnimation = WALK; 265 } 266 267 if (velocity.x > 0.0f) { 268 parentObject.facingDirection.x = 1; 269 } else { 270 parentObject.facingDirection.x = -1; 271 } 272 } else { 273 mCurrentAnimation = IDLE; 274 } 275 } else if (currentAction == ActionType.ATTACK) { 276 mCurrentAnimation = SHOOT; 277 } else if (shouldTakeHit(parentObject)) { 278 mCurrentAnimation = TAKE_HIT; 279 } else if (parentObject.getCurrentAction() == ActionType.DEATH) { 280 mCurrentAnimation = DEATH; 281 } 282 } 283 284 protected void shoot(GameObject parentObject) { 285 if (mSprite.animationFinished() || parentObject.getCurrentAction() != ActionType.ATTACK) { 286 mCurrentAnimation = IDLE; 287 } else if (shouldTakeHit(parentObject)) { 288 mCurrentAnimation = TAKE_HIT; 289 } else if (parentObject.getCurrentAction() == ActionType.DEATH) { 290 mCurrentAnimation = DEATH; 291 } else { 292 final Vector2 velocity = parentObject.getVelocity(); 293 294 if (velocity.x > 0.0f) { 295 parentObject.facingDirection.x = 1; 296 } else if (velocity.x < 0.0f) { 297 parentObject.facingDirection.x = -1; 298 } 299 } 300 } 301 302 protected void jumpStart(GameObject parentObject) { 303 final Vector2 velocity = parentObject.getVelocity(); 304 305 if (velocity.x > 0.0f) { 306 parentObject.facingDirection.x = 1; 307 } else if (velocity.x < 0.0f) { 308 parentObject.facingDirection.x = -1; 309 } 310 parentObject.positionLocked = true; 311 312 if (mSprite.animationFinished()) { 313 mCurrentAnimation = JUMP_AIR; 314 parentObject.positionLocked = false; 315 } 316 } 317 318 protected void jumpAir(GameObject parentObject) { 319 final GameObject.ActionType currentAction = parentObject.getCurrentAction(); 320 if (currentAction == ActionType.MOVE) { 321 final Vector2 velocity = parentObject.getVelocity(); 322 323 if (parentObject.touchingGround()) { 324 if (Math.abs(velocity.x) > 0.0f) { 325 if (shouldRun(parentObject)) { 326 mCurrentAnimation = RUN; 327 } else { 328 mCurrentAnimation = WALK; 329 } 330 } else { 331 mCurrentAnimation = IDLE; 332 } 333 } else { 334 335 if (velocity.x > 0.0f) { 336 parentObject.facingDirection.x = 1; 337 } else if (velocity.x < 0.0f) { 338 parentObject.facingDirection.x = -1; 339 } 340 341 } 342 } else { 343 mCurrentAnimation = IDLE; 344 } 345 } 346 347 protected void takeHit(GameObject parentObject) { 348 if (mSprite.animationFinished()) { 349 if (parentObject.life > 0 && parentObject.getCurrentAction() != ActionType.DEATH) { 350 if (parentObject.getCurrentAction() != ActionType.HIT_REACT) { 351 mCurrentAnimation = IDLE; 352 } 353 } else { 354 mCurrentAnimation = DEATH; 355 } 356 } 357 } 358 359 protected void surprised(GameObject parentObject) { 360 if (mSprite.animationFinished()) { 361 mCurrentAnimation = IDLE; 362 } 363 } 364 365 protected void death(GameObject parentObject) { 366 } 367 368 public void setSprite(SpriteComponent sprite) { 369 mSprite = sprite; 370 } 371 372 public void setChannel(Channel channel) { 373 mChannel = channel; 374 } 375 376 public void setChannelTrigger(int animation) { 377 mChannelTrigger = animation; 378 } 379 380 public void setFlying(boolean flying) { 381 mFlying = flying; 382 } 383 384 public void setStopAtWalls(boolean stop) { 385 mStopAtWalls = stop; 386 } 387} 388