动画精灵问题

时间:2015-02-17 20:49:54

标签: java android animation libgdx

我在学习libgdx游戏开发书的最后,最后一章是关于精灵(兔子)的动画。当它应该加载游戏屏幕时会发生错误,我真的无法弄清楚我做错了什么,我确信这是动画兔子,我一步一步走到这里,这是错误发生的地方:

reg = animation.getKeyFrame(stateTime, true);

如果你能给我一个提示,我将不胜感激。

BunnyHead.java

package com.packtub.libgdx.canyonbunny.game.objects;

import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.packtub.libgdx.canyonbunny.game.Assets;
import com.packtub.libgdx.canyonbunny.util.AudioManager;
import com.packtub.libgdx.canyonbunny.util.Constants;
import com.packtub.libgdx.canyonbunny.util.CharacterSkin;
import com.packtub.libgdx.canyonbunny.util.GamePreferences;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g2d.ParticleEffect;
import com.badlogic.gdx.math.MathUtils;

public class BunnyHead extends AbstractGameObject{
    public static final String TAG = BunnyHead.class.getName();

    private final float JUMP_TIME_MAX = 0.3f;
    private final float JUMP_TIME_MIN = 0.1f;
    private final float JUMP_TIME_OFFSET_FLYING = JUMP_TIME_MAX - 0.018f;
    public ParticleEffect dustParticle = new ParticleEffect();

    //Animacion
    private Animation animNormal;
    private Animation animCopterTransform;
    private Animation animCopterTransformBack;
    private Animation animCopterRotate;


    public enum VIEW_DIRECTION {LEFT,RIGHT}
    public enum JUMP_STATE{
        GROUNDED, FALLING, JUMP_RISING, JUMP_FALLING
    }

    private TextureRegion regHead;
    public VIEW_DIRECTION viewDirection;
    public float timeJumping;
    public JUMP_STATE jumpState;
    public boolean hasFeatherPowerup;
    public float timeLeftFeatherPowerup;

    public BunnyHead(){
        init();
    }

    private void init() {
        dimension.set(1, 1);
        //regHead = Assets.instance.bunny.head;
        animNormal = Assets.instance.bunny.animNormal;
        animCopterTransform = Assets.instance.bunny.animCopterTransform;
        animCopterTransformBack = Assets.instance.bunny.animCopterTransformBack;
        animCopterRotate = Assets.instance.bunny.animCopterRotate;


        //Centra la imagen en el objeto
        origin.set(dimension.x / 2, dimension.y / 2);
        //Pone bordes por colicciones
        bounds.set(0, 0, dimension.x, dimension.y);
        //Se establecen valores fisicos
        terminalVelocity.set(3.0f, 4.0f);
        friction.set(12.0f, 0.0f);
        acceleration.set(0.0f, -25.0f);
        //Ver direccion
        viewDirection = VIEW_DIRECTION.RIGHT;
        //Estado Salto
        jumpState = JUMP_STATE.FALLING;
        timeJumping = 0;
        //Power ups
        hasFeatherPowerup = false;
        timeLeftFeatherPowerup = 0;

        //Particula
        dustParticle.load(Gdx.files.internal("particles/dust.pfx"), Gdx.files.internal("particles"));

    }

    @Override
    public void update(float deltaTime){
        super.update(deltaTime);
        //Maneja la direccion de hacia donde se ve segun la velocidad
        if (velocity.x != 0){
            viewDirection = velocity.x < 0 ? VIEW_DIRECTION.LEFT:VIEW_DIRECTION.RIGHT;
        }
        if (timeLeftFeatherPowerup > 0){
            if (animation == animCopterTransformBack){
                //Reinicia la animacion "Transform" si se recogio otra pluma durante
                //la animacion "TransformBack". De otra manera se quedaria atascada
                //en esta animacion
                setAnimation(animCopterTransform);
            }
            timeLeftFeatherPowerup -= deltaTime;
            if (timeLeftFeatherPowerup < 0) {
                //Se desactiva el Power up
                timeLeftFeatherPowerup = 0;
                setFeatherPowerup(false);
                setAnimation(animCopterTransformBack);
            }
        }

        dustParticle.update(deltaTime);

        //Cambia la animacion acorde al poder de la pluma
        if (hasFeatherPowerup){
            if (animation == animNormal){
                setAnimation(animCopterTransform);
            }else if (animation == animCopterTransform){
                if (animation.isAnimationFinished(stateTime))
                    setAnimation(animCopterRotate);
            }
        }else{
            if (animation == animCopterRotate){
                if (animation.isAnimationFinished(stateTime))
                    setAnimation(animCopterTransformBack);
            }else if (animation == animCopterTransformBack){
                if (animation.isAnimationFinished(stateTime))
                    setAnimation(animNormal);
            }
        }
    }

    @Override
    public void render(SpriteBatch batch) {
        TextureRegion reg = null;

        //Dibujar particulas
        dustParticle.draw(batch);
        //Cambiar color skin
        batch.setColor(CharacterSkin.values()[GamePreferences.instance.charSkin].getColor());

        float dimCorrectionX = 0;
        float dimCorrectionY = 0;

        if (animation != animNormal){
            dimCorrectionX = 0.05f;
            dimCorrectionY = 0.2f;
        }


        //Dibuja imagen
        //reg = regHead;
        reg = animation.getKeyFrame(stateTime, true);

        batch.draw(reg.getTexture(),
                position.x, position.y,
                origin.x, origin.y,
                dimension.x + dimCorrectionX, dimension.y + dimCorrectionY,
                scale.x, scale.y,
                rotation,
                reg.getRegionX(), reg.getRegionY(),
                reg.getRegionWidth(), reg.getRegionHeight(),
                viewDirection == VIEW_DIRECTION.LEFT, false);

        //Reseta el color a blanco
        batch.setColor(1, 1, 1, 1);


    }

}

@Override
    public void update(float deltaTime){
        super.update(deltaTime);
        //Maneja la direccion de hacia donde se ve segun la velocidad
        if (velocity.x != 0){
            viewDirection = velocity.x < 0 ? VIEW_DIRECTION.LEFT:VIEW_DIRECTION.RIGHT;
        }
        if (timeLeftFeatherPowerup > 0){
            if (animation == animCopterTransformBack){
                //Reinicia la animacion "Transform" si se recogio otra pluma durante
                //la animacion "TransformBack". De otra manera se quedaria atascada
                //en esta animacion
                setAnimation(animCopterTransform);
            }
            timeLeftFeatherPowerup -= deltaTime;
            if (timeLeftFeatherPowerup < 0) {
                //Se desactiva el Power up
                timeLeftFeatherPowerup = 0;
                setFeatherPowerup(false);
                setAnimation(animCopterTransformBack);
            }
        }

        dustParticle.update(deltaTime);

        //Cambia la animacion acorde al poder de la pluma
        if (hasFeatherPowerup){
            if (animation == animNormal){
                setAnimation(animCopterTransform);
            }else if (animation == animCopterTransform){
                if (animation.isAnimationFinished(stateTime)){
                    setAnimation(animCopterRotate);
                }
            }
        }else{
            if (animation == animCopterRotate){
                if (animation.isAnimationFinished(stateTime)){
                    setAnimation(animCopterTransformBack);
                    }
            }else if (animation == animCopterTransformBack){
                if (animation.isAnimationFinished(stateTime))
                    setAnimation(animNormal);
            }
        }
    }

Assets.java

package com.packtub.libgdx.canyonbunny.game;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.assets.AssetDescriptor;
import com.badlogic.gdx.assets.AssetErrorListener;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.utils.Disposable;
import com.packtub.libgdx.canyonbunny.util.Constants;
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.utils.Array;

public class Assets implements Disposable, AssetErrorListener{
    public static final String TAG = Assets.class.getName();
    public static final Assets instance = new Assets();
    private AssetManager assetManager;
    public AssetFonts fonts;

    //singleton: previene de inicializaciones desde otras clases
    private Assets () {}

    public AssetBunny bunny;
    public AssetRock rock;
    public AssetGoldCoin goldCoin;
    public AssetFeather feather;
    public AssetLevelDecoration levelDecoration;
    public AssetSounds sounds;
    public AssetMusic music;


    public void init (AssetManager assetManager){
        this.assetManager = assetManager;
        //Se establece el asset manager que maneja los errores
        assetManager.setErrorListener(this);
        //Carga las texturas atlas
        assetManager.load(Constants.TEXTURE_ATLAS_OBJECTS, TextureAtlas.class);
        //Cargar sonido
        assetManager.load("sounds/jump.wav", Sound.class);
        assetManager.load("sounds/jump_with_feather.wav", Sound.class);
        assetManager.load("sounds/pickup_coin.wav", Sound.class);
        assetManager.load("sounds/pickup_feather.wav", Sound.class);
        assetManager.load("sounds/live_lost.wav", Sound.class);
        //Cargar musica
        assetManager.load("music/keith303_-_brand_new_highscore.mp3", Music.class);
        //Se inicia a cargar los assets y se espera que termine
        assetManager.finishLoading();
        Gdx.app.debug(TAG, "# de assets cargados: " 
        + assetManager.getAssetNames().size);
        for (String a : assetManager.getAssetNames()) Gdx.app.debug(TAG, "asset: " + a);

        TextureAtlas atlas = assetManager.get(Constants.TEXTURE_ATLAS_OBJECTS);

        //activa la opcion "texture filtering" para una dibujado mas suave de los pixeles
        for (Texture t : atlas.getTextures()) t.setFilter(TextureFilter.Linear, TextureFilter.Linear);

        //Crea los objetos del juego
        fonts = new AssetFonts();
        bunny = new AssetBunny(atlas);
        rock = new AssetRock(atlas);
        goldCoin = new AssetGoldCoin(atlas);
        feather = new AssetFeather(atlas);
        levelDecoration = new AssetLevelDecoration(atlas);
        sounds = new AssetSounds(assetManager);
        music = new AssetMusic(assetManager);
    }


    public class AssetBunny {
        public final AtlasRegion head;
        public final Animation animNormal;
        public final Animation animCopterTransform;
        public final Animation animCopterTransformBack;
        public final Animation animCopterRotate;

        public AssetBunny (TextureAtlas atlas){
            head = atlas.findRegion("bunny_head");

            Array<AtlasRegion> regions = null;
            AtlasRegion region = null;

            //Animacion: Conejo Normal
            regions = atlas.findRegions("anim_bunny_normal");
            animNormal = new Animation(1.0f / 10.0f, regions,
                    Animation.PlayMode.LOOP_PINGPONG);

            //Animacion: Conejo Helicoptero - Forma de orejas: nudo
            regions = atlas.findRegions("anim_bunny_copter");
            animCopterTransform = new Animation(1.0f / 10.f, regions);

            //Animacion: Conejo Helicoptero - Forma de orejas: sin nudo
            regions = atlas.findRegions("anim_bunny_copter");
            animCopterTransformBack = new Animation(1.0f / 10.0f, regions,
                    Animation.PlayMode.REVERSED);

            //Animacion: Conejo Helicoptero - Gira Orejas
            regions = new Array<AtlasRegion>();
            regions.add(atlas.findRegion("anim_bunny_copter", 4));
            regions.add(atlas.findRegion("anim_bunny_copter", 5));
            animCopterRotate = new Animation(1.0f/ 15.0f, regions);
        }
    }






}

AbstractGameObject.java

package com.packtub.libgdx.canyonbunny.game.objects;

import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.graphics.g2d.Animation;

public abstract class AbstractGameObject {
    public Vector2 position;
    public Vector2 dimension;
    public Vector2 origin;
    public Vector2 scale;
    public Vector2 velocity;
    public Vector2 terminalVelocity;
    public Vector2 friction;
    public Vector2 acceleration;
    public Rectangle bounds;
    public float rotation;
    public float stateTime;
    public Body body;
    public Animation animation;

    public AbstractGameObject(){
        position = new Vector2();
        dimension = new Vector2(1,1);
        origin = new Vector2();
        scale = new Vector2(1,1);
        rotation = 0;
        velocity = new Vector2();
        terminalVelocity = new Vector2(1,1);
        friction = new Vector2();
        acceleration = new Vector2();
        bounds = new Rectangle();
    }

    public void setAnimation(Animation animation){
        this.animation = animation;
        stateTime = 0;
    }

    protected void updateMotionX(float deltaTime){
        //Si es diferente de 0 esta en movimeinto
        if (velocity.x != 0){
            //Se aplica friccion
            if (velocity.x > 0){
                velocity.x = Math.max(velocity.x - friction.x * deltaTime, 0);
            }else{
                velocity.x = Math.min(velocity.x + friction.x * deltaTime, 0);
            }
        }
        //Aplica Acceleracion
        velocity.x += acceleration.x * deltaTime;
        //Asegura que la velocidad no exeda la velocidad positiva o negativa 
        //de la velocidad terminal
        velocity.x = MathUtils.clamp(velocity.x, -terminalVelocity.x, terminalVelocity.x);
    }

    protected void updateMotionY(float deltaTime){
        if (velocity.y != 0){
            //Se aplica friccion
            if (velocity.y > 0){
                velocity.y = Math.max(velocity.y - friction.y * deltaTime, 0);
            }else{
                velocity.y = Math.min(velocity.y + friction.y * deltaTime, 0);
            }
        }
        //Aplica Acceleracion
        velocity.y += acceleration.y * deltaTime;
        //Asegura que la velocidad no exeda la velocidad positiva o negativa 
        //de la velocidad terminal
        velocity.y = MathUtils.clamp(velocity.y, -terminalVelocity.y, terminalVelocity.y);
    }

    public void update(float deltaTime){
        //Se establece los parametros Box2D, mientras que no haya un cuerpo definido
        // en Box2D los gameobject van a utilizar nuestras fisicas simples.
        stateTime += deltaTime;
        if (body == null){
            updateMotionX(deltaTime);
            updateMotionY(deltaTime);
            //mover a una nueva posicion
            position.x += velocity.x * deltaTime;
            position.y += velocity.y * deltaTime;
        }else{
            position.set(body.getPosition());
            rotation = body.getAngle() * MathUtils.radiansToDegrees;
        }
    }

    public abstract void render (SpriteBatch  batch);

}

  

线程“LWJGL Application”中的异常java.lang.NullPointerException     在   com.packtub.libgdx.canyonbunny.game.objects.BunnyHead.render(BunnyHead.java:218)     在com.packtub.libgdx.canyonbunny.game.Level.render(Level.java:182)     在   com.packtub.libgdx.canyonbunny.game.WorldRenderer.renderWorld(WorldRenderer.java:56)     在   com.packtub.libgdx.canyonbunny.game.WorldRenderer.render(WorldRenderer.java:193)     在   com.packtub.libgdx.canyonbunny.screens.GameScreen.render(GameScreen.java:49)     在   com.packtub.libgdx.canyonbunny.screens.DirectedGame.setScreen(DirectedGame.java:37)     在   com.packtub.libgdx.canyonbunny.screens.MenuScreen.onPlayClicked(MenuScreen.java:405)     在   com.packtub.libgdx.canyonbunny.screens.MenuScreen.access $ 3(MenuScreen.java:403)     在   com.packtub.libgdx.canyonbunny.screens.MenuScreen $ 4.changed(MenuScreen.java:301)     在   com.badlogic.gdx.scenes.scene2d.utils.ChangeListener.handle(ChangeListener.java:28)     在com.badlogic.gdx.scenes.scene2d.Actor.notify(Actor.java:181)at   com.badlogic.gdx.scenes.scene2d.Actor.fire(Actor.java:146)at   com.badlogic.gdx.scenes.scene2d.ui.Button.setChecked(Button.java:116)     在   com.badlogic.gdx.scenes.scene2d.ui.Button $ 1.clicked(Button.java:90)     在   com.badlogic.gdx.scenes.scene2d.utils.ClickListener.touchUp(ClickListener.java:89)     在   com.badlogic.gdx.scenes.scene2d.InputListener.handle(InputListener.java:57)     在com.badlogic.gdx.scenes.scene2d.Stage.touchUp(Stage.java:348)at   com.badlogic.gdx.backends.lwjgl.LwjglInput.processEvents(LwjglInput.java:306)     在   com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:200)     在   com.badlogic.gdx.backends.lwjgl.LwjglApplication $ 1.run(LwjglApplication.java:114)

2 个答案:

答案 0 :(得分:1)

解决

在方法中:

private void init() {
    dimension.set(1, 1);
    //regHead = Assets.instance.bunny.head;
    animNormal = Assets.instance.bunny.animNormal;
    animCopterTransform = Assets.instance.bunny.animCopterTransform;
    animCopterTransformBack = Assets.instance.bunny.animCopterTransformBack;
    animCopterRotate = Assets.instance.bunny.animCopterRotate;
    setAnimation(animNormal);


    //Centra la imagen en el objeto
    origin.set(dimension.x / 2, dimension.y / 2);
    //Pone bordes por colicciones
    bounds.set(0, 0, dimension.x, dimension.y);
    //Se establecen valores fisicos
    terminalVelocity.set(3.0f, 4.0f);
    friction.set(12.0f, 0.0f);
    acceleration.set(0.0f, -25.0f);
    //Ver direccion
    viewDirection = VIEW_DIRECTION.RIGHT;
    //Estado Salto
    jumpState = JUMP_STATE.FALLING;
    timeJumping = 0;
    //Power ups
    hasFeatherPowerup = false;
    timeLeftFeatherPowerup = 0;

    //Particula
    dustParticle.load(Gdx.files.internal("particles/dust.pfx"), Gdx.files.internal("particles"));

}

我得到了一个nullpointerexception因为我没有分配一个开始动画,我通过在animCopterRotate下面说明了这个:

setAnimation(animNormal);

这种方式效果很好。谢谢大家的帮助,抱歉我的英语不太好。

答案 1 :(得分:0)

我看不到你声明了浮点变量stateTime。显而易见的是,如果发生NullPointerException,则某些内容为null或未指向任何内容。所以声明 float stateTime = 0; 。在你的渲染方法中(在reg.getKeyFrame之前......)你需要放置: stateTime + = Gdx.graphics.getDeltaTime(); 。所以这可能导致NullPointerException。我给你的Animator课程可能对你有所帮助:

public class Animator implements ApplicationListener{
protected int FRAME_COLUMNS;
protected int FRAME_ROWS;
protected float ANIMATION_SPEED;

protected float xPos;
protected float yPos;

protected float stateTime;


protected com.badlogic.gdx.graphics.g2d.Animation animation;
protected Texture spritesheet;
protected TextureRegion[] frames;
protected SpriteBatch painter;
protected TextureRegion currentFrame;
protected static GameScreen father;


public static float SPEED_FAST = 0.030f;
public static float SPEED_MEDIUM = 0.050f;
public static float SPEED_SLOW = 0.080f;
public static float SPEED_VERY_SLOW = 0.10f;

public Animator(Texture texture, int FRAME_COLUMNS, int FRAME_ROWS) {
    this.FRAME_COLUMNS = FRAME_COLUMNS;
    this.FRAME_ROWS = FRAME_ROWS;
    painter = new SpriteBatch();

    ANIMATION_SPEED = SPEED_SLOW;

    spritesheet = texture;

    TextureRegion[][] tmp = TextureRegion.split(spritesheet, spritesheet.getWidth() / FRAME_COLUMNS, spritesheet.getHeight() / FRAME_ROWS);

    frames = new TextureRegion[FRAME_COLUMNS * FRAME_ROWS];
    int tempIndex = 0;

     for (int i = 0; i < FRAME_ROWS; i++) {
            for (int j = 0; j < FRAME_COLUMNS; j++) {
                frames[tempIndex++] = tmp[i][j];
            }
        }
        animation = new Animation(ANIMATION_SPEED, frames); 
        stateTime = 0f; 


}



@Override
public void create() {
    // TODO Auto-generated method stub

}


@Override
public void resize(int width, int height) {
    // TODO Auto-generated method stub

}


@Override
public void render() {
        stateTime += Gdx.graphics.getDeltaTime();           
        currentFrame = animation.getKeyFrame(stateTime, true);
        painter.begin();
        painter.draw(currentFrame, xPos, yPos);            
        painter.end();

}


@Override
public void pause() {
    // TODO Auto-generated method stub

}


@Override
public void resume() {
    // TODO Auto-generated method stub

}


@Override
public void dispose() {
    // TODO Auto-generated method stub

}

如果您将使用此类,请确保继承它(而不是直接实例化)并使用 super()正确初始化它。