2015-02-17 377 views
0

我正在学习libgdx游戏开发书的末尾,最后一章是关于动画精灵(兔子)的一部分。当它应该加载游戏画面时发生错误,我真的不知道我犯了什么错误的地方,我确信这是与动画兔子,我一步一步地走,这里是错误发生的地方:带动画精灵的Isuee

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应用程序” 显示java.lang.NullPointerException 在 com.packtub.libgdx.canyonbunny.game.objects .BunnyHead.render(BunnyHead.java:218) at com.pack tub.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) at(ChangeListener.java:28) at 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) at com.badlogic.gdx.scenes.scene2d.ui.Button $ 1.clicked(Button.java:90) at 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)在 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)

+1

可能重复[什么是空指针异常,以及如何解决它?](http://stackoverflow.com/questions/218384/what-is-a-null-pointer-exception-and-how -do-i-fix-it) – tnw 2015-02-17 20:50:51

+0

我很抱歉,这篇文章对我非常有帮助。 – user3042518 2015-02-18 00:28:49

+0

基本上,当你得到一个NullPointerException异常时,你可以在错误消息中看到究竟哪行代码有一个空对象。然后,您可以快速找到该错误的来源。在你的情况下,它在BunnyHead类的第218行。 – Tenfour04 2015-02-18 15:23:34

回答

0

我可以”看到你声明了浮点变量stateTime。那么显而易见的是,如果发生NullPointerException是某些内容为空或者没有指向任何内容。所以声明float stateTime = 0;。在你的渲染方法(reg.getKeyFrame之前...)你需要把:stateTime + = Gdx.graphics.getDeltaTime(); 。所以这可能导致NullPointerException。我给你我的动画类,它可以帮助你:

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 

} 

如果要使用这个类一定要继承它(而不是直接将它实例化),并通过使用超级正确初始化( )

+0

float(小写)不是一个对象,因此它不会导致NPE。 – Tenfour04 2015-02-17 23:18:18

+0

我继承了父类的stateTime,因为我认为它不是必须的,所以我会编辑这个帖子并把这个类也放到这里,这样你就可以看到。尽管如此,非常感谢您的帮助。 – user3042518 2015-02-18 00:26:24

+0

我尝试了你告诉我的,但它一直在发生。 – user3042518 2015-02-18 13:00:14

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 achived这样的:

setAnimation(animNormal); 

这样就可以了ked就好了。谢谢大家的帮助,对不起我的英文不太好。