QuickBox2D Contacts Part 3

Actionscript:
  1. import com.actionsnippet.qbox.*;
  2. import Box2D.Common.Math.*;
  3.  
  4. [SWF(width = 800, height = 600, backgroundColor = 0x222222, frameRate=60)]
  5.  
  6. var sim:QuickBox2D = new QuickBox2D(this, {debug:false});
  7.  
  8. sim.createStageWalls();
  9.  
  10. var cup:QuickObject = sim.addPoly({x:3, y:13, wireframe:false, density:0,
  11.                                    points:[0,0, .5, 0, .5,3,  2,3,  2,0,  2.5,0, 2.5, 3.5, 0, 3.5, 0,0]});
  12. var deleter:QuickObject = sim.addBox({x:4.251, y: 15.9, width:1.5, height:0.25, fillColor:0xFF0000});
  13.  
  14. // use a distance joint instead of a group since isCurrentContact
  15. // uses the QuickObject.body property
  16. sim.addJoint({a:cup.body, b:deleter.body, x1:deleter.x, y1:deleter.y+0.5});
  17.  
  18. var circles:Array = [];
  19. for (var i:int = 0; i<10; i++){
  20.     circles[i] = sim.addCircle({x:8 + i, y:5, radius:0.5});
  21. }
  22. var boxes:Array = [];
  23. for (i = 0; i<10; i++){
  24.     boxes[i] = sim.addBox({x:8.5 + i, y:10, width:0.5, height:0.5});
  25. }
  26.  
  27. sim.start();
  28. sim.mouseDrag();
  29.  
  30. var shootVec:b2Vec2 = new b2Vec2(4, -30);
  31.  
  32. // when circles are dropped in the cup they are destroyed
  33. // when boxes are droppped in the cup their linear velocity is altered
  34. var contacts:QuickContacts = sim.addContactListener();
  35. contacts.addEventListener(QuickContacts.ADD, onAdd);
  36. function onAdd(evt:Event):void{
  37.     for (var i:int = 0; i<circles.length; i++){
  38.         var circ:QuickObject = circles[i];
  39.         if (contacts.isCurrentContact(circ, deleter)){
  40.             // it's ok to destroy QuickObject here because they are only actually
  41.             // destroyed after the timeStep has finished at the end of QuickBox2D's
  42.             // internal loop
  43.             circ.destroy();
  44.         }
  45.      }
  46.      for (i = 0; i<boxes.length; i++){
  47.         var box:QuickObject = boxes[i];
  48.         if (contacts.isCurrentContact(box, deleter)){
  49.             box.body.SetLinearVelocity(shootVec);
  50.         }
  51.      }
  52. }

Note: This snippet requires QuickBox2D 1.0 or greater

Here is another example of using QuickBox2D style contacts. In this example there is a cup with a small red box inside of it. When circles are placed inside the cup they are destroyed. When boxes are placed inside the cup they are shot upward.


Have a look at the swf...

A Note About Creation and Destruction

It's worth noting that in Box2D your not supposed to destroy or create rigid bodies within the listener function for any contact events. QuickBox2D gets around this restriction by flagging the rigid body for destruction and destroying it at the end of QuickBox2D's internal loop. This is not the case with creation of rigid bodies - if you attempt to create a rigid body within one of these listener functions you will get an error. See QuickBox2D Contacts Part 1 for an example of creating rigid bodies when there is a collision.

This entry was posted in Box2D, QuickBox2D and tagged , , , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

18 Comments

  1. Posted September 16, 2009 at 9:22 am | Permalink

    I remember you made a post about jumping through platforms, is it any different or easier to do with this with quickbox2d 1.0? Now that 1.0 is out, i’d like to update my blog post on my site with the 1.0 build. THEN, expand upon it with jumping through platforms.

    Thanks,
    Thomas Francis

  2. Posted September 16, 2009 at 9:28 am | Permalink

    Hey Thomas,

    I didn’t add anything that would make jumping through platforms any easier - so you can use the same technique I used in the previous post:

    http://actionsnippet.com/?p=2114

    You would actually want to use contacts for the jumping part though:

    …check if character is colliding with something that qualifies as ground and then allow UP key to be pressed.

    In the original post I just checked to see if there were any contact points around - since there wasn’t anything else going on in the demo…

  3. JasonFuzz
    Posted November 3, 2009 at 7:09 am | Permalink

    Hi Zevan,

    I am having troubles clearing everything on stage, basically i want to reset everything in between levels. I tried sim.destroy() or sim.stop() on a reset button but this only stops the simulation and you can still see the objects on screen.

    I want to be able to clear everything when ever i want to so I can easily clear everything when a player fails or completes a level.

    is there an easy way to do this?

    sorry I not the great at actionscript and it seems this is a little above my level.

    i would suggest creating an example of how to reset the simulation and graphics.

    hope you can help, i will really appreciate it!!
    thanks

    Jason

  4. CD
    Posted November 5, 2009 at 4:15 pm | Permalink

    I too am in need of a function to “reset” - I’ve found that the only way QuickObject.destroy() works is when sim.start is running. I have taken the method of removing everything on the stage and recreating based on their params values. The problem I have encountered is the destroy method doesn’t seem to delete everything and memory is compounded every time I “reset”. Flex Profiler seems to indicate that the _quickobjects Dictionary is still holding reference and thus it wont be garbage collected. Any ideas how to fix this?

    here is my function as it is right now:
    //resets the simulation to objects creation points - uses the skin of the param to capture what type of object will need to be recreated.
    //requires currentObjs - current Array of objects being used by the sim
    //requires sim - current QuickObject2D
    public function resetSim():void {
    var sObj:QuickObject;
    var newObjs:Array = new Array();
    while(sObj = currentObjs.pop()){
    //save off the old params then destroy the object
    var oldParams:Object = sObj.params;
    sObj.destroy();

    if(oldParams.skin is Poly) {
    //special class used to identify different types of objects
    newObjs.push(sim.addPoly(oldParams));
    } else {
    //everything else is a box…would need more for joins-etc
    newObjs.push(sim.addBox(oldParams));
    }
    }
    currentObjs = newObjs;
    newSlide = null;
    }

  5. Posted November 5, 2009 at 4:54 pm | Permalink

    @CD, @Jason … I’ll just make a post about this to answer all your questions. I may need to tweak the dictionary object… but if I’m correct, that won’t be necessary.

    z

  6. Posted November 6, 2009 at 9:06 am | Permalink

    @CD and @Jason… I just did a few tests - found a small memory leak and YES it was because of the dictionary. This leak is so small that it probably wouldn’t make a difference in your projects unless you were creating 1000s of rigid bodies… That said, I have fixed it and will updated it in the next release of QuickBox2D which I’d like to upload on saturday… nothing about the API will change with the 1.1 release… It will just have 2 major bug fixes… this one and another one. I also created an example of how you should be clearing your levels and will upload that tonight or tomorrow…. Thanks for the feedback guys…

  7. Posted November 7, 2009 at 10:36 am | Permalink

    @CD and @Jason …. QuickBox2D 1.1 fixes this issue… thanks again for the feedback…

  8. Matty
    Posted December 8, 2009 at 7:45 pm | Permalink

    QuickBox2D is cool — thanks for this sweet library. I have found one thing that could be a bug, though I’m not sure if it’s part of QuickBox2D.

    In the swf for this, if I drag 2 circles into the red part (not drop them in; pull them all the way in using the mouse), after releasing the mouse button on the 2nd circle, I get an error.
    RangeError: Error #1005: Array index is not a positive integer (-1).
    at Error$/throwError()
    at Array()
    at Box2D.Dynamics::b2Island()
    at Box2D.Dynamics::b2World/Solve()
    at Box2D.Dynamics::b2World/Step()
    at com.actionsnippet.qbox::QuickBox2D/onRender()

    I’d have to guess this has something to do with trying to delete the joint created by dragging an object with the mouse after it’s already been deleted, but I’m not sure.
    I have a (possibly) similar problem with something I’m working on where if I create and delete a lot of objects with joints attached to them, after deleting precisely a certain amount, it throws the same error text/stack. I think I read that QuickBox2D allows deleting in places Box2D wouldn’t — does this mean I can delete objects pretty much anytime I want in my own code?

  9. Matty
    Posted December 9, 2009 at 7:49 pm | Permalink

    I was actually able to fix this in my own project with a quick (somewhat hacky) way by altering b2Body to include a boolean called “isDeleted” that starts as false, and then changing b2World.DestroyBody() to check if isDeleted==true and then return so it doesn’t try to delete an object again. If isDeleted==false, it sets it to true and proceeds with the deletion.

    The problem may have been that DestroyBody was getting called more than once on things (i.e. it was getting called on things already destroyed) resulting in a second decrement of m_bodyCount, which ultimately ended up putting it into the negatives after a several calls. I’m still not exactly sure why it was getting called twice — maybe you have an idea?

  10. Matty
    Posted December 9, 2009 at 8:12 pm | Permalink

    Disregard the fix — I figured out that the problem was with my code. I was calling destroy twice, and that’s why the problem arose. I guess the error in your example might just coincidentally be the same thing.

  11. Hugo
    Posted December 14, 2009 at 4:12 am | Permalink

    Hi,

    I’ve been working on a simulation where I need to know if a moving object (user controlled) makes contact with another solid, its working fine to detect the contacts but I now require the ability to detect which side of the solid it makes contact with.

    The objective is to detect the user controlled object’s velocity at which it hit the solid but in order to know which velocity to use (vertical or horizontal) I need to know where it hits (top, bottom or left, right).

    I was wondering if there is any shortcut for doing this without having to actually make all the calculations and such.

    Any help or pointers would be appreciated, thanks.

  12. Guest
    Posted March 29, 2010 at 1:18 am | Permalink

    When you destroy a circle with:
    circ.destroy();

    you still have the null object in the circles array, right?

  13. lolo
    Posted April 17, 2010 at 3:33 pm | Permalink

    they are errors :
    RangeError: Error #1005: Array index is not a positive integer (-1).
    at Error$/throwError()
    at Array()
    at Box2D.Dynamics::b2Island()
    at Box2D.Dynamics::b2World/Solve()
    at Box2D.Dynamics::b2World/Step()
    at com.actionsnippet.qbox::QuickBox2D/onRender()

  14. Posted July 29, 2010 at 8:43 pm | Permalink

    Hello Zevan.
    Quickbox2d is really awesome. Incredible and easy to use. I’ll make you a good donation soon…

    You told few comments before, that you will do a post telling about how to reset the obsjects position. I think this is good for restarting the level for example.

    Could you give us some explanation about that?

  15. Posted August 28, 2010 at 5:46 pm | Permalink

    I’m putting together my first QuickBox2D game and these examples have been a huge help.
    I’m having beginner issues destroying more complex objects though.

    I have an arch shape using small boxes:

    var RCX:Number = 250/30;
    var RCY:Number = 8.5;
    var pNum:int = 20;
    var pWidth:Number = 28/30;
    var pRadius:Number = 250/30;

    for (var i:int=1; i < pNum; i++) {
    var r:Number = Math.PI/pNum*i+Math.PI;
    var curve:QuickObject=levelOne.addBox({x:RCX+pRadius*Math.cos(r), y:RCY+pRadius*Math.sin(r), width:pWidth, height:4/30, angle:r+Math.PI/2, density:0});
    }

    When I want to destroy it I am trying:
    curve.destroy();
    But it’s not working. The same thing happened when I tried destroying an array but I got around it by destroying each part individually which I can’t do here as they’re not named.

    Any help would be great, thanks.

  16. Khirod
    Posted January 17, 2011 at 5:51 am | Permalink

    Hi
    How to count the number of object (ball etc) drop in dynamic cups , there may more than one cup in a onchange event of a combox.
    Please guide me how to do this ?
    khirod

  17. Orangatang
    Posted June 6, 2012 at 9:36 pm | Permalink

    // use a distance joint instead of a group since isCurrentContact
    // uses the QuickObject.body property

    Hey Zevan Really amazing engine you made, so very useful. I wanted to know if it is possible to add to your engine a custom body with each grouped object as this would give them a lot more potential for control. I would do it myself but I do not think I am advanced enough in programming, and do not have time to understand the full box2d engine. If anyone else has done this please be kind enough to share it.

  18. Posted May 15, 2013 at 2:52 pm | Permalink

    Solution for “RangeError: Error #1005:”

    You can delete items in array. But array itself is not getting empty. You need to splice the array after destroying object.

    function clearArrayItem(no:int)
    {
    items.splice(no,1);
    }

    for (var k:int = 0; k < items.length; k++)
    {
    if (contacts.inCurrentContact(items[k]))
    {
    items[k].destroy(); //destroy item
    setTimeout(clearArrayItem,10,k); //empty array element
    }
    }

    Good library, but we need Kinetics object from newer version of BOX2D

One Trackback

  1. [...] QuickBox2Dによる衝突判定3 – QuickBox2D Contacts Part 3 [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*