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()内でその位置に配置することで反応しますしたがって、それが発生した場所では、それらのボールは互いに1つになります。これを改善できる提案の1つは、物理学の1サイクルの間、各ボールの最後に衝突したオブジェクトを保持することです。たとえば、次のようになります。

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

次に、updatePhysics()で座標を更新するときに、lastCollidedがnullであるかどうかを確認します。そうでない場合は、そのボールの座標と速度を同じ方法で更新し、基本的に別の衝突をシミュレートします。更新物理サイクル内のすべてのイベントをチェックした後、すべてのボールのlastCollidedにnullを割り当てます。

于 2012-10-19T18:43:04.673 に答える