VIDEO FOR CLARITY: https://www.youtube.com/watch?v=3Mrro8sjcqo#t=25
I'm making my first LibGDX game, and I'm having trouble destroying and creating bodies. I've been using this snippet (because it seems to be everywhere) to remove bodies:
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;
}
}
}
}
That works great, just as intended, but shortly after running it, it crashes. I get the whole "AL lib: (EE) alc_cleanup: 1 device not closed" thing. I did some debugging and came to the conclusion that it was crashing when one of my entities fires a projectile, after an object is destroyed. Its a very peculiar problem. The entity that was destroyed was continuously going in a slow circle. After being destroyed, when the next projectile is fired, it will appear as normal, but not move, and take on that same slow circular movement of the entity it destroyed. If the player fires again, it crashes. I'm stumped. Any thoughts?
Here is source code in question
/*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;
}
}
EDIT: Error thrown on crash:
#
# 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
Error logged (only stack trace like thing I could find) (TestControls is the screen we are working in)
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 contact listener that sets flag for delete:
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) {
}
});