Tony Polinelli
Tarwin Stroh-Spijer

contact [at]
touchmypixel.com

6/25 Easey Street
Collingwood, 3066
Vic, Australia

+61 3 8060 5321

Box2D ContactPoint Filtering

I've just had the pleasure of spending 3 days rebuilding and battling with a box2d game i'm adding some features to, to realize that the main issue was that i didnt understand corretly how the box2d ContactListeners work.

When you create a custom Contact Listner, you extend b2ContactListener. this then recieved events Add, Persist, and Remove. these functions are called and a b2ContactPoint is sent as an argument. You are advised to store contact information and act on it AFTER the simulation step is completed. I foolishly thought that i could simply store the b2ContactPoint objects. WRONG!

you cannot store the b2ContactPoint sent to the b2Contactlistener functions. I've modified this page on the box2d site to stress this point. You must copy the contact information and store it in your own custom object as box2d reuses its b2ContactPoint object (storing it in a static var i believe). Not knowing this has cost me a lot of pain as my collisions were alwas *half* working, so i hope you can avoid it.

Contact Manager Class

To act on the collision events i wanted to store them in a useful way than simply in an array. It is useful to group them by their Bodies. I can get a list of collisions like:

Actionscript:
  1. contactManager.getContactPoints(ContactManager.TYPE_ADD, myBody1, myBody2);
  2. // returns an Array of ContactPoint objects

Actionscript:
  1. contactManager.getContacts(ContactManager.TYPE_ADD, myRigidBody);
  2. // returns a Dictionary with colliding bodies as the keys and Arrays holding
  3. // the custom ContactPoint objects as values. Very useful to get all bodies
  4. // colliding with a single object, such as your player.

If you set userData on the b2Bodies it can use useful to check this to see the type of the body (type of enemy for example) and call differnt code on your player to react to collisions.

Actionscript:
  1. package com.touchmypixel.box2D
  2. {
  3.     import Box2D.Collision.b2ContactPoint;
  4.     import Box2D.Dynamics.b2Body;
  5.     import Box2D.Dynamics.b2ContactListener;
  6.     import flash.utils.Dictionary;
  7.  
  8.     public class ContactManager extends b2ContactListener
  9.     {
  10.         public static const TYPE_ADD:String = "ADD";
  11.         public static const TYPE_PERSIST:String = "PERSIST";
  12.         public static const TYPE_REMOVE:String = "REMOVE";
  13.        
  14.         public var contactAdd:Dictionary = new Dictionary();
  15.         public var contactPersist:Dictionary = new Dictionary();
  16.         public var contactRemove:Dictionary = new Dictionary();
  17.        
  18.         public function ContactManager()
  19.         {
  20.             clear();
  21.         }
  22.        
  23.         override public function Add(point:b2ContactPoint):void
  24.         {
  25.             registerContact(contactAdd, point);
  26.         }
  27.        
  28.         override public function Persist(point:b2ContactPoint):void
  29.         {
  30.             registerContact(contactPersist, point);
  31.         }
  32.        
  33.         override public function Remove(point:b2ContactPoint):void
  34.         {
  35.             registerContact(contactRemove,point);
  36.         }
  37.        
  38.         public function registerContact(dic:Dictionary, point:b2ContactPoint)
  39.         {
  40.             var b1:b2Body = point.shape1.GetBody();
  41.             var b2:b2Body = point.shape2.GetBody();
  42.             if (dic[b1] == null) dic[b1] = new Dictionary();
  43.             if (dic[b2] == null) dic[b2] = new Dictionary();
  44.             if (dic[b1][b2] == null) dic[b1][b2] = [];
  45.             if (dic[b2][b1] == null) dic[b2][b1] = [];
  46.            
  47.             var cp:ContactPoint = new ContactPoint(b1, b2, point.shape1, point.shape2);
  48.             dic[b1][b2].push(cp);
  49.             dic[b2][b1].push(cp);
  50.         }
  51.        
  52.         public function getContacts(type:String, body1:b2Body) :D ictionary
  53.         {
  54.             var dic;
  55.             switch(type)
  56.             {
  57.                 case TYPE_ADD: dic = contactAdd; break;
  58.                 case TYPE_PERSIST: dic = contactPersist; break;
  59.                 case TYPE_REMOVE: dic = contactRemove; break;
  60.             }
  61.             return dic[body1] != null ? dic[body1] : new Dictionary();
  62.         }
  63.        
  64.         public function getContactPoints(type:String, b1:b2Body, b2:b2Body):Array
  65.         {
  66.             var contacts = getContacts(type, b1);
  67.             return contacts[b2] != null ? contacts[b2] : [];
  68.         }
  69.        
  70.         public function clear()
  71.         {
  72.             contactAdd = new Dictionary();
  73.             contactPersist = new Dictionary();
  74.             contactRemove = new Dictionary();
  75.         }
  76.     }
  77. }

You will need to make a custom ContactPoint class. I've only stored shape and body information, but you can store position, etc. - remember to use .Copy() on b2Vec's as to copy the value however.

Actionscript:
  1. package com.touchmypixel.box2D
  2. {
  3.     import Box2D.Collision.Shapes.b2Shape;
  4.     import Box2D.Dynamics.b2Body;
  5.  
  6.     public class ContactPoint
  7.     {
  8.         public var body1:b2Body;
  9.         public var body2:b2Body;
  10.         public var shape1:b2Shape;
  11.         public var shape2:b2Shape;
  12.        
  13.         public function ContactPoint(body1:b2Body, body2:b2Body, shape1:b2Shape, s2:b2Shape)
  14.         {
  15.             this.body1 = body1;
  16.             this.body2 = body2;
  17.             this.shape1 = shape1;
  18.             this.shape2 = shape2;
  19.         }
  20.     }
  21. }

It would be good to put the ContactPoint objects in a pool - to save instantiation.

cheers!
tonypee

One comment

  1. Bruno

    I like the smiley face in in line 52. Obviously having fun at work :)

 

Leave a Reply

Our Friends:

Powered by haXe / poko cms | Copyright 2008-09 TouchMyPixel