![JAR search and dependency download from the Maven repository](/logo.png)
com.brashmonkey.spriter.player.SpriterPlayer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of Spriter Show documentation
Show all versions of Spriter Show documentation
A generic Java library for Spriter animation files.
/**************************************************************************
* Copyright 2013 by Trixt0r
* (https://github.com/Trixt0r, Heinrich Reich, e-mail: [email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
package com.brashmonkey.spriter.player;
import com.brashmonkey.spriter.Spriter;
import com.brashmonkey.spriter.SpriterKeyFrameProvider;
import com.brashmonkey.spriter.animation.SpriterAnimation;
import com.brashmonkey.spriter.animation.SpriterKeyFrame;
import com.brashmonkey.spriter.file.FileLoader;
import com.discobeard.spriter.dom.Animation;
import com.discobeard.spriter.dom.Entity;
import com.discobeard.spriter.dom.SpriterData;
import java.util.HashMap;
import java.util.List;
/**
* A SpriterPlayer is the core of a spriter animation.
* Here you can get as many information as you need.
*
* SpriterPlayer plays the given data with the method {@link #update(float, float)}. You have to call this method by your own in your main game loop.
* SpriterPlayer updates the frames by its own. See {@link #setFrameSpeed(int)} for setting the playback speed.
*
* The animations can be drawn by {@link #draw()} which draws all objects with your own implemented Drawer.
*
* Accessing bones and animations via names is also possible. See {@link #getAnimationIndexByName(String)} and {@link #getBoneIndexByName(String)}.
* You can modify the whole animation or only bones at runtime with some fancy methods provided by this class.
* Have a look at {@link #setAngle(float)}, {@link #flipX()}, {@link #flipY()}, {@link #setScale(float)} for animation moddification.
* And see {@link #setBoneAngle(int, float)}, {@link #setBoneScaleX(int, float)}, {@link #setBoneScaleY(int, float)}.
*
* All stuff you set you can also receive by the corresponding getters ;) .
*
* @author Trixt0r
*/
public class SpriterPlayer extends SpriterAbstractPlayer{
private static HashMap loaded = new HashMap();
protected Entity entity;
private SpriterAnimation animation;
private int transitionSpeed = 30;
private int animationIndex = 0;
private int currentKey = 0;
SpriterKeyFrame lastRealFrame, firstKeyFrame, secondKeyFrame, animLastFrame;
boolean transitionTempFixed = true;
private int fixCounter = 0;
private int fixMaxSteps = 100;
private final SpriterData data;
/**
* Constructs a new SpriterPlayer object which animates the given Spriter entity.
* @param data {@link SpriterData} which provides a method to load all needed data to animate. See {@link Spriter#getSpriter(String, com.spriter.file.FileLoader)} for mor information.
* @param entityIndex The entity which should be handled by this player.
* @param loader The loader which has loaded all necessary sprites for the scml file.
*/
public SpriterPlayer(SpriterData data, Entity entity, FileLoader> loader){
super(loader, null);
this.data = data;
this.frame = 0;
this.setEntity(entity);
this.animation = this.animations.get(0);
this.firstKeyFrame = this.animation.frames.get(0);
this.update(0, 0);
}
/**
* Constructs a new SpriterPlayer object which animates the given Spriter entity.
* @param data {@link SpriterData} which provides a method to load all needed data to animate. See {@link Spriter#getSpriter(String, com.spriter.file.FileLoader)} for mor information.
* @param entityIndex The index of the entity which should be handled by this player.
* @param loader The loader which has loaded all necessary sprites for the scml file.
*/
public SpriterPlayer(SpriterData data, int entityIndex, FileLoader> loader){
this(data, data.getEntity().get(entityIndex), loader);
}
/**
* Constructs a new SpriterPlayer object which animates the given Spriter entity.
* @param data {@link Spriter} which provides a method to load all needed data to animate. See {@link Spriter#getSpriter(String, com.spriter.file.FileLoader)} for mor information.
* @param entityIndex The index of the entity which should be handled by this player.
* @param loader The loader which has loaded all necessary sprites for the scml file.
*/
public SpriterPlayer(Spriter spriter, int entityIndex, FileLoader> loader){
this(spriter.getSpriterData(), spriter.getSpriterData().getEntity().get(entityIndex), loader);
}
@Override
protected void step(float xOffset, float yOffset){
//Fetch information
List frameList = this.animation.frames;
if(this.transitionFixed && this.transitionTempFixed){
firstKeyFrame = frameList.get(this.currentKey);
secondKeyFrame = frameList.get((this.currentKey+1)%frameList.size());
//Update
this.frame += this.frameSpeed;
if(this.frame >= this.animation.length){
this.frame = 0;
this.currentKey = 0;
firstKeyFrame = frameList.get(this.currentKey);
secondKeyFrame = frameList.get((this.currentKey+1)%frameList.size());
}
if(this.frame > secondKeyFrame.getTime() && this.frameSpeed >= 0)
this.currentKey = (this.currentKey+1)%frameList.size();
else if(this.frame < firstKeyFrame.getTime()){
if(this.frame < 0){
this.frame = this.animation.length;
this.currentKey = frameList.size()-1;
firstKeyFrame = frameList.get(frameList.size()-1);
secondKeyFrame = frameList.get(0);
}
else this.currentKey = ((this.currentKey-1)+frameList.size())%frameList.size();
}
}
else{
firstKeyFrame = frameList.get(0);
secondKeyFrame = this.lastRealFrame;
float temp =(float)(this.fixCounter)/(float)this.fixMaxSteps;
this.frame = this.lastRealFrame.getTime()+(long)(this.fixMaxSteps*temp);
this.fixCounter= Math.min(this.fixCounter+this.transitionSpeed,this.fixMaxSteps);
//Update
if(this.fixCounter == this.fixMaxSteps){
this.frame = 0;
this.fixCounter = 0;
if(this.lastRealFrame.equals(this.lastFrame)) this.transitionFixed = true;
else this.transitionTempFixed = true;
firstKeyFrame.setTime(0);
}
}
//Interpolate
this.currenObjectsToDraw = firstKeyFrame.getObjects().length;
this.currentBonesToAnimate = firstKeyFrame.getBones().length;
this.transformBones(firstKeyFrame, secondKeyFrame, xOffset, yOffset);
this.transformObjects(firstKeyFrame, secondKeyFrame, xOffset, yOffset);
}
/**
* Sets the animationIndex for this to the given animationIndex.
* This method can make sure that the switching between to animations is smooth.
* By setting transitionSpeed and transitionSteps to appropriate values, you can have nice transitions between two animations.
* Setting transitionSpeed to 1 and transitionSteps to 20 means, that this player will need 20 steps to translate the current animation to the given one.
* @param animationIndex Index of animation to set. Get the index with {@link #getAnimationIndexByName(String)}.
* @param transitionSpeed Speed for the switch between the current animation and the one which has been set.
* @param transitionSteps Steps needed for the transition
*/
public void setAnimatioIndex(int animationIndex, int transitionSpeed, int transitionSteps) throws RuntimeException{
if(animationIndex >= this.entity.getAnimation().size() || animationIndex < 0) throw new RuntimeException("The given animation index does not exist: "+animationIndex+"\n"+
"Index range goes from 0 to " + (this.entity.getAnimation().size()-1));
if(this.animationIndex != animationIndex){
if(this.transitionFixed){
this.lastRealFrame = this.lastFrame;
this.transitionFixed = false;
this.transitionTempFixed = true;
}
else{
this.lastRealFrame = this.lastTempFrame;
this.transitionTempFixed = false;
this.transitionFixed = true;
}
this.transitionSpeed = transitionSpeed;
this.fixMaxSteps = transitionSteps;
this.lastRealFrame.setTime(this.frame+1);
this.animation = this.animations.get(animationIndex);
this.animation.frames.get(0).setTime(this.frame+1+this.fixMaxSteps);
this.currentKey = 0;
this.fixCounter = 0;
this.animationIndex = animationIndex;
}
}
public void setAnimationIndex(int animationIndex) throws RuntimeException{
this.setAnimatioIndex(animationIndex, 1, 1);
}
public void setAnimation(String animationName, int transitionSpeed, int transitionSteps){
int index = getAnimationIndexByName(animationName);
if(index >= this.entity.getAnimation().size() || index < 0) throw new RuntimeException("The animation \""+ animationName+"\" does not exist!");
this.setAnimatioIndex(index, transitionSpeed, transitionSteps);
}
public void setAnimation(String animationName){
this.setAnimation(animationName, 1, 1);
}
/**
* Searches for the animation index with the given name and returns the right one
* @param name name of the animation.
* @return index of the animation if the given name was found, otherwise it returns -1
*/
public int getAnimationIndexByName(String name){
Animation anim = this.getAnimationByName(name);
if(this.getAnimationByName(name) == null) return -1;
else return anim.getId();
}
/**
* Searches for the animation with the given name and returns the right one
* @param name of the animation.
* @return nimation if the given name was found, otherwise it returns null.
*/
public Animation getAnimationByName(String name){
List anims = this.entity.getAnimation();
for(Animation anim: anims)
if(anim.getName().equals(name)) return anim;
return null;
}
/**
* @return current animation index, which has same numbering as in the scml file.
*/
public int getAnimationIndex(){
return this.animationIndex;
}
/**
* @return the entity, which was read from the scml file you loaded before.
*/
public Entity getEntity() {
return entity;
}
/**
* @param entity the entity to set
*/
public void setEntity(Entity entity) {
if(this.entity == entity) return;
this.entity = entity;
if(!alreadyLoaded(entity)){
this.animations = SpriterKeyFrameProvider.generateKeyFramePool(this.data, entity);
loaded.put(entity, this);
}
else this.animations = loaded.get(entity).animations;
this.generateData();
}
/**
* Sets the entity by index.
* @param index
*/
public void setEntity(int index){
setEntity(data.getEntity().get(index));
}
/**
* Sets the character map to the character map with the given name,
* specified in the current set entity ({@link #setEntity(Entity)}).
* If no character map exists with the given name,
* the standard character map is applied.
* @param name
*/
public void setCharacterMap(String name){
super.characterMap = this.entity.getCharacterMapByName(name);
}
/**
* @return the current animation with all its raw data which was read from the scml file.
*/
public SpriterAnimation getAnimation() {
return animation;
}
private static boolean alreadyLoaded(Entity entity){
return loaded.containsKey(entity);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy