Add textual QTEs

master
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);
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
{
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);

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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
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;
}
}
}