2

我最近开始从头开始组装一个小物理模拟,这是我以前从未尝试过的,我遇到了一个关于我在舞台上的物体碰撞之间的相互作用的问题,我认为是我的恒重力。我不确定 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 速度的球上,它就会沉入其中。关于为什么的任何想法?

4

1 回答 1

0

我希望你的球的行为是这样的:当一个球落在另一个球上时,实际上是在地上,另一个球被推到地上,然后你在 updatePhysics() 中通过将它放置到位置来对其做出反应因此,在它起源的地方,这些球变成了另一个球。可以解决此问题的建议之一是将每个球的最后一个碰撞对象保持一个物理周期,如下所示:

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

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

于 2012-10-19T18:43:04.673 回答