2010-08-06 2 views
2

누군가 내 플래시 활동을 클릭하면 많은 계산이 트리거됩니다. 사용자가 다시 클릭하면 (예 : 두 번 클릭) 무거운 계산이 완료되면이 이벤트가 대기열에 추가되고 전달됩니다. 여러 번 클릭하면 문제가 복잡해집니다. 충분히 빠르게 클릭하면 대기중인 무거운 계산이 10 초 후에 완료되고 각 clickEvent는 다음 작업을 천천히 빼내줍니다.모든 mousePressed 이벤트에 대한 정확한 시간을 얻으십시오.

두 가지 질문이 있습니다.

첫 번째 : 클릭이 발생한 정확한 시간은 어떻게 알 수 있습니까? 아래의 예에서 클릭이 끊어진 후에도 빠른 클릭 이벤트가 발생합니다 (SP?).

두 번째 : 모든 클릭을 수집하기위한 좋은 디자인 패턴은 무엇입니까? 내 머리 위로 떨어져 나는 누군가가 enterFrame 이벤트에서 계산하는 동안 클릭하면 내가

  • 연기 어떤 계산이 다음 enterFrame 이벤트까지,하지만 ... 그럼,이 같은 문제를 가지고해야 가정 !

  • 무거운 계산을 가짜 스레드로 분해하는 것이 다른 해결책이지만 프로세서의 속도에 따라 입도를 찾는 것이 어렵습니다.

  • 첫 번째 클릭 후 다음 클릭을 무시하기 위해 플래그를 추가하는 중 ... 그러나이 솔루션은 사용자가 잠겨있을 때 수행하려고 시도했던 것을 추적하지 못하게합니다. 나의 첫 번째 질문에 대한 해결책은 내가 여기서 필요로하는 것이다.

어떤 조언을 주셔서 감사합니다. 여기에 문제를 설명하는 몇 가지 예제 코드입니다 : 누르면 빠른 버튼과 관련된 나의 과거 프로젝트의

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 회 이상을 얻을 수 없었습니다.

결과적으로 프레임 속도가 항상 클릭률보다 빠르다고 생각할 수 있습니다. 거의 모든 경우에 10fps 이하의 프레임 속도는 허용되지 않습니다. 감지 된 화재 이벤트가 대기열에 추가되도록 프로그램을 설정하십시오. 각 프레임은 큐에서 하나의 이벤트 만 처리합니다.

가끔은 많은 계산을 유발합니다.

그렇게하지 마십시오.

프로세스를 완료하는 데 10 분의 1 초 이상이 소요되는 경우 초당 10 회 이상 실행하는 것이 불가능합니다. (적어도 AS3에서) 당신이하는 모든 프로세싱은 다음 프레임을 비판적으로 지연시키지 않도록 설계되어야합니다. 뿐만 아니라 고르지 보이지만, 기아 문제가 시작됩니다.

클릭이 발생했을 때 정확한 시간을 얻으려면 어떻게해야합니까?

괜찮은 프레임 속도를 유지합니다.

+0

또한 [MouseEvent.clickCount] (http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/events/MouseEvent.html#clickCount)가 도움이 될 수 있습니다. – Gunslinger47

0

플레이어가 killTime 메서드를 실행 중일 때 클릭 이벤트에 "정확한"타임 스탬프가 표시되지 않습니다.이러한 이벤트는 메서드가 액션 스크립트 코드 실행을 차단하는 동안 적시에 처리되지 않습니다 (또는 처리기가 호출됩니다).

당신이 원하는대로 (또는 어쨌든 당신이하려고하는 것)하는 유일한 방법은 무거운 처리 부분을 작은 조각, 일종의 녹색 스레드처럼 분해하는 것입니다. google actionscript + green threads를 구현하는 방법에 대한 좋은 예가 많이 있습니다. 어떤 사람들은 문제에 더 많은 구조를 추가하고, 다른 것들은 좀 더 단순하다. 그러나 그들은 모두 같은 기본 생각으로 끓어 간다. 처리량을 청크로 처리하여 임계 값을 초과하지 않는지 확인하십시오. 언제/그랬 으면, 당신의 기능에서 돌아 왔고, 당신이 떠난 곳에서 데리러 다시 전화하기를 기다립니다. 타이머를 사용하거나 EnterFrame에 가입하면됩니다.

게임에 따라 문제가 해결되거나 다른 곳으로 이동할 수 있습니다. Gunslinger47에 의해 만들어진이 점은 게임에 적용되는 경우,이 방법은 정말 작동하지 않습니다

을 프로세스가 완료 0.1 초 보다 더 걸리는 경우, 단순히 불가능 10을보다 그것을 실행의 초당 횟수

그러나 가능한 경우를 예로 들어 설명해 드리겠습니다. 샘플 코드에서 일부 내용을 제거하고 다른 내용을 추가했습니다. 나는 코드가 따라하기 쉽다고 생각하지만, 어쨌든 조금 설명 할게.

진행 상황을 추적하기 위해 내부 클래스 Context을 사용하고 있으며 프로세스를 실행시키는 클릭의 타임 스탬프도 저장하는 데 사용하고 있습니다. 각 프로세스와 관련된 다른 데이터를 저장하는 데 사용할 수 있습니다. 사용자가 버튼을 클릭 할 때마다 이러한 컨텍스트 개체 중 하나가 생성되어 대기열로 푸시됩니다. 대기열에 하나의 항목 (방금 추가 한 항목)이있는 경우 즉시 프로세스를 시작하고 타이머/간격을 설정합니다. 대기열에 물건이 더있는 경우 이미 실행중인 프로세스가 있음을 의미하므로 지금은 아무 것도하지 않습니다.

타이머 메커니즘이 실행될 때마다 이전 반복에서 남은 부분부터 선택됩니다. 이전 상태는 대기열의 첫 번째 항목에 저장됩니다. 카운터를 저장하고 있지만 다른 데이터를 저장할 필요가 있습니다. 이 함수에서는 시간 임계 값을 초과했는지 확인합니다. 여기에는 Date 객체를 사용하는 것보다 가벼운 getTimer()를 호출하는 것이 포함되지만 모든 반복마다 호출하지 않을 수도 있습니다. 대신 N 개의 루프마다 시간을 확인할 수도 있지만 그게 당신에게 달린 것입니다. 또한이 최대 시간은 다소 중재 적입니다. 20 밀리 초 FPS (코드 및 렌더링의 경우 프레임 당 이론적 인 50 밀리 초)로 가정하면 20 밀리 초가 적당 할 것입니다.

프로세스가 완료되면 큐가 이동됩니다. 그런 다음 처리 할 항목이 남아 있는지 확인합니다. 있다면, 우리는 다시 그 물건을 돌려 보내야합니다. 그렇지 않으면, 우리는 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; 
    } 
} 
관련 문제