2 Stimmen

Optimierung von Übergängen/Bewegungsabläufen für ein 2D-Flash-Spiel

Aktualisierung 6 :

Fenomenas schlug mir vor, alles so einfach wie möglich neu zu gestalten. Ich hatte meine Zweifel, dass dies einen Unterschied machen würde, da der Algorithmus derselbe bleibt und die Leistung nicht das Problem zu sein schien. Wie auch immer, es war der einzige Vorschlag, den ich bekam, also hier ist er:

  1. 30 FPS: http://www.feedpostal.com/test/simple/30/SimpleMovement.html
  2. 40 FPS: http://www.feedpostal.com/test/simple/40/SimpleMovement.html
  3. 60 FPS: http://www.feedpostal.com/test/simple/60/SimpleMovement.html
  4. 100 FPS: http://www.feedpostal.com/test/simple/100/SimpleMovement.html

Der Code:

package {
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.utils.getTimer;

    [SWF(width="800", height="600", frameRate="40", backgroundColor="#000000")]

    public class SimpleMovement extends Sprite
    {
        private static const TURNING_SPEED:uint = 180;
        private static const MOVEMENT_SPEED:uint = 400;
        private static const RADIAN_DIVIDE:Number = Math.PI/180;
        private var playerObject:Sprite;
        private var shipContainer:Sprite;
        private var moving:Boolean = false;
        private var turningMode:uint = 0;
        private var movementTimestamp:Number = getTimer();
        private var turningTimestamp:Number = movementTimestamp;

        public function SimpleMovement()
        {
            //step 1: create player object
            playerObject = new Sprite();
            playerObject.graphics.lineStyle(1, 0x000000);
            playerObject.graphics.beginFill(0x6D7B8D);
            playerObject.graphics.drawRect(0, 0, 25, 50);
            //make it rotate around the center
            playerObject.x = 0 - playerObject.width / 2;
            playerObject.y = 0 - playerObject.height / 2;
            shipContainer = new Sprite();
            shipContainer.addChild(playerObject);
            shipContainer.x = 100;
            shipContainer.y = 100;
            shipContainer.rotation = 180;
            addChild(shipContainer);

            //step 2: install keyboard hook when stage is ready
            addEventListener(Event.ADDED_TO_STAGE, stageReady, false, 0, true);

            //step 3: install rendering update poll
            addEventListener(Event.ENTER_FRAME, updatePoller, false, 0, true);
        }

        private function updatePoller(event:Event):void
        {
            var newTime:Number = getTimer();

            //turning
            if (turningMode != 0)
            {

                var turningDeltaTime:Number = newTime - turningTimestamp;
                turningTimestamp = newTime;
                var rotation:Number = TURNING_SPEED * turningDeltaTime / 1000;
                if (turningMode == 1) shipContainer.rotation -= rotation;
                else shipContainer.rotation += rotation;
            }

            //movement
            if (moving)
            {
                var movementDeltaTime:Number = newTime - movementTimestamp;
                movementTimestamp = newTime;
                var distance:Number = MOVEMENT_SPEED * movementDeltaTime / 1000;
                var rAngle:Number = shipContainer.rotation * RADIAN_DIVIDE; //convert degrees to radian
                shipContainer.x += distance * Math.sin(rAngle);
                shipContainer.y -= distance * Math.cos(rAngle);
            }
        }

        private function stageReady(event:Event):void
        {
            //install keyboard hook
            stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown, false, 0, true);
            stage.addEventListener(KeyboardEvent.KEY_UP, keyUp, false, 0, true);
        }

        private final function keyDown(event:KeyboardEvent):void
        {
            if ((event.keyCode == 87) && (!moving))  //87 = W
            {
                movementTimestamp = getTimer();
                moving = true;
            }
            if ((event.keyCode == 65) && (turningMode != 1)) //65 = A
            {
                turningTimestamp = getTimer();
                turningMode = 1;
            }
            else if ((event.keyCode == 68) && (turningMode != 2)) //68 = D
            {
                turningTimestamp = getTimer();
                turningMode = 2;
            }
        }

        private final function keyUp(event:KeyboardEvent):void
        {
            if ((event.keyCode == 87) && (moving)) moving = false; //87 = W
            if (((event.keyCode == 65) || (event.keyCode == 68)) && (turningMode != 0)) turningMode = 0; //65 = A, 68 = D
        }
    }
}

Die Ergebnisse waren so, wie ich es erwartet hatte. Absolut keine Verbesserung. Ich hoffe wirklich, dass jemand einen anderen Vorschlag hat, da diese Sache behoben werden muss. Außerdem bezweifle ich, dass es an meinem System liegt, da ich ein ziemlich gutes habe (8GB RAM, Q9550 QuadCore intel, ATI Radeon 4870 512MB). Außerdem hatte jeder andere, den ich bisher gefragt habe, das gleiche Problem mit meinem Client.

Update 5: ein weiteres Beispiel für ein flüssiges Flash-Spiel, nur um zu zeigen, dass meine Bewegungen definitiv anders sind! Siehe http://www.spel.nl/game/bumpercraft.html

Aktualisierung 4 : Ich habe die Zeit vor dem Rendering (EVENT.RENDER) und direkt nach dem Rendering (EVENT.ENTER_FRAME) verfolgt, die Ergebnisse:

rendering took: 14 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 14 ms
rendering took: 14 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 24 ms
rendering took: 18 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 232 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms

Der Bereich liegt bei 12-16 ms. Während dieser Unterschiede war die schockierende/verzerrender/flimmernde Bewegung bereits im Gange. Es gibt auch eine Spitze von 232 ms, zu dieser Zeit gab es eine relativ große Verwerfung. Das ist aber nicht das größte Problem, das größte Problem sind die ständigen kleinen Verwerfungen bei normalen Bewegungen. Gibt dies irgendjemandem einen Anhaltspunkt?

Update 3: Nach Tests weiß ich, dass die folgenden Faktoren no mein Problem verursacht:

  • Bitmap-Qualität -> mit Photoshop in eine hässliche 8-Farben-optimierte Grafik geändert, keine Verbesserung.
  • Ständige Drehung des Bildes beim Drehen -> deaktiviert, keine Verbesserung
  • Browser-Rendering -> versucht, den Flash-Player allein zu verwenden, keine Verbesserung

Ich bin zu 100 % überzeugt, dass das Problem entweder in meinem Code oder in meinem Algorithmus liegt. Bitte, helfen Sie mir weiter. Es ist jetzt fast zwei Wochen her (1 Woche, in der ich diese Frage auf SO gestellt habe) und ich habe immer noch keine Antwort auf meine Frage bekommen.

Aktualisierung 1: siehe unten für vollständige Flex-Projekt-Quelle und eine Live-Demo demonstriert mein Problem.

Ich arbeite an einem 2d-Flash-Spiel. Spielerschiffe werden als Objekt erstellt:

ships[id] = new GameShip();

Wenn Bewegungs- und Rotationsinformationen verfügbar sind, werden diese an das entsprechende Schiff weitergeleitet:

ships[id].setMovementMode(1); //move forward

Innerhalb dieses GameShip-Objekts funktioniert die Bewegung nun über das Ereignis "Event.ENTER_FRAME":

addEventListener(Event.ENTER_FRAME, movementHandler);

Die folgende Funktion wird dann ausgeführt:

private final function movementHandler(event:Event):void
        {
            var newTimeStamp:uint = UtilLib.getTimeStamp(); //set current timeStamp
            var distance:Number = (newTimeStamp - movementTimeStamp) / 1000 * movementSpeed; //speed = x pixels forward every 1 second
            movementTimeStamp = newTimeStamp; //update old timeStamp
            var diagonalChange:Array = getDiagonalChange(movementAngle, distance); //the diagonal position update based on angle and distance
            charX += diagonalChange[0];
            charY += diagonalChange[1];
            if (shipContainer)
            { //when the container is ready to be worked with
                shipContainer.x = charX;
                shipContainer.y = charY;
            }
        }

private final function getDiagonalChange(angle:Number, distance:Number):Array
        {
            var rAngle:Number = angle * Math.PI/180; //convert degrees to radian
            return [Math.sin(rAngle) * distance, (Math.cos(rAngle) * distance) * -1];
        }

Wenn das Objekt nicht mehr in Bewegung ist, wird der Ereignis-Listener entfernt. Die gleiche Methode wird für die Rotation verwendet. Alles funktioniert nahezu perfekt.

Ich habe die Ziel-FPS des Projekts auf 100 gesetzt und einen FPS-Zähler erstellt. Laut dem FPS-Zähler liegt die durchschnittliche FPS in Firefox bei 100, während die obere Grenze bei 1000 und die untere bei 22 liegt. Ich denke, dass die unteren und oberen FPS nur während der Initialisierung des Clients (Startup) auftreten.

Das Problem ist, dass das Schiff fast perfekt glatt zu sein scheint, während es genau das sein sollte, ohne den "fast" Teil. Es ist fast so, als ob das Schiff sehr schnell "flackert", man kann es nicht wirklich sehen, aber es ist schwer, sich auf das Objekt zu konzentrieren, während es sich mit den Augen bewegt. Außerdem scheint es hin und wieder einen kleinen Framerate-Spike zu geben, so als ob der Client ein paar Frames überspringt und man dann sieht, wie er sich schnell verzieht.

Es ist sehr schwierig zu erklären, was das eigentliche Problem ist, aber im Allgemeinen liegt es daran, dass die Bewegung nicht vollkommen glatt ist. Haben Sie irgendwelche Vorschläge, wie man die Bewegung oder den Übergang von Objekten perfekt glatt machen kann?

Aktualisierung 1:

Ich habe den Client neu erstellt, um mein Problem zu demonstrieren. Bitte sehen Sie es sich an.

Der Kunde: http://feedpostal.com/test/MovementTest.html

Das Actionscript-Projekt (vollständiger Quelltext): http://feedpostal.com/test/MovementTest.rar

Ein Beispiel für ein flüssiges Flash-Spiel (nicht von mir erstellt): http://www.gamesforwork.com/games/swf/Mission%20Racing_august_10th_2009.swf

Es hat mich ziemlich viel Zeit gekostet, diese clientseitige Version zu erstellen, ich hoffe, dass dies bei der Lösung des Problems hilft.

Bitte beachten Sie: Ja, es ist tatsächlich ziemlich glatt. Aber es ist definitiv nicht glatt genug.

9voto

fenomas Punkte 11110

Ich weiß nicht, ob es hier eine goldene Antwort gibt, aber ich habe ein paar Vorschläge.

Zunächst einmal würde ich darauf verzichten, mich mit Dingen wie der Optimierung von Math.PI/180 usw. zu befassen. Die allgemein hohe Framerate sollte deutlich machen, dass einfache Berechnungen nichts verlangsamen.

Zweitens, um die gelegentlichen Spitzen der Anzeigeverzögerung zu beseitigen: Diese sehen für mich sehr danach aus, dass der Garbage Collector sehr häufig läuft. Bei einem sehr kurzen Blick durch Ihren Code konnte ich keine offensichtlichen Ursachen für häufige GCs erkennen, aber ich habe zwei Vorschläge. Erstens: Wenn Sie Zugriff auf die Flash-IDE haben, würde ich versuchen, Ihr Projekt ohne das Flex-Framework neu zu erstellen. Ein Flash-Projekt enthält außer dem von Ihnen eingegebenen Code keinen weiteren Code, aber Flex verwendet eine Menge eigener Arkanität, die nicht immer offensichtlich ist, und eine Interaktion zwischen Ihrem Code und dem Framework könnte GCs verursachen.

Wenn das nicht hilft, könnte man auch versuchen, eine stark vereinfachte Version Ihres Codes zu erstellen (wenn möglich in Flash), die hoffentlich einfach genug ist, um nicht dieselben Ausschläge auszulösen. Ich meine zum Beispiel eine einzige Klasse, die an die Grafik angehängt ist, die nur einen Listener für Tastenereignisse und einen zweiten Listener für Frame- (oder Timer-) Ereignisse hat, in dem keine Variablen erstellt werden. Wenn eine Minimalversion diese Spikes nicht anzeigt, sollte es möglich sein, zwischen dieser und Ihrem vollständigen Client zu triangulieren, um herauszufinden, was die Spikes verursacht.

Was schließlich die allgemeine Glätte betrifft, so möchte ich nur anmerken, dass die Bildschirmaktualisierungen von Flash von Natur aus etwas ungleichmäßig sind, und realistischerweise haben Sie nur zwei Möglichkeiten zur Verfügung. Entweder man bewegt die Darsteller entsprechend den Frame-Updates, was ihre Bewegung etwas ungleichmäßig macht, da die Framerates variieren, oder man bewegt sie entsprechend der verstrichenen Zeit, was ihre Gesamtbewegung glatt macht (in Pixeln pro Sekunde), aber ihre Anzeige etwas ungleichmäßig (in bewegten Pixeln pro Frame). Der Unterschied wird bei höheren FPS vergrößert.

Außerdem ist es wichtig, daran zu denken, dass die Darstellung auf dem Bildschirm nach den Flash-Aktualisierungen stark von der Grafikkarte beeinflusst wird. Insbesondere werden Sie feststellen, dass Scher- und Vsync-Probleme in einer Umgebung sehr auffällig sein können und in einer anderen nicht vorhanden sind. Es gibt keine wirkliche Möglichkeit für den Entwickler, hier Abhilfe zu schaffen, außer generell Animationen mit sehr hohen FPS zu vermeiden und die Gesamtbelastung des Prozessors so gering wie möglich zu halten.

bearbeiten: Weitere Informationen darüber, was ich damit meine, dass das Timing der Bildaktualisierung "von Natur aus ungleichmäßig" ist, finden Sie unter dieser Blogbeitrag . Die Verzögerung zwischen den Bildschirmaktualisierungen, die zwischen 12 und 16 ms variiert, kann nicht beeinflusst werden; sie ist das Ergebnis der Tatsache, dass das Betriebssystem und der Browser die Art und Weise beeinflussen, wie das Timing von Flash funktioniert. (Das ist auch etwas, das Sie selbst in einem leeren Film sehen werden, weshalb die vielen Kommentare in diesem Thread über die Optimierung der Mathematik usw. Ihnen nicht helfen werden). Man kann diese Art von Variation nicht vermeiden, aber wie ich oben sagte, kann man die visuellen Effekte so anpassen, dass sie den gewünschten Effekt hervorrufen. Wie auch immer, ich denke, die Spitzen sind es wert, sich darüber Gedanken zu machen. Die Variation, die du siehst, ist subtil und wird in einem Spiel, in dem viel los ist, kaum auffallen, aber die Spikes sind ungeheuerlich.

bearbeiten 2 Sie fragen: "Glauben Sie wirklich, dass diese flüssigen Spiele denselben Bewegungsalgorithmus verwenden wie ich?"

Die Antwort lautet: Ich glaube, sie tun etwas viel Einfacheres. Sie tun mit ziemlicher Sicherheit eines der folgenden Dinge:

function onEnterFrame() { // move at a constant speed per frame
    ship.angle += dtheta;
    ship.x += speed * Math.cos( ship.angle );
    ship.y += speed * Math.sin( ship.angle );
}

function onEnterFrame2() { // move at a constant speed per second
    var dt:Number = getTimeSinceLastFrame();
    ship.angle += anglePerSecond * dt/1000;
    var dist:Number = speedPerSecond * dt/1000;
    ship.x += dist * Math.cos( ship.angle );
    ship.y += dist * Math.sin( ship.angle );
}

Mit anderen Worten, bewegen Sie sich entweder eine konstante Strecke pro Bild oder eine konstante Strecke pro Sekunde. Das sind die beiden einfachsten Methoden, die Sie anwenden können, und es sind auch die beiden Optionen, die in Flash das beste Ergebnis bringen werden. Bei einer konstanten Framerate sehen sie identisch aus, während die letztgenannte Methode bei leicht variierenden Framerates aus ähnlichen Gründen wie dem "temporalen Aliasing", das in dem von Ihnen verlinkten Artikel erwähnt wird, glatter aussieht. Aber die Wahl zwischen diesen Methoden läuft wirklich darauf hinaus, dass man, wenn ein CPU-Spike auftritt, danach möchte, dass sich das Schiff weiterbewegt oder nicht? Das ist eigentlich eine Frage des Spieldesigns. Eine Sache, die ich in der Vergangenheit getan habe, ist die zweite Methode zu verwenden, während Klemm dt auf höchstens das 2- oder 3-fache der Dauer eines idealen Bildes (1/fps).

Wie Sie wahrscheinlich bemerkt haben, sind die beiden Methoden, die ich gerade empfohlen habe, genau das, was der Artikel "Reparieren Sie Ihren Zeitschritt!" nicht empfiehlt. Dies ist, weil dieser Artikel über numerisch integrierte Physik-Engines ist, und das ist nicht das, was Sie tun. Wenn Sie anfangen, Federn und Schwerkraft zu implementieren, dann ja, immer wenn die Zeitschritte groß werden, wird es eine Menge Fehler einführen, weil für diese Art der Simulation, um die Dinge zu vereinfachen, der Fehler von der Größe des Zeitschritts abhängt. Bei dem, was Sie tun, ist das nicht der Fall, so dass gelegentliche große Zeitschritte keinen Einfluss auf die Korrektheit der Simulation haben.

Antwort auf Update 6

Erstens habe ich Ihnen nicht gesagt, dass Ihr Problem die Leistung ist, sondern das Gegenteil. Ich schlug eine minimale Reproduktion vor, weil ich glaubte, dass Ihr Problem entweder irgendwo anders in Ihrem Projekt lag oder unvermeidbar war, und das tue ich immer noch. Zweitens kann ich mit ziemlicher Sicherheit sagen, dass Sie die Dinge genauso machen wie jedes andere Flash-Spiel, und dass die Probleme, die Sie sehen, nicht anders gelöst werden können als in der Wahrnehmung. In den neuen Links, die Sie gepostet haben, sieht die Animation vollkommen flüssig aus, wenn ich sie im Standalone-SWF-Player betrachte, und hat ein leichtes Flackern an den vorderen und hinteren Rändern in Browsern (mehr in Firefox als in IE). Technisch gesehen glaube ich nicht, dass es sich verbessern kann (vor allem, wenn es im Standalone-Player im Grunde perfekt ist, was bedeutet, dass jede Abgehacktheit in Browsern durch den Container beeinflusst wird).

Natürlich ist die wahrgenommen Die Leistung kann noch verbessert werden. Wenn sich das Schiff beispielsweise nicht so stark vom Hintergrund abheben würde, wäre das Flimmern viel weniger auffällig. Auch würde eine langsamere Bewegung des Schiffes die Bewegung viel flüssiger erscheinen lassen und könnte mit einem sich bewegenden Hintergrund kombiniert werden, um die Illusion einer größeren Geschwindigkeit zu erzeugen (wie in einem Ihrer Beispiele).

Zur Kontrolle habe ich hier eine ähnliche Minimalversion in der IDE erstellt. http://www.fenomas.com/random/ship/ Die Leistung ist mit der Ihren auf meinem Rechner vergleichbar, und wie ich schon sagte, sehe ich wirklich kein Problem. (Abgesehen von den gelegentlichen Spitzen, die, wie ich jetzt feststelle, nur bei mir im Firefox auftreten). Auch hier überzeugt mich vor allem die Tatsache, dass mir beide Versionen im Standalone-Player im Grunde perfekt erscheinen, davon, dass es hier keinen goldenen Algorithmus gibt. Ich weiß, dass das nicht die Antwort ist, die Sie wollen, aber es ist die, die ich bekommen habe.

2voto

Virusescu Punkte 394

Ihr Code läuft für mich reibungslos. Keinerlei Ausschläge. Getestet es mit dem folgenden Code am Ende der updatePoller Funktion hinzugefügt.

var shadow:Sprite = new Sprite();
shadow.graphics.beginFill(0xFFFFFF, 0.01);
shadow.graphics.lineStyle(1, 0xFFFFFF, 0.8);
shadow.graphics.drawRect(0, 0, 25, 50);
this.addChildAt(shadow, 0);
shadow.x = shipContainer.x;
shadow.y = shipContainer.y;
shadow.rotation = shipContainer.rotation;

Die Version mit 100 fps neigt dazu, ungleichmäßige Muster zu erhalten, aber das ist normal, weil es nach deiner Berechnung nicht möglich sein kann, 100 Bilder in einer Sekunde zu rendern, wenn die Berechnung eines Bildes mehr als 10 ms dauert. Also, für mich zumindest, der letzte Code läuft reibungslos, auf 30fps.

Was den unscharfen Teil anbelangt, so ist das ein großer Fehler, und ich hoffe, Sie werden mir nicht böse sein, wenn ich frage: Besteht die Möglichkeit, dass der unscharfe / verschwommene Effekt an Ihrem Monitor liegt? Selbst bei einer Reaktionszeit von 10 ms auf einem LCD-Monitor neigt ein weißes, sich schnell bewegendes Objekt vor einem statischen schwarzen Hintergrund dazu, unscharf auszusehen.

1voto

grapefrukt Punkte 26942

Ich denke, die Wurzel Ihres Problems ist, dass die " Vertikalsynchronisation " nicht mit dem des Bildschirms identisch ist. Das ist das gleiche Problem, das auftritt, wenn Sie einen Film mit 24 Bildern pro Sekunde auf einem Bildschirm mit z. B. 60 Hz ansehen. Die Aktualisierungen stimmen nicht perfekt überein (in Ihrem Fall 100/60), und wenn sie einen größeren Sprung machen, sieht es wie ein kleiner Ruckler in der Bewegung aus.

Dem kann man ein wenig abhelfen, indem man die Bildwiederholrate senkt, denn alles, was über der des Bildschirms liegt, ist sowieso nur Verschwendung von Rechenleistung. Ganz vermeiden lässt es sich nicht, obwohl die neuere wmodes für die Flash-Einbettung könnte eine mögliche Lösung sein.

0voto

Selene Punkte 1907

Darf ich vorschlagen, dass Sie sich voreilig Sorgen machen?

Wenn Sie sich das von Ihnen verlinkte "perfekt flüssige" Flash-Spiel genau ansehen, werden Sie feststellen, dass es Sie mit der "Illusion" einer flüssigen Bewegung täuscht.

Das Auto bewegt sich nicht sehr schnell - wahrscheinlich ein Pixel alle paar Frames. Es ist der Hintergrund, der sich am meisten bewegt. Schauen Sie genau hin: Es gibt ein kleines Ruckeln und den gleichen "schwer zu fokussierenden" Effekt, den Sie zu beheben versuchen, aber da es der Hintergrund ist, scheint das normal zu sein. Und selbst wenn das Auto diese Effekte zeigt, lenken der Hintergrund und das Gameplay davon ab, dass man sie bemerkt.

Ich glaube, Sie bemerken das Ruckeln, weil Sie im Moment nur ein Schiff haben, das sich vor einem vollkommen schwarzen Hintergrund bewegt. Wenn der Rest des Spiels erst einmal steht, hat ein Spieler wahrscheinlich nicht mehr die nötige Aufmerksamkeit, um ein kleines Ruckeln zu bemerken. Was den "schwer zu fokussierenden" Effekt angeht, so verschwindet er, wenn man die Bewegungsgeschwindigkeit des Schiffes verringert.

Warum arbeiten Sie nicht erst an dem Rest des Spiels? Sie können später immer noch zurückkommen und die Bewegung optimieren, wenn es immer noch ein Problem ist. Du verbringst eine Menge Zeit mit einem Animations-Artefakt. Ist das Gameplay nicht viel wichtiger?

0voto

George Profenza Punkte 47681

Das ist eine ziemlich gute Frage. Ich habe den Code gescannt und ich habe ein paar Vorschläge, obwohl mein Rat vielleicht nicht so gut ist.

Ich denke, man kann eine Menge tun, um den Code zu optimieren. Offensichtlich nicht in diesem frühen Stadium. Aber Sie können einen Test mit dem Code machen und sehen, wie schnell er mit dem optimierten Code läuft, dann werden Sie wissen, ob es sich lohnt, weiterzumachen.

Hier sind meine "Einwände":

  • Sie verwenden eine Vielzahl von Divisionen. Die Abteilung ist teurer als Multiplikation.

    var distance:Number = (newTimeStamp - movementTimeStamp) / 1000 * movementSpeed;

kann leicht geschrieben werden als

var distance:Number = (newTimeStamp - movementTimeStamp) * .001 * movementSpeed;
  • Sie haben eine MENGE Verweise auf eine MENGE von Funktionen.

    Dinge wie fixAngle() und so weiter können in derselben Funktion stehen, ohne dass die Aufrufe so oft hin und her laufen. Dies gilt auch für Verweise auf externe Klassen und Math.PI oder Math.sin und so weiter, wie fenomas und Allan betonten.

Ich habe getestet diese Methode für Sinus und Kosinus und sie ist verdammt schnell. Sicherlich macht es den Code schmutzig, aber das ist der Grund, warum man nicht so schnell optimiert, bis man das meiste davon so hinbekommen hat, wie es funktionieren muss, denn Optimieren macht einen nur verrückt, weil der Code schwerer zu lesen ist. Nach meiner Erfahrung sind sin und cos ziemlich teure Operationen.

Wie die anderen bereits erwähnten, machen Sie sich vielleicht zu viele Gedanken. Denken Sie daran, dass es eine Menge Dinge gibt, bei denen Sie an Geschwindigkeit gewinnen können. Solange Ihre gesamte Logik nicht richtig funktioniert, sollten Sie nicht einmal an eine Optimierung denken.

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