2016-04-21 8 views
1

Я застреваю, пытаясь сделать что-то простое. Я хочу, чтобы иметь возможность рассчитывать вверх, пока я не нажму на экран, в какой момент я хочу, чтобы подсчет остановился. На самом деле сам код будет выполнять сложные вычисления AI для игры, но сначала я хочу понять, как управлять циклом while. В андроиде это было бы тривиально.Управление в цикле в Dart

Вот что мой код выглядит

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

Я поставил метод сна() в качестве способа обеспечения того, чтобы управление передается в цикл обработки событий.

Можно ли управлять циклом while без метода sleep()?

+0

Почему вы wan't рассчитывать в цикле? Не могли бы вы просто измерить время, когда вы «начинаете считать» до тех пор, пока не произойдет щелчок? –

+0

Я хочу, чтобы иметь возможность выполнять некоторые куски обработки в цикле while - задача будет искать слова в стек случайных букв. Это необходимо остановить, когда противник движется, поэтому я хочу, чтобы в этот момент можно было изменить значение OK с true на false. –

+0

Я до сих пор не знаю, что вы подразумеваете под «контролем цикла while». В любом случае ваша функция генератора делает ваш код управляемым событием. 'await sleep()' добавляет некоторые дополнительные циклы для основного потока браузера. Я не знаю, полезно ли это. –

ответ

0

обновление

Просто Епдиеий, чтобы очередь событий обрабатывать выдающиеся события без дополнительного использования задержки

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

оригинального

JavaScript и поэтому не может Dart иметь резьбу в браузер, и вам нужно передать управление обратно в очередь событий, чтобы он мог обрабатывать другие события, например, с помощью. 210.

Другим подходом было бы использование веб-мастеров и выполнение тяжелых вычислений в фоновом задании (webworker), чтобы поток потока пользовательского интерфейса мог обрабатывать пользовательские события. Таким образом, можно использовать даже дополнительные ядра ЦП, что невозможно, если весь код работает в потоке пользовательского интерфейса браузеров.

Я не знаю, как создавать веб-мастеров в Дарт, но только с Angular2 Dart Web workers in Angular 2 Dart, где Угловая инициализация. Я не думаю, что это слишком сложно, но я не знаю никаких документов.

+0

Спасибо, Гюнтер. Я ценю комментарий. Я могу заставить работать веб-рабочий, но существует одна и та же проблема: в HTML только spawnuri может работать, поэтому мы можем управлять работником только сообщениями. Цикл while в рабочем состоянии предотвращает выполнение сообщений в рабочем столе, поэтому цикл не может быть остановлен. Было бы неплохо иметь функцию сна для одного такта, так как миллисекунда кажется очень длинной. –

+0

Я предполагаю, что новый 'new Future.delayed.const (Duration.ZERO),() {})' или даже 'new Future.value (null)' может делать то, что вы хотите. Это должно просто помещаться в очередь сообщений без дополнительной задержки для обработки, когда выполняются ранее установленные задачи. https://www.dartlang.org/articles/event-loop/ следует предоставить дополнительную информацию по этой теме. Существуют разные очереди (событие, микрозадача) и завершенные Фьючерсы снова обрабатываются по-разному AFAIR. –

+0

Хорошо, я проверил. 'new Future.delayed.const (Duration.ZERO))' отлично работает, но 'new Future.value()' не делает. –

1

Чтобы предоставить более общий ответ - вместо цикла вы хотите запланировать последовательность будущих задач, каждая из которых выполняет одну итерацию или шаг вашего AI-кода (или любого другого фонового процесса, который вы хотите запустить).

Вы можете шаг задача рекурсивно планировать себя:

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

main() async { 

    doSomething(null); 

} 

Хотя я не рекомендую это делать. Это неудобно контролировать - код шага должен проверять переменную флага, чтобы увидеть, следует ли продолжать или останавливаться, и это бесплатный запуск.

В качестве альтернативы можно использовать Timer:

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

main() async { 

new Timer.periodic(delay, doSomething); 

} 

Это дросселируется с постоянной скоростью и имеет равномерный шаг по времени, и проще остановить (вызов cancel() по таймеру).

Другой подход может синхронизироваться с Жеребьевка циклом обновления браузера, запрашивая будущий кадр анимационного S:

import 'dart:html'; 

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

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

временные шаги не являются постоянными, но вы получите время дельту. Преимущество такого подхода заключается в том, что фреймы фреймов анимации не будут запланированы, если окно браузера будет скрыто.

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

Это очень простые примеры. Настройка правильных фоновых процессов для физического моделирования и ИИ в веб-играх на самом деле удивительно (по крайней мере для меня) нетривиальна. Вот два ресурса, которые я нашел полезными.

http://gameprogrammingpatterns.com/ - отличная бесплатная онлайн-книга шаблонов игрового программирования. http://gameprogrammingpatterns.com/game-loop.html - глава о игровых циклах.

http://gafferongames.com/game-physics/fix-your-timestep/ - часть последовательности статей по физическому моделированию в играх.

0

Следуя всем предложениям, это код, который я закончил, поставив тяжелый подъем в работника с контролируемой остановкой и запуском. Я использовал простой подсчет, чтобы получить эту работу, но это заменяется моими сложными вычислениями AI-игры.

Это использует временные срезы в 100 мсек внутри изолированной рабочей среды, которые могут быть прерваны только после завершения партии. Это позволяет мне получить полную свободу на сложную анимацию на экране, пока все это тяжелая работа выполняется.

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);' имеет тот же эффект, что и 'new Future.delayed (const Duration (миллисекунды: 0),() {});' –

+0

Да, спасибо. Так лучше. –