Skip to content

Instantly share code, notes, and snippets.

@vrobel
Last active December 15, 2015 21:29
Show Gist options
  • Save vrobel/5326294 to your computer and use it in GitHub Desktop.
Save vrobel/5326294 to your computer and use it in GitHub Desktop.
Replicates bug in NAPE when 2 kinematic/static bodies collide with each other and only one begin contact listener is dispatched
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Rectangle;
import nape.util.ShapeDebug;
public class KinematicCollisionDetectionBug extends Sprite
{
public function KinematicCollisionDetectionBug() {
addEventListener( Event.ENTER_FRAME, init );
}
private var game : KinematicCollisionDetectionGame;
private var debug : ShapeDebug;
private function init( e : Event ) : void {
removeEventListener( Event.ENTER_FRAME, init );
stage.frameRate = 60;
var viewport : Rectangle = new Rectangle( 0, 0, stage.stageWidth, stage.stageHeight );
game = new KinematicCollisionDetectionGame( viewport );
debug = new ShapeDebug( viewport.width, viewport.height, 0 );
addChild( debug.display );
addEventListener( Event.ENTER_FRAME, tick );
}
private function tick( e : Event ) : void {
game.step( 1 / stage.frameRate );
debug.clear();
debug.draw( game.getSpace() );
debug.flush();
}
}
}
import flash.geom.Point;
import flash.geom.Rectangle;
import nape.callbacks.CbEvent;
import nape.callbacks.CbType;
import nape.callbacks.InteractionCallback;
import nape.callbacks.InteractionListener;
import nape.callbacks.InteractionType;
import nape.dynamics.InteractionFilter;
import nape.geom.Vec2;
import nape.phys.Body;
import nape.phys.BodyType;
import nape.shape.Circle;
import nape.shape.Polygon;
import nape.shape.Shape;
import nape.space.Space;
class KinematicCollisionDetectionGame
{
private static const BALL_CB : CbType = new CbType();
private static const BULLET_CB : CbType = new CbType();
private static const BALL_FILTER : InteractionFilter = new InteractionFilter( 1, 0, 1, ~1 );
private static const BULLET_FILTER : InteractionFilter = new InteractionFilter( 1, 0, 2, ~2 );
public function KinematicCollisionDetectionGame( gameViewport : Rectangle ) {
viewportCenter = new Point( gameViewport.x + gameViewport.width >> 1, gameViewport.x + gameViewport.height >> 1 );
this.space = new Space();
createContent();
}
private var circle1Movement : MoveCircleAroundBehavior;
private var circle2Movement : MoveCircleAroundBehavior;
private var space : Space;
private var viewportCenter : Point;
public function getSpace() : Space {
return space;
}
public function step( time : Number ) : void {
if ( time > 0 ) {
circle1Movement && circle1Movement.step( time );
circle2Movement && circle2Movement.step( time );
space.step( time );
}
}
private function createContent() : void {
var circle1 : Body = createKinematicBall( 20 );
var circle2 : Body = createKinematicBall( 20 );
if ( circle1 ) circle1Movement = new MoveCircleAroundBehavior( circle1, viewportCenter, 100, Math.PI );
if ( circle2 ) circle2Movement = new MoveCircleAroundBehavior( circle2, viewportCenter, 100, -Math.PI );
createStaticBullet( 80, new Vec2( viewportCenter.x - 100, viewportCenter.y ) );
createBulletListener();
}
private function createBulletListener() : void {
var beginBulletBallListener : InteractionListener = new InteractionListener( CbEvent.BEGIN, InteractionType.ANY, BULLET_CB, BALL_CB, begin_bulletBallHandler );
var endBulletBallListener : InteractionListener = new InteractionListener( CbEvent.END, InteractionType.ANY, BULLET_CB, BALL_CB, end_bulletBallHandler );
if ( beginBulletBallListener ) beginBulletBallListener.space = space;
if ( endBulletBallListener ) endBulletBallListener.space = space;
}
private function begin_bulletBallHandler( cb : InteractionCallback ) : void {
trace( cb.toString() );
}
private function end_bulletBallHandler( cb : InteractionCallback ) : void {
trace( cb.toString() );
}
private function createStaticBullet( size : Number, position : Vec2 = null ) : Body {
var body : Body = new Body( BodyType.STATIC );
body.cbTypes.add( BULLET_CB );
var shape : Shape = new Polygon( Polygon.box( size, size ), null, BULLET_FILTER );
shape.sensorEnabled = true;
body.shapes.add( shape );
position && body.position.set( position );
body.space = space;
return body
}
private function createKinematicBall( radius : Number ) : Body {
var body : Body = new Body( BodyType.KINEMATIC );
body.cbTypes.add( BALL_CB );
var shape : Shape = new Circle( radius, null, null, BALL_FILTER );
shape.sensorEnabled = true;
body.shapes.add( shape );
body.space = space;
return body;
}
}
class MoveCircleAroundBehavior
{
private var body : Body;
private var centerPoint : Point;
private var movementRadius : Number;
private var angularSpeed : Number;
private var currentAngle : Number = 0;
public function MoveCircleAroundBehavior( body : Body, centerPoint : Point, movementRadius : Number, angularSpeed : Number ) {
this.body = body;
this.centerPoint = centerPoint;
this.movementRadius = movementRadius;
this.angularSpeed = angularSpeed;
step( 0 );
}
public function step( t : Number ) : void {
currentAngle += angularSpeed * t;
var currentRelativePosition : Point = Point.polar( movementRadius, currentAngle );
body.position.setxy( currentRelativePosition.x + centerPoint.x, currentRelativePosition.y + centerPoint.y );
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment