diff --git a/src/EventQte.as b/src/EventQte.as index 64ff598..6c27f85 100644 --- a/src/EventQte.as +++ b/src/EventQte.as @@ -9,10 +9,12 @@ package public class EventQte extends Event { public static const QTE:String = "qte"; + public static const QTE_TIMEOUT:String = "qte-timeout"; + public static const QTE_CANCEL:String = "qte-cancel"; public var qte:Qte; - public function EventQte(qte:Qte) + public function EventQte(type:String, qte:Qte) { - super(QTE); + super(type); this.qte = qte; } } diff --git a/src/GamePlayer.as b/src/GamePlayer.as index 689c7d4..dc88119 100644 --- a/src/GamePlayer.as +++ b/src/GamePlayer.as @@ -28,6 +28,7 @@ package addEventListener(MouseEvent.CLICK, onClick); videotube.addEventListener(EventQte.QTE, onQte); + videotube.addEventListener(EventQte.QTE_TIMEOUT, onTimeout); } private function cleanup(e:Event):void { @@ -36,13 +37,27 @@ package videotube.removeEventListener(EventQte.QTE, onQte); } private function onQte(e:EventQte):void - { + { + clearClickarea(); clickarea = new ClickArea(e.qte.rgpoint, 0xffff00, 0.7); addChild(clickarea); } + private function onTimeout(e:EventQte):void + { + if (clickarea != null) + { + // fail + } + clearClickarea(); + } private function onClick(mouse:MouseEvent):void { if (clickarea != null && clickarea.FHit(new Point(mouse.stageX, mouse.stageY))) + clearClickarea(); + } + private function clearClickarea():void + { + if (clickarea != null) { removeChild(clickarea); clickarea = null; diff --git a/src/Qte.as b/src/Qte.as index be3f9a9..a08860a 100644 --- a/src/Qte.as +++ b/src/Qte.as @@ -23,6 +23,10 @@ package return -1; return 1; } + public function secTimeout():Number + { + return secTrigger + 1.0; + } public function ToJson():Object { var jsonRgpoint:Array = []; diff --git a/src/Util.as b/src/Util.as index 69b340d..29bf8a8 100644 --- a/src/Util.as +++ b/src/Util.as @@ -25,6 +25,10 @@ package } return -imin; } + public static function FInTimespan(sec:Number, secPrev:Number, secNow:Number):Boolean + { + return (sec <= secNow) && (sec > secPrev); + } public static function alert(...rgo:*):void { ExternalInterface.call("alert", JSON.encode(rgo)); diff --git a/src/Videotube.as b/src/Videotube.as index 5bb8773..e45cd51 100644 --- a/src/Videotube.as +++ b/src/Videotube.as @@ -17,35 +17,86 @@ package public function pause():void { throw "not implemented"; } public function resume():void { throw "not implemented"; } public function time():Number { throw "not implemented"; } - public function seek(sec:Number):void { throw "not implemented"; } + protected function seekI(sec:Number):void { throw "not implemented"; } private var secPrev:Number; private var iqte:int; + private var iqtePrev:int; protected var gamedisc:Gamedisc; public function Videotube(gamedisc: Gamedisc) { this.gamedisc = gamedisc; secPrev = 0; iqte = 0; + iqtePrev = 0; + } + + public function seek(sec:Number):void + { + seekI(sec); + if (iqtePrev != -1) + { + dispatchEvent(new EventQte(EventQte.QTE_CANCEL, gamedisc.rgqte[iqtePrev])); + iqtePrev = -1; + } + iqte = -1; + } + // returns true if triggered + private function Trigger(iqte:int, ev:String, secNow:Number): Boolean + { + if (iqte >= 0 && iqte < gamedisc.rgqte.length) + { + var qte:Qte = gamedisc.rgqte[iqte]; + var secQte:Number; + if (ev == EventQte.QTE) + secQte = qte.secTrigger; + else + secQte = qte.secTimeout(); + if (Util.FInTimespan(secQte, secPrev, secNow)) + { + dispatchEvent(new EventQte(ev, qte)); + return true; + } + } + return false; } protected function tick(e: Event):void { var secNow:Number = time(); - if (secNow > secPrev && secPrev >= 0) + var fPrevQteProcessed:Boolean = false; + var fQteProcessed:Boolean = false; + if (iqte < 0) { - while(iqte < gamedisc.rgqte.length) - { - var qte:Qte = gamedisc.rgqte[iqte]; + iqte = Util.binarySearch(gamedisc.rgqte, secNow, function(qte:Qte, secNow:Number):int { + if (qte.secTrigger < secNow) + return -1; if (qte.secTrigger > secNow) - break; - if (qte.secTrigger > secPrev) - dispatchEvent(new EventQte(qte)); - iqte ++; - } + return 1; + return 0; + }); + iqtePrev = iqte; } else { - iqte = 0; + // we loop here so that, in the event of being passed bad data, we still do something vaguely sensible. + while (!fPrevQteProcessed && !fQteProcessed) + { + if (Trigger(iqtePrev, EventQte.QTE_TIMEOUT, secNow)) + { + fPrevQteProcessed = false; + iqtePrev ++; + } + else + fPrevQteProcessed = true; + + if (Trigger(iqte, EventQte.QTE, secNow)) + { + fQteProcessed = false; + iqte ++; + } + else + fQteProcessed = true; + } } secPrev = secNow; }