2016-04-21 8 views
1

Ich bin fest und versuche, etwas Einfaches zu tun. Ich möchte in der Lage sein, aufwärts zu zählen, bis ich auf den Bildschirm klicke, an welchem ​​Punkt die Zählung aufhören soll. In Wirklichkeit wird der Code selbst komplexe AI-Berechnungen für ein Spiel durchführen, aber zuerst möchte ich verstehen, wie man die while-Schleife steuert. Bei Android wäre das trivial.Steuern von While-Loops in Dart

Hier ist, was mein Code sieht aus wie

bool OK = true; 

main() async{ 
html.querySelector('#content').onMouseUp.listen((e){ 
    OK = false; 
}); 

await for(int i in naturals){ 
    print(i); 
    await sleep(); 
} 
} 

Stream get naturals async* { 
int k = 0; while (OK) { yield await k++; } 
} 

Future sleep() { 
return new Future.delayed(const Duration(milliseconds: 1),() => "1"); 
} 

ich den Schlaf() -Methode einsetzen als eine Möglichkeit, dass die Kontrolle, um sicherzustellen, wird an die Ereignisschleife übergeben.

Ist es möglich, eine while-Schleife ohne die Methode sleep() zu steuern?

+0

Warum wollen Sie in einer Schleife zählen wan't? Könnten Sie nicht einfach die Zeit messen, in der Sie anfangen zu zählen, bis das Klicken passiert ist? –

+0

Ich möchte in der Lage sein, einige Verarbeitungsabschnitte in einer While-Schleife auszuführen - die Aufgabe wird nach Wörtern in einem Stapel zufälliger Buchstaben suchen. Dies muss gestoppt werden, wenn der Gegner sich bewegt, so dass ich den Wert von OK in diesem Moment von wahr zu falsch ändern kann. –

+0

Ich habe immer noch keine Ahnung, was Sie mit "Kontrolle einer Weile Schleife" meinen. Ihre Generatorfunktion macht Ihren Code trotzdem ereignisgesteuert. 'award sleep()' fügt einige zusätzliche Zyklen für den Browser-Hauptthread hinzu. Ich weiß nicht, ob das nützlich/notwendig ist. –

Antwort

0

Update

Gerade enqueue die Ereigniswarteschlange zu ermöglichen herausragende Ereignisse ohne zusätzliche Verzögerung Verwendung

Future sleep() { 
    return new Future.delayed(Duration.ZERO); 
} 

original

JavaScript zu verarbeiten und kann daher nicht Dart haben Fäden in Der Browser und Sie müssen die Steuerung zurück an die Ereigniswarteschlange übergeben, damit sie andere Ereignisse verarbeiten kann, wie Sie es mittun 210. Ein anderer Ansatz wäre, Webworkers zu verwenden und die umfangreiche Berechnung in einer Hintergrundaufgabe (Webworker) auszuführen, um den UI-Thread für die Verarbeitung von Benutzerereignissen frei zu halten. Auf diese Weise können sogar zusätzliche CPU-Kerne verwendet werden, was nicht möglich ist, wenn der gesamte Code im Browser-UI-Thread ausgeführt wird.

Ich weiß nicht, wie man Webarbeiter in Dart obwohl außer Angular2 Dart Web workers in Angular 2 Dart wo Angular die Initialisierung erstellt. Ich denke nicht, dass es zu schwierig ist, aber ich kenne keine Dokumente.

+0

Danke Gunter. Ich schätze den Kommentar. Ich kann einen Web-Arbeiter zum Arbeiten bringen, aber genau das gleiche Problem existiert: In HTML kann nur spawnuri funktionieren, so dass wir den Arbeiter nur mit Nachrichten steuern können. Die while-Schleife im Worker verhindert, dass Nachrichten in Worker bearbeitet werden, sodass die Schleife nicht gestoppt werden kann. Es wäre schön, eine Schlaffunktion für einen Taktzyklus zu haben, da eine Millisekunde sehr lang erscheint. –

+0

Ich denke, neue 'neue Future.delayed.const (Duration.ZERO),() {})' oder sogar 'neue Future.value (null)' könnte tun, was Sie wollen. Dies sollte nur in die Nachrichtenwarteschlange eingereiht werden, ohne dass eine zusätzliche Verzögerung auftritt, wenn zuvor in die Warteschlange eingereihte Aufgaben ausgeführt werden. https://www.dartlang.org/articles/event-loop/ sollte mehr Informationen zu diesem Thema geben. Es gibt verschiedene Warteschlangen (Event, Microtask) und abgeschlossene Futures werden wieder unterschiedlich mit AFAIR behandelt. –

+0

Ok, ich habe es überprüft. 'new Future.delayed.const (Duration.ZERO))' funktioniert gut, aber 'new Future.value()' nicht. –

1

Um eine allgemeinere Antwort zu geben - statt einer Schleife möchten Sie eine Folge von zukünftigen Aufgaben planen, die jeweils eine Iteration oder einen Schritt Ihres AI-Codes (oder eines anderen Hintergrundprozesses) ausführen.

dynamic doSomething(_) { 
    print('Doing something ...'); 
    if(!stop) { 
    new Future.delayed(delay,(){}).then(doSomething); 
    } 
    return null; 
} 

main() async { 

    doSomething(null); 

} 

Obwohl ich das nicht empfehlen tun:

können Sie die Schrittaufgabe selbst rekursiv planen haben. Es ist schwierig zu steuern - der Schrittcode muss eine Flag-Variable prüfen, um zu sehen, ob sie fortfahren oder anhalten soll und dass sie frei läuft.

void doSomething(Timer timer) { 
    print('Doing something ...'); 
} 

main() async { 

new Timer.periodic(delay, doSomething); 

} 

Diese gedrosselt wird mit einer konstanten Geschwindigkeit und einen gleichförmigen Zeitschritt, und ist leichter (cancel() auf dem Timer nennen) zu stoppen:

Alternativ können Sie ein Timer verwenden.

Ein weiterer Ansatz könnte sein, mit dem Browser des Zieh Refresh-Zyklus zu synchronisieren, indem zukünftigem Animationsrahmen s anfordernden:

import 'dart:html'; 

doSomething(num delta) { 
    print('Doing something ...'); 
    window.animationFrame.then(doSomething); 
} 

void main() { 
    window.animationFrame.then(doSomething); 
} 

Zeitschritte sind nicht konstant, sondern Sie die Zeit Delta bekommen. Der Vorteil dieses Ansatzes besteht darin, dass Animationsrahmen-Futures nicht geplant werden, wenn das Browserfenster ausgeblendet ist.

Siehe How do I drive an animation loop at 60fps with Dart?

Das sind sehr einfache Beispiele. Das Einrichten geeigneter Hintergrundprozesse für die Physiksimulation und AI in Webspielen ist tatsächlich überraschend (zumindest für mich) nicht-trivial. Hier sind zwei Ressourcen, die ich hilfreich fand.

http://gameprogrammingpatterns.com/ - ein nettes kostenloses Online-Buch von Spiel Programmierung Muster. http://gameprogrammingpatterns.com/game-loop.html - Kapitel über Spiel-Loops.

http://gafferongames.com/game-physics/fix-your-timestep/ - Teil einer Reihe von Artikeln über Physik-Simulation in Spielen.

0

Nach allen Vorschlägen ist dies der Code, mit dem ich gelandet bin, indem ich das schwere Heben in einen Arbeiter mit kontrollierbarem Anhalten und Starten bringe. Ich habe das einfache Zählen benutzt, um das zu funktionieren, aber das wird durch meine komplexen KI-Spielberechnungen ersetzt.

Dies verwendet Zeitscheiben von 100 ms innerhalb eines Worker-Isolats, die nur unterbrochen werden können, nachdem der Batch beendet wurde. Dies erlaubt mir die Freiheit, komplexe Animationen auf dem Bildschirm zu haben, während all diese harte Arbeit getan wird.

import 'dart:html' as html; 
import 'dart:isolate'; 
import 'dart:math'; 

SendPort worker; 
bool working = false; 

main() async{ 

    await startWorker(); 

    html.querySelector('#stage').onMouseUp.listen((e){ 
    if(working)worker.send('stop'); 
    else worker.send('go'); 
    }); 

} 

startWorker() async{ 
    var response = new ReceivePort(); 

    await Isolate.spawnUri(Uri.parse("worker.dart"), null ,response.sendPort) 
     .then((_) => response.listen((msg){ 

    if(msg is SendPort) { 
     worker = msg; 
    } 
    else { 
     messageReceived(msg); 
    } 
    })); 
} 

messageReceived(String message){ 
    switch (message){ 
    case 'working': working = true; 
    break; 

    case 'idle': working = false; 
     break; 

    default : print(message); 
     break; 
    } 
} 

worker.dart

import 'dart:isolate'; 
import 'dart:async'; 

SendPort replyTo; 
bool OK = false; 
const timeSlice = 100; 

main(List<String> args, SendPort reply) async{ 
    var response = new ReceivePort(); 
    reply.send(response.sendPort); 
    replyTo = reply; 
    response.listen((msg) => messageReceived(msg)); 
    replyTo.send("Hello from worker. Click to start and stop me"); 
} 

messageReceived(String message){ 
    switch(message){ 
    case 'stop': 
     replyTo.send('idle'); 
     OK = false; 
     break; 

    case 'go': 
     replyTo.send('working'); 
     go(); 
     break; 
    } 
} 

go()async { 
    OK = true; 
    int i = 0; 

    batchJob(){ 
    int startTime = new DateTime.now().millisecondsSinceEpoch; 
    int elapsed = 0; 

    while(elapsed < timeSlice){ 

     i ++; // the central routine 

     elapsed = new DateTime.now().millisecondsSinceEpoch - startTime; 
    } 
} 

    while(OK){ 
    batchJob(); 
    replyTo.send(i.toString()); 
    await new Future.delayed(const Duration(milliseconds: 0),() {}); 
    } 
} 
+0

'new Future.delayed (Duration.ZERO);' hat den gleichen Effekt wie 'new Future.delayed (const Dauer (Millisekunden: 0),() {});' –

+0

Ja, danke. Das ist besser. –