视频的视频: https://www.youtube.com/watch?v=3Mrro8sjcqo#t=25
我正在制作我的第一个LibGDX游戏,而且我在破坏和创建机构方面遇到了麻烦。我一直在使用这个代码片段(因为它似乎无处不在)来删除正文:
private void sweepDeadBodies() {
for (Iterator<Body> iter = tmpBodies.iterator(); iter.hasNext();) {
Body body = iter.next();
if (body != null) {
Entity data = (Entity) body.getUserData(); //Just the bodies data
if (data.isFlaggedForDelete) {
iter.remove();
world.destroyBody(body);
body.setUserData(null);
body = null;
}
}
}
}
这很好,就像预期的那样,但在运行它之后不久就会崩溃。我得到了整个“ AL lib:(EE)alc_cleanup:1设备未关闭”的事情。我做了一些调试并得出结论,当一个物体被摧毁后,当我的一个实体发射一个射弹时它会崩溃。这是一个非常奇特的问题。被摧毁的实体不断进入缓慢的圈子。在被摧毁之后,当下一个射弹被射击时,它将显示为正常,但不会移动,并对其所摧毁的实体进行同样的慢速圆周运动。如果玩家再次开火,它会崩溃。我很难过。有什么想法吗?
以下是有问题的源代码
/*Render Loop in screen:*/
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// Update World, Camera, and State Time
world.step(TIMESTEP, VELOCITYITERATIONS, POSITIONITERATIONS);
sweepDeadBodies();
camera.update();
stateTime += delta;
// Get Fire Buttons
System.out.println(player.stateTime % 2);
if (aButton.isPressed() && player.stateTime / 0.25 >= 1) {
player.stateTime = 0f;
//Projectile in question
Laser laser = new Laser(world, player.getBody().getPosition());
}
// Update the player
player.update(joyStick.getKnobPercentX(), joyStick.getKnobPercentY(),
delta);
enemy.update(delta);
// Order the bodies
world.getBodies(tmpBodies);
Iterator<Body> iterator = tmpBodies.iterator();
int j;
boolean flag = true; // set flag to true to begin first pass
while (flag) {
flag = false; // set flag to false awaiting a possible swap
for (j = 0; j < tmpBodies.size - 1; j++) {
if (tmpBodies.get(j).getType() == BodyType.DynamicBody
&& tmpBodies.get(j + 1).getType() == BodyType.StaticBody) {
tmpBodies.swap(j, j + 1);
flag = true;
}
}
}
/*ADDED THIS, FORGOT TO LEAVE WHEN TRIMMING CODE FOR POST*/
for (Body body : tmpBodies) {
// Entity
if (body.getUserData() instanceof Entity) {
Entity entity = (Entity) body.getUserData();
if (entity.sprite != null) {
entity.sprite.setPosition(body.getPosition().x
- entity.sprite.getWidth() / 2,
body.getPosition().y - entity.sprite.getHeight()
/ 2);
entity.sprite.setRotation(body.getAngle()
* MathUtils.radiansToDegrees);
entity.sprite.draw(batch);
}
// Damage
if (entity.health <= 0) {
// entity.isFlaggedForDelete = true;
entity.die();
}
}
}
// Render Box2D World
debugRenderer.render(world, camera.combined);
// Render Stage
stage.draw();
}
/*Laser Class:*/
public class Laser {
private Body body;
private Fixture fixture;
private Vector2 velocity = new Vector2();
private float speed = 4800;
private World world;
public Laser(World world, Vector2 pos) {
this.world = world;
// Body Definition
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.DynamicBody;
bodyDef.position.set(pos);
bodyDef.fixedRotation = true;
bodyDef.gravityScale = 0;
bodyDef.linearVelocity.x = 100f;
// Shape
PolygonShape shape = new PolygonShape();
shape.setAsBox(2, 0.25f);
// Fixture Definition
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.restitution = 0f;
fixtureDef.friction = .8f;
fixtureDef.density = 0f;
fixtureDef.filter.categoryBits = Entities.CATEGORY_PLAYER_PROJECTILE;
fixtureDef.filter.maskBits = Entities.MASK_PLAYER_PROJECTILE;
// Create Body
body = world.createBody(bodyDef);
fixture = body.createFixture(fixtureDef);
// Assign Entity to Body
Sprite sprite = new Sprite(new Texture("sprites/projectiles/laser.png"));
sprite.setSize(2, 0.25f);
Entity entity = new Entity();
entity.sprite = sprite;
entity.speed = 100f;
entity.damage = 20f;
entity.type = Entities.CATEGORY_PLAYER_PROJECTILE;
body.setUserData(entity);
body.setBullet(true);
}
public float getRestitution() {
return fixture.getRestitution();
}
public void setRestitution(float restitution) {
fixture.setRestitution(restitution);
}
public Body getBody() {
return body;
}
public Fixture getFixture() {
return fixture;
}
}
修改 崩溃时抛出错误:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0000000066bcbd0d, pid=63044, tid=52440
#
# JRE version: Java(TM) SE Runtime Environment (7.0_45-b18) (build 1.7.0_45-b18)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (24.45-b08 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C [gdx-box2d64.dll+0xbd0d]
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# C:\Programming\Eclipse Projects\#######\desktop\hs_err_pid63044.log
#
# If you would like to submit a bug report, please visit:
# http://bugreport.sun.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
AL lib: (EE) alc_cleanup: 1 device not closed
记录错误(只有堆栈跟踪,就像我能找到的那样) (TestControls是我们正在使用的屏幕)
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j com.badlogic.gdx.physics.box2d.World.jniCreateBody(JIFFFFFFFFZZZZZF)J+0
j com.badlogic.gdx.physics.box2d.World.createBody(Lcom/badlogic/gdx/physics/box2d/BodyDef;)Lcom/badlogic/gdx/physics/box2d/Body;+80
J ####.###########.########.screens.levels.TestControls.render(F)V
j com.badlogic.gdx.Game.render()V+19
j com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop()V+619
j com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run()V+27
v ~StubRoutines::call_stub
为删除设置标志的世界联系人侦听器:
world.setContactListener(new ContactListener() {
@Override
public void beginContact(Contact contact) {
}
@Override
public void endContact(Contact contact) {
if (contact.getFixtureA().getFilterData().categoryBits == Entities.CATEGORY_PLAYER_PROJECTILE
&& contact.getFixtureB().getFilterData().categoryBits == Entities.CATEGORY_ENEMY) {
((Entity) contact.getFixtureA().getBody().getUserData()).isFlaggedForDelete = true;
((Entity) contact.getFixtureB().getBody().getUserData())
.damage(((Entity) contact.getFixtureA().getBody()
.getUserData()).damage);
}
if (contact.getFixtureA().getFilterData().categoryBits == Entities.CATEGORY_ENEMY
&& contact.getFixtureB().getFilterData().categoryBits == Entities.CATEGORY_PLAYER_PROJECTILE) {
((Entity) contact.getFixtureB().getBody().getUserData()).isFlaggedForDelete = true;
((Entity) contact.getFixtureA().getBody().getUserData())
.damage(((Entity) contact.getFixtureB().getBody()
.getUserData()).damage);
}
}
@Override
public void preSolve(Contact contact, Manifold oldManifold) {
}
@Override
public void postSolve(Contact contact, ContactImpulse impulse) {
}
});
答案 0 :(得分:3)
过去两天我遇到了完全相同的问题。
这是一个简单的错误,我有一个实体的ArrayList,此刻显示。如果碰撞发生,我就像你一样设置一个标志。稍后,我运行我的Entity ArrayList并删除被标记的每个实体主体 - 但不是实体本身!
这是我的删除代码。它适用于我,我希望它也适合你。
CopyOnWriteArrayList<Entity> entities = new CopyOnWriteArrayList<Entity>();
public void deleteEntities() {
for(Entity entity: entities){
Body body = entity.getBody();
if (body != null) {
EntityData data = (EntityData) body.getUserData();
if (data.isFlaggedForDelete()) {
final Array<JointEdge> list = body.getJointList();
//delete all joints attached
while (list.size > 0) {
myWorld.getWorld().destroyJoint(list.get(0).joint);
}
//nullify everything, remove the entity from entities and destroy the body
body.setUserData(null);
myWorld.getWorld().destroyBody(body);
entities.remove(entity);
body = null;
}
}
}
}
此外,请确保您不要太早处置()!也可能是一个问题。
我希望这有用:-)
答案 1 :(得分:1)
您必须将激光器放入阵列中。他们正在超出范围并被摧毁,但身体仍然活着。箱体由box2d回收,因此可能会导致问题。在渲染中创建它们也是非常糟糕的。您应该使用池来处理生命周期短的任何事情。
以任何方式接触被处理的身体都会炸毁游戏,所以最好不要在游戏过程中丢弃它们。
我最近发布了广泛使用池的libgdx / box2d游戏。您可以在GitHub查看代码。
同样是endContact(),清理它。它无法阅读。这样的事可能吗?
@Override
public void endContact(Contact contact) {
Fixture fA = contact.getFixtureA();
Fixture fB = contact.getFixtureB();
if (isPlayerProjectile(fA) && isEnemy(fB)) {
Entity projectile = (Entity) contact.getFixtureA().getBody().getUserData();
Entity enemy = (Entity) contact.getFixtureB().getBody().getUserData();
solveProjectileEnemyContact(projectile, enemy);
} else if (isPlayerProjectile(fB) && isEnemy(fA)) {
Entity projectile = (Entity) contact.getFixtureB().getBody().getUserData();
Entity enemy = (Entity) contact.getFixtureA().getBody().getUserData();
solveProjectileEnemyContact(projectile, enemy);
}
}
private boolean isPlayerProjectile(Fixture fixture){
return fixture.getFilterData().categoryBits == Entities.CATEGORY_PLAYER_PROJECTILE;
}
private boolean isEnemy(Fixture fixture){
return fixture.getFilterData().categoryBits == Entities.CATEGORY_ENEMY;
}
private void solveProjectileEnemyContact(Entity projectile, Entity enemy){
projectile.isFlaggedForDelete = true;
enemy.damage(projectile.damage);
}
答案 2 :(得分:-1)
我知道这个问题很古老,但我想分享一下这个完全相同的错误,我选择的答案没有帮助。
因此对于任何仍然遇到此问题的人来说,这就是我解决它的方法:
我不是随机创建和删除我的身体,而是只用2种方法创建和删除所有创建和删除:
filterOptions
删除:
[
'attribute' => 'name',
'label' => 'labelname',
...
....
'filterOptions' => [ 'title' => 'prova'],
],
我打电话给他们:
//CREATE ALL
public void createAll(){
if(!world.isLocked()){ //KEY FACTOR
if(createEnemy){
createEnemy();
}
if(createBullet){
createBullet();
}
}
}
最后我的createEnemy():
//get rid of all bodies (toBeDeleted is an Array<Body>)
public void sweepDeadBodies() {
if(!world.isLocked()){ // KEY FACTOR
Array<Body> wB = getBodies();
for (Body body : wB) {
if(body!=null && toBeDeleted.contains(body, false)) {
body.setUserData(null);
world.destroyBody(body);
toBeDeleted.removeValue(body, false);
}
}
}
}
和我的createBullet():
@Override
public void draw() {
super.draw();
glyphLayout.setText(scoreFont, score);
//Do all my deleting and creating after the world.step !!! VERY IMPORTANT!!!
sweepDeadBodies();
removeEmtpyActors(); //I use actors as containers for the body, so here i loop though them all and nullify them
createAll();
renderer.render(world, camera.combined);
}
toBeDeleted中的所有实体都在我将它们标记为删除后如下:
private void createEnemy() {
Enemy enemy= new Enemy(WorldUtils.createEnemy(world));
((UserData) enemy.getBody().getUserData()).isFlaggedForDelete = false;
addActor(enemy);
addGameActor(enemy); //again this is just for me, you might be using entities or something else
createEnemy = false;
}
并像这样添加它们:
public void createBullet(){
Bullet bullet = new Bullet(WorldUtils.createBullet(world));
((UserData) bullet.getBody().getUserData()).isFlaggedForDelete = false;
addActor(bullet);
addGameActor(bullet);
bullet.fire(); //just adds a linear impulse
createBullet= false;
}
在我的更新方法中!
我希望这有助于某人。基本上我的错误是创建/销毁尸体而不检查世界是否被锁定,我通过调用!world.isLocked()来修复!