2 Stimmen

Kollisionserkennung und Clipping-Probleme in AS3

Ich habe vor kurzem begonnen, zusammen eine kleine Physik-Simulation von Grund auf, etwas, das ich noch nie versucht, und ich habe in ein Problem in Bezug auf die Interaktion zwischen der Kollision der Objekte, die ich auf der Bühne haben, und was ich denke, ist meine konstante Schwerkraft laufen. Ich bin nicht sicher, ob 200 Zeilen Code ist zu groß für hier, aber das ist, was ich habe.

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);
        }

    }

}

Es ist ein sehr einfaches System für die Kollision zu überprüfen, nur den Radius der Objekte zu vergleichen, und Midair Kollisionen scheinen in Ordnung, aber wenn ein Ball landet auf einem anderen, die keine x oder y Geschwindigkeit hat, es sinkt einfach in sie. Hat jemand eine Idee, warum das so ist?

0voto

Vesper Punkte 18347

Ich erwarte, dass sich deine Eier so verhalten: Wenn eine Kugel auf der anderen landet, die eigentlich auf dem Boden liegt, wird die andere Kugel in den Boden gedrückt, dann reagiert man in updatePhysics() darauf, indem man sie in die Position bringt, aus der sie stammt, also werden diese Kugeln ineinander verschoben. Einer der Vorschläge, der dies beheben könnte, wäre, das letzte kollidierte Objekt für jeden der Bälle für einen Zyklus der Physik zu halten, etwa so:

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

Wenn du dann deine Koordinaten in updatePhysics() aktualisierst, überprüfe, ob lastCollided null ist, und wenn nicht, aktualisiere die Koordinaten und die Geschwindigkeit des Balls auf die gleiche Weise, was im Wesentlichen eine weitere Kollision simuliert. Nach der Überprüfung für alle Ereignisse innerhalb der Update-Physik-Zyklus, zuweisen null zu lastCollided aller Bälle.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X