Add textual QTEs

This commit is contained in:
Jeremy Penner 2012-05-24 08:43:41 -04:00
parent 952097a307
commit d91609dcfa
8 changed files with 255 additions and 59 deletions

View file

@ -17,6 +17,11 @@ package
super(type); super(type);
this.qte = qte; this.qte = qte;
} }
public function qteCircle():QteCircle {
return qte as QteCircle;
}
public function qteText():QteText {
return qte as QteText;
}
} }
} }

View file

@ -1,9 +1,14 @@
package package
{ {
import flash.display.DisplayObject;
import flash.display.InteractiveObject;
import flash.display.Sprite; import flash.display.Sprite;
import flash.events.Event; import flash.events.Event;
import flash.events.FocusEvent;
import flash.geom.Point;
import flash.text.TextField; import flash.text.TextField;
import flash.text.TextFormat; import flash.text.TextFormat;
import flash.text.TextFormatAlign;
/** /**
* ... * ...
@ -16,6 +21,7 @@ package
protected var videotube:Videotube; protected var videotube:Videotube;
protected var gamedisc:Gamedisc; protected var gamedisc:Gamedisc;
protected var clickarea:ClickArea; protected var clickarea:ClickArea;
protected var typein:TextField;
protected var text:TextField; protected var text:TextField;
protected var textValues: Array; protected var textValues: Array;
public function Game(videotube:Videotube, gamedisc:Gamedisc) public function Game(videotube:Videotube, gamedisc:Gamedisc)
@ -31,8 +37,11 @@ package
stage.addEventListener(Event.ACTIVATE, onFocus); stage.addEventListener(Event.ACTIVATE, onFocus);
stage.addEventListener(Event.DEACTIVATE, onLoseFocus); stage.addEventListener(Event.DEACTIVATE, onLoseFocus);
stage.addEventListener(FocusEvent.KEY_FOCUS_CHANGE, preventWidgetFocusChange);
stage.addEventListener(FocusEvent.MOUSE_FOCUS_CHANGE, preventWidgetFocusChange);
clickarea = null; clickarea = null;
typein = null;
if (text != null) if (text != null)
removeChild(text); removeChild(text);
text = null; text = null;
@ -50,13 +59,19 @@ package
stage.removeEventListener(Event.ACTIVATE, onFocus); stage.removeEventListener(Event.ACTIVATE, onFocus);
stage.removeEventListener(Event.DEACTIVATE, onLoseFocus); stage.removeEventListener(Event.DEACTIVATE, onLoseFocus);
stage.removeEventListener(FocusEvent.KEY_FOCUS_CHANGE, preventWidgetFocusChange);
stage.removeEventListener(FocusEvent.MOUSE_FOCUS_CHANGE, preventWidgetFocusChange);
if (hasFocus) if (hasFocus)
onPause(); onPause();
clearClickarea(); clearClickarea();
} }
protected function focussedChild():InteractiveObject {
return null;
}
protected function onFocus(e:Event):void { protected function onFocus(e:Event):void {
trace("received focus"); trace("received focus");
trace(stage.focus);
popText(); popText();
hasFocus = true; hasFocus = true;
stage.addEventListener(Event.EXIT_FRAME, onFocusEnded); stage.addEventListener(Event.EXIT_FRAME, onFocusEnded);
@ -67,11 +82,16 @@ package
} }
protected function onLoseFocus(e:Event): void { protected function onLoseFocus(e:Event): void {
trace("lost focus"); trace("lost focus");
trace(stage.focus);
pushText("Paused\nCLICK TO PLAY", 0x000000, 0xFFFFFF); pushText("Paused\nCLICK TO PLAY", 0x000000, 0xFFFFFF);
hasFocus = false; hasFocus = false;
onPause(); onPause();
} }
protected function preventWidgetFocusChange(e:Event): void {
trace("preventing focus change");
e.preventDefault();
stage.focus = focussedChild();
}
protected function onPause(): void { protected function onPause(): void {
trace("onPause"); trace("onPause");
videotube.pause(); videotube.pause();
@ -84,6 +104,24 @@ package
protected function fPlaying(): Boolean { protected function fPlaying(): Boolean {
return false; return false;
} }
public function addClickarea(center:Point, radius:Number):void {
clearClickarea();
clickarea = new ClickArea(center, radius, 0x4444ee, 0.4)
addChild(clickarea);
}
public function addTypein(text:String):void {
clearTypein();
typein = new TextField();
typein.x = 0;
typein.y = stage.stageHeight / 2;
typein.width = stage.stageWidth;
typein.height = 64;
typein.background = true;
Util.setText(typein, text, 40, 0x222222, 0xffffff);
addChild(typein);
}
public function clearClickarea(): void public function clearClickarea(): void
{ {
if (clickarea != null) { if (clickarea != null) {
@ -91,9 +129,22 @@ package
clickarea = null; clickarea = null;
} }
} }
public function clearTypein(): void
{
if (typein != null) {
removeChild(typein);
typein = null;
}
}
public function clearQteUI(): void {
clearClickarea();
clearTypein();
}
protected function pushText(html:String, bgcolor:int, fgcolor:int): void { protected function pushText(html:String, bgcolor:int, fgcolor:int): void {
if (text == null) if (text == null) {
text = Util.addTextFieldFullScreen(this); text = Util.addTextFieldFullScreen(this);
text.selectable = false;
}
textValues.push( { 'html': html, 'bgcolor':bgcolor, 'fgcolor':fgcolor } ); textValues.push( { 'html': html, 'bgcolor':bgcolor, 'fgcolor':fgcolor } );
trace("saying: " + html); trace("saying: " + html);
Util.setText(text, html, 164, bgcolor, fgcolor); Util.setText(text, html, 164, bgcolor, fgcolor);

View file

@ -1,10 +1,14 @@
package package
{ {
import flash.display.Bitmap;
import flash.display.DisplayObject;
import flash.display.InteractiveObject;
import flash.display.Sprite; import flash.display.Sprite;
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; import flash.geom.Point;
import flash.text.TextFieldType;
/** /**
* ... * ...
* @author jjp * @author jjp
@ -12,6 +16,7 @@ package
public class GameEditor extends Game public class GameEditor extends Game
{ {
protected var qte:Qte; protected var qte:Qte;
protected var fTyping:Boolean;
public override function GameEditor(videotube:Videotube, gamedisc:Gamedisc) { public override function GameEditor(videotube:Videotube, gamedisc:Gamedisc) {
super(videotube, gamedisc); super(videotube, gamedisc);
qte = null; qte = null;
@ -20,6 +25,7 @@ package
{ {
super.onResume(); super.onResume();
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp); stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
stage.addEventListener(MouseEvent.MOUSE_DOWN, onClick); stage.addEventListener(MouseEvent.MOUSE_DOWN, onClick);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onDrag); stage.addEventListener(MouseEvent.MOUSE_MOVE, onDrag);
@ -31,6 +37,7 @@ package
{ {
super.onPause(); super.onPause();
stage.removeEventListener(KeyboardEvent.KEY_UP, onKeyUp); stage.removeEventListener(KeyboardEvent.KEY_UP, onKeyUp);
stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
stage.removeEventListener(MouseEvent.MOUSE_DOWN, onClick); stage.removeEventListener(MouseEvent.MOUSE_DOWN, onClick);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onDrag); stage.removeEventListener(MouseEvent.MOUSE_MOVE, onDrag);
@ -38,8 +45,14 @@ package
videotube.removeEventListener(EventQte.QTE_TIMEOUT, onQteEnd); videotube.removeEventListener(EventQte.QTE_TIMEOUT, onQteEnd);
videotube.removeEventListener(EventQte.QTE_CANCEL, onQteEnd); videotube.removeEventListener(EventQte.QTE_CANCEL, onQteEnd);
} }
override protected function focussedChild():InteractiveObject {
if (typein)
return typein;
return super.focussedChild();
}
protected override function fPlaying():Boolean { protected override function fPlaying():Boolean {
return true; return !fTyping;
} }
public function onQteBegin(e: EventQte):void public function onQteBegin(e: EventQte):void
{ {
@ -51,7 +64,12 @@ package
clearClickarea(); clearClickarea();
qte = null; qte = null;
} }
addClickArea(e.qte); qte = e.qte;
if (e.qteCircle()) {
addClickarea(e.qteCircle().center, e.qteCircle().radius);
} else if (e.qteText()) {
addTypein(e.qteText().text);
}
} }
} }
public function onQteEnd(e: EventQte):void public function onQteEnd(e: EventQte):void
@ -59,49 +77,87 @@ package
trace("editor qte end"); trace("editor qte end");
Util.assert(qte == e.qte); Util.assert(qte == e.qte);
gamedisc.repostQte(qte); gamedisc.repostQte(qte);
clearClickarea(); clearQteUI();
qte = null; qte = null;
} }
public function onKeyUp(key: KeyboardEvent):void public function onKeyUp(key: KeyboardEvent):void
{ {
if (key.keyCode == 46 && qte != null) {// delete if (!fTyping) {
gamedisc.DeleteQte(qte, videotube); if (key.keyCode == 46 && qte != null) {// delete
clearClickarea(); gamedisc.DeleteQte(qte, videotube);
qte = null; clearQteUI();
} else if (key.keyCode == 37) { // leftArrow qte = null;
videotube.seek(videotube.time() - 3); } else if (key.keyCode == 37) { // leftArrow
clearClickarea(); videotube.seek(videotube.time() - 3);
qte = null; clearQteUI();
} else if (key.keyCode == 39) { // rightArrow qte = null;
videotube.seek(videotube.time() + 3); } else if (key.keyCode == 39) { // rightArrow
clearClickarea(); videotube.seek(videotube.time() + 3);
qte = null; clearQteUI();
qte = null;
}
} else {
Util.assert(qte as QteText);
if (key.keyCode == 13) { // enter
var text:String = typein.text;
if (text.length > 0) {
trace("Creating QTE: " + text);
var qteText:QteText = qte as QteText;
qteText.text = text;
// 300ms per character + 500ms reaction time
qteText.msTimeout = ((text.length * 300) + 500) + qteText.msTrigger;
gamedisc.AddQte(qteText, videotube);
gamedisc.repostQte(qteText);
} else {
gamedisc.DeleteQte(qte, videotube);
qte = null;
clearTypein();
}
stage.focus = this;
fTyping = false;
videotube.resume();
}
} }
} }
private function addClickArea(qteNew: Qte):void private function onKeyDown(key:KeyboardEvent): void {
{ if (!fTyping && qte == null) {
qte = qteNew; if (key.charCode >= 0x20 && key.charCode <= 0x7e) { // printable character
clickarea = new ClickArea(qte.center, qte.radius, 0x4444ee, 0.4); var ch:String = String.fromCharCode(key.charCode);
addChild(clickarea); trace("typed character: '" + ch + "'");
qte = new QteText(ch, videotube.time(), videotube.time() + 0.1, /*fDirty*/true);
addTypein(ch);
typein.type = TextFieldType.INPUT;
trace("focusing");
stage.focus = typein;
typein.setSelection(ch.length, ch.length);
fTyping = true;
videotube.pause();
}
}
} }
private function moveClickArea(point:Point): void private function moveClickArea(point:Point): void
{ {
if (qte) { var qteCircle:QteCircle = qte as QteCircle;
qte.moveTo(point); if (qteCircle) {
qteCircle.moveTo(point);
clickarea.moveTo(point); clickarea.moveTo(point);
} }
} }
public function onClick(e: MouseEvent):void public function onClick(e: MouseEvent):void
{ {
trace("clicked"); if (!fTyping) {
var point:Point = new Point(e.stageX, e.stageY); trace("clicked" + qte);
if (qte) var point:Point = new Point(e.stageX, e.stageY);
moveClickArea(point); if (qte)
else { moveClickArea(point);
var qte:Qte = new Qte(point, 75, videotube.time(), -1, true /*fDirty*/); else {
addClickArea(qte); var qte:QteCircle = new QteCircle(point, 75, videotube.time(), -1, true /*fDirty*/);
gamedisc.AddQte(qte, videotube); addClickarea(qte.center, qte.radius);
this.qte = qte;
gamedisc.AddQte(qte, videotube);
}
} }
} }
public function onDrag(e: MouseEvent):void public function onDrag(e: MouseEvent):void

View file

@ -9,6 +9,7 @@ package
import flash.text.StyleSheet; import flash.text.StyleSheet;
import flash.text.TextField; import flash.text.TextField;
import flash.text.TextFieldAutoSize; import flash.text.TextFieldAutoSize;
import flash.text.TextFieldType;
import flash.text.TextFormat; import flash.text.TextFormat;
/** /**
* ... * ...
@ -17,9 +18,11 @@ package
public class GamePlayer extends Game public class GamePlayer extends Game
{ {
private var fAlive: Boolean; private var fAlive: Boolean;
private var ichNext: int;
public override function GamePlayer(videotube:Videotube, gamedisc:Gamedisc) { public override function GamePlayer(videotube:Videotube, gamedisc:Gamedisc) {
super(videotube, gamedisc); super(videotube, gamedisc);
fAlive = true; fAlive = true;
ichNext = -1;
} }
protected override function onResume():void protected override function onResume():void
{ {
@ -43,19 +46,26 @@ package
private function onQte(e:EventQte):void private function onQte(e:EventQte):void
{ {
trace(e.qte.secTrigger() + "gameplayer start" + e.qte.secTimeout()); trace(e.qte.secTrigger() + "gameplayer start" + e.qte.secTimeout());
clearClickarea(); trace(e.qte);
clickarea = new ClickArea(e.qte.center, e.qte.radius, 0x4444ee, 0.4); clearQteUI();
addChild(clickarea); if (e.qteCircle()) {
addClickarea(e.qteCircle().center, e.qteCircle().radius);
} else if (e.qteText()) {
addTypein(e.qteText().text);
typein.type = TextFieldType.DYNAMIC;
typein.selectable = false;
ichNext = 0;
}
} }
private function onTimeout(e:EventQte):void private function onTimeout(e:EventQte):void
{ {
trace("gameplayer timeout"); trace("gameplayer timeout");
if (clickarea != null) { if (clickarea != null || typein != null) {
pushText("OH SHIT\n\nhit R to restart", 0x0000FF, 0xFF0000); pushText("OH SHIT\n\nhit R to restart", 0x0000FF, 0xFF0000);
videotube.pause(); videotube.pause();
fAlive = false; fAlive = false;
} }
clearClickarea(); clearQteUI();
} }
private function onClick(mouse:MouseEvent):void private function onClick(mouse:MouseEvent):void
{ {
@ -69,8 +79,25 @@ package
videotube.seek(0); videotube.seek(0);
videotube.resume(); videotube.resume();
} }
if (typein != null) {
var text:String = typein.text;
var ch:String = String.fromCharCode(event.charCode).toLowerCase();
var chToMatch:String = text.substr(ichNext, 1).toLowerCase();
trace(chToMatch + ":" + ch);
if (ch == chToMatch) {
ichNext ++;
if (ichNext >= text.length) {
clearTypein();
ichNext = -1;
} else {
var format:TextFormat = new TextFormat();
format.size = 40;
format.color = 0xFFFF00;
typein.setTextFormat(format, 0, ichNext);
}
}
}
trace("key:", event.keyCode); trace("key:", event.keyCode);
} }
} }
} }

View file

@ -161,9 +161,9 @@ package
rgqte = []; rgqte = [];
for each (var jsonQte:Object in json.qtes) for each (var jsonQte:Object in json.qtes)
{ {
var qte:Qte = new Qte(); var qte:Qte = Qte.FromJson(jsonQte);
qte.FromJson(jsonQte); if (qte)
rgqte.push(qte); rgqte.push(qte);
} }
urlVideo = json.url; urlVideo = json.url;
typeVideotube = json.ktube; typeVideotube = json.ktube;

View file

@ -7,16 +7,12 @@ package
*/ */
public class Qte public class Qte
{ {
public var center:Point;
public var radius:Number;
public var msTrigger:int; public var msTrigger:int;
public var msTimeout:int; public var msTimeout:int;
public var fDirty:Boolean; public var fDirty:Boolean;
public function Qte(center: Point = null, radius: Number = -1, secTrigger:Number = -1, secTimeout:Number = -1, fDirty: Boolean = false) public function Qte(secTrigger:Number = -1, secTimeout:Number = -1, fDirty: Boolean = false)
{ {
this.center = center;
this.radius = radius;
if (secTrigger >= 0) if (secTrigger >= 0)
this.msTrigger = int(secTrigger * 1000); this.msTrigger = int(secTrigger * 1000);
else else
@ -32,11 +28,7 @@ package
} }
this.fDirty = fDirty; 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.msTrigger == qte2.msTrigger) if (qte1.msTrigger == qte2.msTrigger)
@ -51,18 +43,31 @@ package
} }
public function secTimeout():Number public function secTimeout():Number
{ {
return secTrigger() + 1.0; return msTimeout / 1000.0;
} }
protected function shapeToJson():Object {
return null;
}
protected function setShapeFromJson(shape:Object):void {}
public function ToJson():Object public function ToJson():Object
{ {
return { shape: {center: [center.x, center.y], radius: radius}, ms_trigger: msTrigger, ms_finish: msTimeout }; return { shape: this.shapeToJson(), ms_trigger: msTrigger, ms_finish: msTimeout };
} }
public function FromJson(json:Object):void public static function FromJson(json:Object):Qte
{ {
center = new Point(json.shape.center[0], json.shape.center[1]); var qte:Qte;
radius = json.shape.radius; if (json.shape.radius)
msTrigger = json.ms_trigger; qte = new QteCircle();
msTimeout = json.ms_finish; else if (json.shape.text)
qte = new QteText();
else
return null;
qte.setShapeFromJson(json.shape);
qte.msTrigger = json.ms_trigger;
qte.msTimeout = json.ms_finish;
return qte;
} }
} }
} }

31
src/QteCircle.as Normal file
View file

@ -0,0 +1,31 @@
package {
import flash.geom.Point;
/**
* ...
* @author Jeremy Penner
*/
public class QteCircle extends Qte {
public var center:Point;
public var radius:Number;
public function QteCircle(center:Point = null, radius:Number = -1, secTrigger:Number = -1, secTimeout:Number = -1, fDirty:Boolean = false) {
this.center = center;
this.radius = radius;
super(secTrigger, secTimeout, fDirty);
}
public function moveTo(center: Point): void
{
fDirty = true;
this.center = center;
}
protected override function shapeToJson(): Object {
return { center: [center.x, center.y], radius: radius };
}
protected override function setShapeFromJson(shape:Object): void {
center = new Point(shape.center[0], shape.center[1]);
radius = shape.radius;
}
}
}

21
src/QteText.as Normal file
View file

@ -0,0 +1,21 @@
package {
/**
* ...
* @author Jeremy Penner
*/
public class QteText extends Qte {
public var text:String;
public function QteText(text:String = null, secTrigger:Number=-1, secTimeout:Number=-1, fDirty:Boolean=false) {
super(secTrigger, secTimeout, fDirty);
this.text = text;
}
override protected function shapeToJson():Object {
return { 'text': text };
}
override protected function setShapeFromJson(shape:Object):void {
text = shape.text;
}
}
}