Tony Polinelli
Tarwin Stroh-Spijer

contact [at]
touchmypixel.com

6/25 Easey Street
Collingwood, 3066
Vic, Australia

+61 3 8060 5321

Archive for December, 2009

Wednesday, December 23rd, 2009

For the upcomming article that Tarwin wrote for .NET magazine on Caching Animations in Flash here is a quick rundown & downloadable example.

The code is split into two classes:

AnimationCache

This is a very simple singleton class used to cache the rendered frames of any animation (MovieClip) that you want. All you need to do is call .cacheAnimation(identifier)  with the library identifier of your movieClip to store its frames in memory.

Animation

An animation displays the cached frames. You can retrieve instances from the AnimationCache via the getAnimation method. This will save memory, as each instance of the animation (if you have many jellyfish for example) will be referencing the same bitmap data. You can also create a new Animation(identifier), to create and cache a new animation from the library.

The animation class has similar functionality to MovieClip – play(), stop(), gotoAndPlay, etc.

To define the region that is cached (the first frame might be small, while frame 10 might be HUGE for example), you can define a ‘bounds’ clip. This is a child clip on the first frame of the MovieClip to be cached. It can also be used to crop an animation.

There are a few extra little features that we have in there that were used in scarygirl, you can find them out yourself ;P

Note: we have removed the queued caching system that we used in scarygirl, to simplify the code. If you are caching a lot of animations, you will need to look at ways to asyncronously cache frames. hint: think timeouts ;P

DOWNLOAD EXAMPLE HERE

cheers Tony

Monday, December 14th, 2009

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

Our Friends:

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