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 /** 20 * Provides an interface for controlling a sprite with animations. Manages a list of animations 21 * and provides a drawable surface with the correct animation frame to a render component each 22 * frame. Also manages horizontal and vertical flipping. 23 */ 24 public class SpriteComponent extends GameComponent { 25 26 private PhasedObjectManager mAnimations; 27 private float mAnimationTime; 28 private int mCurrentAnimationIndex; 29 private int mWidth; 30 private int mHeight; 31 private float mOpacity; 32 private RenderComponent mRenderComponent; 33 private DynamicCollisionComponent mCollisionComponent; 34 private boolean mVisible; 35 private SpriteAnimation mCurrentAnimation; 36 private boolean mAnimationsDirty; 37 SpriteComponent(int width, int height)38 public SpriteComponent(int width, int height) { 39 super(); 40 mAnimations = new PhasedObjectManager(); 41 42 reset(); 43 mWidth = width; 44 mHeight = height; 45 setPhase(ComponentPhases.PRE_DRAW.ordinal()); 46 } 47 SpriteComponent()48 public SpriteComponent() { 49 super(); 50 mAnimations = new PhasedObjectManager(); 51 52 reset(); 53 54 setPhase(ComponentPhases.PRE_DRAW.ordinal()); 55 } 56 57 @Override reset()58 public void reset() { 59 mWidth = 0; 60 mHeight = 0; 61 mVisible = true; 62 mCurrentAnimationIndex = -1; 63 mAnimations.removeAll(); 64 mAnimations.commitUpdates(); 65 mAnimationTime = 0.0f; 66 mRenderComponent = null; 67 mCollisionComponent = null; 68 mCurrentAnimation = null; 69 mOpacity = 1.0f; 70 mAnimationsDirty = false; 71 } 72 73 @Override update(float timeDelta, BaseObject parent)74 public void update(float timeDelta, BaseObject parent) { 75 mAnimationTime += timeDelta; 76 final PhasedObjectManager animations = mAnimations; 77 final int currentAnimIndex = mCurrentAnimationIndex; 78 79 if (mAnimationsDirty) { 80 animations.commitUpdates(); 81 mAnimationsDirty = false; 82 } 83 boolean validFrameAvailable = false; 84 if (animations.getCount() > 0 && currentAnimIndex != -1) { 85 SpriteAnimation currentAnimation = mCurrentAnimation; 86 87 if (currentAnimation == null && currentAnimIndex != -1) { 88 currentAnimation = findAnimation(currentAnimIndex); 89 if (currentAnimation == null) { 90 // We were asked to play an animation that doesn't exist. Revert to our 91 // default animation. 92 // TODO: throw an assert here? 93 mCurrentAnimation = (SpriteAnimation)animations.get(0); 94 currentAnimation = mCurrentAnimation; 95 } else { 96 mCurrentAnimation = currentAnimation; 97 } 98 } 99 100 GameObject parentObject = (GameObject)parent; 101 AnimationFrame currentFrame = currentAnimation.getFrame(mAnimationTime); 102 if (currentFrame != null) { 103 validFrameAvailable = true; 104 final RenderComponent render = mRenderComponent; 105 if (render != null) { 106 final DrawableFactory factory = sSystemRegistry.drawableFactory; 107 if (mVisible && currentFrame.texture != null && factory != null) { 108 // Fire and forget. Allocate a new bitmap for this animation frame, set it up, and 109 // pass it off to the render component for drawing. 110 DrawableBitmap bitmap = factory.allocateDrawableBitmap(); 111 bitmap.setWidth(mWidth); 112 bitmap.setHeight(mHeight); 113 bitmap.setOpacity(mOpacity); 114 updateFlip(bitmap, parentObject.facingDirection.x < 0.0f, 115 parentObject.facingDirection.y < 0.0f); 116 bitmap.setTexture(currentFrame.texture); 117 render.setDrawable(bitmap); 118 } else { 119 render.setDrawable(null); 120 } 121 } 122 123 if (mCollisionComponent != null) { 124 mCollisionComponent.setCollisionVolumes(currentFrame.attackVolumes, 125 currentFrame.vulnerabilityVolumes); 126 } 127 } 128 } 129 130 if (!validFrameAvailable) { 131 // No current frame = draw nothing! 132 if (mRenderComponent != null) { 133 mRenderComponent.setDrawable(null); 134 } 135 if (mCollisionComponent != null) { 136 mCollisionComponent.setCollisionVolumes(null, null); 137 } 138 } 139 } 140 playAnimation(int index)141 public final void playAnimation(int index) { 142 if (mCurrentAnimationIndex != index) { 143 mAnimationTime = 0; 144 mCurrentAnimationIndex = index; 145 mCurrentAnimation = null; 146 } 147 } 148 findAnimation(int index)149 public final SpriteAnimation findAnimation(int index) { 150 return (SpriteAnimation)mAnimations.find(index); 151 } 152 addAnimation(SpriteAnimation anim)153 public final void addAnimation(SpriteAnimation anim) { 154 mAnimations.add(anim); 155 mAnimationsDirty = true; 156 } 157 animationFinished()158 public final boolean animationFinished() { 159 boolean result = false; 160 if (mCurrentAnimation != null 161 && !mCurrentAnimation.getLoop() 162 && mAnimationTime > mCurrentAnimation.getLength()) { 163 result = true; 164 } 165 return result; 166 } 167 168 getWidth()169 public final float getWidth() { 170 return mWidth; 171 } 172 getHeight()173 public final float getHeight() { 174 return mHeight; 175 } 176 setSize(int width, int height)177 public final void setSize(int width, int height) { 178 mWidth = width; 179 mHeight = height; 180 } 181 updateFlip(DrawableBitmap bitmap, boolean horzFlip, boolean vertFlip)182 protected final void updateFlip(DrawableBitmap bitmap, boolean horzFlip, boolean vertFlip) { 183 bitmap.setFlip(horzFlip, vertFlip); 184 } 185 setRenderComponent(RenderComponent component)186 public final void setRenderComponent(RenderComponent component) { 187 mRenderComponent = component; 188 } 189 setCollisionComponent(DynamicCollisionComponent component)190 public final void setCollisionComponent(DynamicCollisionComponent component) { 191 mCollisionComponent = component; 192 } 193 getVisible()194 public final boolean getVisible() { 195 return mVisible; 196 } 197 setVisible(boolean visible)198 public final void setVisible(boolean visible) { 199 mVisible = visible; 200 } 201 getCurrentAnimationTime()202 public final float getCurrentAnimationTime() { 203 return mAnimationTime; 204 } 205 setCurrentAnimationTime(float time)206 public final void setCurrentAnimationTime(float time) { 207 mAnimationTime = time; 208 } 209 setOpacity(float opacity)210 public final void setOpacity(float opacity) { 211 mOpacity = opacity; 212 } 213 getCurrentAnimation()214 public final int getCurrentAnimation() { 215 return mCurrentAnimationIndex; 216 } 217 getAnimationCount()218 public final int getAnimationCount() { 219 return mAnimations.getConcreteCount(); 220 } 221 } 222