Вы не получите «точные» временные метки для событий щелчка, если игрок занят выполнением вашего метода killTime.Эти события не будут обработаны своевременно (или, скорее, ваши обработчики будут вызваны), пока ваш метод блокирует выполнение кода Actionscript.
Единственный способ сделать то, что вы хотите (или то, что, я думаю, вы пытаетесь сделать)в любом случае) разбивает тяжелую обрабатывающую часть на более мелкие кусочки, вроде зеленых нитей, как вы и предлагали.Существует множество примеров того, как реализовать это, если вы используете Google Actionscript + зеленые темы.Некоторые добавляют больше структуры к проблеме, другие более просты, но все они сводятся к одной и той же основной идее.Проводите обработку кусками, проверяя, не превышаете ли вы пороговое значение;когда / если вы это сделаете, вернитесь из своей функции и подождите, пока вам не позвонят, чтобы продолжить с того места, где вы ушли.Вы можете использовать таймер или подписаться на EnterFrame для этого.
В зависимости от вашей игры это может решить вашу проблему или просто переместить ее в другое место.Если это замечание, сделанное Gunslinger47, применимо к вашей игре, этот подход на самом деле не сработает:
Если процесс занимает больше десятой доли секунды, просто невозможно выполнить его больше, чем10 раз в секунду
Однако, вот эскиз возможной реализации, если предположить, что это не так.Я удалил некоторые вещи из вашего примера кода и добавил другие.Я думаю, что за кодом легко следовать, но в любом случае я просто объясню немного.
Я использую внутренний класс Context
для отслеживания прогресса и также использую его для сохранения метки времени клика, вызвавшего запуск процесса.Вы можете использовать его для хранения других данных, связанных с каждым процессом.Каждый раз, когда пользователь нажимает кнопку, один из этих объектов контекста создается и помещается в очередь.Если в очереди только один элемент (который мы только что добавили), мы сразу запускаем процесс и устанавливаем таймер / интервал.Если в очереди больше материала, значит, процесс уже запущен, поэтому мы пока ничего не делаем.
Каждый раз, когда запускается механизм таймера, он начинает с того места, где он ушел в предыдущей итерации.Предыдущее состояние сохраняется в первом элементе очереди.Я храню счетчик, но вам может понадобиться сохранить другие данные там.В этой функции я проверяю, превышен ли порог времени.Это включает вызов getTimer (), который является более легким, чем использование объекта Date, но вы, вероятно, не захотите вызывать его для каждой итерации.Вместо этого вы можете проверить время только каждые N петель, но это на ваше усмотрение.Кроме того, это максимальное время несколько произвольно.Вы должны немного его настроить, хотя 20 мс кажется разумным для 20 FPS swf (предполагая теоретические 50 мс на кадр для кода и рендеринга).
Когда процесс завершается, очередь сдвигается.Затем мы проверяем, остались ли предметы для обработки.Если таковые имеются, мы просто позволяем этой вещи снова работать.В противном случае мы остановим его, удалив EnterFrame.
Обратите внимание, что при использовании этого подхода «зеленой многопоточности» возникают некоторые накладные расходы, поскольку выполнение одного и того же кода всего за один шаг будет заметно быстрее.Так что это не идеально, но часто это единственный способ сохранить работоспособность вашего приложения во время обработки.
package {
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.events.Event;
import flash.utils.getTimer;
public class clicky extends Sprite {
private static var _lastTraceTime:Number = new Date().getTime();
private var _sp:Sprite;
private var _queue:Array;
private const MAX_TIME:int = 20;
public function clicky( ):void {
super( );
stage.align=StageAlign.TOP_LEFT;
stage.scaleMode=StageScaleMode.NO_SCALE;
_queue = [];
_sp = new Sprite( );
addChild( _sp );
_sp.graphics.beginFill( 0xFF00AA, 1 );
_sp.graphics.drawRect( 10, 10, 100, 100 );
_sp.graphics.endFill( );
_sp.addEventListener( MouseEvent.MOUSE_DOWN, mDnCb, false, 0, true );
}
private function mDnCb( evt:MouseEvent ):void {
_queue.push(new Context(new Date()));
if(_queue.length == 1) {
initProcess();
}
}
private function initProcess():void {
trace("initProcess");
killTime();
addEventListener(Event.ENTER_FRAME,run);
}
private function processDone():void {
trace("processDone, " + _queue[0].clickTime);
_queue.shift();
if(_queue.length == 0) {
removeEventListener(Event.ENTER_FRAME,run);
}
}
private function run(e:Event):void {
killTime();
}
private function paintThatRect( c:uint ):void {
_sp.graphics.beginFill( c, 1 );
_sp.graphics.drawRect( 10, 10, 100, 100 );
_sp.graphics.endFill( );
}
private function killTime():void {
var r:Rectangle=new Rectangle(0,0,100,100);
var initTime:int = getTimer();
var runningTime:int = 0;
var loops:int = 500000;
var ctx:Context = _queue[0];
for(var i:int = ctx.i; i < loops; i++) {
var t:Rectangle=new Rectangle(i,i,i,i);
if (t.intersects(r)||r.containsRect(t)||t.containsRect(r)) {
r=t.union(r);
}
runningTime = getTimer() - initTime;
if(runningTime >= MAX_TIME) {
break;
}
}
ctx.i = i;
if(i == loops) {
trace(i);
processDone();
}
}
}
}
class Context {
public var i:int = 0;
public var clickTime:Date;
public function Context(clickTime:Date) {
this.clickTime = clickTime;
}
public function reset():void {
i = 0;
}
}