我在学习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)
答案 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()正确初始化它。