AS3中的碰撞检测和剪切问题

时间:2012-10-17 17:14:07

标签: actionscript-3 collision-detection game-physics

我最近开始从头开始组装一个小物理模拟,这是我以前从未尝试过的,我遇到了关于我在舞台上的物体碰撞与我之间的相互作用的问题认为是我不断的引力。我不确定200行代码是否太大了,但这就是我所拥有的。

package  {

    import flash.events.*;
    import flash.display.*;
    import flash.geom.Rectangle;


    [SWF (width="1500", height="1000", frameRate="24")]
    public class ElasticityV2 extends MovieClip{
        /* Gravity is 9.8 m/s2, which for flash, since it's being applied every frame, needs to be 
        divided out by the frame rate as to not have super fast acceleration. GravMulti is to balance
        out gravity's speed, as it seemed a little slow after the framerate division. Resistance is acting
        like friction for now, and slows down the objects in the air and on the ground at the same rate.
        Elasticity is how bouncy each object is and how the force it recieves is applied*/
        public var gravMulti:Number = 5;
        public var gravity:Number = gravMulti *(9.8/stage.frameRate);
        public var resistance:Number = 0.98;
        public var elasticity:Number = 0.8;
        public var floor:Number = stage.stageHeight - 100;

        public var objectList:Array = new Array();
        public var shadowList:Array = new Array();
        public var yVelocityList:Array = new Array();
        public var xVelocityList:Array = new Array();
        public var massList:Array = new Array();
        public var frictionList:Array = new Array();
        public var lastXList:Array = new Array();
        public var lastYList:Array = new Array();
        public var elasticityList:Array = new Array();
        public var dragList:Array = new Array();

        public var spawnNum:int = 20;

        public var bounding:Rectangle = new Rectangle(0,0,stage.stageWidth - 100,stage.stageHeight);

        public var distantBackground:Background = new Background();
        public var starLight:Light = new Light();


        public function ElasticityV2() {

            addChild(starLight);
            starLight.x = stage.stageWidth/2;
            starLight.y = -400;
            starLight.addEventListener(MouseEvent.MOUSE_DOWN, onLightDrag);
            starLight.addEventListener(MouseEvent.MOUSE_UP, onLightDrag);
            starLight.addEventListener(MouseEvent.MOUSE_OUT, onLightDrag);

            for(var s:int=0;s<spawnNum;s++){
                var ballShadow:Shadow = new Shadow();
                addChild(ballShadow);
                setChildIndex(ballShadow,0);
                ballShadow.y = floor - (ballShadow.height/2);
                ballShadow.x = 100;
                shadowList.push(ballShadow);

                var ball:ElasticBall = new ElasticBall();
                var dragging:Boolean = false;
                addChild(ball);
                ball.y = 100;
                ball.x = s * 200;
                objectList.push(ball);
                yVelocityList.push(randomMe(20,-20));
                xVelocityList.push(randomMe(40,-40));
                massList.push(randomMe(20,5));
                frictionList.push(randomMe(0.6,0.01));
                objectList[s].width = objectList[s].height = massList[s] * 10;
                elasticityList.push(elasticity);
                dragList.push(dragging);
                ball.addEventListener(MouseEvent.MOUSE_DOWN, onDrag);
                ball.addEventListener(MouseEvent.MOUSE_UP, onDrag);
                ball.addEventListener(MouseEvent.MOUSE_OUT, onDrag);
            }

            addChild(distantBackground);
            distantBackground.y = stage.stageHeight - distantBackground.height;
            distantBackground.width = stage.stageWidth;
            setChildIndex(distantBackground,0);

            addEventListener(Event.ENTER_FRAME, onGameLoop);

        }

        public function onGameLoop(e:Event):void{
            //checkCollision();
            for(var i:int=0;i<objectList.length;i++){
                updatePhysics(i);
                updateShadows(i,starLight);
            }
        }

        public function updatePhysics(objRef:int):void{
            if(lastXList[objRef] != undefined){
                if(lastXList[objRef] != objectList[objRef].x){
                    xVelocityList[objRef] = objectList[objRef].x - lastXList[objRef];
                }
            }

            if(lastYList[objRef]!= undefined){
                if(lastYList[objRef] != objectList[objRef].y){
                    yVelocityList[objRef] = 4*(objectList[objRef].y - lastYList[objRef])/stage.frameRate;
                }
            }

            if(objectList[objRef].y>= floor - objectList[objRef].height){
                yVelocityList[objRef] = -(yVelocityList[objRef] * elasticityList[objRef]);  
                objectList[objRef].y = floor - objectList[objRef].height;
            }
            if(objectList[objRef].y<= 0){
                yVelocityList[objRef] = -(yVelocityList[objRef] * elasticityList[objRef]);  
                objectList[objRef].y = 0;
            }
            if(objectList[objRef].x > (stage.stageWidth - objectList[objRef].width)){
                xVelocityList[objRef]=-xVelocityList[objRef];
                objectList[objRef].x = stage.stageWidth - objectList[objRef].width;
            }
            if (objectList[objRef].x <0){
                xVelocityList[objRef]=-xVelocityList[objRef];
                objectList[objRef].x = 0;
            }



            if(!dragList[objRef]){
                yVelocityList[objRef]+=gravity;
                objectList[objRef].y += yVelocityList[objRef];
                xVelocityList[objRef]= (xVelocityList[objRef] * resistance);
                if(-0.5<xVelocityList[objRef] && xVelocityList[objRef]<0.5){
                    xVelocityList[objRef] = 0;
                }
                objectList[objRef].x += xVelocityList[objRef];
            }
            lastXList[objRef] = objectList[objRef].x;
            lastYList[objRef] = objectList[objRef].y;

            if(xVelocityList[objRef] == 0){
                xVelocityList[objRef]=randomMe(90,-90);
                yVelocityList[objRef]=randomMe(90,-90); 
            }
        }

        public function onDrag(e:Event):void{
            if(e.type == "mouseDown"){
                setChildIndex(DisplayObjectContainer(e.target),numChildren - 1)
                e.target.startDrag(false,bounding);
                //xVelocityList[objRef] = yVelocityList[objRef] = 0;
                //dragging = true;
            }else{
                e.target.stopDrag();
                //dragging = false;
            }


        }

        public function onLightDrag(e:Event):void{
            if(e.type == "mouseDown"){
                e.target.startDrag(false,bounding);
            }else{
                e.target.stopDrag();
            }
        }

        public function updateShadows(objRef:int, lightSource:MovieClip):void{

            //-----Cut for convenience------
        }

        public function checkCollision():void{
            for(var v:int=0;v<objectList.length;v++){
                var ball1 = objectList[v];
                for(var w:int=v+1;w<objectList.length;w++){
                    var ball2 = objectList[w];
                    if((ball1.x + getRadius(ball1) + getRadius(ball2) > ball2.x) && (ball1.x < ball2.x + getRadius(ball1) + getRadius(ball2)) && (ball1.y + getRadius(ball1) + getRadius(ball2) > ball2.y) && (ball1.y < ball2.y + getRadius(ball1) + getRadius(ball2))){

                        var dx:Number = ball2.x - ball1.x;
                        var dy:Number = ball2.y - ball1.y;

                        var dist:Number = Math.sqrt((dx * dx) + (dy * dy));

                        if(dist < getRadius(ball1)+getRadius(ball2)){



                            var newX1:Number;
                            var newY1:Number;
                            var newX2:Number;
                            var newY2:Number;

                            trace("Magnitude 1 is : " + (Math.sqrt((xVelocityList[v] * xVelocityList[v]) + (yVelocityList[v] * yVelocityList[v]))));
                            trace("Magnitude 2 is : " + (Math.sqrt((xVelocityList[w] * xVelocityList[w]) + (yVelocityList[w] * yVelocityList[w]))));

                            newX1 = ((massList[v] * xVelocityList[v])+(massList[w] * xVelocityList[w]))/(massList[v] + massList[w]) * 2 - xVelocityList[v];
                            newY1 = ((massList[v] * yVelocityList[v])+(massList[w] * yVelocityList[w]))/(massList[v] + massList[w]) * 2 - yVelocityList[v];
                            newX2 = ((massList[v] * xVelocityList[v])+(massList[w] * xVelocityList[w]))/(massList[v] + massList[w]) * 2 - xVelocityList[w];
                            newY2 = ((massList[v] * yVelocityList[v])+(massList[w] * yVelocityList[w]))/(massList[v] + massList[w]) * 2 - yVelocityList[w];

                            xVelocityList[v] = newX1;
                            yVelocityList[v] = newY1;
                            xVelocityList[w] = newX2;
                            yVelocityList[w] = newY2;

                            ball1.x += newX1;
                            ball1.y += newY1;
                            ball2.x += newX2;
                            ball2.y += newY2;

                        }

                    }
                }
            }
        }

        public function randomMe(high:Number, low:Number = 0):Number{
            return Math.random() * (high - low) + low;
        }

        public function getRadius(obj:MovieClip):Number{
            return obj.width/2;
        }

        public function centerX(obj:MovieClip):Number{
            return obj.x + getRadius(obj);
        }

        public function centerY(obj:MovieClip):Number{
            return obj.y + getRadius(obj);
        }

    }

}

这是一个非常简单的系统来检查碰撞,只是比较物体的半径,并且空中碰撞似乎很好,但是如果一个球落在另一个没有x或y速度的顶部,它就会沉入其中。关于为什么的任何想法?

1 个答案:

答案 0 :(得分:0)

我希望你的球表现得像这样:当一个球落在另一个球的顶部时,它实际上躺在地上,另一个球被推到地上,然后你在updatePhysics()中通过放置它做出反应因此,这些球变成了另一个球。其中一个可以解决这个问题的建议是在一个物理循环中为每个球保持最后一个碰撞对象,如下所示:

if(dist < getRadius(ball1)+getRadius(ball2)){
    // process collision
    ball1.lastCollided=ball2;
    ball2.lastCollided=ball1;
}

然后,当您更新updatePhysics()中的坐标时,检查lastCollided是否为null,如果不是,则更新该球的坐标并以相同的方式加速,基本上模拟另一次碰撞。检查更新物理周期内的所有事件后,将null指定给所有球的lastCollided。