Talking about Actionscript 3 and Flash.
One of the features which highly contribute to the success of a physics engine is the collision detection.
NAPE has a robust collision detection, although you won’t find that much information around the web, that’s why this blog is a must read :)
To explain the basics of NAPE collision detection, I stripped the Hundreds game prototype and now I only have one ball running around the stage and bouncing off walls.
I will show you how to detect collision between the ball and the walls.
Look at the result:
Each time the balls bounce off the walls, the stage color changes.
This is the script:
package {
import flash.display.Sprite;
import flash.events.Event;
import nape.geom.Vec2;
import nape.phys.Body;
import nape.phys.BodyList;
import nape.phys.BodyType;
import nape.shape.Polygon;
import nape.shape.Circle;
import nape.space.Space;
import nape.util.ShapeDebug;
import nape.shape.ShapeList;
import nape.callbacks.*;
public class Main extends Sprite {
private var napeWorld:Space=new Space(new Vec2(0,0));
private var debug:ShapeDebug=new ShapeDebug(640,480,0x00ff00);
private var napeDebugSprite:Sprite=new Sprite();
private var circleSpeed:Number=150;
private var interactionListener:InteractionListener;
private var wallCollisionType:CbType=new CbType();
private var ballCollisionType:CbType=new CbType();
private var ball:Body;
public function Main():void {
interactionListener=new InteractionListener(CbEvent.BEGIN,InteractionType.COLLISION,wallCollisionType,ballCollisionType,ballToWall);
napeWorld.listeners.add(interactionListener);
addChild(napeDebugSprite);
napeDebugSprite.addChild(debug.display);
ball=addCircle();
addWall(320,0,640,10);
addWall(320,480,640,10);
addWall(0,240,10,480);
addWall(640,240,10,480);
addEventListener(Event.ENTER_FRAME,update);
}
private function ballToWall(collision:InteractionCallback):void {
graphics.clear();
graphics.beginFill(Math.random()*0xFFFFFF,0.5);
graphics.drawRect(0,0,stage.stageWidth, stage.stageHeight );
graphics.endFill();
}
private function addCircle():Body {
var napeBody:Body=new Body(BodyType.DYNAMIC,new Vec2(Math.round(Math.random()*600+20),Math.round(Math.random()*440+20)));
napeBody.cbTypes.add(ballCollisionType);
var circle:Circle=new Circle(10);
circle.material.elasticity=0.5;
circle.material.density=1;
circle.material.staticFriction=0;
napeBody.shapes.add(circle);
napeBody.space=napeWorld;
napeBody.userData.name="circle";
var randomAngle:Number=Math.random()*2*Math.PI;
napeBody.velocity=new Vec2(circleSpeed*Math.cos(randomAngle),circleSpeed*Math.sin(randomAngle));
return napeBody;
}
private function addWall(pX:Number,pY:Number,w:Number,h:Number):void {
var napeBody:Body=new Body(BodyType.STATIC,new Vec2(pX,pY));
napeBody.cbTypes.add(wallCollisionType);
var polygon:Polygon=new Polygon(Polygon.box(w,h));
polygon.material.elasticity=0.5;
polygon.material.density=1;
polygon.material.staticFriction=0;
napeBody.shapes.add(polygon);
napeBody.space=napeWorld;
}
private function update(e:Event):void {
napeWorld.step(1/30,10,10);
var velocity:Vec2=ball.velocity;
var speed:Number=velocity.length;
var ratio:Number=circleSpeed/speed;
ball.velocity.muleq(ratio);
debug.clear();
debug.draw(napeWorld);
debug.flush();
}
}
}
Let’s comment line by line what’s involved in collision detection:
private var interactionListener:InteractionListener; private var wallCollisionType:CbType=new CbType(); private var ballCollisionType:CbType=new CbType();
Line 20: defining an interaction listener. Since a collision is an interaction, we need to define it at first.
Lines 21-22: these are Callback Types, and I am going to use them in a smart way to detect only some kind of collisions. Think about a Callback Type like a built-in Box2D collision filtering, if you are used to it.
interactionListener=new InteractionListener(CbEvent.BEGIN,InteractionType.COLLISION,wallCollisionType,ballCollisionType,ballToWall); napeWorld.listeners.add(interactionListener);
Line 25: the core of the script: the Interaction Listener. You can handle any type of interaction with it, but since I am looking for collisions, here is the list of arguments:
CbEvent.BEGIN: the event type to listen for, in this example the begin of the event.
InteractionType.COLLISION: the interaction type to listen for, in this example a collision.
wallCollisionType: the OptionType to match first Interactor against, in this case the wall collision type
ballCollisionType: the OptionType to match second Interactor against, in this case the ball collision type
ballToWall: the callback function
Line 26: at this time, the newly created listeners is added to the NAPE world.
Line 44: this is how I add the ball to its Callback Type
Line 58: same thing for the wall.
And that’s it. No need to download any source code, just copy/paste it in the Hundreds game prototype source code.
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.