LibGDX - 使用 ShapeRenderer 时出现 NullPointerException
LibGDX - NullPointerException when using ShapeRenderer
我正在尝试使用 LibGDX 上的 class 进行一些 JUnit 测试,但在尝试初始化所述 class 时出现 NullPointerError,这可以追溯到使用ShapeRenderer.
这是我初始化的class:
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.game.Point;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import java.util.ArrayList;
import static java.lang.Math.abs;
public class Player{
int health;
int range;
public Point position;
ShapeRenderer shape = new ShapeRenderer();
public Sprite drawable;
public Player(int health, int range, Point position,Texture img){
this.health = health;
this.range = range;
this.position = position;
this.drawable = new Sprite(img);
drawable.setPosition(position.x - drawable.getWidth()/2,position.y - drawable.getHeight()/2);
}
public boolean inRange(Player target){
if(abs(target.position.x - this.position.x) < this.range &&
abs(target.position.y - this.position.y) < this.range){
return true;
}
return false;
}
public void drawBox(ArrayList<Player> target, OrthographicCamera camera, Sprite sprite) {
shape.setProjectionMatrix(camera.combined);
shape.begin(ShapeType.Line);
boolean redBox = false;
for(Player player: target) {
if (this.inRange(player)) {
redBox = true;
}
}
if (redBox) {
shape.setColor(Color.RED);
}
else {
shape.setColor(Color.GREEN);
}
shape.rect(position.x - range, position.y - range, range * 2, range * 2);
shape.end();
}
}
以下是来自 PlayerTest 的相关代码:
import com.entities.Player;
import com.game.Point;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Assertions;
class PlayerTest {
@Test
public void testInRangeBoundary() {
Player e = new Player(0,5, new Point(5,5));
Assertions.assertTrue(e.inRange(new Player(0,0,new Point(9,0))));
}
}
这是我得到的错误:
java.lang.NullPointerException
at com.badlogic.gdx.graphics.glutils.ShaderProgram.loadShader(ShaderProgram.java:209)
at com.badlogic.gdx.graphics.glutils.ShaderProgram.compileShaders(ShaderProgram.java:188)
at com.badlogic.gdx.graphics.glutils.ShaderProgram.<init>(ShaderProgram.java:171)
at com.badlogic.gdx.graphics.glutils.ImmediateModeRenderer20.createDefaultShader(ImmediateModeRenderer20.java:233)
at com.badlogic.gdx.graphics.glutils.ImmediateModeRenderer20.<init>(ImmediateModeRenderer20.java:56)
at com.badlogic.gdx.graphics.glutils.ShapeRenderer.<init>(ShapeRenderer.java:116)
at com.badlogic.gdx.graphics.glutils.ShapeRenderer.<init>(ShapeRenderer.java:111)
at com.badlogic.gdx.graphics.glutils.ShapeRenderer.<init>(ShapeRenderer.java:107)
at com.entities.Player.<init>(Player.java:22)
at PlayerTest.testInRangeBoundary(PlayerTest.java:10) <19 internal calls>
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) <9 internal calls>
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) <21 internal calls>
(参考第 22 行是 'ShapeRenderer shape = new ShapeRenderer();' 行)
我知道 NullPointerException 通常意味着某些内容尚未初始化,但我不确定如何处理它。
如有任何帮助,我们将不胜感激!
Gdx.gl
在测试期间为空,与所有其他 Gdx
字段一样。这里发生的是您在 Entity 构造函数中创建一个新的 ShapeRenderer 对象。然后 ShapeRenderer 尝试访问 libGDX 的渲染 APIs 但它们没有初始化,所以你得到一个异常。
由于您并不是真正测试您的实体是否被正确绘制,而是 inRange
方法是否正常工作,因此您希望阻止调用任何 libGDX 的 API 在测试期间。
有很多选项可以解决这个问题。您可以重新排列您的代码:
- 正如@Code-Apprentice 指出的,通过将游戏逻辑和渲染逻辑分成两个 classes。你可以有一个
Entity
class 和一个 EntityRenderer
class。你只考前者。
- 或者不在构造函数中实例化 ShapeRenderer。相反,ShapeRenderer 可以作为参数传递给
drawBox
方法。如果我没记错的话,ShapeRenderer 是相当重的对象,所以如果你有很多实体,你可能还是想这样做。
另一种可能性是在测试期间模拟 libGDX 的 API。
- 使用 Mockito,你可以做到
Gdx.gl = mock(GL20.class)
。
- 或者您可以创建一个
HeadlessApplication
来正确初始化 Gdx
class.
这两个选项都是described here。但是,尽可能重构您的代码,保持游戏逻辑和渲染分离是一个很好的做法。
我正在尝试使用 LibGDX 上的 class 进行一些 JUnit 测试,但在尝试初始化所述 class 时出现 NullPointerError,这可以追溯到使用ShapeRenderer.
这是我初始化的class:
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.game.Point;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import java.util.ArrayList;
import static java.lang.Math.abs;
public class Player{
int health;
int range;
public Point position;
ShapeRenderer shape = new ShapeRenderer();
public Sprite drawable;
public Player(int health, int range, Point position,Texture img){
this.health = health;
this.range = range;
this.position = position;
this.drawable = new Sprite(img);
drawable.setPosition(position.x - drawable.getWidth()/2,position.y - drawable.getHeight()/2);
}
public boolean inRange(Player target){
if(abs(target.position.x - this.position.x) < this.range &&
abs(target.position.y - this.position.y) < this.range){
return true;
}
return false;
}
public void drawBox(ArrayList<Player> target, OrthographicCamera camera, Sprite sprite) {
shape.setProjectionMatrix(camera.combined);
shape.begin(ShapeType.Line);
boolean redBox = false;
for(Player player: target) {
if (this.inRange(player)) {
redBox = true;
}
}
if (redBox) {
shape.setColor(Color.RED);
}
else {
shape.setColor(Color.GREEN);
}
shape.rect(position.x - range, position.y - range, range * 2, range * 2);
shape.end();
}
}
以下是来自 PlayerTest 的相关代码:
import com.entities.Player;
import com.game.Point;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Assertions;
class PlayerTest {
@Test
public void testInRangeBoundary() {
Player e = new Player(0,5, new Point(5,5));
Assertions.assertTrue(e.inRange(new Player(0,0,new Point(9,0))));
}
}
这是我得到的错误:
java.lang.NullPointerException
at com.badlogic.gdx.graphics.glutils.ShaderProgram.loadShader(ShaderProgram.java:209)
at com.badlogic.gdx.graphics.glutils.ShaderProgram.compileShaders(ShaderProgram.java:188)
at com.badlogic.gdx.graphics.glutils.ShaderProgram.<init>(ShaderProgram.java:171)
at com.badlogic.gdx.graphics.glutils.ImmediateModeRenderer20.createDefaultShader(ImmediateModeRenderer20.java:233)
at com.badlogic.gdx.graphics.glutils.ImmediateModeRenderer20.<init>(ImmediateModeRenderer20.java:56)
at com.badlogic.gdx.graphics.glutils.ShapeRenderer.<init>(ShapeRenderer.java:116)
at com.badlogic.gdx.graphics.glutils.ShapeRenderer.<init>(ShapeRenderer.java:111)
at com.badlogic.gdx.graphics.glutils.ShapeRenderer.<init>(ShapeRenderer.java:107)
at com.entities.Player.<init>(Player.java:22)
at PlayerTest.testInRangeBoundary(PlayerTest.java:10) <19 internal calls>
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) <9 internal calls>
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) <21 internal calls>
(参考第 22 行是 'ShapeRenderer shape = new ShapeRenderer();' 行)
我知道 NullPointerException 通常意味着某些内容尚未初始化,但我不确定如何处理它。
如有任何帮助,我们将不胜感激!
Gdx.gl
在测试期间为空,与所有其他 Gdx
字段一样。这里发生的是您在 Entity 构造函数中创建一个新的 ShapeRenderer 对象。然后 ShapeRenderer 尝试访问 libGDX 的渲染 APIs 但它们没有初始化,所以你得到一个异常。
由于您并不是真正测试您的实体是否被正确绘制,而是 inRange
方法是否正常工作,因此您希望阻止调用任何 libGDX 的 API 在测试期间。
有很多选项可以解决这个问题。您可以重新排列您的代码:
- 正如@Code-Apprentice 指出的,通过将游戏逻辑和渲染逻辑分成两个 classes。你可以有一个
Entity
class 和一个EntityRenderer
class。你只考前者。 - 或者不在构造函数中实例化 ShapeRenderer。相反,ShapeRenderer 可以作为参数传递给
drawBox
方法。如果我没记错的话,ShapeRenderer 是相当重的对象,所以如果你有很多实体,你可能还是想这样做。
另一种可能性是在测试期间模拟 libGDX 的 API。
- 使用 Mockito,你可以做到
Gdx.gl = mock(GL20.class)
。 - 或者您可以创建一个
HeadlessApplication
来正确初始化Gdx
class.
这两个选项都是described here。但是,尽可能重构您的代码,保持游戏逻辑和渲染分离是一个很好的做法。