java 是否有一个通用的方法来计算动画的结束和动画之间的切换时,他们完成?

z9ju0rcb  于 2023-09-29  发布在  Java
关注(0)|答案(1)|浏览(81)

我正在做一个游戏,它有不统一的关键帧动画,这样就可以为了平衡的目的而改变启动,活动和恢复帧。我有循环动画,如闲置和步行,循环相当顺利,但攻击动画,只有发挥一次是非常口吃,有时发挥多次。
我已经尝试了以下计算没有帮助的伪ish代码

in animation class:
isAnimationFinished(float time)
    return (time / animationLength) >= 0.95
    // Note: 0.95 seemed like a good value as it seemed that the last frame in any animation
    // would result in a value between 0.95 and 0.99 when used in this calculation. 

// frameTimes is an array of floats that stores the amount of time, in milliseconds,
// that a key frame should be drawn for. 
// One example of an array used is:
float[] jabFrames = {
    FRAME * frameData[0].getStartUpFrames(), FRAME * frameData[0].getActiveFrames(),
    FRAME * frameData[0].getRecoveryFrames()
};
// Where FRAME is a float of 1/60f and frameData is an int array

getAnimationDuration()
    sum = 0.0
    for each floatValue in frameTimes:
        sum += floatValue 
    return sum

...

in the pawn class's draw function:

draw(deltaTime):
    stateTime += deltaTime (time since last render)

    get the animation based on the animation_state

    if(animation_state is JAB and animation.isAnimationFinished(stateTime))
        animation_state = IDLE

    if(stateTime >= animation.getAnimationDuration())
        stateTime -= animation.getAnimationDuration()

    drawAnimation()
mrphzbgm

mrphzbgm1#

如果使用libGDX中的Animation类,则可以使用以下方法(从API):

  • getAnimationDuration:整个动画的持续时间,帧数乘以帧持续时间,以秒为单位
  • isAnimationFinished(float):如果不循环播放(PlayMode#NORMAL),给定状态时间,动画是否结束。

所以你只需要知道当前的stateTime,就像你在伪代码中已经做过的那样计算:

public void draw(float deltaTime) {
    stateTime += deltaTime;
    
    //...
}

有关如何使用libGDX动画的进一步介绍,请参阅this tutorial
在我的一个项目中,我使用了一个 Package 器类来实现一些额外的功能。如果你想使用它,你可以在GitHub上找到它,或者使用它的当前版本:

AnimationDirector

import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.Animation.PlayMode;

import net.jfabricationgames.gdx.screens.game.GameScreen;

import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;

public class AnimationDirector<T extends TextureRegion> {
    
    public static boolean isTextureRight(boolean initialAnimationDirectionIsRight, AnimationDirector<TextureRegion> animation) {
        return initialAnimationDirectionIsRight != animation.getKeyFrame().isFlipX();
    }
    
    public static boolean isTextureLeft(boolean initialAnimationDirectionIsRight, AnimationDirector<TextureRegion> animation) {
        return initialAnimationDirectionIsRight == animation.getKeyFrame().isFlipX();
    }
    
    private float stateTime;
    private Animation<T> animation;
    
    private AnimationSpriteConfig spriteConfig;
    
    public AnimationDirector(Animation<T> animation) {
        this.animation = animation;
        initializeSpriteConfigWithoutPosition();
    }
    
    protected void initializeSpriteConfigWithoutPosition() {
        T keyFrame = animation.getKeyFrame(0);
        spriteConfig = new AnimationSpriteConfig().setWidth(keyFrame.getRegionWidth()).setHeight(keyFrame.getRegionHeight());
    }
    
    /**
     * Draw the current key frame of this animation onto the {@link SpriteBatch}.<br>
     * ATTENTION: This method will throw an {@link IllegalStateException} if this AnimationDirector does not contain an AnimationSpriteConfig object.
     */
    public void draw(SpriteBatch batch) {
        if (spriteConfig == null) {
            throw new IllegalStateException("No AnimationSpriteConfig. Please add an AnimationSpriteConfig in order to use the draw method");
        }
        T keyFrame = getKeyFrame();
        float x = spriteConfig.x + ((spriteConfig.width - keyFrame.getRegionWidth()) * GameScreen.WORLD_TO_SCREEN * 0.5f);
        float y = spriteConfig.y + ((spriteConfig.height - keyFrame.getRegionHeight()) * GameScreen.WORLD_TO_SCREEN * 0.5f);
        batch.draw(keyFrame, x, y, spriteConfig.width * 0.5f, spriteConfig.height * 0.5f, keyFrame.getRegionWidth(), keyFrame.getRegionHeight(),
                GameScreen.WORLD_TO_SCREEN, GameScreen.WORLD_TO_SCREEN, 0f);
    }
    
    public void drawInMenu(SpriteBatch batch) {
        if (spriteConfig == null) {
            throw new IllegalStateException("No AnimationSpriteConfig. Please add an AnimationSpriteConfig in order to use the draw method");
        }
        
        T keyFrame = getKeyFrame();
        batch.draw(keyFrame, spriteConfig.x, spriteConfig.y, spriteConfig.width, spriteConfig.height);
    }
    
    /**
     * Get the frame at the current time.
     */
    public T getKeyFrame() {
        return animation.getKeyFrame(stateTime);
    }
    
    public float getStateTime() {
        return stateTime;
    }
    
    public void increaseStateTime(float delta) {
        stateTime += delta;
    }
    
    public void setStateTime(float stateTime) {
        this.stateTime = stateTime;
    }
    
    /**
     * Reset the state time to 0 to restart the animation.
     */
    public void resetStateTime() {
        stateTime = 0;
    }
    
    /**
     * Set the animation state time to the end of the animation.
     */
    public void endAnimation() {
        stateTime = animation.getAnimationDuration();
    }
    
    public void setPlayMode(PlayMode playMode) {
        animation.setPlayMode(playMode);
    }
    
    /**
     * Get the {@link Animation} that this object holds.
     */
    public Animation<T> getAnimation() {
        return animation;
    }
    
    public boolean isAnimationFinished() {
        return animation.isAnimationFinished(stateTime);
    }
    
    public float getAnimationDuration() {
        return animation.getAnimationDuration();
    }
    
    /**
     * Flip all key frames of the animation.
     */
    public void flip(boolean x, boolean y) {
        for (TextureRegion region : animation.getKeyFrames()) {
            region.flip(x, y);
        }
    }
    
    public AnimationSpriteConfig getSpriteConfig() {
        return spriteConfig;
    }
    
    public void setSpriteConfig(AnimationSpriteConfig spriteConfig) {
        this.spriteConfig = spriteConfig;
    }
    
    public AnimationSpriteConfig getSpriteConfigCopy() {
        return new AnimationSpriteConfig(spriteConfig);
    }
}

AnimationSpriteConfig

import com.badlogic.gdx.graphics.g2d.Sprite;

public class AnimationSpriteConfig {
    
    public static AnimationSpriteConfig fromSprite(Sprite sprite) {
        AnimationSpriteConfig spriteConfig = new AnimationSpriteConfig();
        spriteConfig.width = sprite.getWidth();
        spriteConfig.height = sprite.getHeight();
        spriteConfig.x = sprite.getX();
        spriteConfig.y = sprite.getY();
        
        return spriteConfig;
    }
    
    public AnimationSpriteConfig() {}
    
    public AnimationSpriteConfig(AnimationSpriteConfig spriteConfig) {
        this.x = spriteConfig.x;
        this.y = spriteConfig.y;
        this.width = spriteConfig.width;
        this.height = spriteConfig.height;
    }
    
    public float x;
    public float y;
    public float width;
    public float height;
    
    public AnimationSpriteConfig setX(float x) {
        this.x = x;
        return this;
    }
    
    public AnimationSpriteConfig setY(float y) {
        this.y = y;
        return this;
    }
    
    public AnimationSpriteConfig setWidth(float width) {
        this.width = width;
        return this;
    }
    
    public AnimationSpriteConfig setHeight(float height) {
        this.height = height;
        return this;
    }
}

相关问题