Add textual QTEs
This commit is contained in:
parent
952097a307
commit
d91609dcfa
|
@ -17,6 +17,11 @@ package
|
|||
super(type);
|
||||
this.qte = qte;
|
||||
}
|
||||
public function qteCircle():QteCircle {
|
||||
return qte as QteCircle;
|
||||
}
|
||||
public function qteText():QteText {
|
||||
return qte as QteText;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
55
src/Game.as
55
src/Game.as
|
@ -1,9 +1,14 @@
|
|||
package
|
||||
{
|
||||
import flash.display.DisplayObject;
|
||||
import flash.display.InteractiveObject;
|
||||
import flash.display.Sprite;
|
||||
import flash.events.Event;
|
||||
import flash.events.FocusEvent;
|
||||
import flash.geom.Point;
|
||||
import flash.text.TextField;
|
||||
import flash.text.TextFormat;
|
||||
import flash.text.TextFormatAlign;
|
||||
|
||||
/**
|
||||
* ...
|
||||
|
@ -16,6 +21,7 @@ package
|
|||
protected var videotube:Videotube;
|
||||
protected var gamedisc:Gamedisc;
|
||||
protected var clickarea:ClickArea;
|
||||
protected var typein:TextField;
|
||||
protected var text:TextField;
|
||||
protected var textValues: Array;
|
||||
public function Game(videotube:Videotube, gamedisc:Gamedisc)
|
||||
|
@ -31,8 +37,11 @@ package
|
|||
|
||||
stage.addEventListener(Event.ACTIVATE, onFocus);
|
||||
stage.addEventListener(Event.DEACTIVATE, onLoseFocus);
|
||||
stage.addEventListener(FocusEvent.KEY_FOCUS_CHANGE, preventWidgetFocusChange);
|
||||
stage.addEventListener(FocusEvent.MOUSE_FOCUS_CHANGE, preventWidgetFocusChange);
|
||||
|
||||
clickarea = null;
|
||||
typein = null;
|
||||
if (text != null)
|
||||
removeChild(text);
|
||||
text = null;
|
||||
|
@ -50,13 +59,19 @@ package
|
|||
|
||||
stage.removeEventListener(Event.ACTIVATE, onFocus);
|
||||
stage.removeEventListener(Event.DEACTIVATE, onLoseFocus);
|
||||
stage.removeEventListener(FocusEvent.KEY_FOCUS_CHANGE, preventWidgetFocusChange);
|
||||
stage.removeEventListener(FocusEvent.MOUSE_FOCUS_CHANGE, preventWidgetFocusChange);
|
||||
|
||||
if (hasFocus)
|
||||
onPause();
|
||||
clearClickarea();
|
||||
}
|
||||
protected function focussedChild():InteractiveObject {
|
||||
return null;
|
||||
}
|
||||
protected function onFocus(e:Event):void {
|
||||
trace("received focus");
|
||||
trace(stage.focus);
|
||||
popText();
|
||||
hasFocus = true;
|
||||
stage.addEventListener(Event.EXIT_FRAME, onFocusEnded);
|
||||
|
@ -67,11 +82,16 @@ package
|
|||
}
|
||||
protected function onLoseFocus(e:Event): void {
|
||||
trace("lost focus");
|
||||
trace(stage.focus);
|
||||
pushText("Paused\nCLICK TO PLAY", 0x000000, 0xFFFFFF);
|
||||
hasFocus = false;
|
||||
onPause();
|
||||
}
|
||||
|
||||
protected function preventWidgetFocusChange(e:Event): void {
|
||||
trace("preventing focus change");
|
||||
e.preventDefault();
|
||||
stage.focus = focussedChild();
|
||||
}
|
||||
protected function onPause(): void {
|
||||
trace("onPause");
|
||||
videotube.pause();
|
||||
|
@ -84,6 +104,24 @@ package
|
|||
protected function fPlaying(): Boolean {
|
||||
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
|
||||
{
|
||||
if (clickarea != null) {
|
||||
|
@ -91,9 +129,22 @@ package
|
|||
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 {
|
||||
if (text == null)
|
||||
if (text == null) {
|
||||
text = Util.addTextFieldFullScreen(this);
|
||||
text.selectable = false;
|
||||
}
|
||||
textValues.push( { 'html': html, 'bgcolor':bgcolor, 'fgcolor':fgcolor } );
|
||||
trace("saying: " + html);
|
||||
Util.setText(text, html, 164, bgcolor, fgcolor);
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
package
|
||||
{
|
||||
import flash.display.Bitmap;
|
||||
import flash.display.DisplayObject;
|
||||
import flash.display.InteractiveObject;
|
||||
import flash.display.Sprite;
|
||||
import flash.events.Event;
|
||||
import flash.events.KeyboardEvent;
|
||||
import flash.events.MouseEvent;
|
||||
import flash.geom.Point;
|
||||
import flash.text.TextFieldType;
|
||||
/**
|
||||
* ...
|
||||
* @author jjp
|
||||
|
@ -12,6 +16,7 @@ package
|
|||
public class GameEditor extends Game
|
||||
{
|
||||
protected var qte:Qte;
|
||||
protected var fTyping:Boolean;
|
||||
public override function GameEditor(videotube:Videotube, gamedisc:Gamedisc) {
|
||||
super(videotube, gamedisc);
|
||||
qte = null;
|
||||
|
@ -20,6 +25,7 @@ package
|
|||
{
|
||||
super.onResume();
|
||||
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
|
||||
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
|
||||
stage.addEventListener(MouseEvent.MOUSE_DOWN, onClick);
|
||||
stage.addEventListener(MouseEvent.MOUSE_MOVE, onDrag);
|
||||
|
||||
|
@ -31,6 +37,7 @@ package
|
|||
{
|
||||
super.onPause();
|
||||
stage.removeEventListener(KeyboardEvent.KEY_UP, onKeyUp);
|
||||
stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
|
||||
stage.removeEventListener(MouseEvent.MOUSE_DOWN, onClick);
|
||||
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onDrag);
|
||||
|
||||
|
@ -38,8 +45,14 @@ package
|
|||
videotube.removeEventListener(EventQte.QTE_TIMEOUT, onQteEnd);
|
||||
videotube.removeEventListener(EventQte.QTE_CANCEL, onQteEnd);
|
||||
}
|
||||
|
||||
override protected function focussedChild():InteractiveObject {
|
||||
if (typein)
|
||||
return typein;
|
||||
return super.focussedChild();
|
||||
}
|
||||
protected override function fPlaying():Boolean {
|
||||
return true;
|
||||
return !fTyping;
|
||||
}
|
||||
public function onQteBegin(e: EventQte):void
|
||||
{
|
||||
|
@ -51,7 +64,12 @@ package
|
|||
clearClickarea();
|
||||
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
|
||||
|
@ -59,49 +77,87 @@ package
|
|||
trace("editor qte end");
|
||||
Util.assert(qte == e.qte);
|
||||
gamedisc.repostQte(qte);
|
||||
clearClickarea();
|
||||
clearQteUI();
|
||||
qte = null;
|
||||
}
|
||||
|
||||
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;
|
||||
if (!fTyping) {
|
||||
if (key.keyCode == 46 && qte != null) {// delete
|
||||
gamedisc.DeleteQte(qte, videotube);
|
||||
clearQteUI();
|
||||
qte = null;
|
||||
} else if (key.keyCode == 37) { // leftArrow
|
||||
videotube.seek(videotube.time() - 3);
|
||||
clearQteUI();
|
||||
qte = null;
|
||||
} else if (key.keyCode == 39) { // rightArrow
|
||||
videotube.seek(videotube.time() + 3);
|
||||
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
|
||||
{
|
||||
qte = qteNew;
|
||||
clickarea = new ClickArea(qte.center, qte.radius, 0x4444ee, 0.4);
|
||||
addChild(clickarea);
|
||||
private function onKeyDown(key:KeyboardEvent): void {
|
||||
if (!fTyping && qte == null) {
|
||||
if (key.charCode >= 0x20 && key.charCode <= 0x7e) { // printable character
|
||||
var ch:String = String.fromCharCode(key.charCode);
|
||||
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
|
||||
{
|
||||
if (qte) {
|
||||
qte.moveTo(point);
|
||||
var qteCircle:QteCircle = qte as QteCircle;
|
||||
if (qteCircle) {
|
||||
qteCircle.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);
|
||||
if (!fTyping) {
|
||||
trace("clicked" + qte);
|
||||
var point:Point = new Point(e.stageX, e.stageY);
|
||||
if (qte)
|
||||
moveClickArea(point);
|
||||
else {
|
||||
var qte:QteCircle = new QteCircle(point, 75, videotube.time(), -1, true /*fDirty*/);
|
||||
addClickarea(qte.center, qte.radius);
|
||||
this.qte = qte;
|
||||
gamedisc.AddQte(qte, videotube);
|
||||
}
|
||||
}
|
||||
}
|
||||
public function onDrag(e: MouseEvent):void
|
||||
|
|
|
@ -9,6 +9,7 @@ package
|
|||
import flash.text.StyleSheet;
|
||||
import flash.text.TextField;
|
||||
import flash.text.TextFieldAutoSize;
|
||||
import flash.text.TextFieldType;
|
||||
import flash.text.TextFormat;
|
||||
/**
|
||||
* ...
|
||||
|
@ -17,9 +18,11 @@ package
|
|||
public class GamePlayer extends Game
|
||||
{
|
||||
private var fAlive: Boolean;
|
||||
private var ichNext: int;
|
||||
public override function GamePlayer(videotube:Videotube, gamedisc:Gamedisc) {
|
||||
super(videotube, gamedisc);
|
||||
fAlive = true;
|
||||
ichNext = -1;
|
||||
}
|
||||
protected override function onResume():void
|
||||
{
|
||||
|
@ -43,19 +46,26 @@ package
|
|||
private function onQte(e:EventQte):void
|
||||
{
|
||||
trace(e.qte.secTrigger() + "gameplayer start" + e.qte.secTimeout());
|
||||
clearClickarea();
|
||||
clickarea = new ClickArea(e.qte.center, e.qte.radius, 0x4444ee, 0.4);
|
||||
addChild(clickarea);
|
||||
trace(e.qte);
|
||||
clearQteUI();
|
||||
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
|
||||
{
|
||||
trace("gameplayer timeout");
|
||||
if (clickarea != null) {
|
||||
if (clickarea != null || typein != null) {
|
||||
pushText("OH SHIT\n\nhit R to restart", 0x0000FF, 0xFF0000);
|
||||
videotube.pause();
|
||||
fAlive = false;
|
||||
}
|
||||
clearClickarea();
|
||||
clearQteUI();
|
||||
}
|
||||
private function onClick(mouse:MouseEvent):void
|
||||
{
|
||||
|
@ -69,8 +79,25 @@ package
|
|||
videotube.seek(0);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -161,9 +161,9 @@ package
|
|||
rgqte = [];
|
||||
for each (var jsonQte:Object in json.qtes)
|
||||
{
|
||||
var qte:Qte = new Qte();
|
||||
qte.FromJson(jsonQte);
|
||||
rgqte.push(qte);
|
||||
var qte:Qte = Qte.FromJson(jsonQte);
|
||||
if (qte)
|
||||
rgqte.push(qte);
|
||||
}
|
||||
urlVideo = json.url;
|
||||
typeVideotube = json.ktube;
|
||||
|
|
39
src/Qte.as
39
src/Qte.as
|
@ -7,16 +7,12 @@ package
|
|||
*/
|
||||
public class Qte
|
||||
{
|
||||
public var center:Point;
|
||||
public var radius:Number;
|
||||
public var msTrigger:int;
|
||||
public var msTimeout:int;
|
||||
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)
|
||||
this.msTrigger = int(secTrigger * 1000);
|
||||
else
|
||||
|
@ -32,11 +28,7 @@ package
|
|||
}
|
||||
this.fDirty = fDirty;
|
||||
}
|
||||
public function moveTo(center: Point): void
|
||||
{
|
||||
fDirty = true;
|
||||
this.center = center;
|
||||
}
|
||||
|
||||
public static function compare(qte1:Qte, qte2:Qte):int
|
||||
{
|
||||
if (qte1.msTrigger == qte2.msTrigger)
|
||||
|
@ -51,18 +43,31 @@ package
|
|||
}
|
||||
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
|
||||
{
|
||||
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]);
|
||||
radius = json.shape.radius;
|
||||
msTrigger = json.ms_trigger;
|
||||
msTimeout = json.ms_finish;
|
||||
var qte:Qte;
|
||||
if (json.shape.radius)
|
||||
qte = new QteCircle();
|
||||
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
31
src/QteCircle.as
Normal 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
21
src/QteText.as
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue