Toony Flash game prototype

Friday 25 May 2012
I want to show you a tiny cute game which is perfect for writing a tutorial about it, and it would also be interesting to port on a mobile device.
I am talking about Toony by Riccardo Amabili and it deserves some minutes of your time, trying to match falling toonies with the ones in your toolbar.

In this post you will find a fully commented script to create a Toony prototype just using functions bound to event listeners.
There are four events which handle entire game:
MOUSE_DOWN: when the mouse is pressed on a toony, will allow the player to drag it
MOUSE_UP: when the mouse is released, it’s time to stop dragging the toony and check whether there’s a match or not
ENTER_FRAME: the main function, used to update toonies position
TIMER: to be called every two seconds, to generate a new toony
And there’s only a MovieClip called Toony which contains four frames, with a different shape in each frame.
This is the script:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package {
 import flash.display.Sprite;
 import flash.events.MouseEvent;
 import flash.events.Event;
 import flash.utils.Timer;
 import flash.events.TimerEvent;
 public class Main extends Sprite {
  // variable to see which toony I am moving, if any. Starts at null value because
  // I am not moving any toony at the beginning of the game
  private var movingToony:Toony=null;
  // timer to handle new toony creation. A new toony will be created every 2 seconds
  private var theTimer:Timer=new Timer(2000);
  // vector to manage all toonies
  private var toonyVector:Vector.<Toony>=new Vector.<Toony>();
  public function Main() {
   // creation of the four draggable toonies
   for (var i:int=1; i<=4; i++) {
    var toony:Toony=new Toony();
    addChild(toony);
    toony.gotoAndStop(i);
    toony.x=i*100+80;
    toony.y=430;
    toony.buttonMode=true;
    // event to be triggered when the player presses the mouse button over a toony
    toony.addEventListener(MouseEvent.MOUSE_DOWN,toonyClicked);
   }
   // main game loop
   addEventListener(Event.ENTER_FRAME,update);
   // event to be triggered when the player releases the mouse button
   stage.addEventListener(MouseEvent.MOUSE_UP,toonyReleased);
   // event to be triggered avery two seconds, to generate a new toony
   theTimer.addEventListener(TimerEvent.TIMER,newToony);
   // starting the timer
   theTimer.start();
  }
  // what happens when the player presses the mouse on a toony?
  private function toonyClicked(e:MouseEvent):void {
   // if I am not moving any toony...
   if (movingToony==null) {
    // setting the toony I am about to move to the toony I just pressed the mouse on
    movingToony=e.target as Toony;
   }
  }
  // what happens when the player releases the mouse?
  private function toonyReleased(e:MouseEvent):void {
   // if I am moving a toony...
   if (movingToony!=null) {
    // looping through toonies vector
    for (var i:int=toonyVector.length-1; i>=0; i--) {
     // if I am touching a falling toony with the same shape as the toony I am currently moving...
     // (that is: if both toonies are showing the same frame...)
     if (toonyVector[i].hitTestPoint(mouseX,mouseY,true)&&movingToony.currentFrame==toonyVector[i].currentFrame) {
      // the toonies match!! Highlighting the falling toony
      toonyVector[i].alpha=1;
     }
    }
    // putting the moved toony back to its place
    movingToony.y=430;
    movingToony.x=movingToony.currentFrame*100+80;
    // setting the variable which hold the moving toony to null
    // I am not moving any toony now
    movingToony=null;
   }
  }
  // how do I create a new toony?
  private function newToony(e:TimerEvent):void {
   // it's simple: I just create a new Toony instance and place it
   // randomly in the game field with a random frame shown
   var toony:Toony = new Toony();
   addChild(toony);
   toony.x=Math.random()*600+20;
   toony.y=-32;
   toony.gotoAndStop(Math.ceil(Math.random()*4));
   toony.alpha=0.5;
   // pushing the newly created toony into toonies vector
   toonyVector.push(toony);
  }
  // main function
  private function update(e:Event):void {
   // if I am moving a toony...
   if (movingToony!=null) {
    // updating toony position according to mouse position
    movingToony.x=mouseX;
    movingToony.y=mouseY;
   }
   // looping through toonies vector
   for (var i:int=toonyVector.length-1; i>=0; i--) {
    // moving toonies down
    toonyVector[i].y++;
    // removing toonies from the stage if they are too close to the bottom of the stage
    if (toonyVector[i].y>350) {
     removeChild(toonyVector[i]);
     // removing toony item from toonies vector
     toonyVector.splice(i,1);
    }
   }
  }
 }
}
 
 
 Download the source code.

Understanding Box2D kinematic bodies

So you are used to work with Box2D and know everything about body types, such as static bodies and dynamic bodies… why nobody talks about kinematic bodies?
I think kinematic bodies are great to do some tasks, but first let me briefly explain the difference among body types.
A dynamic body is a body which is affected by world forces and react to collisions. And you already met a million of them.
A static body is a body which isn’t affected by world forces it does not react to collisions. It can’t be moved. Fullstop.
A kinematic body is an hybrid body which is not affected by forces and collisions like a static body but can moved with a linear velocity like a dynamic body.
So I made this little, commented script where dynamic spheres fall down at every second in a world full of moving kinematic bodies. The effect is unique and can be used in some games.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package {
 import flash.display.Sprite;
 import flash.events.Event;
 import flash.utils.Timer;
 import flash.events.TimerEvent;
 import Box2D.Dynamics.*;
 import Box2D.Collision.*;
 import Box2D.Collision.Shapes.*;
 import Box2D.Common.Math.*;
 public class Main extends Sprite {
  private var world:b2World=new b2World(new b2Vec2(0,5),true);
  private var worldScale:Number=30;
  private var timer:Timer=new Timer(1000);
  public function Main() {
   debugDraw();
   for (var i:int=0; i<10; i++) {
    // building 10 kinematic spheres
    // five on the left side of the stage moving right
    // five on the right side of the stage moving left
    kinematicSphere(640*(i%2),50+40*i,10,(1-2*(i%2))*(Math.random()*10+5));
   }
   addEventListener(Event.ENTER_FRAME,updateWorld);
   // I will make a dynamic sphere fall from the top of the stage
   // at every second
   timer.start();
   timer.addEventListener(TimerEvent.TIMER,addSphere);
  }
  private function addSphere(e:TimerEvent):void {
   dynamicSphere(320,-10,10);
  }
  private function dynamicSphere(pX:int,pY:int,r:Number):void {
   var bodyDef:b2BodyDef=new b2BodyDef();
   bodyDef.position.Set(pX/worldScale,pY/worldScale);
   bodyDef.type=b2Body.b2_dynamicBody;
   var circleShape:b2CircleShape=new b2CircleShape(r/worldScale);
   var fixtureDef:b2FixtureDef=new b2FixtureDef();
   fixtureDef.shape=circleShape;
   var theDynamic:b2Body=world.CreateBody(bodyDef);
   theDynamic.CreateFixture(fixtureDef);
  }
  private function kinematicSphere(pX:int,pY:int,r:Number,hV):void {
   var bodyDef:b2BodyDef=new b2BodyDef();
   bodyDef.position.Set(pX/worldScale,pY/worldScale);
   // ************************** HERE IS THE MAGIC LINE ************************** \\
   bodyDef.type=b2Body.b2_kinematicBody;
   var circleShape:b2CircleShape=new b2CircleShape(r/worldScale);
   var fixtureDef:b2FixtureDef=new b2FixtureDef();
   fixtureDef.shape=circleShape;
   var theKinematic:b2Body=world.CreateBody(bodyDef);
   theKinematic.CreateFixture(fixtureDef);
   // look, I can set a linear velocity
   theKinematic.SetLinearVelocity(new b2Vec2(hV,0));
  }
  private function debugDraw():void {
   var debugDraw:b2DebugDraw=new b2DebugDraw();
   var debugSprite:Sprite=new Sprite();
   addChild(debugSprite);
   debugDraw.SetSprite(debugSprite);
   debugDraw.SetDrawScale(worldScale);
   debugDraw.SetFlags(b2DebugDraw.e_shapeBit);
   debugDraw.SetFillAlpha(0.5);
   world.SetDebugDraw(debugDraw);
  }
  private function updateWorld(e:Event):void {
   world.Step(1/30,10,10);
   world.ClearForces();
   for (var b:b2Body = world.GetBodyList(); b; b = b.GetNext()) {
    // changing kinematic sphere linear velocity if it touches stage edges
    if (b.GetType()==b2Body.b2_kinematicBody) {
     var xSpeed:Number=b.GetLinearVelocity().x;
     var xPos:Number=b.GetWorldCenter().x*worldScale;
     if ((xPos<10&&xSpeed<0) || (xPos>630&&xSpeed>0)) {
      xSpeed*=-1;
      b.SetLinearVelocity(new b2Vec2(xSpeed,0));
     }
    }
    else {
     if (b.GetWorldCenter().y*worldScale>480) {
      world.DestroyBody(b);
     }
    }
   }
   world.DrawDebugData();
  }
 }
}
 
 
Also look how debug draw shows kinematic bodies.
Download the source code.

Simulating mud/slime with Box2D, bitmaps and filters

This is an attempt to simulate something like mud/slime with Box2D for a game concept I am trying do develop.
I won’t go much in detail with the tutorial because at the moment I am still fine-tuning the effect, but I am showing you a step by step process to achieve a slime-looking effect.
First, let’s create some static objects:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package {
 import flash.display.Sprite;
 import flash.events.Event;
 import Box2D.Dynamics.*;
 import Box2D.Collision.*;
 import Box2D.Collision.Shapes.*;
 import Box2D.Common.Math.*;
 public class Main extends Sprite {
  private var world:b2World=new b2World(new b2Vec2(0,5),true);
  private var worldScale:Number=30;
  public function Main() {
   debugDraw();
   var polygonShape:b2PolygonShape = new b2PolygonShape();
   var fixtureDef:b2FixtureDef = new b2FixtureDef();
   fixtureDef.restitution=0;
   fixtureDef.density=1;
   fixtureDef.friction=0.4;
   var bodyDef:b2BodyDef= new b2BodyDef();
   bodyDef.position.Set(320/worldScale,240/worldScale);
   var container:b2Body;
   container=world.CreateBody(bodyDef);
   polygonShape.SetAsOrientedBox(132/worldScale/2,12/worldScale/2,new b2Vec2(0/worldScale,144/worldScale),0);
   fixtureDef.shape=polygonShape;
   container.CreateFixture(fixtureDef);
   polygonShape.SetAsOrientedBox(12/worldScale/2,200/worldScale/2,new b2Vec2(-60/worldScale,0/worldScale),0);
   fixtureDef.shape=polygonShape;
   container.CreateFixture(fixtureDef);
   polygonShape.SetAsOrientedBox(12/worldScale/2,276/worldScale/2,new b2Vec2(60/worldScale,0/worldScale),0);
   fixtureDef.shape=polygonShape;
   container.CreateFixture(fixtureDef);
   addEventListener(Event.ENTER_FRAME,update);
  }
  private function debugDraw():void {
   var debugDraw:b2DebugDraw = new b2DebugDraw();
   var debugSprite:Sprite = new Sprite();
   addChild(debugSprite);
   debugDraw.SetSprite(debugSprite);
   debugDraw.SetDrawScale(worldScale);
   debugDraw.SetFlags(b2DebugDraw.e_shapeBit|b2DebugDraw.e_jointBit);
   debugDraw.SetFillAlpha(0.5);
   world.SetDebugDraw(debugDraw);
  }
  private function update(e:Event):void {
   world.Step(1/30,6,2);
   world.ClearForces();
   world.DrawDebugData();
  }
 }
}
I am just creating some kind of container with a hole in the bottom.
Then, I skin the container with a transparent image and create one little ball at every frame, someone would call them particle. I remove them when they leave the stage to the bottom, and I don’t place more than 200 balls at the same time, although I was able to place about 300 of them without stressing that much my CPU.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package {
 import flash.display.Sprite;
 import flash.events.Event;
 import Box2D.Dynamics.*;
 import Box2D.Collision.*;
 import Box2D.Collision.Shapes.*;
 import Box2D.Common.Math.*;
 public class Main extends Sprite {
  private var world:b2World=new b2World(new b2Vec2(0,5),true);
  private var worldScale:Number=30;
  public function Main() {
   debugDraw();
   var backgroundImage:BackgroundImage=new BackgroundImage();
   addChild(backgroundImage);
   var polygonShape:b2PolygonShape = new b2PolygonShape();
   var fixtureDef:b2FixtureDef = new b2FixtureDef();
   fixtureDef.restitution=0;
   fixtureDef.density=1;
   fixtureDef.friction=0.4;
   var bodyDef:b2BodyDef= new b2BodyDef();
   bodyDef.position.Set(320/worldScale,240/worldScale);
   var container:b2Body;
   container=world.CreateBody(bodyDef);
   polygonShape.SetAsOrientedBox(132/worldScale/2,12/worldScale/2,new b2Vec2(0/worldScale,144/worldScale),0);
   fixtureDef.shape=polygonShape;
   container.CreateFixture(fixtureDef);
   polygonShape.SetAsOrientedBox(12/worldScale/2,200/worldScale/2,new b2Vec2(-60/worldScale,0/worldScale),0);
   fixtureDef.shape=polygonShape;
   container.CreateFixture(fixtureDef);
   polygonShape.SetAsOrientedBox(12/worldScale/2,276/worldScale/2,new b2Vec2(60/worldScale,0/worldScale),0);
   fixtureDef.shape=polygonShape;
   container.CreateFixture(fixtureDef);
   addEventListener(Event.ENTER_FRAME,update);
  }
  private function addCircle(pX:Number,pY:Number,h:Number):void {
   var circleShape:b2CircleShape = new b2CircleShape(h/worldScale);
   var fixtureDef:b2FixtureDef = new b2FixtureDef();
   fixtureDef.density=3;
   fixtureDef.friction=0.4;
   fixtureDef.restitution=0;
   fixtureDef.shape=circleShape;
   var bodyDef:b2BodyDef = new b2BodyDef();
   bodyDef.type=b2Body.b2_dynamicBody;
   bodyDef.position.Set(pX/worldScale,pY/worldScale);
   bodyDef.userData=new WaterCircle();
   var box:b2Body=world.CreateBody(bodyDef);
   box.CreateFixture(fixtureDef);
  }
  private function debugDraw():void {
   var debugDraw:b2DebugDraw = new b2DebugDraw();
   var debugSprite:Sprite = new Sprite();
   addChild(debugSprite);
   debugDraw.SetSprite(debugSprite);
   debugDraw.SetDrawScale(worldScale);
   debugDraw.SetFlags(b2DebugDraw.e_shapeBit|b2DebugDraw.e_jointBit);
   debugDraw.SetFillAlpha(0.5);
   world.SetDebugDraw(debugDraw);
  }
  private function update(e:Event):void {
   var waterParticles:Number=0;
   world.Step(1/30,6,2);
   world.ClearForces();
   for (var b:b2Body = world.GetBodyList(); b; b = b.GetNext()) {
    if (b.GetUserData()!=null) {
     waterParticles++;
     if (b.GetPosition().y*worldScale>480) {
      world.DestroyBody(b);
     }
    }
   }
   if (waterParticles<300) {
    addCircle(320+1-Math.random()*2,-10,5);
   }
   world.DrawDebugData();
  }
 }
}
At this time I have a continuous flux of balls falling down the container.
Next steps consists in rendering balls on a separate DisplayObject using a Bitmap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package {
 import flash.display.Sprite;
 import flash.events.Event;
 import flash.display.BitmapData;
 import flash.display.Bitmap;
 import flash.geom.Matrix;
 import Box2D.Dynamics.*;
 import Box2D.Collision.*;
 import Box2D.Collision.Shapes.*;
 import Box2D.Common.Math.*;
 public class Main extends Sprite {
  private var world:b2World=new b2World(new b2Vec2(0,5),true);
  private var worldScale:Number=30;
  private var waterBitmapData:BitmapData=new BitmapData(640,480,false,0xFF333333);
  private var waterBitmap:Bitmap=new Bitmap(waterBitmapData);
  private var waterMatrix:Matrix=new Matrix();
  public function Main() {
   addChild(waterBitmap);
   var backgroundImage:BackgroundImage=new BackgroundImage();
   addChild(backgroundImage);
   var polygonShape:b2PolygonShape = new b2PolygonShape();
   var fixtureDef:b2FixtureDef = new b2FixtureDef();
   fixtureDef.restitution=0;
   fixtureDef.density=1;
   fixtureDef.friction=0.4;
   var bodyDef:b2BodyDef= new b2BodyDef();
   bodyDef.position.Set(320/worldScale,240/worldScale);
   var container:b2Body;
   container=world.CreateBody(bodyDef);
   polygonShape.SetAsOrientedBox(132/worldScale/2,12/worldScale/2,new b2Vec2(0/worldScale,144/worldScale),0);
   fixtureDef.shape=polygonShape;
   container.CreateFixture(fixtureDef);
   polygonShape.SetAsOrientedBox(12/worldScale/2,200/worldScale/2,new b2Vec2(-60/worldScale,0/worldScale),0);
   fixtureDef.shape=polygonShape;
   container.CreateFixture(fixtureDef);
   polygonShape.SetAsOrientedBox(12/worldScale/2,276/worldScale/2,new b2Vec2(60/worldScale,0/worldScale),0);
   fixtureDef.shape=polygonShape;
   container.CreateFixture(fixtureDef);
   addEventListener(Event.ENTER_FRAME,update);
  }
  private function addCircle(pX:Number,pY:Number,h:Number):void {
   var circleShape:b2CircleShape = new b2CircleShape(h/worldScale);
   var fixtureDef:b2FixtureDef = new b2FixtureDef();
   fixtureDef.density=3;
   fixtureDef.friction=0.4;
   fixtureDef.restitution=0;
   fixtureDef.shape=circleShape;
   var bodyDef:b2BodyDef = new b2BodyDef();
   bodyDef.type=b2Body.b2_dynamicBody;
   bodyDef.position.Set(pX/worldScale,pY/worldScale);
   bodyDef.userData=new WaterCircle();
   var box:b2Body=world.CreateBody(bodyDef);
   box.CreateFixture(fixtureDef);
  }
  private function debugDraw():void {
   var debugDraw:b2DebugDraw = new b2DebugDraw();
   var debugSprite:Sprite = new Sprite();
   addChild(debugSprite);
   debugDraw.SetSprite(debugSprite);
   debugDraw.SetDrawScale(worldScale);
   debugDraw.SetFlags(b2DebugDraw.e_shapeBit|b2DebugDraw.e_jointBit);
   debugDraw.SetFillAlpha(0.5);
   world.SetDebugDraw(debugDraw);
  }
  private function update(e:Event):void {
   var waterParticles:Number=0;
   waterBitmapData.fillRect(waterBitmapData.rect,0xFF333333);
   world.Step(1/30,6,2);
   world.ClearForces();
   for (var b:b2Body = world.GetBodyList(); b; b = b.GetNext()) {
    if (b.GetUserData()!=null) {
     waterParticles++;
     if (b.GetPosition().y*worldScale>480) {
      world.DestroyBody(b);
     }
     else {
      waterMatrix.tx=b.GetPosition().x*worldScale;
      waterMatrix.ty=b.GetPosition().y*worldScale;
      waterBitmapData.draw(b.GetUserData(),waterMatrix);
     }
    }
   }
   if (waterParticles<300) {
    addCircle(320+1-Math.random()*2,-10,5);
   }
   world.DrawDebugData();
  }
 }
}
Now I can remove the debug draw as all Box2D assets have their own DisplayObject representing them
And now, since I am using a Bitmap, I can add a blur filter to balls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package {
 import flash.display.Sprite;
 import flash.events.Event;
 import flash.display.BitmapData;
 import flash.display.Bitmap;
 import flash.geom.Matrix;
 import flash.filters.BlurFilter;
 import flash.filters.BitmapFilterQuality;
 import flash.geom.Point;
 import Box2D.Dynamics.*;
 import Box2D.Collision.*;
 import Box2D.Collision.Shapes.*;
 import Box2D.Common.Math.*;
 public class Main extends Sprite {
  private var world:b2World=new b2World(new b2Vec2(0,5),true);
  private var worldScale:Number=30;
  private var waterBitmapData:BitmapData=new BitmapData(640,480,false,0xFF333333);
  private var waterBitmap:Bitmap=new Bitmap(waterBitmapData);
  private var waterMatrix:Matrix=new Matrix();
  private var waterBlur:BlurFilter=new BlurFilter(15,15,flash.filters.BitmapFilterQuality.HIGH);
  public function Main() {
   addChild(waterBitmap);
   var backgroundImage:BackgroundImage=new BackgroundImage();
   addChild(backgroundImage);
   var polygonShape:b2PolygonShape = new b2PolygonShape();
   var fixtureDef:b2FixtureDef = new b2FixtureDef();
   fixtureDef.restitution=0;
   fixtureDef.density=1;
   fixtureDef.friction=0.4;
   var bodyDef:b2BodyDef= new b2BodyDef();
   bodyDef.position.Set(320/worldScale,240/worldScale);
   var container:b2Body;
   container=world.CreateBody(bodyDef);
   polygonShape.SetAsOrientedBox(132/worldScale/2,12/worldScale/2,new b2Vec2(0/worldScale,144/worldScale),0);
   fixtureDef.shape=polygonShape;
   container.CreateFixture(fixtureDef);
   polygonShape.SetAsOrientedBox(12/worldScale/2,200/worldScale/2,new b2Vec2(-60/worldScale,0/worldScale),0);
   fixtureDef.shape=polygonShape;
   container.CreateFixture(fixtureDef);
   polygonShape.SetAsOrientedBox(12/worldScale/2,276/worldScale/2,new b2Vec2(60/worldScale,0/worldScale),0);
   fixtureDef.shape=polygonShape;
   container.CreateFixture(fixtureDef);
   addEventListener(Event.ENTER_FRAME,update);
  }
  private function addCircle(pX:Number,pY:Number,h:Number):void {
   var circleShape:b2CircleShape = new b2CircleShape(h/worldScale);
   var fixtureDef:b2FixtureDef = new b2FixtureDef();
   fixtureDef.density=3;
   fixtureDef.friction=0.4;
   fixtureDef.restitution=0;
   fixtureDef.shape=circleShape;
   var bodyDef:b2BodyDef = new b2BodyDef();
   bodyDef.type=b2Body.b2_dynamicBody;
   bodyDef.position.Set(pX/worldScale,pY/worldScale);
   bodyDef.userData=new WaterCircle();
   var box:b2Body=world.CreateBody(bodyDef);
   box.CreateFixture(fixtureDef);
  }
  private function debugDraw():void {
   var debugDraw:b2DebugDraw = new b2DebugDraw();
   var debugSprite:Sprite = new Sprite();
   addChild(debugSprite);
   debugDraw.SetSprite(debugSprite);
   debugDraw.SetDrawScale(worldScale);
   debugDraw.SetFlags(b2DebugDraw.e_shapeBit|b2DebugDraw.e_jointBit);
   debugDraw.SetFillAlpha(0.5);
   world.SetDebugDraw(debugDraw);
  }
  private function update(e:Event):void {
   var waterParticles:Number=0;
   waterBitmapData.fillRect(waterBitmapData.rect,0xFF333333);
   world.Step(1/30,6,2);
   world.ClearForces();
   for (var b:b2Body = world.GetBodyList(); b; b = b.GetNext()) {
    if (b.GetUserData()!=null) {
     waterParticles++;
     if (b.GetPosition().y*worldScale>480) {
      world.DestroyBody(b);
     }
     else {
      waterMatrix.tx=b.GetPosition().x*worldScale;
      waterMatrix.ty=b.GetPosition().y*worldScale;
      waterBitmapData.draw(b.GetUserData(),waterMatrix);
     }
    }
   }
   if (waterParticles<300) {
    addCircle(320+1-Math.random()*2,-10,5);
   }
   waterBitmapData.applyFilter(waterBitmapData,waterBitmapData.rect,new Point(0,0),waterBlur);
  }
 }
}
At this time I’m getting a “smoke” effect, but this is not what I want
So the final step is to add a threshold to change some colors of my bitmap balls/smoke, play a bit with transparency and add a better background
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package {
 import flash.display.Sprite;
 import flash.events.Event;
 import flash.display.BitmapData;
 import flash.display.Bitmap;
 import flash.geom.Matrix;
 import flash.filters.BlurFilter;
 import flash.filters.BitmapFilterQuality;
 import flash.geom.Point;
 import Box2D.Dynamics.*;
 import Box2D.Collision.*;
 import Box2D.Collision.Shapes.*;
 import Box2D.Common.Math.*;
 public class Main extends Sprite {
  private var world:b2World=new b2World(new b2Vec2(0,5),true);
  private var worldScale:Number=30;
  private var waterBitmapData:BitmapData=new BitmapData(640,480,true,0x00000000);
  private var waterBitmap:Bitmap=new Bitmap(waterBitmapData);
  private var waterMatrix:Matrix=new Matrix();
  private var waterBlur:BlurFilter=new BlurFilter(15,15,flash.filters.BitmapFilterQuality.HIGH);
  public function Main() {
   var realBg:RealBg=new RealBg();
   addChild(realBg);
   addChild(waterBitmap);
   var backgroundImage:BackgroundImage=new BackgroundImage();
   addChild(backgroundImage);
   var polygonShape:b2PolygonShape = new b2PolygonShape();
   var fixtureDef:b2FixtureDef = new b2FixtureDef();
   fixtureDef.restitution=0;
   fixtureDef.density=1;
   fixtureDef.friction=0.4;
   var bodyDef:b2BodyDef= new b2BodyDef();
   bodyDef.position.Set(320/worldScale,240/worldScale);
   var container:b2Body;
   container=world.CreateBody(bodyDef);
   polygonShape.SetAsOrientedBox(132/worldScale/2,12/worldScale/2,new b2Vec2(0/worldScale,144/worldScale),0);
   fixtureDef.shape=polygonShape;
   container.CreateFixture(fixtureDef);
   polygonShape.SetAsOrientedBox(12/worldScale/2,200/worldScale/2,new b2Vec2(-60/worldScale,0/worldScale),0);
   fixtureDef.shape=polygonShape;
   container.CreateFixture(fixtureDef);
   polygonShape.SetAsOrientedBox(12/worldScale/2,276/worldScale/2,new b2Vec2(60/worldScale,0/worldScale),0);
   fixtureDef.shape=polygonShape;
   container.CreateFixture(fixtureDef);
   addEventListener(Event.ENTER_FRAME,update);
  }
  private function addCircle(pX:Number,pY:Number,h:Number):void {
   var circleShape:b2CircleShape = new b2CircleShape(h/worldScale);
   var fixtureDef:b2FixtureDef = new b2FixtureDef();
   fixtureDef.density=3;
   fixtureDef.friction=0.4;
   fixtureDef.restitution=0;
   fixtureDef.shape=circleShape;
   var bodyDef:b2BodyDef = new b2BodyDef();
   bodyDef.type=b2Body.b2_dynamicBody;
   bodyDef.position.Set(pX/worldScale,pY/worldScale);
   bodyDef.userData=new WaterCircle();
   var box:b2Body=world.CreateBody(bodyDef);
   box.CreateFixture(fixtureDef);
  }
  private function debugDraw():void {
   var debugDraw:b2DebugDraw = new b2DebugDraw();
   var debugSprite:Sprite = new Sprite();
   addChild(debugSprite);
   debugDraw.SetSprite(debugSprite);
   debugDraw.SetDrawScale(worldScale);
   debugDraw.SetFlags(b2DebugDraw.e_shapeBit|b2DebugDraw.e_jointBit);
   debugDraw.SetFillAlpha(0.5);
   world.SetDebugDraw(debugDraw);
  }
  private function update(e:Event):void {
   var waterParticles:Number=0;
   waterBitmapData.fillRect(waterBitmapData.rect,0x00000000);
   world.Step(1/30,6,2);
   world.ClearForces();
   for (var b:b2Body = world.GetBodyList(); b; b = b.GetNext()) {
    if (b.GetUserData()!=null) {
     waterParticles++;
     if (b.GetPosition().y*worldScale>480) {
      world.DestroyBody(b);
     }
     else {
      waterMatrix.tx=b.GetPosition().x*worldScale;
      waterMatrix.ty=b.GetPosition().y*worldScale;
      waterBitmapData.draw(b.GetUserData(),waterMatrix);
     }
    }
   }
   if (waterParticles<300) {
    addCircle(320+1-Math.random()*2,-10,5);
   }
   waterBitmapData.applyFilter(waterBitmapData,waterBitmapData.rect,new Point(0,0),waterBlur);
   waterBitmapData.threshold(waterBitmapData,waterBitmapData.rect,new Point(0,0),">",0X11444444,0x88FF00FF,0xFFFFFFFF, true);
  }
 }
}
And that’s it! Not the best slime ever seen, but it’s dynamically generated by Box2D, this means it has a real mass, which is quite awesome.
How would you improve it?
Download the source code of the last example.
 

ACTION SCRIPT 3.0 Copyright © 2011-2012 | Powered by Blogger