如何正确删除以下版本的box2d主体:Box2dWeb-2.1.a.3,Box2D_v2.3.1r3? Box2D错误? [英] How to properly delete a box2d body in version: Box2dWeb-2.1.a.3, Box2D_v2.3.1r3? Box2D bug?

查看:67
本文介绍了如何正确删除以下版本的box2d主体:Box2dWeb-2.1.a.3,Box2D_v2.3.1r3? Box2D错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

既然发现了问题,我也发现Box2D for web的每一面都在泄漏:/

Since the problem has been found I've also find out that Box2D for web is leaking on every side :/

为了说明这一点,我制作了一个在静态多边形中移动的简单圆,这是一段时间后的结果.

To show this I made a simple circle moving in a static polygon and here is the result after some time.

请注意以下各项是如何泄漏的,因为我没有创建任何物体或以任何方式改变世界:

Notice how the following items are leaking as I'm not creating any body or changing the world in any way:

  • b2Vec2
  • 功能
  • b2ManifoldPoint
  • b2ContactID
  • b2Manifold
  • b2ContactEdge
  • b2PolyAndCircleContact
  • 数组
  • ...

我有一个问题,因为我正在分析游戏,而垃圾收集器不会删除我的尸体,联系人和其他东西.然后,我查看了它们在GC中保留的内容以及Box2D本身.这可能会导致2个选择:我做得不好或Box2D正在泄漏.我认为是我的原因.

I have a problem because I'm profiling my game and the garbage collector doesnt' delete my bodies, contacts and other stuff. Then I've looked at what are they keeping from the GC and was the Box2D itself. This might lead to 2 options: I'm doing it bad or Box2D is leaking. I consider is my cause.

到底是什么?

  • contact.m_nodeA.other似乎是最常用于阻止其进入GC的系统.
  • 其他时间:联系人中的m_fixtureB ...查看图片

您可以看到该主体具有__destroyed属性.这是在使用world.DestroyBody(body)删除之前手动设置的.

You can see that the body has a __destroyed property. That is set manually before deleting it with world.DestroyBody(body)

当我销毁尸体时,我会在世界上调用step方法后将其命名.

When I destroy a body I call it after I call the step method on the world.

从box2d方法中可以看到,它不会摆脱其他变量,也不会将其更改为另一个主体,而我的主体不是GC.

As you can see from the box2d method it doesn't get rid of the other variable nor it changes it to another body and my body is not GC.

对我在这里想念的东西有任何想法吗?

Any idea of what I'm missing here?

var gravity = new Box2D.Vec2(0, 0);
var doSleep = true;
var world = new Box2D.World(gravity, doSleep);
var step = false;

var fixtureDef = new Box2D.FixtureDef();
fixtureDef.density = 1.0;
fixtureDef.friction = 0.5;
fixtureDef.restitution = 0.2;
fixtureDef.shape = new Box2D.PolygonShape();
fixtureDef.shape.SetAsBox(1, 1);
var bodyDef = new Box2D.BodyDef;
bodyDef.type = Box2D.Body.b2_dynamicBody;
bodyDef.position.x = 0.4;
bodyDef.position.y = 0.4;

var bodies = []
var fix = [];
window.c = function(){
    for(var i = 0; i < 100; i++){
        var body = world.CreateBody(bodyDef);
        body._id = i;

        fix.push(body.CreateFixture(fixtureDef));
        bodies.push(body);

    }
    if(step){world.Step(1/60, 3, 3); world.ClearForces();}
    console.log('Created', bodies)
    fixtureDef = null;
    bodyDef = null;
}

window.d = function(){
    _.each(bodies, function(body, i){
        body.DestroyFixture(fix[i]);
        world.DestroyBody(body);

        fix[i] = null;
        bodies[i] = null;
    })
    if(step){world.Step(1/60, 3, 3); world.ClearForces();}
    bodies = null;
    fix = null;
}

将步骤更改为true,然后再次出现内存泄漏问题.

Change the step to true and the memory leak problem appears again.

文件中的代码:

var gravity = new Box2D.Vec2(0, 0);
var doSleep = true;
var world = new Box2D.World(gravity, doSleep);

var bodies = []
window.c = function(){
    for(var i = 0; i < 100; i++){
        var bodyDef = new Box2D.BodyDef();
        bodyDef.type = 2;

        var shape = new Box2D.PolygonShape();
        shape.SetAsBox(1, 1);

        var fixtureDef   = new Box2D.FixtureDef();
        fixtureDef.shape = shape;
        var body = world.CreateBody(bodyDef);
        body._id = i;
        body.CreateFixture(fixtureDef);
        bodies.push(body);
    }
    world.Step(0.3, 3, 3);
    console.log('Created', bodies)
}
window.d = function(){
    _.each(bodies, function(body, i){
        world.DestroyBody(body);
        bodies[i] = null;
    })
    world.Step(0.3, 3, 3);
    bodies = null;
}

打开谷歌浏览器:

  • 然后打开您的个人资料并制作快照.
  • 现在在控制台中运行c()方法以创建100个实体
  • 现在快照2
  • 在快照中搜索b2Body,您会发现100个对象计数
  • 现在运行d()删除所有身体;
  • 通过单击垃圾桶强制收集垃圾
  • 制作快照3
  • 搜索b2Body,您还将发现100个对象计数

在最后一步,只能是0个对象,因为它们已被销毁.取而代之的是,您会发现:

At the last step should only be 0 objects as they have been destroyed. Instead of this you'll find this:

现在您可以看到b2ContactEdge提供了很多参考.现在,如果您删除了世界,那么在代码的步骤部分,您将只看到2个对身体的引用.

Now you can see there are a lot of references from b2ContactEdge. Now if you remove the world.Step part of the code you will only see 2 references to the body.

如果您删除此行

body.CreateFixture(fixtureDef);

或使身体静止不再泄漏.

or making the body static is not leaking anymore.

我的游戏循环

...gameLoop = function(o){
    // used a lot here
    var world = o.world;

    // calculate the new positions
    var worldStepSeconds = o.worldStepMs / 1000;

    // step world
    world.Step(worldStepSeconds, o.velocityIterations, o.positionIterations)

    // render debug
    if(o.renderDebug){
        world.DrawDebugData();
    }

    // always to not accumulate forces, maybe some bug occurs
    world.ClearForces();

    // tick all ticking entities
    _.each(o.getTickEntitiesFn(), function(actor){
        if(!actor) return;
        actor.tick(o.worldStepMs, o.lastFrameMs);
    })


    // update PIXI entities
    var body = world.GetBodyList();
    var worldScale = world.SCALE;
    var destroyBody = world.DestroyBody.bind(world);
    while(body){
        var actor = null;
        var visualEntity = null;
        var box2DEntity = o.getBox2DEntityByIdFn(body.GetUserData());
        if(box2DEntity){
            visualEntity = o.getVisualEntityByIdFn(box2DEntity.getVisualEntityId());
            if(box2DEntity.isDestroying()){
                // optimization
                body.__destroyed = true;
                world.DestroyBody(body);
                box2DEntity.completeDestroy();
            }
        }
        if(visualEntity){
            if(visualEntity.isDestroying()){
                visualEntity.completeDestroy();
            }else{
                var inverseY = true;
                var bodyDetails = Utils.getScreenPositionAndRotationOfBody(world, body, inverseY);
                visualEntity.updateSprite(bodyDetails.x, bodyDetails.y, bodyDetails.rotation);
            }
        }
        // this delegates out functionality for each body processed
        if(o.triggersFn.eachBody) o.triggersFn.eachBody(world, body, visualEntity);

        body = body.GetNext();
    }

    // when a joint is created is then also created it's visual counterpart and then set to userData.
    var joint = world.GetJointList();
    while(joint){
        var pixiGraphics = joint.GetUserData();
        if(pixiGraphics){
            // In order to draw a distance joint we need to know the start and end positions.
            // The joint saves the global (yes) anchor positions for each body.
            // After that we need to scale to our screen and invert y axis.
            var anchorA           = joint.GetAnchorA();
            var anchorB           = joint.GetAnchorB();
            var screenPositionA = anchorA.Copy();
            var screenPositionB = anchorB.Copy();
            // scale
            screenPositionA.Multiply(world.SCALE);
            screenPositionB.Multiply(world.SCALE);
            // invert y
            screenPositionA.y = world.CANVAS_HEIGHT - screenPositionA.y
            screenPositionB.y = world.CANVAS_HEIGHT - screenPositionB.y

            // draw a black line
            pixiGraphics.clear();
            pixiGraphics.lineStyle(1, 0x000000, 0.7);
            pixiGraphics.moveTo(screenPositionA.x, screenPositionA.y);
            pixiGraphics.lineTo(screenPositionB.x, screenPositionB.y);
        }
        joint = joint.GetNext();
    }

    // render the PIXI scene
    if(o.renderPixi){
        o.renderer.render(o.stage)
    }

    // render next frame
    requestAnimFrame(o.requestAnimFrameFn);
}

Box2d中的代码:

b2ContactManager.prototype.Destroy = function (c) {
var fixtureA = c.GetFixtureA();
var fixtureB = c.GetFixtureB();
var bodyA = fixtureA.GetBody();
var bodyB = fixtureB.GetBody();
if (c.IsTouching()) {
this.m_contactListener.EndContact(c);
}
if (c.m_prev) {
c.m_prev.m_next = c.m_next;
}
if (c.m_next) {
c.m_next.m_prev = c.m_prev;
}
if (c == this.m_world.m_contactList) {
this.m_world.m_contactList = c.m_next;
}
if (c.m_nodeA.prev) {
c.m_nodeA.prev.next = c.m_nodeA.next;
}
if (c.m_nodeA.next) {
c.m_nodeA.next.prev = c.m_nodeA.prev;
}
if (c.m_nodeA == bodyA.m_contactList) {
bodyA.m_contactList = c.m_nodeA.next;
}
if (c.m_nodeB.prev) {
c.m_nodeB.prev.next = c.m_nodeB.next;
}
if (c.m_nodeB.next) {
c.m_nodeB.next.prev = c.m_nodeB.prev;
}
if (c.m_nodeB == bodyB.m_contactList) {
bodyB.m_contactList = c.m_nodeB.next;
}
this.m_contactFactory.Destroy(c);
--this.m_contactCount;
}


b2ContactFactory.prototype.Destroy = function (contact) {
    if (contact.m_manifold.m_pointCount > 0) {
        contact.m_fixtureA.m_body.SetAwake(true);
        contact.m_fixtureB.m_body.SetAwake(true);
    }
    var type1 = parseInt(contact.m_fixtureA.GetType());
    var type2 = parseInt(contact.m_fixtureB.GetType());
    var reg = this.m_registers[type1][type2];
    if (true) {
        reg.poolCount++;
        contact.m_next = reg.pool;
        reg.pool = contact;
    }
    var destroyFcn = reg.destroyFcn;
    destroyFcn(contact, this.m_allocator);
}

推荐答案

我有同样的问题,但我想我是从哪里找出来的.

I have the same problem, but I think I find out from where it comes.

尝试使用功能,例如GetFixtureA()代替m_fixtureA,而不是m _ *.

Instead of m_* try functions, like GetFixtureA() instead of m_fixtureA.

这篇关于如何正确删除以下版本的box2d主体:Box2dWeb-2.1.a.3,Box2D_v2.3.1r3? Box2D错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆