jesses / wck

Box2d Flash Alchemy Port + World Construction Kit (AS3 Physics Engine)
http://sideroller.com/wck
358 stars 55 forks source link

b2body.destroy() #13

Closed Teresa101 closed 12 years ago

Teresa101 commented 12 years ago

Hi, I'm trying to remove the main character from the stage by calling the function destroy(). Here is my example code:

var bottomWall:bottom_wall = e.other.m_userData as bottom_wall; if (bottomWall) { b2body.destroy(); }

It does not work and I got the following output when running the movie test:

Assertion failed: (IsLocked() == false), function DestroyBody, file ../Box2D/Dynamics/b2World.cpp, line 130.

[object AlchemyExit] at Function/() at Function/() at Box2DAS.Dynamics::b2Body/destroy() at panda/handleContact() at flash.events::EventDispatcher/dispatchEventFunction() at flash.events::EventDispatcher/dispatchEvent() at Box2DAS.Common::b2EventDispatcher/dispatchEvent() at Box2DAS.Dynamics::b2ContactListener/ContactDispatch() at Box2DAS.Dynamics::b2ContactListener/BeginContact() at Box2DAS.Dynamics::b2World/BeginContact() at Function/http://adobe.com/AS3/2006/builtin::apply() at global/AS3_CallTS() at Function/http://adobe.com/AS3/2006/builtin::apply() at Function/() at cmodule.Box2D::FSM__ZN13WorldListener12BeginContactEP9b2Contact/work() at Function/() at Function/() at Box2DAS.Dynamics::b2World/HandleStep() at flash.events::EventDispatcher/dispatchEventFunction() at flash.events::EventDispatcher/dispatchEvent() at Box2DAS.Common::b2EventDispatcher/dispatchEvent() at Box2DAS.Dynamics::b2World/Step() at wck::World/step()

I don't really know how to resolve this issues. Would you help me please as I'm new with box2d and wck. Much appreciated!

jesses commented 12 years ago

2 things:

  1. You're trying to remove the object from a contact callback, which means you are doing it mid timestep. Box2D doesn't allow you to do this.
  2. You shouldn't call destroy() manually. Instead, just remove it from the stage (just call remove() on the BodyShape). You actually CAN do this mid timestep, because it will delay the actual destruction of the object until after the timestep for you.
Teresa101 commented 12 years ago

Thank you for your reply, Jesses. I did call remove() on the BodyShape, but it not only removed the main character, but also everything inside my world movie clip, which is not what I wanted. I created a movie clip of my world and then put everything in my world and all the actions happen inside that world. When I wanted to remove only the main character from my world, it removed everything as well. So I just thought I might try to call destroy() to see if it works.

jesses commented 12 years ago

You'll have to post your code. It sounds like you're calling "remove()" on the wck.World, not the BodyShape.

Teresa101 commented 12 years ago

I had this code in my panda class

public class panda extends Box {

  [...]

  var bottomWall:bottom_wall = e.other.m_userData as bottom_wall;
  if (bottomWall) {
      this.remove();
  }

}

Teresa101 commented 12 years ago

Below is part of the code in my Panda class that I called remove() method. I assumed this method would remove my Panda only, but it removed everything inside my World movie clip. I'm stuck at this and don't really know what's wrong. Thank you for taking a look and help me with this. Much appreciated!

package {

import Box2DAS.*;
import Box2DAS.Collision.*;
import Box2DAS.Collision.Shapes.*;
import Box2DAS.Common.*;
import Box2DAS.Dynamics.*;
import Box2DAS.Dynamics.Contacts.*;
import Box2DAS.Dynamics.Joints.*;
import cmodule.Box2D.*;
import extras.*;
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.text.*;
import flash.utils.*;
import misc.*;
import shapes.*;
import wck.*;

public class Panda extends Box 
{
    public var contacts:ContactList;

    public override function create():void 
    {
        reportBeginContact = true;
        reportEndContact = true;
        fixedRotation = true;
        super.create();
        listenWhileVisible(world, StepEvent.STEP, parseInput, false, 10);
        listenWhileVisible(this, ContactEvent.BEGIN_CONTACT, handleContact);
        listenWhileVisible(this, ContactEvent.BEGIN_CONTACT, handleContact);
        contacts = new ContactList();
        contacts.listenTo(this);
    }

    public function handleContact(e:ContactEvent):void 
    {
            var bottomWall:bottom_wall = e.other.m_userData as bottom_wall;
            if (bottomWall) {
                this.remove();
            }
    }
jesses commented 12 years ago

That looks correct, beside the fact that you're listening to BEGIN_CONTACT twice, but I don't think that would cause problems. Could you post the full project?

Teresa101 commented 12 years ago

Hi Jesses, I'm sorry that I can't post the full project here for confidential concern that I have to adhere with my company's policy. I hope that you can spot out the problem from the main three classes below that I've run the test on wck. I had to create my own World class to adjust the way myWorld only scrolling horizontally, but not vertically.

Here are the whole code of wckTest class, Panda class and myWorld class.

package { import Box2DAS.; import Box2DAS.Collision.; import Box2DAS.Collision.Shapes.; import Box2DAS.Common.; import Box2DAS.Dynamics.; import Box2DAS.Dynamics.Contacts.; import Box2DAS.Dynamics.Joints.; import cmodule.Box2D.; import wck.; import shapes.; import misc.; import extras.; import flash.utils.; import flash.events.; import flash.display.; import flash.text.; import flash.geom.*;

public class wckTest extends WCK 
{
    public function wckTest():void
    {           
        if (stage) init();
        else addEventListener(Event.ADDED_TO_STAGE, init);

    }

    private function init(e:Event = null):void
    {
        removeEventListener(Event.ADDED_TO_STAGE, init);
        // entry point
    }
}

}

package {

import Box2DAS.*;
import Box2DAS.Collision.*;
import Box2DAS.Collision.Shapes.*;
import Box2DAS.Common.*;
import Box2DAS.Dynamics.*;
import Box2DAS.Dynamics.Contacts.*;
import Box2DAS.Dynamics.Joints.*;
import cmodule.Box2D.*;
import extras.*;
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.text.*;
import flash.utils.*;
import misc.*;
import shapes.*;
import wck.*;

public class Panda extends Box 
{
    public var contacts:ContactList;

    public override function create():void 
    {
        reportBeginContact = true;
        reportEndContact = true;
        fixedRotation = true;
        super.create();
        listenWhileVisible(world, StepEvent.STEP, parseInput, false, 10);
        listenWhileVisible(this, ContactEvent.BEGIN_CONTACT, handleContact);
        contacts = new ContactList();
        contacts.listenTo(this);
    }

    public function handleContact(e:ContactEvent):void 
    {
            //Detect collison with other static objects
            var blueCat:blueCat = e.other.m_userData as blueCat;
            var orangeCat:orangeCat = e.other.m_userData as orangeCat;
            var blueDog:blueDog = e.other.m_userData as blueDog;
            var orangeDog:orangeDog = e.other.m_userData as orangeDog;

            if(blueCat) {
                blueCat.remove();
                var sparkles1:particles = new particles();
                addChild(sparkles1);
                sparkles1._isSensor = true;
                sparkles1._categoryBits = 0x02;
                sparkles1._maskBits = 0x03;
                sparkles1.applyGravity = false;
                sparkles1.enabled = false;
                sparkles1.x = stage.stageWidth/5;
                sparkles1.y = stage.stageHeight/-8;

                var myBlueCatTimer:Timer = new Timer(1500,1);
                myBlueCatTimer.addEventListener(TimerEvent.TIMER, removeSparkles1);
                function removeSparkles1 (e:TimerEvent):void{
                    sparkles1.remove();
                }
                myBlueCatTimer.start();

            }
            else if(orangeCat) {
                orangeCat.remove();
                var sparkles2:particles = new particles();
                addChild(sparkles2);
                sparkles2._isSensor = true;
                sparkles2._categoryBits = 0x02;
                sparkles2._maskBits = 0x03;
                sparkles2.applyGravity = false;
                sparkles2.enabled = false;
                sparkles2.x = stage.stageWidth/5;
                sparkles2.y = stage.stageHeight/-8;

                var myOrangeCatTimer:Timer = new Timer(1500,1);
                myOrangeCatTimer.addEventListener(TimerEvent.TIMER, removeSparkles2);
                function removeSparkles2 (e:TimerEvent):void{
                    sparkles2.remove();
                }
                myOrangeCatTimer.start();
            }

            else if(blueDog) {
                blueDog.remove();
                var sparkles3:particles = new particles();
                addChild(sparkles3);
                sparkles3._isSensor = true;
                sparkles3._categoryBits = 0x02;
                sparkles3._maskBits = 0x03;
                sparkles3.applyGravity = false;
                sparkles3.enabled = false;
                sparkles3.x = stage.stageWidth/5;
                sparkles3.y = stage.stageHeight/-8;

                var myBlueDogTimer:Timer = new Timer(1500,1);
                myBlueDogTimer.addEventListener(TimerEvent.TIMER, removeSparkles3);
                function removeSparkles3 (e:TimerEvent):void{
                    sparkles3.remove();
                }
                myBlueDogTimer.start();

            }
            else if(orangeDog) {
                orangeDog.remove();
                var sparkles4:particles = new particles();
                addChild(sparkles4);
                sparkles4._isSensor = true;
                sparkles4._categoryBits = 0x02;
                sparkles4._maskBits = 0x03;
                sparkles4.applyGravity = false;
                sparkles4.enabled = false;
                sparkles4.x = stage.stageWidth/5;
                sparkles4.y = stage.stageHeight/-8;

                var myOrangeDogTimer:Timer = new Timer(1500,1);
                myOrangeDogTimer.addEventListener(TimerEvent.TIMER, removeSparkles4);
                function removeSparkles4 (e:TimerEvent):void{
                    sparkles4.remove();
                }
                myOrangeDogTimer.start();
            }

            var bottomWall:bottom_wall = e.other.m_userData as bottom_wall;
            if (bottomWall) {
                this.remove();
            }
    }

    public function parseInput(e:Event):void 
    {
        //var manifold:b2WorldManifold = null;
        //var dot:Number = -1;

        // Search for the most ground/floor-like contact.
        if(!contacts.isEmpty()) {
            contacts.forEach(function(keys:Array, c:ContactEvent) {
                //var wm:b2WorldManifold = c.getWorldManifold();
                //if(wm.normal) { 

                    // Dot producting the contact normal with gravity indicates how floor-like the
                    // contact is. If the dot product = 1, it is a flat foor. If it is -1, it is
                    // a ceiling. If it's 0.5, it's a sloped floor. Save the contact manifold
                    // that is the most floor like.
                    //var d:Number = wm.normal.dot(gravity);
                    //if(!manifold || d > dot) {
                        //manifold = wm;
                        //dot = d;
                    //}
                //}
            });
            contacts.clean();
    }
        //var left:Boolean = Input.kd('A', 'LEFT');
        //var right:Boolean = Input.kd('D', 'RIGHT');
        var keyJump:Boolean = Input.kd('UP', 'UP');
        var mouseJump:Boolean = Input.mouseIsDown;

        //var v:V2;

        // Here we could add a dot product threshold for disallowing the player from jumping
        // off of walls, ceilings, etc. For example:
        //if(jump && manifold) {
        if(keyJump || mouseJump){
            //v = manifold.normal.clone().multiplyN(-2);
            //b2body.ApplyImpulse(v, b2body.GetWorldCenter());
            //holder.removeChild(objects[currentObject]);
            //holder.addChild(objects[currentObject = ++currentObject % objects.length]);
            gotoAndStop(2);
            b2body.ApplyImpulse(new V2(1.5, 0), b2body.GetWorldCenter());
            b2body.ApplyImpulse(new V2(0, -0.5), b2body.GetWorldCenter());

        }
        else {
            gotoAndStop(1);
            b2body.ApplyImpulse(new V2(0, 0.2), b2body.GetWorldCenter());
        }
        //else if(left) {
            //b2body.ApplyImpulse(new V2(-0.1, 0), b2body.GetWorldCenter());
        //}
        //else if(right) {
            //b2body.ApplyImpulse(new V2(0.1, 0), b2body.GetWorldCenter());             
        //}
    }
}

}

package { import Box2DAS.; import Box2DAS.Collision.; import Box2DAS.Collision.Shapes.; import Box2DAS.Common.; import Box2DAS.Dynamics.; import Box2DAS.Dynamics.Contacts.; import Box2DAS.Dynamics.Joints.; import cmodule.Box2D.; import wck.; import gravity.; import misc.; import flash.utils.; import flash.events.; import flash.display.; import flash.text.; import flash.geom.; import flash.ui.*;

public class myWorld extends World
{
    public override function create():void 
    {
        if(!focus && focusOn != '') {
            focus = Util.getDisplayObjectByPath(this, focusOn);
        }
        pos = globalToLocal(new Point(stage.stageWidth, stage.stageHeight));
        rot = rotation;
        super.create();
        if(scrolling) {
            listenWhileVisible(stage, Event.ENTER_FRAME, updateScroll, false, -9999);
        }
    }

    /**
     * Reorient so that the focus object or position is in the center of the stage.
     */
    public override function updateScroll(e:Event = null):void {
        if(!scrolling) {
            return;
        }
        /// If we have a focus object, then find the new position of the focus object in the viewport.
        if(focus) {
            pos = Util.localizePoint(this, focus, localPos);
        }
        var p:Point = pos.clone();
        rot = scrollRotation();
        var r:Number = rot;
        /// If mid-focus-change, tween from the old position & rotation to the new one.
        if(tFunc != null) {
            if(++tFrames == tFramesTot) {
                tFunc = null;
            }
            else {
                r = tFunc(tFrames, tRot, Util.findBetterAngleTarget(tRot, r) - tRot, tFramesTot);
                p.x = tFunc(tFrames, tPos.x, p.x - tPos.x, tFramesTot);
                p.y = tFunc(tFrames, tPos.y, this.y - tPos.y, tFramesTot);
            }
        }

        /// Set the position and rotation of the viewport.
        rotation = r;
        x = 0;
        y = 0;
        p = localToGlobal(p);
        x = stage.stageWidth/4.5 - p.x;
        y = stage.stageHeight;
        /// Nudge the viewport based on the mouse.
        if(Input.mouseDetected) {
            x += (stage.stageWidth / 2 - Input.mousePos.x) * (tFunc != null ? tFunc(tFrames, tMX, mouseNudgeX - tMX, tFramesTot) : mouseNudgeX);
            y += (stage.stageHeight / 2 - Input.mousePos.y) * (tFunc != null ? tFunc(tFrames, tMY, mouseNudgeY - tMY, tFramesTot) : mouseNudgeY);
        }
        //x = Math.round(x);
        //y = Math.round(y);
        if(shake) {
            x += shake.x;
            y += shake.y;
            shake.normalize(shake.length * -0.5);
            if(shake.length < 1) {
                shake = null;
            }
        }

    }

}

}

jesses commented 12 years ago

Ok, I've looked at that code a couple of times now. I don't see anything blatantly wrong but I have a guess. Could it be that after you remove the panda, since it's no longer on the stage it messes up the scrolling? The scrolling uses localToGlobal and globalToLocal, I'm not sure what those do when an object isn't on the stage. Try seeing what "pos" is in your scrolling function after removing the panda. Maybe the world is being moved to an undefined position, making it look like everything is being removed.

Teresa101 commented 12 years ago

What you said does make sense as the world is set in scrolling, which means everything inside the world follows the panda's movement. I'll check out the scrolling function to see what I can do to override. It might be that I have to reset the "pos" after removing the panda. Thanks for pointing that out, Jesses!