deltaluca/nape

Changing Shapes of Body results in Tunneling

IAmJulianAcosta opened this issue · 1 comments

Hi, I'm using nape width AIRKinect (http://www.as3nui.com/air-kinect/), and I'm trying to generate a Body from the image generated from kinect (which I've done succesfully).

I'm trying to make a game when people have to collect items over their arms, but I'm having tunneling problems, when the person raises an arm very fast, some of the objects fall.

I tried the following:

  • Clearing the shapes of the object and adding new ones
  • Replacing the body with a new (generated) one.

I used this example: BodyFromGraphic

Here is a sample code (without using kinect, just using a generated shape to illustrate the problem):

package {
    //////////////FLASH.DISPLAY/////////////
    import flash.display.DisplayObject;
    import flash.display.Sprite;
    import flash.display.StageQuality;
    import flash.display.MovieClip;
    import flash.display.Bitmap;
    import flash.display.Stage;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.display.Shape;
    import flash.display.Graphics;
    import flash.display.IGraphicsData;
    import flash.display.GraphicsPath;
    import flash.display.GraphicsStroke;
    import flash.display.CapsStyle;
    //////////////TEXTO EN PANTALLA/////////////
    import flash.text.TextField;
    import flash.system.System;
    import flash.utils.getTimer;
    //////////////FLASH.EVENTS/////////////
    import flash.events.MouseEvent;
    import flash.events.Event;
    import flash.events.TimerEvent;
    //////////////UTILS/////////////
    import flash.utils.Timer;
    //////////////NAPE/////////////
    import nape.geom.Vec2;
    import nape.phys.Body;
    import nape.phys.BodyType;
    import nape.geom.AABB;
    import nape.geom.GeomPoly;
    import nape.geom.GeomPolyList;
    import nape.geom.IsoFunction;
    import nape.geom.MarchingSquares;
    import nape.phys.Body;
    import nape.shape.Circle;
    import nape.shape.Polygon;
    import Template;
    import IsoBody;
    import DisplayObjectIso;
    import nape.shape.Shape;

    public class NapeReplaceShapes extends Template {
        private var bmp:Bitmap;
        private var skeletonContainer:Sprite;
        private var bones:Shape;
        private var boneSet:Boolean;
        private var bonesIso:DisplayObjectIso;
        private var bonesBody:Body;
        private var timer:Timer;
        public var frameRate:TextField;
        public var memory:TextField;
        private var frames = 0;
        public var curTimer:Number;
        public var prevTimer:Number;
        var xx:Number = 0;
        var yy: Number = 350;
        var xxx:Number = 600;
        var yyy:Number = 350;
        var frameNumber:int = 0;

        public function NapeReplaceShapes () {
            super ({
               gravity : Vec2.get(0, 500),
            noReset : true,
            shapeDebug : false
            });
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            bones = new Shape();

            addChild (bones);

            timer = new Timer(30,0);
            timer.addEventListener (TimerEvent.TIMER, crearObjetoConTiempo);
            timer.start ();

            addEventListener (Event.ENTER_FRAME, update);
        }

        protected function update (e:Event):void {
            if (contains(bones)) {
                removeChild (bones);
            }
            bones = new Shape ();
            bones.x = 0;
            bones.y = 0;
            frameNumber++;
            trace (frameNumber);
            if (yy > 000 && frameNumber > 10) {
                yy-=20;
                yyy-=20;
            }

            /////////////////////////TEST///////////////////////////
            bones.graphics.lineStyle (10, 0x00CCFF, 1, true, "normal", "ROUND");
            bones.graphics.moveTo (0, 0);
            bones.graphics.lineTo (xx, yy);
            bones.graphics.moveTo (xx, yy);
            bones.graphics.lineTo (xxx, yyy);

            bonesIso = new DisplayObjectIso(bones);
            addChild (bonesIso.displayObject);
            if (bonesBody == null) {
                bonesBody = IsoBody.run(bonesIso,bonesIso.bounds);
                bonesBody.type = BodyType.KINEMATIC;
                space.bodies.add (bonesBody);
            }
            else {
                bonesBody.shapes.clear();
                var calculationBody:Body = IsoBody.run(bonesIso,bonesIso.bounds);
                for (var i:int = 0; i < calculationBody.shapes.length; i++) {
                    bonesBody.shapes.add (calculationBody.shapes.at(i).copy());
                }
                calculationBody = null;
            }
            removeChild (bonesIso.displayObject);
            bonesIso = null;
            var x1:int = bones.getBounds(bones).x;
            var w:int = bones.getBounds(bones).width;
            var x2:int = x1 + w;
            var px = (x1 + x2) / 2;
            var y1:int = bones.getBounds(bones).y;
            var h:int = bones.getBounds(bones).height;
            var y2:int = y1 + h;
            var py = (y1 + y2) / 2;
            bonesBody.position.setxy (px, py);
            var deltaX:Number = bonesBody.bounds.x - x1;
            var deltaY:Number = bonesBody.bounds.y - y1;

            bonesBody.position.setxy (px-deltaX, py-deltaY);

            //addChild (bones);

        }

        private function crearObjetoConTiempo (evento:TimerEvent):void {
            generateObject (new Vec2 (Math.random () * width,0));

        }

        private function generateObject (pos:Vec2):void {
            var body:Body = new Body(BodyType.DYNAMIC);
            body.position = pos;

            // Add random one of either a Circle, Box or Pentagon.
            if (Math.random() < 0.33) {
                body.shapes.add (new Circle(10));
            }
            else if (Math.random() < 0.66) {
                body.shapes.add (new Polygon(Polygon.box(10, 10)));
            }
            else {
                body.shapes.add (new Polygon(Polygon.regular(10, 10, 5)));
            }
            space.bodies.add (body);
        }

        override protected function init ():void {
            var w:uint = stage.stageWidth / 2;
            var h:uint = stage.stageHeight / 2;
            createBorder ();
        }

        override protected function postUpdate (deltaTime:Number):void {
            for (var i:int = 0; i < space.liveBodies.length; i++) {
                var body:Body = space.liveBodies.at(i);
                var graphic:DisplayObject = body.userData.graphic;
                if (graphic == null) {
                    continue;
                }

                var graphicOffset:Vec2 = body.userData.graphicOffset;
                var position:Vec2 = body.localPointToWorld(graphicOffset);
                graphic.x = position.x;
                graphic.y = position.y;
                graphic.rotation = (body.rotation * 180/Math.PI) % 360;
                position.dispose ();
            }
        }
    }
}

Am I doing anything wrong?
Thanks.

Realise this is a very old issue, lost to depths of github notification hell.

For reference for anyone that might read this, the issue is that 'changing' shapes at runtime will very likely lead to breaking the behaviour of the physics since the new shapes, whenever they occupy a superset of space then their predecessor (they get bigger, or move such that the new shape is not completely inside the old shape) ultimately leads to the objects that were colliding with the old shape now being penetrated inside of the new shape which could cause the object to then be resolved badly by being pushed out in the 'wrong' direction. If in this kinect example if you were moving your arm very fast with thin sections since you're removing shapes and adding new ones instead of having shapes 'moving' then you completely negate any continuous collision detection since the 'arm' is not really moving at all, it's just teleporting from one place to another (ignoring that it's also changing it's shape) which can certainly lead to objects completely 'falling through' the arm.