2010-08-06 2 views
2

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

У меня есть два вопроса.

Во-первых: как я могу получить точное время, когда произошел щелчок? В приведенном ниже примере я получаю отправку быстрых кликов после того, как клик был взломан (sp?).

Во-вторых: что такое хороший шаблон дизайна для сбора каждого щелчка? С верхней части моей головы, я полагаю, я должен

  • отложить любое вычисление до следующего события EnterFrame, но если кто-то щелкает в процессе вычислений на события EnterFrame ... ну тогда, у меня такая же проблема !

  • Я полагаю, что разрушение тяжелых вычислений в psuedo-thread - это еще одно решение, но в зависимости от скорости процессора трудно найти детализацию.

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

Благодарим за любые советы. Вот некоторые примеры код для демонстрации вопроса:

package 
{ 
    import flash.display.Sprite; 
    import flash.display.StageAlign; 
    import flash.display.StageScaleMode; 
    import flash.events.MouseEvent; 
    import flash.geom.Rectangle; 

    public class clicky extends Sprite 
    { 
     private static var _lastTraceTime:Number = new Date().getTime(); 

     private var _sp:Sprite; 
     private var _state1:Boolean; 

     public function clicky():void 
     { super(); 

      stage.align = StageAlign.TOP_LEFT; 
      stage.scaleMode = StageScaleMode.NO_SCALE; 

      _state1 = true; 

      _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 
     { traceTime("click"); 
      _state1 = !_state1; 
      var c:uint = 0xFF0000; 
      if (_state1) 
      { c = 0x00FFAA; 
      } 
      paintThatRect(c); 

      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); 
      for (var i:uint = 0; i < 500000; i++) 
      { 
       var t:Rectangle = new Rectangle(i, i, i, i); 
       if (t.intersects(r) || r.containsRect(t) || t.containsRect(r)) 
       { r = t.union(r); 
       } 
      } 
     } 

     public static function traceTime(note:String):Number 
     { var nowTime:Number = new Date().getTime(); 
      var diff:Number = (nowTime-_lastTraceTime); 
      trace("[t" + diff + "] " + note); 
      _lastTraceTime = nowTime; 
      return diff; 
     } 
    } 
} 
+0

Вы не объяснили, почему вам нужно время. Что вы планировали с этим делать? – Gunslinger47

+0

Я хотел бы знать, какую скорость они нажимали, чтобы они могли ... стрелять в цель так много раз. Хиты должны быстро развиваться, чтобы быть эффективными. – jedierikb

ответ

1

Один из моих прошлых проектов, связанных быстрое нажатие кнопки, так что я сделал обзор, чтобы увидеть, как быстро я могу обычно ожидать игроков нажать. Самый быстрый кликер, который я мог найти, не мог пройти 10 раз в секунду.

В результате вы можете предположить, что частота кадров всегда будет быстрее, чем скорость нажатия. Частота кадров 10 кадров в секунду или менее неприемлема практически во всех случаях. Установите свою программу так, чтобы все обнаруженные события пожара были добавлены в очередь. Каждый кадр обрабатывает только одно событие пожара из очереди.

Иногда это вызывает множество вычислений.

Не делайте этого тогда.

Если процесс занимает более одной десятой секунды, его просто невозможно выполнить более 10 раз в секунду. (по крайней мере, в AS3) Любая обработка, которую вы делаете, должна быть сконструирована таким образом, чтобы она не критически задерживала следующий кадр. Мало того, что это будет выглядеть очень изменчиво, но вы начнете испытывать голод.

Как я могу получить точное время, когда щелчок состоялся?

Поддерживая приличную частоту кадров.

+0

Также возможно [MouseEvent.clickCount] (http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/events/MouseEvent.html#clickCount). – Gunslinger47

0

Вы не получите «точные» временные метки для событий щелчка, если игрок занят запуском вашего метода killTime.Эти события не будут обрабатываться своевременно (точнее, ваши обработчики будут вызваны), в то время как ваш метод блокирует выполнение кода actionscript.

Единственный способ сделать то, что вы хотите (или то, что, я думаю, вы пытаетесь сделать в любом случае), разбивает тяжелую часть обработки на более мелкие кусочки, вроде как зеленые нити, как вы предполагали. Существует множество примеров того, как реализовать это, если вы используете google actionscript + green threads. Некоторые добавляют больше структуры к проблеме, другие более просты, но все они сводятся к одной и той же базовой идее. Выполняйте обработку в кусках, проверяя, что вы не превышаете некоторый порог; когда/если вы это сделаете, вернитесь из своей функции и дождитесь, когда вас снова вызовут, чтобы выбрать, откуда вы ушли. Для этого вы можете использовать таймер или подписаться на 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; 
    } 
} 
Смежные вопросы