2017-01-20 20 views
-1

У меня возникла повторяющаяся «случайная» фатальная ошибка в мини-игре libgdx, которую я разрабатываю. Для того, что я собрал, это собственная ошибка box2d, связанная с созданием тела. Возможной причиной этого является генерация тела во время тайм-аута, но я считаю, что я принял соответствующие встречные меры.Почему у меня иногда есть box2Dcrash, когда я создаю тела в LIbgdx

Следующий случай кажется похожим, но на самом деле речь шла об удалении объектов из массива при прохождении через него: Deleting and creating body in libGDX.

Что касается моего вопроса, вот выход аварии:

< консоли>

EntityManager: entity generation begin --------- 
IceSpike: generating physics 
IceSpike: generated physics 
IceSpike: generating graphics 
EntityManager: entity generation registered 
IceSpike: generating physics 
IceSpike: generated physics 
IceSpike: generating graphics 
EntityManager: entity generation registered 
IceSpike: generating physics 
# 
# A fatal error has been detected by the Java Runtime Environment: 
# 
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0000000066bcbd0d, pid=5288, tid=0x00000000000013d4 
# 
# JRE version: Java(TM) SE Runtime Environment (8.0_111-b14) (build 1.8.0_111-b14) 
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.111-b14 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: 
# D:\Codage\projects\eclipse\git\spacegame\SpaceGame\android\assets\hs_err_pid5288.log 
# 
# If you would like to submit a bug report, please visit: 
# http://bugreport.java.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 

Файл журнала: http://pastebin.com/JjBGnTri

Когда речь идет о коде, я буду стараться сделайте как можно проще. Надеюсь, я не режу часть этой проблемы.

У меня есть EntityManager, который обрабатывает поколение и уничтожение моих сущностей. Все объекты в игре наследуются от Entity (большой абстрактный блок). Все они имеют тело box2d, которое генерируется в generatePhysics(World physics).

EntityManager

private GameWorld world; 
private Array<Entity> generation; 
private Array<Entity> generationCpy; 
private Array<Entity> trash; 
private Array<Entity> trashCpy; 

public void update(float delta) 
{ 
    //generate new entities 
    Gdx.app.debug(this.getClass().getSimpleName(), "entity generation begins ---------"); 
    if(generation.size != 0) 
    { 
     generationCpy = new Array<Entity>(generation); 
     for (Entity entity : generationCpy) 
     { 
      entity.generate(world.getPhysics(),world.getAssetManager()); 
     } 
    } 

    //destroy old entities 
    Gdx.app.debug(this.getClass().getSimpleName(), "entity destruction begins ---------"); 
    if(trash.size != 0) 
    { 
     trashCpy = new Array<Entity>(trash); 
     for(Entity entity : trashCpy) 
     { 
      trash.removeValue(entity, true); 
      entity.destroy(world.getPhysics()); 
      entity = null; 
     } 
    } 
    Gdx.app.debug(this.getClass().getSimpleName(), "entity generation complete ------"); 

Entity

public final void generate(World physics, AssetManager assetManager) 
{ 
    if(state != EntityState.GENERATED) 
    { 
     generatePhysics(physics); 
     generateGraphics(assetManager); 
     setState(EntityState.GENERATED); 
    } 
    else 
     Gdx.app.error(this.getClass().getSimpleName(), "entity couldn't be generated. It had allready been generated"); 
} 

До сих пор, только шипы, кажется, это касается, и большую часть времени, все проходит гладко. Остальное время, это врезаться часть:

IceSpikes

@Override 
public void generatePhysics(World physics) 
{ 
    Gdx.app.debug(this.getClass().getSimpleName(), "generating physics"); 

    BodyDef bodyDef = new BodyDef(); 
    bodyDef.type = BodyType.DynamicBody; 
    bodyDef.position.set(this.position.cpy().scl(1/PPM)); 

    body = physics.createBody(bodyDef); 
    body.setBullet(true); 

    PolygonShape shape = new PolygonShape(); 
    Vector2 vertices[] = new Vector2[3]; 
    vertices[0] = new Vector2(-width/2,-height/2).scl(1f/PPM); 
    vertices[1] = new Vector2(0,height/2).scl(1f/PPM); 
    vertices[2] = new Vector2(width/2,-height/2).scl(1f/PPM); 
    shape.set(vertices);   

    FixtureDef fixtureDef = new FixtureDef(); 
    fixtureDef.shape = shape; 
    fixtureDef.density = 1f; 
    fixtureDef.restitution = 1f; 
    fixtureDef.filter.categoryBits = CollisionManager.BIT_PROJECTILE; 
    fixtureDef.filter.maskBits = CollisionManager.BIT_PLAYER; 

    Fixture fixture = body.createFixture(fixtureDef); 
    fixture.setUserData(this); 

    shape.dispose(); 

    Gdx.app.debug(this.getClass().getSimpleName(), "generated physics"); 
} 

Это говорит о том, что связано с созданием синхронизации из IceSpikes, который после столкновения (в world.step()). Тем не менее, это как раз и точка моей системы управления сущностями. Он генерирует/удаляет тела вне world.step(), как кажется, подтверждается выходом.

Кроме того, скопированные массивы настроены таким образом, чтобы предотвратить удаление объектов из массива генерации и мусора, в то время как они пересекаются.

Должно быть, я что-то упустил, но что? Любая идея, как исходить оттуда?

+0

Почему это проголосовало? Я новичок, и я, по крайней мере, знаю, почему, поэтому я могу улучшить свой пост в следующий раз ... – MeMeek

+0

Кто-то на форуме libgdx сказал, что это может произойти из-за промаха '.scl (1f/PPM)', приводящего к слишком маленькие тела, которые затем взорвутся. Тем не менее, я попытался увеличить их немного больше, и у меня все еще есть проблема. Я все еще расследую. – MeMeek

ответ

0

Вопрос был вызван множественным созданием/уничтожением того же тела, вызванным множественными ссылками в моем entityManager. Моя система управления сущностью основана на слушателях. Каждый объект имеет перечисление EntityState, и диспетчер сущности уведомляется при изменении состояния. Я думал, что я гарантирую, что это состояние меняется только один раз в остальной части кода, но, как оказалось, это не так.

Простым решением было добавить условие if(this.state != state).

Вот как это выглядит сейчас:

public final void setState(EntityState state) 
{ 
    if(this.state == state) 
     Gdx.app.error(this.getClass().getSimpleName(), "the state was allready " + state); 
    else 
    { 
     this.state = state; 
     switch(state) 
     { 
      case CREATED:  notifyCreation(this);  break; 
      case GENERATED:  notifyGeneration(this);  break; 
      case TO_BE_REMOVED: notifyFlagForRemoval(this); break; 
      case INACTIVE:  notifyDestruction(this); break; 
      default : Gdx.app.error(this.getClass().getSimpleName(), "entity state became " + state); 
     } 
    } 
} 

Однако, «почему» до сих пор ускользает меня немного, потому что я был Allready принимать определенные меры противодействия, как среди прочего, проверка, если тело было нулевым, прежде разрушая его:

protected final void destroyBody(World physics) 
{ 
    Gdx.app.debug(this.getClass().getSimpleName(), "destroying body"); 
    if(body != null) 
    { 
    final Array<JointEdge> joints = body.getJointList(); 
    while (joints.size > 0) 
    { 
     Gdx.app.log("GameWorld", "destroying joint"); 
     Joint joint = joints.get(0).joint; 
     physics.destroyJoint(joint); 
     joints.removeIndex(0); 
    } 
    physics.destroyBody(body); 
    } 
    else 
    { 
    Gdx.app.error(this.getClass().getSimpleName(), "entity's body not found. No action taken."); 
    } 

}

насколько я обеспокоен, это фиксируется, даже если исправление очень специфична к моему делу и чувствует себя несколько Hacky ко мне.

0

создание и удаление объекта (в основном имеющего физический компонент) должно быть связано с блокировкой.

создание и удаление должно выполняться, когда физический мир разблокирован.

private World physicsWorld; 
private PhysicsSystem physicsSystem; 

@Override 
protected void initialize() { 

    physicsWorld =physicsSystem.getPhysicsWorld(); 
} 

@Override 
protected void processSystem() { 

    if(!physicsWorld.isLocked()) { 
      removeBodyFromWorld();  
      addBodyIntoWorld(); 
    } 
} 

В методе removeBodyFromWorld удалите желаемую сущность и создайте новое тело в методе addBodyIntoWorld.

Надеюсь, это может быть полезно.
Благодаря

+0

Благодарим вас за ответ. Боюсь, я уже убеждаюсь, что не нахожусь в физическом мире. Я jadded условие 'if (! World.getPhysics(). IsLocked())' для генерации и удаления сущности, просто чтобы быть уверенным, но проблема остается. Тем не менее, я рад, что вы познакомили меня с методом 'isLocked()'. В будущем это может пригодиться. – MeMeek

0

Как уже ли вы что-то упускается из виду, из кода, размещенных здесь, вы упускать из виду shape касаемо vertices (в методе generatePhysics).

Нигде полигону не приказано использовать эти вершины (или любые другие вершины). Прежде чем создавать прибор, который будет использовать многоугольник, необходимо установить не более 3 или более вершин.

+0

А, спасибо. Как насчет кода, который выводит сообщение «зарегистрированное сущностью»? Я не вижу этого и хочу также проверить его логику. –

+0

Это из моей системы управления сущностями. Он основан на EntityState. EntityManager прослушивает изменения состояния и помещает объекты в массив генерации, конкретный массив (снаряд/астероид/коллектив ...) или мусор. Я пришел к мысли, что проблема, скорее всего, придет оттуда. Ему нужно больше исследований с моей стороны в данный момент (что я сейчас делаю), поэтому я думаю, что сообщение «приостановлено». – MeMeek