Huge overhaul.
- fix flaws with videotube's QTE-finding algorithm which caused breakage when seeking around in the video, qtes were added, or anyone sneezed - switch from arbitrary polygons to simple circles, simplifying the editing interface considerably - support for deletes and overwrites of QTEs - new server protocol - pause/resume when focus lost - some degree of error handling - restart key - videotube API no longer autostarts; 'play' becomes 'enqueue' and is called once
This commit is contained in:
parent
bc576d08b5
commit
46e54c44df
|
@ -1,14 +1,16 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<project>
|
<project version="2">
|
||||||
<!-- Output SWF options -->
|
<!-- Output SWF options -->
|
||||||
<output>
|
<output>
|
||||||
<movie disabled="False" />
|
<movie outputType="Application" />
|
||||||
<movie input="" />
|
<movie input="" />
|
||||||
<movie path="bin\LaserTube.swf" />
|
<movie path="bin\LaserTube.swf" />
|
||||||
<movie fps="30" />
|
<movie fps="30" />
|
||||||
<movie width="800" />
|
<movie width="800" />
|
||||||
<movie height="600" />
|
<movie height="600" />
|
||||||
<movie version="10" />
|
<movie version="10" />
|
||||||
|
<movie minorVersion="0" />
|
||||||
|
<movie platform="Flash Player" />
|
||||||
<movie background="#FFFFFF" />
|
<movie background="#FFFFFF" />
|
||||||
</output>
|
</output>
|
||||||
<!-- Other classes to be compiled into your SWF -->
|
<!-- Other classes to be compiled into your SWF -->
|
||||||
|
@ -24,6 +26,7 @@
|
||||||
<option locale="" />
|
<option locale="" />
|
||||||
<option loadConfig="" />
|
<option loadConfig="" />
|
||||||
<option optimize="True" />
|
<option optimize="True" />
|
||||||
|
<option omitTraces="True" />
|
||||||
<option showActionScriptWarnings="True" />
|
<option showActionScriptWarnings="True" />
|
||||||
<option showBindingWarnings="True" />
|
<option showBindingWarnings="True" />
|
||||||
<option showInvalidCSS="True" />
|
<option showInvalidCSS="True" />
|
||||||
|
@ -39,7 +42,7 @@
|
||||||
<option staticLinkRSL="True" />
|
<option staticLinkRSL="True" />
|
||||||
<option additional="" />
|
<option additional="" />
|
||||||
<option compilerConstants="" />
|
<option compilerConstants="" />
|
||||||
<option customSDK="" />
|
<option minorVersion="" />
|
||||||
</build>
|
</build>
|
||||||
<!-- SWC Include Libraries -->
|
<!-- SWC Include Libraries -->
|
||||||
<includeLibraries>
|
<includeLibraries>
|
||||||
|
@ -82,4 +85,6 @@
|
||||||
<option showHiddenPaths="False" />
|
<option showHiddenPaths="False" />
|
||||||
<option testMovie="Default" />
|
<option testMovie="Default" />
|
||||||
</options>
|
</options>
|
||||||
|
<!-- Plugin storage -->
|
||||||
|
<storage />
|
||||||
</project>
|
</project>
|
|
@ -13,38 +13,26 @@ package
|
||||||
private var shape:Shape;
|
private var shape:Shape;
|
||||||
private var shapeHidden:Shape;
|
private var shapeHidden:Shape;
|
||||||
private var fHidden:Boolean;
|
private var fHidden:Boolean;
|
||||||
public function ClickArea(rgpoint: Array, color:uint, alpha:Number = 1)
|
public function ClickArea(center: Point, radius:Number, color:uint, alpha:Number = 1)
|
||||||
{
|
{
|
||||||
super();
|
super();
|
||||||
shape = drawShape(new Shape(), rgpoint, color, null, alpha);
|
shape = drawShape(new Shape(), new Point(0,0), radius, color, null, alpha);
|
||||||
shapeHidden = drawShape(new Shape(), rgpoint, color, null, 0);
|
shapeHidden = drawShape(new Shape(), new Point(0,0), radius, color, null, 0);
|
||||||
fHidden = false;
|
fHidden = false;
|
||||||
|
moveTo(center);
|
||||||
addChild(shape);
|
addChild(shape);
|
||||||
}
|
}
|
||||||
public static function drawShape(shape:Shape, rgpoint:Array, color:uint, colorLine:* = null, alpha:Number = 1):Shape
|
public function moveTo(centerNew: Point):void
|
||||||
|
{
|
||||||
|
x = centerNew.x;
|
||||||
|
y = centerNew.y;
|
||||||
|
}
|
||||||
|
public static function drawShape(shape:Shape, center:Point, radius:Number, color:uint, colorLine:* = null, alpha:Number = 1):Shape
|
||||||
{
|
{
|
||||||
shape.graphics.clear();
|
shape.graphics.clear();
|
||||||
if (rgpoint.length > 0)
|
shape.graphics.beginFill(color, alpha);
|
||||||
{
|
shape.graphics.drawCircle(center.x, center.y, radius);
|
||||||
if (colorLine != null)
|
shape.graphics.endFill();
|
||||||
shape.graphics.lineStyle(1, colorLine);
|
|
||||||
shape.graphics.beginFill(color, alpha);
|
|
||||||
var fFirstPoint:Boolean = true;
|
|
||||||
for each (var point:Point in rgpoint)
|
|
||||||
{
|
|
||||||
if (fFirstPoint)
|
|
||||||
{
|
|
||||||
shape.graphics.moveTo(point.x, point.y);
|
|
||||||
fFirstPoint = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
shape.graphics.lineTo(point.x, point.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
shape.graphics.lineTo(rgpoint[0].x, rgpoint[0].y);
|
|
||||||
shape.graphics.endFill();
|
|
||||||
}
|
|
||||||
return shape;
|
return shape;
|
||||||
}
|
}
|
||||||
public function Show():void
|
public function Show():void
|
||||||
|
|
115
src/Game.as
Normal file
115
src/Game.as
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
package
|
||||||
|
{
|
||||||
|
import flash.display.Sprite;
|
||||||
|
import flash.events.Event;
|
||||||
|
import flash.text.TextField;
|
||||||
|
import flash.text.TextFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ...
|
||||||
|
* @author Jeremy Penner
|
||||||
|
*/
|
||||||
|
public class Game extends Sprite
|
||||||
|
{
|
||||||
|
public static var hasFocus:Boolean = false;
|
||||||
|
|
||||||
|
protected var videotube:Videotube;
|
||||||
|
protected var gamedisc:Gamedisc;
|
||||||
|
protected var clickarea:ClickArea;
|
||||||
|
protected var text:TextField;
|
||||||
|
protected var textValues: Array;
|
||||||
|
public function Game(videotube:Videotube, gamedisc:Gamedisc)
|
||||||
|
{
|
||||||
|
this.videotube = videotube;
|
||||||
|
this.gamedisc = gamedisc;
|
||||||
|
addEventListener(Event.ADDED_TO_STAGE, init);
|
||||||
|
}
|
||||||
|
protected function init(e:Event):void {
|
||||||
|
trace("init");
|
||||||
|
removeEventListener(Event.ADDED_TO_STAGE, init);
|
||||||
|
addEventListener(Event.REMOVED_FROM_STAGE, cleanup);
|
||||||
|
|
||||||
|
stage.addEventListener(Event.ACTIVATE, onFocus);
|
||||||
|
stage.addEventListener(Event.DEACTIVATE, onLoseFocus);
|
||||||
|
|
||||||
|
clickarea = null;
|
||||||
|
if (text != null)
|
||||||
|
removeChild(text);
|
||||||
|
text = null;
|
||||||
|
textValues = [];
|
||||||
|
|
||||||
|
if (hasFocus) {
|
||||||
|
onFocus(null);
|
||||||
|
} else {
|
||||||
|
onLoseFocus(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected function cleanup(e:Event):void {
|
||||||
|
trace("cleanup");
|
||||||
|
removeEventListener(Event.REMOVED_FROM_STAGE, cleanup);
|
||||||
|
|
||||||
|
stage.removeEventListener(Event.ACTIVATE, onFocus);
|
||||||
|
stage.removeEventListener(Event.DEACTIVATE, onLoseFocus);
|
||||||
|
|
||||||
|
if (hasFocus)
|
||||||
|
onPause();
|
||||||
|
clearClickarea();
|
||||||
|
}
|
||||||
|
protected function onFocus(e:Event):void {
|
||||||
|
trace("received focus");
|
||||||
|
popText();
|
||||||
|
hasFocus = true;
|
||||||
|
stage.addEventListener(Event.EXIT_FRAME, onFocusEnded);
|
||||||
|
}
|
||||||
|
protected function onFocusEnded(e:Event): void {
|
||||||
|
stage.removeEventListener(Event.EXIT_FRAME, onFocusEnded);
|
||||||
|
onResume();
|
||||||
|
}
|
||||||
|
protected function onLoseFocus(e:Event): void {
|
||||||
|
trace("lost focus");
|
||||||
|
pushText("Paused\nCLICK TO PLAY", 0x000000, 0xFFFFFF);
|
||||||
|
hasFocus = false;
|
||||||
|
onPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function onPause(): void {
|
||||||
|
trace("onPause");
|
||||||
|
videotube.pause();
|
||||||
|
}
|
||||||
|
protected function onResume(): void {
|
||||||
|
trace("onResume");
|
||||||
|
if (fPlaying())
|
||||||
|
videotube.resume();
|
||||||
|
}
|
||||||
|
protected function fPlaying(): Boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public function clearClickarea(): void
|
||||||
|
{
|
||||||
|
if (clickarea != null) {
|
||||||
|
removeChild(clickarea);
|
||||||
|
clickarea = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected function pushText(html:String, bgcolor:int, fgcolor:int): void {
|
||||||
|
if (text == null)
|
||||||
|
text = Util.addTextFieldFullScreen(this);
|
||||||
|
textValues.push( { 'html': html, 'bgcolor':bgcolor, 'fgcolor':fgcolor } );
|
||||||
|
trace("saying: " + html);
|
||||||
|
Util.setText(text, html, 164, bgcolor, fgcolor);
|
||||||
|
}
|
||||||
|
protected function popText(): void {
|
||||||
|
if (textValues.length > 0) {
|
||||||
|
textValues.pop();
|
||||||
|
if (textValues.length > 0) {
|
||||||
|
var val:Object = textValues.pop();
|
||||||
|
pushText(val['html'], val['bgcolor'], val['fgcolor']);
|
||||||
|
} else {
|
||||||
|
removeChild(text);
|
||||||
|
text = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,69 +4,111 @@ package
|
||||||
import flash.events.Event;
|
import flash.events.Event;
|
||||||
import flash.events.KeyboardEvent;
|
import flash.events.KeyboardEvent;
|
||||||
import flash.events.MouseEvent;
|
import flash.events.MouseEvent;
|
||||||
|
import flash.geom.Point;
|
||||||
/**
|
/**
|
||||||
* ...
|
* ...
|
||||||
* @author jjp
|
* @author jjp
|
||||||
*/
|
*/
|
||||||
public class GameEditor extends Sprite
|
public class GameEditor extends Game
|
||||||
{
|
{
|
||||||
private var videotube:Videotube;
|
protected var qte:Qte;
|
||||||
private var gamedisc:Gamedisc;
|
public override function GameEditor(videotube:Videotube, gamedisc:Gamedisc) {
|
||||||
private var sketchShape:SketchShape;
|
super(videotube, gamedisc);
|
||||||
private var clickarea:ClickArea;
|
qte = null;
|
||||||
|
|
||||||
public function GameEditor(videotube:Videotube, gamedisc:Gamedisc)
|
|
||||||
{
|
|
||||||
this.videotube = videotube;
|
|
||||||
this.gamedisc = gamedisc;
|
|
||||||
addEventListener(Event.ADDED_TO_STAGE, init);
|
|
||||||
}
|
}
|
||||||
public function init(e: Event):void
|
protected override function onResume():void
|
||||||
{
|
{
|
||||||
removeEventListener(Event.ADDED_TO_STAGE, init);
|
super.onResume();
|
||||||
addEventListener(Event.REMOVED_FROM_STAGE, cleanup);
|
|
||||||
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
|
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
|
||||||
|
stage.addEventListener(MouseEvent.MOUSE_DOWN, onClick);
|
||||||
sketchShape = new SketchShape();
|
stage.addEventListener(MouseEvent.MOUSE_MOVE, onDrag);
|
||||||
addChild(sketchShape);
|
|
||||||
sketchShape.addEventListener(SketchShape.DRAW_BEGIN, onDrawBegin);
|
|
||||||
sketchShape.addEventListener(SketchShape.DRAW_END, onDrawEnd);
|
|
||||||
|
|
||||||
clickarea = null;
|
|
||||||
videotube.addEventListener(EventQte.QTE, onQteBegin);
|
videotube.addEventListener(EventQte.QTE, onQteBegin);
|
||||||
videotube.addEventListener(EventQte.QTE_TIMEOUT, onQteEnd);
|
videotube.addEventListener(EventQte.QTE_TIMEOUT, onQteEnd);
|
||||||
|
videotube.addEventListener(EventQte.QTE_CANCEL, onQteEnd);
|
||||||
}
|
}
|
||||||
public function cleanup(e: Event):void
|
protected override function onPause():void
|
||||||
{
|
{
|
||||||
removeEventListener(Event.REMOVED_FROM_STAGE, cleanup);
|
super.onPause();
|
||||||
stage.removeEventListener(KeyboardEvent.KEY_UP, onKeyUp);
|
stage.removeEventListener(KeyboardEvent.KEY_UP, onKeyUp);
|
||||||
sketchShape.removeEventListener(SketchShape.DRAW_BEGIN, onDrawBegin);
|
stage.removeEventListener(MouseEvent.MOUSE_DOWN, onClick);
|
||||||
sketchShape.removeEventListener(SketchShape.DRAW_END, onDrawEnd);
|
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onDrag);
|
||||||
|
|
||||||
|
videotube.removeEventListener(EventQte.QTE, onQteBegin);
|
||||||
|
videotube.removeEventListener(EventQte.QTE_TIMEOUT, onQteEnd);
|
||||||
|
videotube.removeEventListener(EventQte.QTE_CANCEL, onQteEnd);
|
||||||
|
}
|
||||||
|
protected override function fPlaying():Boolean {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
public function onQteBegin(e: EventQte):void
|
public function onQteBegin(e: EventQte):void
|
||||||
{
|
{
|
||||||
clickarea = new ClickArea(e.qte.rgpoint, 0x4444ee, 0.4);
|
trace("editor qte begin");
|
||||||
addChild(clickarea);
|
if (e.qte != qte) {
|
||||||
|
Util.assert(qte == null);
|
||||||
|
if (qte != null) {
|
||||||
|
gamedisc.repostQte(qte);
|
||||||
|
clearClickarea();
|
||||||
|
qte = null;
|
||||||
|
}
|
||||||
|
addClickArea(e.qte);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public function onQteEnd(e: EventQte):void
|
public function onQteEnd(e: EventQte):void
|
||||||
{
|
{
|
||||||
removeChild(clickarea);
|
trace("editor qte end");
|
||||||
clickarea = null;
|
Util.assert(qte == e.qte);
|
||||||
}
|
gamedisc.repostQte(qte);
|
||||||
public function onKeyUp(key: KeyboardEvent):void
|
clearClickarea();
|
||||||
{
|
qte = null;
|
||||||
|
|
||||||
}
|
|
||||||
private function onDrawBegin(e: Event): void
|
|
||||||
{
|
|
||||||
videotube.pause();
|
|
||||||
}
|
|
||||||
private function onDrawEnd(e: Event): void
|
|
||||||
{
|
|
||||||
gamedisc.AddQte(new Qte(sketchShape.rgpoint, videotube.time()));
|
|
||||||
videotube.resume();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function onKeyUp(key: KeyboardEvent):void
|
||||||
|
{
|
||||||
|
if (key.keyCode == 46 && qte != null) {// delete
|
||||||
|
gamedisc.DeleteQte(qte, videotube);
|
||||||
|
clearClickarea();
|
||||||
|
qte = null;
|
||||||
|
} else if (key.keyCode == 37) { // leftArrow
|
||||||
|
videotube.seek(videotube.time() - 3);
|
||||||
|
clearClickarea();
|
||||||
|
qte = null;
|
||||||
|
} else if (key.keyCode == 39) { // rightArrow
|
||||||
|
videotube.seek(videotube.time() + 3);
|
||||||
|
clearClickarea();
|
||||||
|
qte = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private function addClickArea(qteNew: Qte):void
|
||||||
|
{
|
||||||
|
qte = qteNew;
|
||||||
|
clickarea = new ClickArea(qte.center, qte.radius, 0x4444ee, 0.4);
|
||||||
|
addChild(clickarea);
|
||||||
|
}
|
||||||
|
private function moveClickArea(point:Point): void
|
||||||
|
{
|
||||||
|
if (qte) {
|
||||||
|
qte.moveTo(point);
|
||||||
|
clickarea.moveTo(point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function onClick(e: MouseEvent):void
|
||||||
|
{
|
||||||
|
trace("clicked");
|
||||||
|
var point:Point = new Point(e.stageX, e.stageY);
|
||||||
|
if (qte)
|
||||||
|
moveClickArea(point);
|
||||||
|
else {
|
||||||
|
var qte:Qte = new Qte(point, 75, videotube.time(), -1, true /*fDirty*/);
|
||||||
|
addClickArea(qte);
|
||||||
|
gamedisc.AddQte(qte, videotube);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function onDrag(e: MouseEvent):void
|
||||||
|
{
|
||||||
|
if (e.buttonDown)
|
||||||
|
moveClickArea(new Point(e.stageX, e.stageY));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -3,6 +3,7 @@ package
|
||||||
import flash.display.Shape;
|
import flash.display.Shape;
|
||||||
import flash.display.Sprite;
|
import flash.display.Sprite;
|
||||||
import flash.events.Event;
|
import flash.events.Event;
|
||||||
|
import flash.events.KeyboardEvent;
|
||||||
import flash.events.MouseEvent;
|
import flash.events.MouseEvent;
|
||||||
import flash.geom.Point;
|
import flash.geom.Point;
|
||||||
import flash.text.StyleSheet;
|
import flash.text.StyleSheet;
|
||||||
|
@ -13,56 +14,45 @@ package
|
||||||
* ...
|
* ...
|
||||||
* @author jjp
|
* @author jjp
|
||||||
*/
|
*/
|
||||||
public class GamePlayer extends Sprite
|
public class GamePlayer extends Game
|
||||||
{
|
{
|
||||||
private var videotube:Videotube;
|
private var fAlive: Boolean;
|
||||||
private var gamedisc:Gamedisc;
|
public override function GamePlayer(videotube:Videotube, gamedisc:Gamedisc) {
|
||||||
private var clickarea:ClickArea;
|
super(videotube, gamedisc);
|
||||||
private var textDeath:TextField;
|
fAlive = true;
|
||||||
|
|
||||||
public function GamePlayer(videotube:Videotube, gamedisc:Gamedisc)
|
|
||||||
{
|
|
||||||
this.videotube = videotube;
|
|
||||||
this.gamedisc = gamedisc;
|
|
||||||
clickarea = null;
|
|
||||||
textDeath = null;
|
|
||||||
addEventListener(Event.ADDED_TO_STAGE, init);
|
|
||||||
}
|
}
|
||||||
private function init(e:Event):void
|
protected override function onResume():void
|
||||||
{
|
{
|
||||||
removeEventListener(Event.ADDED_TO_STAGE, init);
|
super.onResume();
|
||||||
addEventListener(Event.REMOVED_FROM_STAGE, cleanup);
|
|
||||||
|
|
||||||
addEventListener(MouseEvent.CLICK, onClick);
|
addEventListener(MouseEvent.CLICK, onClick);
|
||||||
videotube.addEventListener(EventQte.QTE, onQte);
|
videotube.addEventListener(EventQte.QTE, onQte);
|
||||||
videotube.addEventListener(EventQte.QTE_TIMEOUT, onTimeout);
|
videotube.addEventListener(EventQte.QTE_TIMEOUT, onTimeout);
|
||||||
|
stage.addEventListener(KeyboardEvent.KEY_UP, onKey);
|
||||||
}
|
}
|
||||||
private function cleanup(e:Event):void
|
protected override function onPause():void
|
||||||
{
|
{
|
||||||
removeEventListener(Event.REMOVED_FROM_STAGE, cleanup);
|
super.onPause();
|
||||||
removeEventListener(MouseEvent.CLICK, onClick);
|
removeEventListener(MouseEvent.CLICK, onClick);
|
||||||
videotube.removeEventListener(EventQte.QTE, onQte);
|
videotube.removeEventListener(EventQte.QTE, onQte);
|
||||||
|
videotube.removeEventListener(EventQte.QTE_TIMEOUT, onTimeout);
|
||||||
|
stage.removeEventListener(KeyboardEvent.KEY_UP, onKey);
|
||||||
|
}
|
||||||
|
protected override function fPlaying():Boolean {
|
||||||
|
return fAlive;
|
||||||
}
|
}
|
||||||
private function onQte(e:EventQte):void
|
private function onQte(e:EventQte):void
|
||||||
{
|
{
|
||||||
|
trace(e.qte.secTrigger() + "gameplayer start" + e.qte.secTimeout());
|
||||||
clearClickarea();
|
clearClickarea();
|
||||||
clickarea = new ClickArea(e.qte.rgpoint, 0xffff00, 0.7);
|
clickarea = new ClickArea(e.qte.center, e.qte.radius, 0x4444ee, 0.4);
|
||||||
addChild(clickarea);
|
addChild(clickarea);
|
||||||
}
|
}
|
||||||
private function onTimeout(e:EventQte):void
|
private function onTimeout(e:EventQte):void
|
||||||
{
|
{
|
||||||
if (clickarea != null)
|
trace("gameplayer timeout");
|
||||||
{
|
if (clickarea != null) {
|
||||||
videotube.pause();
|
pushText("OH SHIT\n\nhit R to restart", 0x0000FF, 0xFF0000);
|
||||||
textDeath = new TextField();
|
fAlive = false;
|
||||||
textDeath.htmlText = "<p align='center'>YOU ARE DEAD</p>";
|
|
||||||
textDeath.wordWrap = true;
|
|
||||||
textDeath.background = true;
|
|
||||||
textDeath.backgroundColor = 0x0000FF;
|
|
||||||
textDeath.width = stage.stageWidth;
|
|
||||||
textDeath.height = stage.stageHeight;
|
|
||||||
textDeath.setTextFormat(new TextFormat(null, 164, 0xFF0000));
|
|
||||||
addChild(textDeath);
|
|
||||||
}
|
}
|
||||||
clearClickarea();
|
clearClickarea();
|
||||||
}
|
}
|
||||||
|
@ -71,13 +61,14 @@ package
|
||||||
if (clickarea != null && clickarea.FHit(new Point(mouse.stageX, mouse.stageY)))
|
if (clickarea != null && clickarea.FHit(new Point(mouse.stageX, mouse.stageY)))
|
||||||
clearClickarea();
|
clearClickarea();
|
||||||
}
|
}
|
||||||
private function clearClickarea():void
|
private function onKey(event:KeyboardEvent):void {
|
||||||
{
|
if (!fAlive && event.keyCode == 82) {
|
||||||
if (clickarea != null)
|
fAlive = true;
|
||||||
{
|
popText();
|
||||||
removeChild(clickarea);
|
videotube.seek(0);
|
||||||
clickarea = null;
|
videotube.resume();
|
||||||
}
|
}
|
||||||
|
trace("key:", event.keyCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
130
src/Gamedisc.as
130
src/Gamedisc.as
|
@ -1,8 +1,12 @@
|
||||||
package
|
package
|
||||||
{
|
{
|
||||||
import com.adobe.serialization.json.JSON;
|
import com.adobe.serialization.json.JSON;
|
||||||
|
import flash.display.IBitmapDrawable;
|
||||||
|
import flash.events.Event;
|
||||||
import flash.events.EventDispatcher;
|
import flash.events.EventDispatcher;
|
||||||
|
import flash.events.IOErrorEvent;
|
||||||
import flash.net.sendToURL;
|
import flash.net.sendToURL;
|
||||||
|
import flash.net.URLLoader;
|
||||||
import flash.net.URLRequest;
|
import flash.net.URLRequest;
|
||||||
import flash.net.URLRequestHeader;
|
import flash.net.URLRequestHeader;
|
||||||
import flash.net.URLRequestMethod;
|
import flash.net.URLRequestMethod;
|
||||||
|
@ -17,29 +21,121 @@ package
|
||||||
public static const VIDEOTUBE_YOUTUBE:String = "yt";
|
public static const VIDEOTUBE_YOUTUBE:String = "yt";
|
||||||
|
|
||||||
public var urlVideo:String;
|
public var urlVideo:String;
|
||||||
public var urlPostQte:String;
|
|
||||||
public var headerPostQte:Object;
|
|
||||||
public var typeVideotube:String;
|
public var typeVideotube:String;
|
||||||
public var rgqte:Array;
|
public var rgqte:Array;
|
||||||
|
|
||||||
|
protected var urlPostQte:String;
|
||||||
|
protected var csrf:String;
|
||||||
|
protected var queuePost:Array;
|
||||||
|
|
||||||
public function Gamedisc(urlVideo:String = null, typeVideotube:String = null)
|
public function Gamedisc(urlVideo:String = null, typeVideotube:String = null)
|
||||||
{
|
{
|
||||||
this.urlVideo = urlVideo;
|
this.urlVideo = urlVideo;
|
||||||
this.typeVideotube = typeVideotube;
|
this.typeVideotube = typeVideotube;
|
||||||
this.rgqte = [];
|
this.rgqte = [];
|
||||||
|
this.urlPostQte = null;
|
||||||
|
this.csrf = null;
|
||||||
|
this.queuePost = [];
|
||||||
}
|
}
|
||||||
public function AddQte(qte:Qte):void
|
public function setUrlPost(urlPostQte:String, csrf:String):void {
|
||||||
|
trace("setting url", urlPostQte, csrf);
|
||||||
|
this.urlPostQte = urlPostQte;
|
||||||
|
this.csrf = csrf;
|
||||||
|
}
|
||||||
|
public function fCanEdit():Boolean {
|
||||||
|
return urlPostQte != null;
|
||||||
|
}
|
||||||
|
public function AddQte(qte:Qte, videotube:Videotube):void
|
||||||
{
|
{
|
||||||
rgqte.splice(Math.abs(Util.binarySearch(rgqte, qte, Qte.compare)), 0, qte);
|
var iqte:int = Math.abs(Util.binarySearch(rgqte, qte, Qte.compare));
|
||||||
if (urlPostQte != null)
|
var cqteDrop:int = 0;
|
||||||
{
|
while (true) {
|
||||||
|
var iqteToDrop:int = iqte + cqteDrop;
|
||||||
|
if (iqteToDrop >= rgqte.length)
|
||||||
|
break;
|
||||||
|
if (rgqte[iqteToDrop].secTrigger() <= qte.secTimeout()) {
|
||||||
|
cqteDrop ++;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (iqte > 0 && rgqte[iqte - 1].secTimeout() >= qte.secTrigger()) {
|
||||||
|
iqte --;
|
||||||
|
cqteDrop ++;
|
||||||
|
}
|
||||||
|
rgqte.splice(iqte, cqteDrop, qte);
|
||||||
|
|
||||||
|
Util.assert(qte.secTrigger() == videotube.time());
|
||||||
|
videotube.onQtesChanged(iqte + 1, qte);
|
||||||
|
}
|
||||||
|
public function DeleteQte(qte:Qte, videotube:Videotube):void
|
||||||
|
{
|
||||||
|
var iqte:int = Util.binarySearch(rgqte, qte, Qte.compare);
|
||||||
|
Util.assert(iqte >= 0);
|
||||||
|
rgqte.splice(iqte, 1);
|
||||||
|
|
||||||
|
post("delete", { 'ms_trigger': qte.msTrigger } );
|
||||||
|
videotube.onQtesChanged(iqte, null);
|
||||||
|
}
|
||||||
|
protected function post(action: String, val:Object):void {
|
||||||
|
if (urlPostQte != null) {
|
||||||
|
val['action'] = action;
|
||||||
|
val['csrf'] = csrf;
|
||||||
|
queuePost.push(JSON.encode(val));
|
||||||
|
if (queuePost.length == 1) {
|
||||||
|
doNextPost();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected function doNextPost(): void {
|
||||||
|
if (queuePost.length > 0) {
|
||||||
var req:URLRequest = new URLRequest(urlPostQte);
|
var req:URLRequest = new URLRequest(urlPostQte);
|
||||||
req.method = URLRequestMethod.POST;
|
req.method = URLRequestMethod.POST;
|
||||||
for (var key:String in headerPostQte)
|
req.data = queuePost.shift();
|
||||||
req.requestHeaders.push(new URLRequestHeader(key, headerPostQte[key]));
|
req.contentType = 'application/json';
|
||||||
var data:URLVariables = new URLVariables();
|
var loader:URLLoader = new URLLoader();
|
||||||
data.qte = JSON.encode(qte.ToJson());
|
loader.addEventListener(Event.COMPLETE, onPostComplete);
|
||||||
req.data = data;
|
loader.addEventListener(IOErrorEvent.IO_ERROR, onPostFailed);
|
||||||
sendToURL(req);
|
loader.load(req);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected function onPostComplete(event:Event): void {
|
||||||
|
event.target.removeEventListener(Event.COMPLETE, onPostComplete);
|
||||||
|
event.target.removeEventListener(IOErrorEvent.IO_ERROR, onPostFailed);
|
||||||
|
try {
|
||||||
|
var result:Object = JSON.decode(event.target.data);
|
||||||
|
csrf = result.csrf;
|
||||||
|
|
||||||
|
if (result.err != 'ok') {
|
||||||
|
if (result.err == 'invalid') {
|
||||||
|
reportError("Sorry, another browser has begun editing the video.");
|
||||||
|
} else if (result.err == 'expired') {
|
||||||
|
reportError("Sorry, your editing session has timed out.");
|
||||||
|
} else {
|
||||||
|
reportError();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
doNextPost();
|
||||||
|
}
|
||||||
|
} catch (e:Error) {
|
||||||
|
trace(e);
|
||||||
|
reportError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected function onPostFailed(event:Event): void {
|
||||||
|
event.target.removeEventListener(Event.COMPLETE, onPostComplete);
|
||||||
|
event.target.removeEventListener(IOErrorEvent.IO_ERROR, onPostFailed);
|
||||||
|
reportError();
|
||||||
|
}
|
||||||
|
protected function reportError(error:String = "Sorry, something weird happened. It's my fault. Reload the page to try again."): void {
|
||||||
|
Main.instance.fatalError(error);
|
||||||
|
}
|
||||||
|
public function repostQte(qte:Qte): void
|
||||||
|
{
|
||||||
|
if (qte.fDirty && urlPostQte != null)
|
||||||
|
{
|
||||||
|
post("put", { 'qte': qte.ToJson() } );
|
||||||
|
qte.fDirty = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function CreateVideotube():Videotube
|
public function CreateVideotube():Videotube
|
||||||
|
@ -60,19 +156,17 @@ package
|
||||||
json.urlPostQte = urlPostQte;
|
json.urlPostQte = urlPostQte;
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
public function FromJson(json:Object, jsonPostHeaders:Object):void
|
public function FromJson(json:Object):void
|
||||||
{
|
{
|
||||||
rgqte = [];
|
rgqte = [];
|
||||||
for each (var jsonQte:Object in json.rgqte)
|
for each (var jsonQte:Object in json.qtes)
|
||||||
{
|
{
|
||||||
var qte:Qte = new Qte();
|
var qte:Qte = new Qte();
|
||||||
qte.FromJson(jsonQte);
|
qte.FromJson(jsonQte);
|
||||||
rgqte.push(qte);
|
rgqte.push(qte);
|
||||||
}
|
}
|
||||||
urlVideo = json.urlVideo;
|
urlVideo = json.url;
|
||||||
typeVideotube = json.typeVideotube;
|
typeVideotube = json.ktube;
|
||||||
urlPostQte = json.urlPostQte;
|
|
||||||
headerPostQte = jsonPostHeaders;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
42
src/Main.as
42
src/Main.as
|
@ -7,6 +7,7 @@ package
|
||||||
import flash.events.MouseEvent;
|
import flash.events.MouseEvent;
|
||||||
import flash.external.ExternalInterface;
|
import flash.external.ExternalInterface;
|
||||||
import flash.geom.Point;
|
import flash.geom.Point;
|
||||||
|
import flash.text.TextField;
|
||||||
import flash.ui.Keyboard;
|
import flash.ui.Keyboard;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,11 +20,25 @@ package
|
||||||
private var gamedisc:Gamedisc;
|
private var gamedisc:Gamedisc;
|
||||||
private var gameeditor:GameEditor;
|
private var gameeditor:GameEditor;
|
||||||
private var gameplayer:GamePlayer;
|
private var gameplayer:GamePlayer;
|
||||||
|
private var debug:Boolean;
|
||||||
|
|
||||||
|
public static var instance:Main;
|
||||||
|
|
||||||
public function Main():void
|
public function Main():void
|
||||||
{
|
{
|
||||||
gamedisc = new Gamedisc();
|
instance = this;
|
||||||
gamedisc.FromJson(JSON.decode(loaderInfo.parameters.jsonDisc), JSON.decode(loaderInfo.parameters.jsonPostHeaders));
|
if (loaderInfo.parameters.jsonDisc) {
|
||||||
|
gamedisc = new Gamedisc();
|
||||||
|
gamedisc.FromJson(JSON.decode(loaderInfo.parameters.jsonDisc));
|
||||||
|
trace("+++LOADING+++", loaderInfo.parameters.urlPostQte, loaderInfo.parameters.csrf);
|
||||||
|
if (loaderInfo.parameters.urlPostQte && loaderInfo.parameters.csrf) {
|
||||||
|
gamedisc.setUrlPost(JSON.decode(loaderInfo.parameters.urlPostQte), JSON.decode(loaderInfo.parameters.csrf));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// debugging
|
||||||
|
gamedisc = new Gamedisc("The%20Last%20Eichhof%20-%20Longplay.flv", Gamedisc.VIDEOTUBE_FLV);
|
||||||
|
debug = true;
|
||||||
|
}
|
||||||
videotube = gamedisc.CreateVideotube();
|
videotube = gamedisc.CreateVideotube();
|
||||||
if (stage) init();
|
if (stage) init();
|
||||||
else addEventListener(Event.ADDED_TO_STAGE, init);
|
else addEventListener(Event.ADDED_TO_STAGE, init);
|
||||||
|
@ -61,19 +76,34 @@ package
|
||||||
gameplayer = new GamePlayer(videotube, gamedisc);
|
gameplayer = new GamePlayer(videotube, gamedisc);
|
||||||
addChild(gameplayer);
|
addChild(gameplayer);
|
||||||
}
|
}
|
||||||
videotube.seek(0);
|
videotube.enqueue();
|
||||||
}
|
}
|
||||||
private function onVideotubeReady(event:Event = null):void
|
private function onVideotubeReady(event:Event = null):void
|
||||||
{
|
{
|
||||||
toggleGame();
|
toggleGame();
|
||||||
if (gamedisc.urlPostQte == null)
|
if (!gamedisc.fCanEdit())
|
||||||
toggleGame();
|
toggleGame();
|
||||||
videotube.play();
|
|
||||||
}
|
}
|
||||||
private function onKey(key:KeyboardEvent):void
|
private function onKey(key:KeyboardEvent):void
|
||||||
{
|
{
|
||||||
if (key.keyCode == Keyboard.SPACE && gamedisc.urlPostQte != null)
|
if (key.keyCode == Keyboard.SPACE && debug)
|
||||||
toggleGame();
|
toggleGame();
|
||||||
}
|
}
|
||||||
|
public function fatalError(message:String):void {
|
||||||
|
var text:TextField = Util.addTextFieldFullScreen(this);
|
||||||
|
Util.setText(text, message, 64, 0xffffff, 0x440000);
|
||||||
|
if (gameplayer)
|
||||||
|
removeChild(gameplayer);
|
||||||
|
if (gameeditor)
|
||||||
|
removeChild(gameeditor);
|
||||||
|
if (videotube) {
|
||||||
|
videotube.pause();
|
||||||
|
removeChild(videotube);
|
||||||
|
}
|
||||||
|
gameplayer = null;
|
||||||
|
gameeditor = null;
|
||||||
|
videotube = null;
|
||||||
|
stage.removeEventListener(KeyboardEvent.KEY_UP, onKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
55
src/Qte.as
55
src/Qte.as
|
@ -7,39 +7,62 @@ package
|
||||||
*/
|
*/
|
||||||
public class Qte
|
public class Qte
|
||||||
{
|
{
|
||||||
public var rgpoint:Array;
|
public var center:Point;
|
||||||
public var secTrigger:Number;
|
public var radius:Number;
|
||||||
|
public var msTrigger:int;
|
||||||
|
public var msTimeout:int;
|
||||||
|
public var fDirty:Boolean;
|
||||||
|
|
||||||
public function Qte(rgpoint: Array = null, secTrigger:Number = -1)
|
public function Qte(center: Point = null, radius: Number = -1, secTrigger:Number = -1, secTimeout:Number = -1, fDirty: Boolean = false)
|
||||||
{
|
{
|
||||||
this.rgpoint = rgpoint;
|
this.center = center;
|
||||||
this.secTrigger = secTrigger;
|
this.radius = radius;
|
||||||
|
if (secTrigger >= 0)
|
||||||
|
this.msTrigger = int(secTrigger * 1000);
|
||||||
|
else
|
||||||
|
this.msTrigger = -1;
|
||||||
|
|
||||||
|
if (secTimeout >= 0) {
|
||||||
|
this.msTimeout = int(secTimeout * 1000);
|
||||||
|
Util.assert(msTimeout > msTrigger);
|
||||||
|
} else if (msTrigger >= 0) {
|
||||||
|
msTimeout = msTrigger + 1000; // 1 second timeout by default
|
||||||
|
} else {
|
||||||
|
msTimeout = -1;
|
||||||
|
}
|
||||||
|
this.fDirty = fDirty;
|
||||||
|
}
|
||||||
|
public function moveTo(center: Point): void
|
||||||
|
{
|
||||||
|
fDirty = true;
|
||||||
|
this.center = center;
|
||||||
}
|
}
|
||||||
public static function compare(qte1:Qte, qte2:Qte):int
|
public static function compare(qte1:Qte, qte2:Qte):int
|
||||||
{
|
{
|
||||||
if (qte1.secTrigger == qte2.secTrigger)
|
if (qte1.msTrigger == qte2.msTrigger)
|
||||||
return 0;
|
return 0;
|
||||||
else if (qte1.secTrigger < qte2.secTrigger)
|
else if (qte1.msTrigger < qte2.msTrigger)
|
||||||
return -1;
|
return -1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
public function secTrigger():Number
|
||||||
|
{
|
||||||
|
return msTrigger / 1000.0;
|
||||||
|
}
|
||||||
public function secTimeout():Number
|
public function secTimeout():Number
|
||||||
{
|
{
|
||||||
return secTrigger + 1.0;
|
return secTrigger() + 1.0;
|
||||||
}
|
}
|
||||||
public function ToJson():Object
|
public function ToJson():Object
|
||||||
{
|
{
|
||||||
var jsonRgpoint:Array = [];
|
return { shape: {center: [center.x, center.y], radius: radius}, ms_trigger: msTrigger, ms_finish: msTimeout };
|
||||||
for each(var point:Point in rgpoint)
|
|
||||||
jsonRgpoint.push([point.x, point.y]);
|
|
||||||
return { rgpoint: jsonRgpoint, secTrigger: secTrigger };
|
|
||||||
}
|
}
|
||||||
public function FromJson(json:Object):void
|
public function FromJson(json:Object):void
|
||||||
{
|
{
|
||||||
rgpoint = []
|
center = new Point(json.shape.center[0], json.shape.center[1]);
|
||||||
for each(var jsonPoint:Array in json.rgpoint)
|
radius = json.shape.radius;
|
||||||
rgpoint.push(new Point(jsonPoint[0], jsonPoint[1]));
|
msTrigger = json.ms_trigger;
|
||||||
secTrigger = json.secTrigger;
|
msTimeout = json.ms_finish;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
35
src/Util.as
35
src/Util.as
|
@ -1,7 +1,15 @@
|
||||||
package
|
package
|
||||||
{
|
{
|
||||||
import com.adobe.serialization.json.JSON;
|
import com.adobe.serialization.json.JSON;
|
||||||
|
import flash.display.Bitmap;
|
||||||
|
import flash.display.BitmapData;
|
||||||
|
import flash.display.DisplayObject;
|
||||||
|
import flash.display.DisplayObjectContainer;
|
||||||
|
import flash.display.Shape;
|
||||||
|
import flash.display.Sprite;
|
||||||
import flash.external.ExternalInterface;
|
import flash.external.ExternalInterface;
|
||||||
|
import flash.text.TextField;
|
||||||
|
import flash.text.TextFormat;
|
||||||
/**
|
/**
|
||||||
* ...
|
* ...
|
||||||
* @author jjp
|
* @author jjp
|
||||||
|
@ -33,6 +41,31 @@ package
|
||||||
{
|
{
|
||||||
ExternalInterface.call("alert", JSON.encode(rgo));
|
ExternalInterface.call("alert", JSON.encode(rgo));
|
||||||
}
|
}
|
||||||
|
public static function assert(cond:Boolean, msg:String = "Assertion failed"): void
|
||||||
|
{
|
||||||
|
if (!cond) {
|
||||||
|
throw new Error(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static function BitmapFromSprite(sprite: DisplayObject):Bitmap
|
||||||
|
{
|
||||||
|
var bitmapData:BitmapData = new BitmapData(sprite.width, sprite.height);
|
||||||
|
bitmapData.draw(sprite);
|
||||||
|
return new Bitmap(bitmapData);
|
||||||
|
}
|
||||||
|
public static function addTextFieldFullScreen(parent: DisplayObjectContainer): TextField {
|
||||||
|
var text:TextField = new TextField();
|
||||||
|
text.wordWrap = true;
|
||||||
|
text.background = true;
|
||||||
|
text.width = parent.stage.stageWidth;
|
||||||
|
text.height = parent.stage.stageHeight;
|
||||||
|
parent.addChild(text);
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
public static function setText(text:TextField, html:String, size:int, bgcolor:int, fgcolor:int):void {
|
||||||
|
text.htmlText = "<p align='center'>" + html + "</p>";
|
||||||
|
text.backgroundColor = bgcolor;
|
||||||
|
text.setTextFormat(new TextFormat(null, size, fgcolor));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -3,6 +3,8 @@ package
|
||||||
import flash.display.Sprite;
|
import flash.display.Sprite;
|
||||||
import flash.events.Event;
|
import flash.events.Event;
|
||||||
import flash.events.EventDispatcher;
|
import flash.events.EventDispatcher;
|
||||||
|
import flash.text.TextField;
|
||||||
|
import flash.text.TextFormat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ...
|
* ...
|
||||||
|
@ -11,9 +13,10 @@ package
|
||||||
public class Videotube extends Sprite
|
public class Videotube extends Sprite
|
||||||
{
|
{
|
||||||
public static const READY:String = "videotube-ready";
|
public static const READY:String = "videotube-ready";
|
||||||
|
private static const DEBUG_VIDEO:Boolean = false;
|
||||||
|
|
||||||
public function fready():Boolean { throw "not implemented"; }
|
public function fready():Boolean { throw "not implemented"; }
|
||||||
public function play():void { throw "not implemented"; }
|
public function enqueue():void { throw "not implemented"; }
|
||||||
public function pause():void { throw "not implemented"; }
|
public function pause():void { throw "not implemented"; }
|
||||||
public function resume():void { throw "not implemented"; }
|
public function resume():void { throw "not implemented"; }
|
||||||
public function time():Number { throw "not implemented"; }
|
public function time():Number { throw "not implemented"; }
|
||||||
|
@ -21,84 +24,132 @@ package
|
||||||
|
|
||||||
private var secPrev:Number;
|
private var secPrev:Number;
|
||||||
private var iqte:int;
|
private var iqte:int;
|
||||||
private var iqtePrev:int;
|
private var qtePrev:Qte;
|
||||||
protected var gamedisc:Gamedisc;
|
protected var gamedisc:Gamedisc;
|
||||||
|
private var textDebug:TextField;
|
||||||
public function Videotube(gamedisc: Gamedisc)
|
public function Videotube(gamedisc: Gamedisc)
|
||||||
{
|
{
|
||||||
this.gamedisc = gamedisc;
|
this.gamedisc = gamedisc;
|
||||||
secPrev = 0;
|
secPrev = 0;
|
||||||
iqte = 0;
|
iqte = 0;
|
||||||
iqtePrev = 0;
|
qtePrev = null;
|
||||||
|
if (DEBUG_VIDEO) {
|
||||||
|
textDebug = new TextField();
|
||||||
|
textDebug.x = 0;
|
||||||
|
textDebug.y = 0;
|
||||||
|
textDebug.width = 640;
|
||||||
|
textDebug.height = 70;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function seek(sec:Number):void
|
public function seek(sec:Number):void
|
||||||
{
|
{
|
||||||
|
trace("seeking");
|
||||||
seekI(sec);
|
seekI(sec);
|
||||||
if (iqtePrev != -1)
|
cancelPrev();
|
||||||
{
|
|
||||||
dispatchEvent(new EventQte(EventQte.QTE_CANCEL, gamedisc.rgqte[iqtePrev]));
|
|
||||||
iqtePrev = -1;
|
|
||||||
}
|
|
||||||
iqte = -1;
|
iqte = -1;
|
||||||
|
trace("seek to " + sec + ":" + iqte);
|
||||||
}
|
}
|
||||||
// returns true if triggered
|
// returns true if triggered
|
||||||
private function Trigger(iqte:int, ev:String, secNow:Number): Boolean
|
private function Trigger(qte:Qte, ev:String, secNow:Number): Boolean
|
||||||
{
|
{
|
||||||
if (iqte >= 0 && iqte < gamedisc.rgqte.length)
|
if (qte != null)
|
||||||
{
|
{
|
||||||
var qte:Qte = gamedisc.rgqte[iqte];
|
|
||||||
var secQte:Number;
|
var secQte:Number;
|
||||||
if (ev == EventQte.QTE)
|
if (ev == EventQte.QTE)
|
||||||
secQte = qte.secTrigger;
|
secQte = qte.secTrigger();
|
||||||
else
|
else
|
||||||
secQte = qte.secTimeout();
|
secQte = qte.secTimeout();
|
||||||
|
//trace("testing " + iqte + " for " + ev + " " + secQte + " in " + secPrev + ":" + secNow);
|
||||||
if (Util.FInTimespan(secQte, secPrev, secNow))
|
if (Util.FInTimespan(secQte, secPrev, secNow))
|
||||||
{
|
{
|
||||||
|
trace("triggered " + ev);
|
||||||
dispatchEvent(new EventQte(ev, qte));
|
dispatchEvent(new EventQte(ev, qte));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
protected function cancelPrev():void {
|
||||||
|
if (qtePrev != null) {
|
||||||
|
dispatchEvent(new EventQte(EventQte.QTE_CANCEL, qtePrev));
|
||||||
|
qtePrev = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
protected function tick(e: Event):void
|
protected function tick(e: Event):void
|
||||||
{
|
{
|
||||||
var secNow:Number = time();
|
var secNow:Number = time();
|
||||||
var fPrevQteProcessed:Boolean = false;
|
var fPrevQteProcessed:Boolean = false;
|
||||||
var fQteProcessed:Boolean = false;
|
var fQteProcessed:Boolean = false;
|
||||||
|
if (secNow < secPrev) {
|
||||||
|
iqte = -1;
|
||||||
|
cancelPrev();
|
||||||
|
secPrev = secNow;
|
||||||
|
}
|
||||||
if (iqte < 0)
|
if (iqte < 0)
|
||||||
{
|
{
|
||||||
iqte = Util.binarySearch(gamedisc.rgqte, secNow, function(qte:Qte, secNow:Number):int {
|
trace("finding qte for time " + secNow);
|
||||||
if (qte.secTrigger < secNow)
|
iqte = Math.abs(Util.binarySearch(gamedisc.rgqte, secNow, function(qte:Qte, secNow:Number):int {
|
||||||
|
if (qte.secTrigger() < secNow)
|
||||||
return -1;
|
return -1;
|
||||||
if (qte.secTrigger > secNow)
|
if (qte.secTrigger() > secNow)
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
});
|
}));
|
||||||
iqtePrev = iqte;
|
cancelPrev();
|
||||||
|
if (iqte < gamedisc.rgqte.length)
|
||||||
|
trace("found: " + iqte + " at " + gamedisc.rgqte[iqte].secTrigger());
|
||||||
|
else
|
||||||
|
trace("at end of qtes");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// we loop here so that, in the event of being passed bad data, we still do something vaguely sensible.
|
// we loop here so that, in the event of being passed bad data, we still do something vaguely sensible.
|
||||||
while (!fPrevQteProcessed && !fQteProcessed)
|
while (!fPrevQteProcessed && !fQteProcessed)
|
||||||
{
|
{
|
||||||
if (Trigger(iqtePrev, EventQte.QTE_TIMEOUT, secNow))
|
//trace(secNow + ":: prev" + iqtePrev + ", iqte" + iqte);
|
||||||
|
if (Trigger(qtePrev, EventQte.QTE_TIMEOUT, secNow))
|
||||||
{
|
{
|
||||||
fPrevQteProcessed = false;
|
fPrevQteProcessed = false;
|
||||||
iqtePrev ++;
|
qtePrev = null;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
fPrevQteProcessed = true;
|
fPrevQteProcessed = true;
|
||||||
|
|
||||||
if (Trigger(iqte, EventQte.QTE, secNow))
|
var qte:Qte = null;
|
||||||
|
if (iqte >= 0 && iqte < gamedisc.rgqte.length)
|
||||||
|
qte = gamedisc.rgqte[iqte];
|
||||||
|
if (Trigger(qte, EventQte.QTE, secNow))
|
||||||
{
|
{
|
||||||
|
Util.assert(qtePrev == null);
|
||||||
fQteProcessed = false;
|
fQteProcessed = false;
|
||||||
iqte ++;
|
iqte ++;
|
||||||
|
qtePrev = qte;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
fQteProcessed = true;
|
fQteProcessed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (DEBUG_VIDEO) {
|
||||||
|
var txt:String = int(secNow * 1000) + "ms";
|
||||||
|
if (iqte < gamedisc.rgqte.length)
|
||||||
|
txt += " | next qte at " + gamedisc.rgqte[iqte].msTrigger;
|
||||||
|
if (qtePrev != null)
|
||||||
|
txt += " | qte over at " + qtePrev.msTimeout;
|
||||||
|
textDebug.htmlText = txt;
|
||||||
|
textDebug.backgroundColor = 0x000000;
|
||||||
|
textDebug.setTextFormat(new TextFormat(null, 16, 0xffffff));
|
||||||
|
if (textDebug.parent == this)
|
||||||
|
removeChild(textDebug);
|
||||||
|
addChild(textDebug);
|
||||||
|
}
|
||||||
|
|
||||||
secPrev = secNow;
|
secPrev = secNow;
|
||||||
}
|
}
|
||||||
|
public function onQtesChanged(iqteNext: int, qtePrev:Qte): void {
|
||||||
|
iqte = iqteNext;
|
||||||
|
cancelPrev();
|
||||||
|
this.qtePrev = qtePrev;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -38,11 +38,15 @@ package
|
||||||
removeEventListener(Event.REMOVED_FROM_STAGE, cleanup);
|
removeEventListener(Event.REMOVED_FROM_STAGE, cleanup);
|
||||||
stage.removeEventListener(Event.ENTER_FRAME, tick);
|
stage.removeEventListener(Event.ENTER_FRAME, tick);
|
||||||
}
|
}
|
||||||
public override function fready():Boolean { return true; }
|
public override function fready():Boolean { return true; }
|
||||||
public override function play():void { stream.play(gamedisc.urlVideo); }
|
|
||||||
public override function pause():void { stream.pause(); }
|
public override function pause():void { stream.pause(); }
|
||||||
public override function resume():void { stream.resume(); }
|
public override function resume():void { stream.resume(); }
|
||||||
public override function time():Number { return stream.time; }
|
public override function time():Number { return stream.time; }
|
||||||
public override function seek(sec:Number):void { stream.seek(sec); }
|
protected override function seekI(sec:Number):void { stream.seek(sec); }
|
||||||
|
public override function enqueue():void {
|
||||||
|
seek(0);
|
||||||
|
stream.play(gamedisc.urlVideo);
|
||||||
|
stream.pause();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,6 +16,7 @@ package
|
||||||
{
|
{
|
||||||
super(gamedisc);
|
super(gamedisc);
|
||||||
Security.allowDomain("www.youtube.com");
|
Security.allowDomain("www.youtube.com");
|
||||||
|
Security.allowDomain("*.ytimage.com");
|
||||||
player = null;
|
player = null;
|
||||||
loader = new Loader();
|
loader = new Loader();
|
||||||
loader.contentLoaderInfo.addEventListener(Event.INIT, onLoaderInit);
|
loader.contentLoaderInfo.addEventListener(Event.INIT, onLoaderInit);
|
||||||
|
@ -23,12 +24,23 @@ package
|
||||||
}
|
}
|
||||||
private function onLoaderInit(event:Event):void
|
private function onLoaderInit(event:Event):void
|
||||||
{
|
{
|
||||||
|
trace("yt: loader init");
|
||||||
addChild(loader);
|
addChild(loader);
|
||||||
loader.contentLoaderInfo.removeEventListener(Event.INIT, onLoaderInit);
|
loader.contentLoaderInfo.removeEventListener(Event.INIT, onLoaderInit);
|
||||||
loader.content.addEventListener("onReady", onPlayerReady);
|
player = loader.content;
|
||||||
|
player.addEventListener("onReady", onPlayerReady);
|
||||||
|
player.addEventListener("onStateChange", onStateChange);
|
||||||
|
player.addEventListener("onError", onError);
|
||||||
|
}
|
||||||
|
private function onStateChange(event:Event):void {
|
||||||
|
trace("yt: state " + player.getPlayerState());
|
||||||
|
}
|
||||||
|
private function onError(event:Event):void {
|
||||||
|
trace("yt: error", Object(event).data);
|
||||||
}
|
}
|
||||||
private function onPlayerReady(event:Event):void
|
private function onPlayerReady(event:Event):void
|
||||||
{
|
{
|
||||||
|
trace("yt: player ready");
|
||||||
player = loader.content;
|
player = loader.content;
|
||||||
player.setSize(stage.stageWidth, stage.stageHeight);
|
player.setSize(stage.stageWidth, stage.stageHeight);
|
||||||
player.cueVideoById(gamedisc.urlVideo);
|
player.cueVideoById(gamedisc.urlVideo);
|
||||||
|
@ -36,11 +48,11 @@ package
|
||||||
stage.addEventListener(Event.ENTER_FRAME, tick);
|
stage.addEventListener(Event.ENTER_FRAME, tick);
|
||||||
dispatchEvent(new Event(Videotube.READY));
|
dispatchEvent(new Event(Videotube.READY));
|
||||||
}
|
}
|
||||||
public override function fready():Boolean { return player !== null; }
|
public override function fready():Boolean { return player !== null && player.getPlayerState() >= 0; }
|
||||||
public override function play():void { player.playVideo(); }
|
public override function enqueue():void { seek(0); }
|
||||||
public override function pause():void { player.pauseVideo(); }
|
public override function pause():void { player.pauseVideo(); }
|
||||||
public override function resume():void { player.playVideo(); }
|
public override function resume():void { player.playVideo(); }
|
||||||
public override function time():Number { return player.getCurrentTime(); }
|
public override function time():Number { return player.getCurrentTime(); }
|
||||||
public override function seek(sec:Number):void { player.seekTo(sec, true); }
|
protected override function seekI(sec:Number):void { player.seekTo(sec, true); }
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue