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
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 */
24public 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
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
48    public SpriteComponent() {
49        super();
50        mAnimations = new PhasedObjectManager();
51
52        reset();
53
54        setPhase(ComponentPhases.PRE_DRAW.ordinal());
55    }
56
57    @Override
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
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
141    public final void playAnimation(int index) {
142        if (mCurrentAnimationIndex != index) {
143            mAnimationTime = 0;
144            mCurrentAnimationIndex = index;
145            mCurrentAnimation = null;
146        }
147    }
148
149    public final SpriteAnimation findAnimation(int index) {
150        return (SpriteAnimation)mAnimations.find(index);
151    }
152
153    public final void addAnimation(SpriteAnimation anim) {
154        mAnimations.add(anim);
155        mAnimationsDirty = true;
156    }
157
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
169    public final float getWidth() {
170        return mWidth;
171    }
172
173    public final float getHeight() {
174        return mHeight;
175    }
176
177    public final void setSize(int width, int height) {
178        mWidth = width;
179        mHeight = height;
180    }
181
182    protected final void updateFlip(DrawableBitmap bitmap, boolean horzFlip, boolean vertFlip) {
183        bitmap.setFlip(horzFlip, vertFlip);
184    }
185
186    public final void setRenderComponent(RenderComponent component) {
187        mRenderComponent = component;
188    }
189
190    public final void setCollisionComponent(DynamicCollisionComponent component) {
191        mCollisionComponent = component;
192    }
193
194    public final boolean getVisible() {
195        return mVisible;
196    }
197
198    public final void setVisible(boolean visible) {
199        mVisible = visible;
200    }
201
202    public final float getCurrentAnimationTime() {
203        return mAnimationTime;
204    }
205
206    public final void setCurrentAnimationTime(float time) {
207        mAnimationTime = time;
208    }
209
210    public final void setOpacity(float opacity) {
211        mOpacity = opacity;
212    }
213
214    public final int getCurrentAnimation() {
215        return mCurrentAnimationIndex;
216    }
217
218    public final int getAnimationCount() {
219        return mAnimations.getConcreteCount();
220    }
221}
222