package net.alcuria.umbracraft.engine.components; import net.alcuria.umbracraft.Game; import net.alcuria.umbracraft.definitions.anim.AnimationDefinition; import net.alcuria.umbracraft.definitions.anim.AnimationFrameDefinition; import net.alcuria.umbracraft.engine.components.AnimationCollectionComponent.Pose; import net.alcuria.umbracraft.engine.components.AnimationGroupComponent.Direction; import net.alcuria.umbracraft.engine.entities.Entity; import net.alcuria.umbracraft.listeners.Listener; import net.alcuria.umbracraft.listeners.TypeListener; import net.alcuria.umbracraft.util.StringUtils; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Array; /** A component to display a single animation. * @author Andrew Keturi */ public class AnimationComponent implements Component { //private float alpha = 1; private Listener completeListener; private int curFrameCount, curFrameIndex; private AnimationDefinition definition; private final Direction direction; private TypeListener<String> frameChangedListener; // invoked when a frame changes private Array<TextureRegion> frames; private boolean mirrorAll; private final Vector2 origin = new Vector2(); private boolean played = false; private final String template; private Pose templatePose; private int templateX, templateY; public AnimationComponent(AnimationDefinition definition) { this.definition = definition; template = null; direction = null; } public AnimationComponent(String template, int x, int y, Pose pose, Direction direction, AnimationDefinition definition) { this.definition = definition; this.template = template; this.direction = direction; templateX = x; templateY = y; templatePose = pose; } @Override public void create(Entity entity) { // see if we need to template this. if so create definition if (StringUtils.isNotEmpty(template)) { //TODO: at some point config this correctly definition = new AnimationDefinition(); definition.width = 24; definition.height = 32; definition.originX = 24 / 2; definition.originY = 2; definition.frames = new Array<AnimationFrameDefinition>(); definition.filename = template; switch (templatePose) { case WALKING: int idx[] = { 0, 1, 2, 1 }; for (int i = 0; i < idx.length; i++) { AnimationFrameDefinition walkFrameDef = new AnimationFrameDefinition(); walkFrameDef.duration = 5; walkFrameDef.x = templateX * 3 + idx[i]; walkFrameDef.y = templateY * 4 + direction.getTemplateIndex(); definition.frames.add(walkFrameDef); } break; default: AnimationFrameDefinition idleFrameDef = new AnimationFrameDefinition(); idleFrameDef.duration = 5; idleFrameDef.x = templateX * 3 + 1; idleFrameDef.y = templateY * 4 + direction.getTemplateIndex(); definition.frames.add(idleFrameDef); break; } } // now create frames = new Array<TextureRegion>(); curFrameCount = curFrameIndex = 0; if (definition != null) { // definition-based animation final Texture texture = Game.assets().get("sprites/animations/" + definition.filename + ".png", Texture.class); for (AnimationFrameDefinition frame : definition.frames) { frames.add(new TextureRegion(texture, frame.x * definition.width, frame.y * definition.height, definition.width, definition.height)); } origin.x = definition.originX; origin.y = definition.originY; } } @Override public void dispose(Entity entity) { } /** @return the {@link AnimationFrameDefinition} of the current frame playing */ public AnimationFrameDefinition getFrameDefinition() { if (definition == null || definition.frames == null) { throw new NullPointerException("Frames are null"); } return definition.frames.get(curFrameIndex); } @Override public void render(Entity entity) { if (frames != null && frames.size > 0) { final boolean mirror = mirrorAll ? !definition.frames.get(curFrameIndex).mirror : definition.frames.get(curFrameIndex).mirror; final Color color = definition.frames.get(curFrameIndex).color; Color oldColor = null; if (color != null) { Game.batch().setColor(color); oldColor = Game.batch().getColor(); } // Game.batch().draw(frames.get(0), entity.position.x - origin.x, entity.position.y - origin.y); Game.batch().draw(frames.get(curFrameIndex), entity.position.x + (mirror ? definition.width : 0) - origin.x, entity.position.y + entity.position.z - origin.y, mirror ? -definition.width : definition.width, definition.height); if (color != null) { Game.batch().setColor(oldColor); Game.batch().setColor(Color.WHITE); } } } /** Resets an animation, invokes the frame change listener. */ public void reset() { curFrameCount = curFrameIndex = 0; played = false; if (frameChangedListener != null) { frameChangedListener.invoke(definition.frames.get(curFrameIndex).particle); } } /** Sets a listener to invoke once the animation has run thru. Note, for * animations with keeplast this should still be invoked. * @param completeListener the listener */ public void setCompleteListener(Listener completeListener) { this.completeListener = completeListener; } /** Sets a listener to invoke when an animation's frame changes. * @param frameChangedListener the listener to invoke on frame change */ public void setFrameChangedListener(TypeListener<String> frameChangedListener) { this.frameChangedListener = frameChangedListener; } /** Set to true to flip all x images in the definition * @param mirrorAll whether or not to flip all */ public void setMirrorAll(boolean mirrorAll) { this.mirrorAll = mirrorAll; } /** Sets the rendering origin of the sprite * @param x * @param y */ public void setOrigin(float x, float y) { origin.x = x; origin.y = y; } /** Sets the rendering origin of the sprite * @param origin the new origin {@link Vector2} to use. Member fields are * set rather than tracking a pointer. */ public void setOrigin(Vector2 origin) { this.origin.x = origin.x; this.origin.y = origin.y; } @Override public void update(Entity entity) { curFrameCount++; if (curFrameCount > definition.frames.get(curFrameIndex).duration) { curFrameCount = 0; curFrameIndex = (curFrameIndex + 1) % definition.frames.size; if (curFrameIndex == 0 && !played && completeListener != null) { completeListener.invoke(); played = true; } if (definition.keepLast && curFrameIndex == 0) { curFrameIndex = definition.frames.size - 1; return; } if (frameChangedListener != null) { frameChangedListener.invoke(definition.frames.get(curFrameIndex).particle); } } } }