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