package Roguelike.Sprite; import Roguelike.Global; import Roguelike.Sound.SoundInstance; import Roguelike.Sprite.SpriteAnimation.AbstractSpriteAnimation; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.utils.Array; public final class Sprite { public enum AnimationMode { NONE, TEXTURE, SHRINK, SINE } public String fileName; private static final Color tempColour = new Color(); public Color colour = new Color( Color.WHITE ); public float renderDelay = -1; public boolean showBeforeRender = false; public float repeatDelay = 0; public float repeatAccumulator; public float animationDelay; public float animationAccumulator; public float rotation; public int[] size = { 1, 1 }; public Array<TextureRegion> textures; public AbstractSpriteAnimation spriteAnimation; public SpriteAction spriteAction; public AnimationState animationState; public SoundInstance sound; public boolean drawActualSize; public float[] baseScale = { 1, 1 }; public Sprite( String fileName, float animationDelay, Array<TextureRegion> textures, Color colour, AnimationMode mode, SoundInstance sound, boolean drawActualSize ) { this.fileName = fileName; this.textures = textures; this.animationDelay = animationDelay; this.sound = sound; this.drawActualSize = drawActualSize; animationState = new AnimationState(); animationState.mode = mode; this.colour = colour; } public float getLifetime() { return spriteAnimation != null ? spriteAnimation.duration : animationDelay * textures.size; } public float getRemainingLifetime() { return spriteAnimation != null ? spriteAnimation.duration - spriteAnimation.time : animationDelay * (textures.size - animationState.texIndex); } public boolean update( float delta ) { if ( renderDelay > 0 ) { renderDelay -= delta; if ( renderDelay > 0 ) { return false; } } if (repeatAccumulator > 0) { repeatAccumulator -= delta; } boolean looped = false; if (repeatAccumulator <= 0) { if (spriteAction != null && spriteAction.firePoint == SpriteAction.FirePoint.Start) { spriteAction.evaluate(); spriteAction = null; } animationAccumulator += delta; while ( animationAccumulator >= animationDelay ) { animationAccumulator -= animationDelay; if ( animationState.mode == AnimationMode.TEXTURE ) { if (spriteAction != null && spriteAnimation == null && animationState.texIndex == textures.size/2 && spriteAction.firePoint == SpriteAction.FirePoint.Middle) { spriteAction.evaluate(); spriteAction = null; } animationState.texIndex++; if ( animationState.texIndex >= textures.size ) { animationState.texIndex = 0; looped = true; repeatAccumulator = repeatDelay; } } else if ( animationState.mode == AnimationMode.SHRINK ) { animationState.isShrunk = !animationState.isShrunk; looped = animationState.isShrunk; } else if ( animationState.mode == AnimationMode.SINE ) { looped = true; } } } if ( animationState.mode == AnimationMode.SINE ) { animationState.sinOffset = (float) Math.sin( animationAccumulator / ( animationDelay / ( 2 * Math.PI ) ) ); } if ( spriteAnimation != null ) { looped = spriteAnimation.update( delta ); if (spriteAnimation.time >= spriteAnimation.duration / 2) { if (spriteAction != null && spriteAction.firePoint == SpriteAction.FirePoint.Middle) { spriteAction.evaluate(); spriteAction = null; } } if ( looped ) { spriteAnimation = null; } } if (looped) { if (spriteAction != null && spriteAction.firePoint == SpriteAction.FirePoint.End) { spriteAction.evaluate(); spriteAction = null; } } return looped; } public void render( Batch batch, int x, int y, int width, int height ) { float scaleX = baseScale[0]; float scaleY = baseScale[1]; if ( spriteAnimation != null ) { float[] scale = spriteAnimation.getRenderScale(); if ( scale != null ) { scaleX = scale[0]; scaleY = scale[1]; } } render( batch, x, y, width, height, scaleX, scaleY, animationState ); } public void render( Batch batch, int x, int y, int width, int height, float scaleX, float scaleY, AnimationState animationState ) { Color oldCol = null; if ( colour.a == 0 ) { return; } else if ( colour.r != 1 || colour.g != 1 || colour.b != 1 || colour.a != 1 ) { oldCol = batch.getColor(); Color col = tempColour.set( oldCol ).mul( colour ); batch.setColor( col ); } drawTexture( batch, textures.items[animationState.texIndex], x, y, width, height, scaleX, scaleY, animationState ); if ( oldCol != null ) { batch.setColor( oldCol ); } } private void drawTexture( Batch batch, TextureRegion texture, int x, int y, int width, int height, float scaleX, float scaleY, AnimationState animationState ) { if ( renderDelay > 0 && !showBeforeRender ) { return; } if ( drawActualSize ) { float widthRatio = width / 32.0f; float heightRatio = height / 32.0f; int trueWidth = (int) ( texture.getRegionWidth() * widthRatio ); int trueHeight = (int) ( texture.getRegionHeight() * heightRatio ); int widthOffset = ( trueWidth - width ) / 2; x -= widthOffset; width = trueWidth; height = trueHeight; } width = width * size[0]; height = height * size[1]; if ( animationState.mode == AnimationMode.SHRINK && animationState.isShrunk ) { height *= 0.9f; } else if ( animationState.mode == AnimationMode.SINE ) { y += ( height / 20 ) * animationState.sinOffset; } // Check if not onscreen if ( x + width < 0 || y + height < 0 || x > Global.Resolution[0] || y > Global.Resolution[1] ) { return; // skip drawing } batch.draw( texture, x, y, width / 2.0f, height / 2.0f, width, height, scaleX, scaleY, rotation ); } public TextureRegion getCurrentTexture() { return textures.get( animationState.texIndex ); } public Sprite copy() { Sprite sprite = new Sprite( fileName, animationDelay, textures, colour, animationState.mode, sound, drawActualSize ); if ( spriteAnimation != null ) { sprite.spriteAnimation = spriteAnimation.copy(); } return sprite; } public static final class AnimationState { public AnimationMode mode; public int texIndex; public boolean isShrunk; public float sinOffset; public AnimationState copy() { AnimationState as = new AnimationState(); as.mode = mode; as.texIndex = texIndex; as.isShrunk = isShrunk; as.sinOffset = sinOffset; return as; } public void set( AnimationState other ) { mode = other.mode; texIndex = other.texIndex; isShrunk = other.isShrunk; sinOffset = other.sinOffset; } } }