运行我的游戏时,我收到一个空指针异常。在我创建攻击类之前,我没有遇到过这个问题。有时我可以发送攻击按钮,直到所有敌人都被摧毁,其他时候几乎立即抛出异常(大部分时间是在与墙壁或敌人发生碰撞时发生)。攻击涉及三个主要类别:Level1State,Champion和Attack。请帮我找错,我一直在搜索/测试几天。
为什么会这样?它有时如何变为空,而其他时候它工作正常?另外,如何解决这个问题?
就这是一个重复的问题而言,每种情况似乎都不同。我已经回顾了其他帖子,但还没有找到解决我问题的方法。
Exception in thread "LWJGL Application" java.lang.NullPointerException
at com.badlogic.gdx.graphics.g2d.SpriteBatch.switchTexture(SpriteBatch.java:1056)
at com.badlogic.gdx.graphics.g2d.SpriteBatch.draw(SpriteBatch.java:565)
at com.badlogic.gdx.graphics.g2d.Sprite.draw(Sprite.java:515)
at com.foxdonut.eiu.sprites.Champion.draw(Champion.java:225)
at com.foxdonut.eiu.states.Level1State.render(Level1State.java:172)
at com.badlogic.gdx.Game.render(Game.java:46)
at com.foxdonut.eiu.EIUGame.render(EIUGame.java:43)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:225)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:126)
Champion.Java(第225行是此文件中的最后一行)
public class Champion extends Sprite{
public enum champState {STANDING, RUNNING, JUMPING, FALLING, ATTACK, RUN_ATTACK}
public champState currentState;
public champState previousState;
public World world;
public Body b2body;
private TextureAtlas atlas;
private Level1State screen;
private Array<Attack> attacks;
// Champion States
private TextureRegion champStand;
private TextureRegion champAttack;
private Animation<TextureRegion> champRun;
private Animation<TextureRegion> champJump;
private Animation<TextureRegion> champRunAttack;
private boolean runningRight;
private float champStateTimer; // how long in state
private Config config = Config.getInstance();
public Champion(Level1State screen){
atlas = new TextureAtlas("champion.pack");
this.screen = screen;
this.world = screen.getWorld();
// Initialize states
currentState = champState.JUMPING;
previousState = champState.JUMPING;
champStateTimer = 0;
runningRight = true;
// Create an array of texture regions to pass the constructor for the animation
Array<TextureRegion> frames = new Array<TextureRegion>();
// Run right animation
// start x, start y, dimensions(x,y)
for(int i = 1; i < 4; i++)
frames.add(new TextureRegion(atlas.findRegion("champ"), i * 27, 5, 27, 25));
champRun = new Animation<TextureRegion>(0.1f, frames);
frames.clear();
// Jump Animation
for(int i = 4; i < 5; i++)
frames.add(new TextureRegion(atlas.findRegion("champ"), 108, 0, 27, 30));
champJump = new Animation<TextureRegion>(0.1f, frames);
frames.clear();
// Standing still
champStand = new TextureRegion(atlas.findRegion("champ"), 0, 5, 27, 25);
setBounds(0, 0, 27 / EIUGame.PPM, 25 / EIUGame.PPM);
setRegion(champStand);
// Standing still and attacking
champAttack = new TextureRegion(atlas.findRegion("champ"), 0, 31, 27, 25);
setBounds(0, 0, 27 / EIUGame.PPM, 25 / EIUGame.PPM);
setRegion(champAttack);
// Running and attacking
for(int i = 1; i < 4; i++)
frames.add(new TextureRegion(atlas.findRegion("champ"), i * 27, 31, 27, 25));
champRunAttack = new Animation<TextureRegion>(0.1f, frames);
frames.clear();
defineChampion();
setBounds(0, 0, 27 / EIUGame.PPM, 25 / EIUGame.PPM);
setRegion(champStand);
attacks = new Array<Attack>();
}
public void update(float dt){
setPosition(b2body.getPosition().x -getWidth() / 2, b2body.getPosition().y - getHeight() / 2);
setRegion(getFrame(dt));
for(Attack atk : attacks){
atk.update(dt);
if(atk.isDestroyed())
attacks.removeValue(atk, true);
}
}
public TextureRegion getFrame(float dt){
currentState = getState();
TextureRegion region;
switch(currentState){
case STANDING:
region = champStand;
break;
case JUMPING:
region = (TextureRegion) champJump.getKeyFrame(champStateTimer, true);
break;
case RUNNING:
region = (TextureRegion) champRun.getKeyFrame(champStateTimer, true);
break;
case FALLING:
region = champStand;
break;
case ATTACK:
region = champAttack;
break;
case RUN_ATTACK:
region = (TextureRegion) champRunAttack.getKeyFrame(champStateTimer, true);
break;
default:
region = champStand;
break;
}
// Given that the sprite initially is facing right
// If there is no x-axis velocity, or is running left, and region is not flipped (facing right)
if((b2body.getLinearVelocity().x < 0 || !runningRight) && !region.isFlipX()){
region.flip(true, false);
runningRight = false;
}
// If moving on x-axis or is running right, and region is flipped (facing left)
else if((b2body.getLinearVelocity().x > 0 || runningRight) && region.isFlipX()){
region.flip(true, false);
runningRight = true;
}
champStateTimer = currentState == previousState ? champStateTimer + dt : 0;
previousState = currentState;
return region;
}
// Returns the state of the character
public champState getState(){
if(b2body.getLinearVelocity().y > 0 || (b2body.getLinearVelocity().y < 0 && previousState == champState.JUMPING))
return champState.JUMPING;
else if(b2body.getLinearVelocity().y < 0)
return champState.FALLING;
else if(Gdx.input.isKeyPressed(config.getAttackInt()) && (b2body.getLinearVelocity().x != 0))
return champState.RUN_ATTACK;
else if(b2body.getLinearVelocity().x != 0)
return champState.RUNNING;
else if(Gdx.input.isKeyJustPressed(config.getAttackInt()) && (b2body.getLinearVelocity().x == 0))
return champState.ATTACK;
else
return champState.STANDING;
}
public void defineChampion(){
BodyDef bdef = new BodyDef(); // Define body
bdef.position.set(196 / EIUGame.PPM, 128 / EIUGame.PPM);
bdef.type = BodyDef.BodyType.DynamicBody; // Make character movable
b2body = world.createBody(bdef); // Create the body
FixtureDef fdef = new FixtureDef(); // Define Fixture
PolygonShape pShape = new PolygonShape();
// Create a rectangle using an array of 4 vertices
Vector2[] vertex = new Vector2[4];
vertex[0] = new Vector2( 7, 9).scl(1 / EIUGame.PPM);
vertex[1] = new Vector2( 7, -9).scl(1 / EIUGame.PPM);
vertex[2] = new Vector2(-7, -9).scl(1 / EIUGame.PPM);
vertex[3] = new Vector2(-7, 9).scl(1 / EIUGame.PPM);
pShape.set(vertex);
fdef.filter.categoryBits = EIUGame.CHAMP_BIT; // What we are
fdef.filter.maskBits = EIUGame.GROUND_BIT | // What we can collide with
EIUGame.MEM_CHIP_BLUE_BIT |
EIUGame.MEM_CHIP_GREEN_BIT |
EIUGame.MEM_CHIP_RED_BIT |
EIUGame.ENEMY_BIT |
EIUGame.ENEMY_HEAD_BIT |
EIUGame.DEATH_BIT;
fdef.shape = pShape; // Define shape of fixture as polygon
b2body.createFixture(fdef).setUserData(this); // Create Fixture in body
EdgeShape head = new EdgeShape(); // Line between 2 different points
// A contact "sensor"
// Relative to Box2D body Center
// A point offset by -1 and 10 above head
// A point offset by 1 and 10 above head
head.set(new Vector2(-1 / EIUGame.PPM, 10 / EIUGame.PPM),
new Vector2( 1 / EIUGame.PPM, 10 / EIUGame.PPM));
fdef.shape = head; // Set shape
fdef.isSensor = true; // Doesn't allow collision
// Allows for query of data
b2body.createFixture(fdef).setUserData("head"); // Uniquely sets fixture as "head"
}
public void attack(){
attacks.add(new Attack(screen, b2body.getPosition().x, b2body.getPosition().y, runningRight ? true : false));
}
public void draw(Batch batch){
super.draw(batch);
for(Attack atk : attacks)
atk.draw(batch);
}
}
Attack.Java
public class Attack extends Sprite{
Level1State screen;
World world;
TextureAtlas attackRightAtlas;
TextureAtlas attackLeftAtlas;
Array<TextureRegion> frames;
Animation <TextureRegion> attackRightAnimation;
Animation <TextureRegion> attackLeftAnimation;
TextureRegion region;
float stateTime;
boolean destroyed;
boolean setToDestroy;
boolean attackRight;
Body b2body;
public Attack(Level1State screen, float x, float y, boolean attackRight){
this.attackRight = attackRight;
this.screen = screen;
this.world = screen.getWorld();
if (attackRight){
frames = new Array<TextureRegion>();
attackRightAtlas = new TextureAtlas("attack/attackRight.pack");
for (int i = 0; i < 3; i++)
frames.add(new TextureRegion(attackRightAtlas.findRegion("attackRight"), i * 24, 0, 24, 25));
attackRightAnimation = new Animation<TextureRegion>(0.1f, frames);
//setRegion(attackRightAnimation.getKeyFrame(0));
frames.clear();
stateTime = 0;
region = (TextureRegion) attackRightAnimation.getKeyFrame(stateTime, true);
}
else{
frames = new Array<TextureRegion>();
attackLeftAtlas = new TextureAtlas("attack/attackLeft.pack");
for (int i = 0; i < 3; i++)
frames.add(new TextureRegion(attackLeftAtlas.findRegion("attackLeft"), i * 24, 0, 24, 25));
attackLeftAnimation = new Animation<TextureRegion>(0.1f, frames);
//setRegion(attackLeftAnimation.getKeyFrame(0));
frames.clear();
stateTime = 0;
region = (TextureRegion) attackLeftAnimation.getKeyFrame(stateTime, true);
}
setBounds(x, y, 24 / EIUGame.PPM, 25 / EIUGame.PPM);
setToDestroy = false;
destroyed = false;
defineAttack();
}
public void defineAttack(){
BodyDef bdef = new BodyDef();
// Offset the attack so it appears to the side of the character
bdef.position.set(attackRight ? getX() + 13.5f / EIUGame.PPM : getX() - 13.5f / EIUGame.PPM, getY());
bdef.type = BodyDef.BodyType.DynamicBody;
bdef.gravityScale = 0;
if(!world.isLocked())
b2body = world.createBody(bdef);
FixtureDef fdef = new FixtureDef(); // Define Fixture
CircleShape shape = new CircleShape();
shape.setRadius(5 / EIUGame.PPM);
fdef.filter.categoryBits = EIUGame.ATTACK_BIT; // What fixture is
fdef.filter.maskBits = EIUGame.GROUND_BIT | // What fixture can collide with
EIUGame.MEM_CHIP_BLUE_BIT |
EIUGame.MEM_CHIP_GREEN_BIT |
EIUGame.MEM_CHIP_RED_BIT |
EIUGame.ENEMY_BIT;
fdef.shape = shape;
fdef.restitution = 1;
fdef.friction = 0;
b2body.createFixture(fdef).setUserData(this);
b2body.setLinearVelocity(new Vector2(attackRight ? 3 : -3, 0));
}
public void update(float dt){
stateTime += dt;
if(setToDestroy && !destroyed){
world.destroyBody(b2body);
destroyed = true;
stateTime = 0;
}
else if (!destroyed){
if (attackRight)
setRegion(attackRightAnimation.getKeyFrame(stateTime, true));
else
setRegion(attackLeftAnimation.getKeyFrame(stateTime, true));
setPosition(b2body.getPosition().x - getWidth() / 2, b2body.getPosition().y - getHeight() / 2);
if((stateTime > 2 || setToDestroy) && !destroyed) {
world.destroyBody(b2body);
destroyed = true;
}
if(b2body.getLinearVelocity().y > 2f)
b2body.setLinearVelocity(b2body.getLinearVelocity().x, 2f);
if((attackRight && b2body.getLinearVelocity().x < 0) || (!attackRight && b2body.getLinearVelocity().x > 0))
setToDestroy();
}
}
public void setToDestroy(){
setToDestroy = true;
}
public boolean isDestroyed(){
return destroyed;
}
}
Level1State.Java(第172行的错误在render方法中) ----第172行:champ.draw(mapRenderer.getBatch());
public class Level1State implements Screen {
private MusicAndSoundManager msm = MusicAndSoundManager.getInstance();
private Config config = Config.getInstance();
private TextureAtlas atlas;
private OrthographicCamera gameCam, parallaxCam;
private Viewport gamePort;
private GamePad gamepad;
private Hud hud;
private PauseState pause;
private TmxMapLoader maploader; // Loads a tilemap
private TiledMap map; // Reference to map itself
private OrthogonalTiledMapRenderer mapRenderer; // Renders our map to screen
private Champion champ;
// Box2D variables
private World world;
private Box2DDebugRenderer b2dr; // Shows outlines of fixtures and bodies in box2D world
private B2DWorldCreator creator;
private int backgroundLayer = 0;
private int foregroundLayer = 1;
private TiledMapImageLayer imgLayer;
private TiledMapTileLayer tileLayer;
public Level1State(EIUGame game) {
gamepad = new GamePad();
atlas = new TextureAtlas("champion.pack");
gameCam = new OrthographicCamera(); // Centered on and follows the player
parallaxCam = new OrthographicCamera(); // Follows the player at a slower rate and moves the background
// Create a FitViewport to maintain virtual aspect ratio for the gameport and the parallax camera
gamePort = new FitViewport(EIUGame.V_WIDTH / EIUGame.PPM, EIUGame.V_HEIGHT / EIUGame.PPM, gameCam);
parallaxCam.setToOrtho(false, EIUGame.V_WIDTH / EIUGame.PPM, EIUGame.V_HEIGHT / EIUGame.PPM);
// Center the camera at the gamePort
gameCam.position.set(gamePort.getWorldWidth() / 2 +32f, gamePort.getWorldHeight() / 2, 0);
// Map loading and layer definitions to specify what we are drawing for the map //
maploader = new TmxMapLoader();
map = maploader.load("TestLevel.tmx");
imgLayer = (TiledMapImageLayer)map.getLayers().get(backgroundLayer);
tileLayer = (TiledMapTileLayer)map.getLayers().get(foregroundLayer);
// Pass our tile map to a MapRenderer so that we can manipulate the batch for drawing and update purposes
mapRenderer = new OrthogonalTiledMapRenderer(map, 1 / EIUGame.PPM);
hud = new Hud(game.batch); // Add an instance of the game HUD
// Box2D initialization
// Gravity set to -10, set bodies to "rest" that don't need physics calculations
world = new World(new Vector2(0,-10), true);
b2dr = new Box2DDebugRenderer();
creator = new B2DWorldCreator(this); // Create Box2D map
// Create Champion in game world
champ = new Champion(this);
// Contact listener for hitting head on objects
world.setContactListener(new WorldContactListener());
pause = new PauseState(game);
pause.addPauseToStage(hud.stage);
// Since we have multiple input processors to work with it'll be best to use a multiplexer
InputMultiplexer multiplexer = new InputMultiplexer();
multiplexer.addProcessor(hud.getStage());
multiplexer.addProcessor(gamepad.getStage());
Gdx.input.setInputProcessor(multiplexer);
}
// Simple method to return atlas
public TextureAtlas getAtlas(){
return atlas;
}
@Override
public void show() {}
// Updating of Game World
public void update(float dt){
// Clear the game screen with black // Move to render
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
for (Enemy enemy : creator.getCogs()){
enemy.update(dt);
if(!enemy.isDestroyed() && enemy.getX() < champ.getX() + 224 / EIUGame.PPM)
enemy.b2body.setActive(true);
}
config.animateChamp(champ);
gamepad.animateChamp(champ, pause);
// Run at 60fps, velocity of 6, position 2
world.step(1/60f, 6, 2);
// Update the champion
champ.update(dt);
hud.update(dt);
// Move camera with champion
parallaxCam.position.x = champ.b2body.getPosition().x/2.00f + 1.1f;
parallaxCam.update();
mapRenderer.setView(parallaxCam);
mapRenderer.renderImageLayer(imgLayer);
gameCam.position.x = champ.b2body.getPosition().x;
gameCam.update();
mapRenderer.setView(gameCam);
mapRenderer.renderTileLayer(tileLayer);
}
@Override
public void render(float delta) {
if(Gdx.input.isKeyJustPressed(Input.Keys.ESCAPE)) {
pause.togglePause();
}
// If the game is paused prevent character movement and HUD updates
if(!pause.getPauseState()) {
// Get the batch to begin updating the screen
mapRenderer.getBatch().begin();
// Handles player movement
update(delta);
champ.draw(mapRenderer.getBatch());
for (Enemy enemy : creator.getCogs())
enemy.draw(mapRenderer.getBatch());
mapRenderer.getBatch().end();
//b2dr.render(world, gameCam.combined);
}
hud.stage.draw();
gamepad.draw();
}
@Override
public void resize(int width, int height) {
gamePort.update(width, height);
gamepad.resize(width, height);
}
public TiledMap getMap(){
return map;
}
public World getWorld(){
return world;
}
@Override
public void pause() {}
@Override
public void resume() {}
@Override
public void hide() {}
@Override
public void dispose() {
map.dispose();
mapRenderer.dispose();
world.dispose();
b2dr.dispose();
hud.dispose();
gamepad.dispose();
}
}
我知道这要经历很多事情。但是,我自己花了很多时间在这上面,似乎无法弄明白。是时候问专家了。