Explorar o código

Login config + Various miscs + Router

Nik Atlas %!s(int64=6) %!d(string=hai) anos
pai
achega
c6d0187a36

+ 25 - 0
src/Game/Router.js

@@ -0,0 +1,25 @@
+class Router {
+	constructor(stage) {
+		this.stage = stage;
+		this.routes = {};
+
+		this.currentRoute = null;
+		this.currentRouteLink = "";
+	}
+
+	addRoute = (link, actors) => {
+		this.routes[link] = actors;
+	}
+
+	go = (link) => {
+		const newRoute = this.routes[link];
+		if (this.currentRoute !== null)
+			this.stage.removeChild(this.currentRoute);
+		
+		this.stage.addChild(newRoute);
+		this.currentRoute = newRoute;
+		this.currentRouteLink = link;
+	}
+}
+
+export default Router;

+ 25 - 8
src/Game/app.js

@@ -1,21 +1,37 @@
 import './app.css'
 import * as PIXI from 'pixi.js'
 
-
+import Router from './Router.js'
 import Menu from './views/Menu';
 
 
 class App {
 	constructor(){
 		this.animateables = [];
-	}
-	init() {
 		this.app = new PIXI.Application(window.innerWidth, window.innerHeight, {backgroundColor : 0x1099bb});
 		window.onresize = this.resize;
+		this.app.view.style.display = 'none';
 		document.body.appendChild(this.app.view);
 
-		this.add(new Menu(this.app));
+
+		this._router = new Router(this.app.stage);
+		this._router.addRoute('Login', new Menu(this.app, 'LoginMenuConfig.js'));
+		this._router.addRoute('Test', new Menu(this.app, 'TestMenuConfig.js'));
+
+	}
+	destroy() {
+		this.app.view.style.display = 'none';
+		this.animateables = [];
+	}
+	init() {
+		this.app.view.style.display = 'block';
+		this._router.go("Login");
+	}
+
+	router() {
+		return this._router;	
 	}
+
 	/////////
 	resize = () => {
     	const w = window.innerWidth;
@@ -28,9 +44,9 @@ class App {
 			try{
 				this.animateables[i].step(dt);
 			} catch(e) {
-				console.log("Problem running animateable : ");
-				console.log(e);
-				console.log(this.animateables[i]);
+				info("Problem running animateable : ");
+				info(e);
+				info(this.animateables[i]);
 			}
 		}
 	}
@@ -39,9 +55,10 @@ class App {
 	}
 }
 
+const info = (e) => console.log(e);
 
 let singleton = null;
 function getSingleton () {
 	return singleton = (singleton === null ? new App() : singleton); 
 }
-export default getSingleton();
+export default getSingleton();

+ 9 - 0
src/Game/misc/Button.js

@@ -8,6 +8,15 @@ class Button extends PIXI.Sprite{
 
 		this.interactive = true;
 		this.buttonMode = true;
+
+		this.textNode = new PIXI.Text(text,{fontFamily : 'Arial', fontSize: 24, fill : 0xFFFFFF, align : 'center'});
+		this.textNode.anchor.set(0.5, 0.5);
+		
+		this.addChild(this.textNode);
+	}
+
+	onClick(fn) {
+		this.on('pointerdown', (e) => fn(e));
 	}
 }
 

+ 914 - 0
src/Game/misc/PixiTextInput.js

@@ -0,0 +1,914 @@
+let PIXI = null;
+if (typeof module !== 'undefined') {
+	PIXI = require("pixi.js");
+}
+
+/**
+ * Text input field for pixi.js.
+ * A simple example:
+ *
+ *     // We need a container
+ *     var container = new PIXI.Container();
+ *
+ *     // Same style options as PIXI.Text
+ *     var style={ ... };
+ *
+ *     var inputField = new PixiTextInput("hello",style);
+ *     container.addChild(inputField);
+ *
+ * The style definitions accepted by the constructor are the same as those accepted by
+ * [PIXI.Text](http://www.goodboydigital.com/pixijs/docs/classes/Text.html).
+ * @class PixiTextInput
+ * @constructor
+ * @param {String} [text] The initial text.
+ * @param {Object} [style] Style definition, same as for PIXI.Text
+ * @param {Boolean} [password] Indicate if field should be shown as a password field
+ * @param {Boolean} [useNativeTextInput] Indicate if the textfield should create a native fallback for mobile
+ */
+function PixiTextInput(text, style, password, useNativeTextInput) {
+	PIXI.Container.call(this);
+	window.pixiTextInputTarget = this;
+
+	if (!text)
+		text = "";
+
+	text = text.toString();
+
+	if (style && style.wordWrap)
+		throw Error("wordWrap is not supported for input fields");
+
+	this._text = text;
+	this._placeholder = "";
+
+	if (useNativeTextInput) {
+		this._nativeTextInput = this.getNativeTextInput(password);
+		this.bindNativeTextInput();
+	}
+
+	this.localWidth = 100;
+	this._backgroundColor = 0xffffff;
+	this._caretColor = 0x000000;
+	this._borderColor = 0x000000;
+	this._borderWidth = 0;
+	this._background = true;
+	this._password = false;
+	this._value = text;
+
+	if ( typeof password !== "undefined" && password !== undefined && password === true ) {
+		this._password = true;
+		this.syncValue();
+	}
+
+	this.style = style;
+	this.textField = new PIXI.Text(this._value, style);
+
+	this.localHeight =
+		this.textField.style.fontSize +
+		this.textField.style.strokeThickness
+		+ 4;
+
+	this.textColor = this.textField.style.fill;
+
+	this.backgroundGraphics = new PIXI.Graphics();
+	this.textFieldMask = new PIXI.Graphics();
+	this.selectionGraphics = new PIXI.Graphics();
+	this.caret = new PIXI.Graphics();
+	this.drawElements();
+
+	this.addChild(this.backgroundGraphics);
+	this.addChild(this.selectionGraphics);
+	this.addChild(this.textField);
+	this.addChild(this.caret);
+	this.addChild(this.textFieldMask);
+
+	this.scrollIndex = 0;
+	this._caretIndex = 0;
+	this.caretFlashInterval = null;
+	this._secondCaretIndex = 0;
+	this.blur();
+	this.updateCaretPosition();
+
+	this.backgroundGraphics.interactive = true;
+	this.backgroundGraphics.buttonMode = true;
+	this.backgroundGraphics.defaultCursor = "text";
+
+	this.backgroundGraphics.mousedown = this.onBackgroundMouseDown.bind(this);
+	this.keyEventClosure = this.onKeyEvent.bind(this);
+	this.windowBlurClosure = this.onWindowBlur.bind(this);
+	this.documentMouseDownClosure = this.onDocumentMouseDown.bind(this);
+	this.isFocusClick = false;
+
+	this.updateText();
+
+	this.textField.mask = this.textFieldMask;
+
+	this.keypress = null;
+	this.keydown = null;
+	this.change = null;
+
+	this.ctrlDown = false;
+	this.shiftDown = false;
+}
+
+PixiTextInput.prototype = Object.create(PIXI.Container.prototype);
+PixiTextInput.prototype.constructor = PixiTextInput;
+
+/**
+ * Someone clicked.
+ * @method onBackgroundMouseDown
+ * @private
+ */
+PixiTextInput.prototype.onBackgroundMouseDown = function(e) {
+	if (this._nativeTextInput) {
+		this._nativeTextInput.focus();
+	}
+	var x = this.toLocal(e.data.global).x;
+	this._caretIndex = this.getCaretIndexByCoord(x);
+	this.updateCaretPosition();
+
+	this.focus();
+
+	this.isFocusClick = true;
+	var scope = this;
+	setTimeout(function() {
+		scope.isFocusClick = false;
+	}, 0);
+}
+
+/**
+ * Focus this input field.
+ * @method focus
+ */
+PixiTextInput.prototype.focus = function() {
+	window.pixiTextInputTarget = this;
+	this.blur();
+
+	this.handleCopyReference = this.handleCopy.bind(this);
+	document.addEventListener("copy", this.handleCopyReference);
+	this.handleCutReference = this.handleCut.bind(this);
+	document.addEventListener("cut", this.handleCutReference);
+	this.handlePasteReference = this.handlePaste.bind(this);
+	document.addEventListener("paste", this.handlePasteReference);
+
+	document.addEventListener("keydown", this.keyEventClosure);
+	document.addEventListener("keypress", this.keyEventClosure);
+	document.addEventListener("keyup", this.keyEventClosure);
+	document.addEventListener("mousedown", this.documentMouseDownClosure);
+
+	window.addEventListener("blur", this.windowBlurClosure);
+
+	if(this._nativeTextInput) {
+		this._nativeTextInput.focus();
+	}
+
+	this.showCaret();
+}
+
+/**
+ * Handle key event.
+ * @method onKeyEvent
+ * @private
+ */
+PixiTextInput.prototype.onKeyEvent = function(e) {
+	//console.log("key event");
+	//console.log(e);
+	//console.log(this.scrollIndex);
+
+	if (e.type === "keypress") {
+		if (e.charCode < 32){
+			return;
+		}
+		if(e.charCode===32){
+			e.preventDefault();
+		}
+		if(this.ctrlDown && (e.charCode===67 ||
+			 									 e.charCode===99 ||
+											   e.charCode===86 ||
+											   e.charCode===118 ||
+											   e.charCode===88 ||
+											   e.charCode===120) ){
+			//console.log("ctrl+c|v|x");
+			return;
+		}
+
+		if(this._selection){
+			this.deleteSelectedText();
+			this.moveCarretRight();
+		}
+
+		this._text =
+			this._text.substring(0, this._caretIndex) +
+			String.fromCharCode(e.charCode) +
+			this._text.substring(this._caretIndex);
+
+		this._selection = false;
+		this.syncValue();
+
+		this._caretIndex++;
+		this.ensureCaretInView();
+		this.showCaret();
+		this.updateText();
+		this.drawElements();
+		this.trigger(this.keypress, e);
+		this.trigger(this.change);
+	}
+
+	if (e.type === "keydown") {
+		switch (e.keyCode) {
+			case 8: //backspace
+				if(this._selection){
+					this.deleteSelectedText();
+				} else if (this._caretIndex > 0) {
+					this._text =
+						this._text.substring(0, this._caretIndex - 1) +
+						this._text.substring(this._caretIndex);
+
+					this.syncValue();
+
+					this._caretIndex--;
+					this.ensureCaretInView();
+					this.showCaret();
+					this.updateText();
+				}
+				e.preventDefault();
+				this.trigger(this.change);
+				break;
+
+			case 16://shift
+				this.shiftDown = true;
+				break;
+
+			case 17:
+				this.ctrlDown = true;
+				break;
+
+			case 35:
+				this._caretIndex = this._text.length;
+				e.preventDefault();
+
+				this.ensureCaretInView();
+				this.updateCaretPosition();
+				this.showCaret();
+				this.updateText();
+				break;
+
+			case 36:
+				this._caretIndex = 0;
+				e.preventDefault();
+
+				this.ensureCaretInView();
+				this.updateCaretPosition();
+				this.showCaret();
+				this.updateText();
+				break;
+
+			case 46:
+				this._text =
+					this._text.substring(0, this._caretIndex) +
+					this._text.substring(this._caretIndex + 1);
+
+				this.syncValue();
+
+				this.ensureCaretInView();
+				this.updateCaretPosition();
+				this.showCaret();
+				this.updateText();
+				e.preventDefault();
+				this.trigger(this.change);
+				break;
+
+			case 39://right arrow
+				if(this.shiftDown && !this._selection){
+					this._selection=true;
+					this._secondCaretIndex = this._caretIndex;
+				}
+				/*if(this.shiftDown && this._selection){
+					if(this._secondCaretIndex+1<this._text.length){
+						this._secondCaretIndex++;
+					}
+				} else {*/
+					if(this.ctrlDown && this._caretIndex+1 < this._text.length){
+						let nextPosition = this._text.indexOf(" ", this._caretIndex);
+						if(nextPosition!==this._caretIndex){
+							this._caretIndex = (nextPosition!==-1)?nextPosition:this._text.length;
+						} else this.moveCarretRight();
+					} else this.moveCarretRight();
+				//}
+				if(!this.shiftDown){
+					this._selection = false;
+				}
+
+				this.ensureCaretInView();
+				this.updateCaretPosition();
+				this.showCaret();
+				this.updateText();
+				this.drawElements();
+				break;
+
+			case 37://left arrow
+				if(this.shiftDown && !this._selection){
+					this._selection=true;
+					this._secondCaretIndex = this._caretIndex;
+				}
+				/*if(this.shiftDown && this._selection){
+					if(this._secondCaretIndex+1>0){
+						this._secondCaretIndex--;
+					}
+				} else {*/
+					if(this.ctrlDown && this._caretIndex+1 > 0){
+						let nextPosition = this._text.lastIndexOf(" ", this._caretIndex-1);
+						if(nextPosition!==this._caretIndex){
+							this._caretIndex = (nextPosition!==-1)?nextPosition:0;
+						} else this.moveCarretLeft();
+					} else this.moveCarretLeft();
+				//}
+				if(!this.shiftDown){
+					this._selection = false;
+				}
+
+				this.ensureCaretInView();
+				this.updateCaretPosition();
+				this.showCaret();
+				this.updateText();
+				this.drawElements();
+				break;
+
+			case 65://A
+				if(this.ctrlDown){
+					this._selection = true;
+					this._caretIndex = 0;
+					this._secondCaretIndex = this._text.length;
+					this.drawElements();
+					e.preventDefault();
+				}
+				break;
+			default:break;
+		}
+
+		this.trigger(this.keydown, e);
+	}
+
+	if(e.type === "keyup"){
+		switch (e.keyCode) {
+			case 16:
+				this.shiftDown = false;
+				break;
+			case 17:
+				this.ctrlDown = false;
+				break;
+			default:
+
+		}
+	}
+}
+
+PixiTextInput.prototype.handleCopy = function(e){
+	e.clipboardData.setData('text/plain', this.getSelectedText());
+	e.preventDefault();
+}
+
+PixiTextInput.prototype.handleCut = function(e){
+	e.clipboardData.setData('text/plain', this.getSelectedText());
+	if(this._selection){
+		this.deleteSelectedText();
+		this.moveCarretRight();
+	}
+	e.preventDefault();
+}
+
+PixiTextInput.prototype.handlePaste = function(e){
+	var txtToInsert = e.clipboardData.getData('text/plain');
+	if(this._selection){
+		this.deleteSelectedText();
+		this.moveCarretRight();
+	}
+	this.insertText(txtToInsert);
+	e.preventDefault();
+}
+
+PixiTextInput.prototype.deleteSelectedText = function(e){
+	var startPosition;
+	var endPosition;
+	if(this._caretIndex>this._secondCaretIndex){
+		startPosition = this._secondCaretIndex;
+		endPosition = this._caretIndex;
+	} else {
+		startPosition = this._caretIndex;
+		endPosition = this._secondCaretIndex;
+	}
+	if(startPosition===0 && endPosition===this._text.length){
+		this._text = "";
+	} else {
+		this._text =
+		this._text.substring(0, startPosition) +
+		this._text.substring(endPosition);
+	}
+
+	this._selection = false;
+
+	this.syncValue();
+
+	this._caretIndex=startPosition;
+	if(this._caretIndex<0){
+		this._caretIndex=0;
+	}
+	this.ensureCaretInView();
+	this.showCaret();
+	this.updateText();
+	this.drawElements();
+}
+
+PixiTextInput.prototype.insertText = function(txt){
+	this._text = this._text.substring(0, this._caretIndex)
+						 + txt
+						 + this._text.substring(this._caretIndex);
+
+	this._selection = false;
+	this._caretIndex += txt.length;
+	this.updateCaretPosition();
+	this.syncValue();
+	this.ensureCaretInView();
+	this.showCaret();
+	this.updateText();
+	this.drawElements();
+}
+
+PixiTextInput.prototype.moveCarretRight = function(){
+	if(this._selection && !this.shiftDown){
+		if(this._caretIndex<this._secondCaretIndex){
+			this._caretIndex = this._secondCaretIndex;
+		}
+	} else {
+		this._caretIndex++;
+		if (this._caretIndex > this._text.length){
+			this._caretIndex = this._text.length;
+		}
+	}
+}
+
+PixiTextInput.prototype.moveCarretLeft = function(){
+	if(this._selection && !this.shiftDown){
+		if(this._caretIndex>this._secondCaretIndex){
+			this._caretIndex = this._secondCaretIndex;
+		}
+	} else {
+		this._caretIndex--;
+		if (this._caretIndex < 0){
+			this._caretIndex = 0;
+		}
+	}
+}
+
+/**
+ * Ensure the caret is not outside the bounds.
+ * @method ensureCaretInView
+ * @private
+ */
+PixiTextInput.prototype.ensureCaretInView = function() {
+	this.updateCaretPosition();
+
+	while (this.caret.position.x >= this.localWidth - 1) {
+		this.scrollIndex++;
+		this.updateCaretPosition();
+	}
+
+	while (this.caret.position.x < 0) {
+		this.scrollIndex -= 2;
+		if (this.scrollIndex < 0)
+			this.scrollIndex = 0;
+		this.updateCaretPosition();
+	}
+}
+
+/**
+ * Blur ourself.
+ * @method blur
+ */
+PixiTextInput.prototype.blur = function() {
+	document.removeEventListener("copy", this.handleCopyReference);
+	document.removeEventListener("cut", this.handleCutReference);
+	document.removeEventListener("paste", this.handlePasteReference);
+
+	document.removeEventListener("keydown", this.keyEventClosure);
+	document.removeEventListener("keypress", this.keyEventClosure);
+	document.removeEventListener("keyup", this.keyEventClosure);
+	document.removeEventListener("mousedown", this.documentMouseDownClosure);
+	window.removeEventListener("blur", this.windowBlurClosure);
+
+	this.hideCaret();
+}
+
+/**
+ * Window blur.
+ * @method onDocumentMouseDown
+ * @private
+ */
+PixiTextInput.prototype.onDocumentMouseDown = function() {
+	if (this._nativeTextInput) {
+		this._nativeTextInput.blur();
+	}
+	if (!this.isFocusClick)
+		this.blur();
+}
+
+/**
+ * Window blur.
+ * @method onWindowBlur
+ * @private
+ */
+PixiTextInput.prototype.onWindowBlur = function() {
+	if (this._nativeTextInput) {
+		this._nativeTextInput.blur();
+	}
+	this.blur();
+}
+
+/**
+ * Update caret Position.
+ * @method updateCaretPosition
+ * @private
+ */
+PixiTextInput.prototype.updateCaretPosition = function() {
+	if (this._caretIndex < this.scrollIndex) {
+		this.caret.position.x = -1;
+		return;
+	}
+
+	var sub = this._value.substring(0, this._caretIndex).substring(this.scrollIndex);
+	this.caret.position.x = this.textField.context.measureText(sub).width;
+}
+
+/**
+ * Update text.
+ * @method updateText
+ * @private
+ */
+PixiTextInput.prototype.updateText = function() {
+	this.textField.text = this._value.substring(this.scrollIndex);
+}
+
+/**
+ * Sync the password field value
+ * @method syncValue
+ * @private
+ */
+PixiTextInput.prototype.syncValue = function() {
+	if(this.textField && this.textField.style.fill!==this.textColor){
+		this.textField.style.fill = this.textColor;
+		this.textField.alpha = 1;
+	}
+	if (this._password) {
+		this._value = this._text.replace(/./g,"*");
+	} else if(this._text.length===0 && this._placeholder) {
+		this._value = this._placeholder;
+		if(this.textField){
+			this.textField.style.fill = 0xCCCCCC;
+			this.textField.alpha = 0.5;
+		}
+	} else {
+		this._value = this._text;
+	}
+}
+
+/**
+ * Draw the background and caret.
+ * @method drawElements
+ * @private
+ */
+PixiTextInput.prototype.drawElements = function() {
+	this.backgroundGraphics.clear();
+	this.backgroundGraphics.beginFill(this._backgroundColor);
+
+	if (this._borderWidth > 0) {
+		this.backgroundGraphics.lineStyle( this._borderWidth, this._borderColor );
+	}
+
+	if (this._background) {
+		this.backgroundGraphics.drawRect(0, 0, this.localWidth, this.localHeight);
+	}
+
+	this.selectionGraphics.clear();
+	if(this._selection && this._caretIndex!==this._secondCaretIndex){
+		var selectionStart;
+		var selectionEnd;
+		var offset = 0;
+		if(this._caretIndex>this._secondCaretIndex){
+			selectionStart = this._secondCaretIndex;
+			selectionEnd = this._caretIndex;
+		} else {
+			selectionStart = this._caretIndex;
+			selectionEnd = this._secondCaretIndex;
+		}
+		if(selectionStart>0){
+			offset = this.textField.context.measureText(this._text.substring(0, selectionStart)).width;
+			if(this.scrollIndex){
+				offset -= this.textField.context.measureText(this._text.substring(0, this.scrollIndex)).width;
+			}
+		}
+		var sub = this._text.substring(selectionStart, selectionEnd);
+		var selectedWidth = this.textField.context.measureText(sub).width;
+		if(offset+selectedWidth>this.localWidth){
+			selectedWidth = this.localWidth-offset;
+		}
+
+		/*
+		var sub = this._value.substring(0, this._caretIndex).substring(this.scrollIndex);
+		this.caret.position.x = this.textField.context.measureText(sub).width;
+		*/
+		this.selectionGraphics.beginFill(0xDDDDDD, 0.3);
+		this.selectionGraphics.drawRect(offset, 0, selectedWidth, this.localHeight)
+	}
+
+	this.backgroundGraphics.endFill();
+	this.backgroundGraphics.hitArea = new PIXI.Rectangle(0, 0, this.localWidth, this.localHeight);
+
+	this.textFieldMask.clear();
+	this.textFieldMask.beginFill(this._backgroundColor);
+	this.textFieldMask.drawRect(0, 0, this.localWidth, this.localHeight);
+	this.textFieldMask.endFill();
+
+	this.caret.clear();
+	this.caret.beginFill(this._caretColor);
+	this.caret.drawRect(1, 1, 1, this.localHeight - 2);
+	this.caret.endFill();
+}
+
+/**
+ * Show caret.
+ * @method showCaret
+ * @private
+ */
+PixiTextInput.prototype.showCaret = function() {
+	if (this.caretFlashInterval) {
+		clearInterval(this.caretFlashInterval);
+		this.caretFlashInterval = null;
+	}
+
+	this.caret.visible = true;
+	this.caretFlashInterval = setInterval(this.onCaretFlashInterval.bind(this), 500);
+}
+
+/**
+ * Hide caret.
+ * @method hideCaret
+ * @private
+ */
+PixiTextInput.prototype.hideCaret = function() {
+	if (this.caretFlashInterval) {
+		clearInterval(this.caretFlashInterval);
+		this.caretFlashInterval = null;
+	}
+
+	this.caret.visible = false;
+}
+
+/**
+ * Caret flash interval.
+ * @method onCaretFlashInterval
+ * @private
+ */
+PixiTextInput.prototype.onCaretFlashInterval = function() {
+	this.caret.visible = !this.caret.visible;
+}
+
+/**
+ * Map position to caret index.
+ * @method getCaretIndexByCoord
+ * @private
+ */
+PixiTextInput.prototype.getCaretIndexByCoord = function(x) {
+	var smallest = 10000;
+	var cand = 0;
+	var visible = this._text.substring(this.scrollIndex);
+
+	for (let i = 0; i < visible.length + 1; i++) {
+		var sub = visible.substring(0, i);
+		var w = this.textField.context.measureText(sub).width;
+
+		if (Math.abs(w - x) < smallest) {
+			smallest = Math.abs(w - x);
+			cand = i;
+		}
+	}
+
+	return this.scrollIndex + cand;
+}
+
+PixiTextInput.prototype.getSelectedText = function(){
+	if(this._selection){
+		if(this._caretIndex<this._secondCaretIndex){
+			return this._text.substring(this._caretIndex, this._secondCaretIndex);
+		} else if(this._caretIndex>this._secondCaretIndex){
+			return this._text.substring(this._secondCaretIndex, this._caretIndex);
+		}
+	}
+	return "";
+}
+
+/**
+ * The width of the PixiTextInput. This is overridden to have a slightly
+ * different behaivour than the other DisplayObjects. Setting the
+ * width of the PixiTextInput does not change the scale, but it rather
+ * makes the field larger. If you actually want to scale it,
+ * use the scale property.
+ * @property width
+ * @type Number
+ */
+Object.defineProperty(PixiTextInput.prototype, "width", {
+	get: function() {
+		return this.scale.x * this.getLocalBounds().width;
+	},
+
+	set: function(v) {
+		this.localWidth = v;
+		this.drawElements();
+		this.ensureCaretInView();
+		this.updateText();
+	}
+});
+
+/**
+ * The text in the input field. Setting will have the implicit function of resetting the scroll
+ * of the input field and removing focus.
+ * @property text
+ * @type String
+ */
+Object.defineProperty(PixiTextInput.prototype, "text", {
+	get: function() {
+		return this._text;
+	},
+
+	set: function(v) {
+		this._text = v.toString();
+		this.syncValue();
+		this.scrollIndex = 0;
+		this.caretIndex = 0;
+		this.blur();
+		this.updateText();
+	}
+});
+
+/**
+ * The color of the background for the input field.
+ * This needs to be specified as an integer, not using HTML
+ * notation, e.g. for red background:
+ *
+ *     myInputText.backgroundColor = 0xff0000;
+ *
+ * In order for the background to be drawn, the `background`
+ * property needs to be true. If not, this property will have
+ * no effect.
+ * @property backgroundColor
+ * @type Integer
+ */
+Object.defineProperty(PixiTextInput.prototype, "backgroundColor", {
+	get: function() {
+		return this._backgroundColor;
+	},
+
+	set: function(v) {
+		this._backgroundColor = v;
+		this.drawElements();
+	}
+});
+
+Object.defineProperty(PixiTextInput.prototype, "borderColor", {
+	get: function() {
+		return this._borderColor;
+	},
+
+	set: function(v) {
+		this._borderColor = v;
+		this.drawElements();
+	}
+});
+
+Object.defineProperty(PixiTextInput.prototype, "borderWidth", {
+	get: function() {
+		return this._borderWidth;
+	},
+
+	set: function(v) {
+		this._borderWidth = v;
+		this.drawElements();
+	}
+});
+
+
+/**
+ * The color of the caret.
+ * @property caretColor
+ * @type Integer
+ */
+Object.defineProperty(PixiTextInput.prototype, "caretColor", {
+	get: function() {
+		return this._caretColor;
+	},
+
+	set: function(v) {
+		this._caretColor = v;
+		this.drawElements();
+	}
+});
+
+/**
+ * Determines if the background should be drawn behind the text.
+ * The color of the background is specified using the backgroundColor
+ * property.
+ * @property background
+ * @type Boolean
+ */
+Object.defineProperty(PixiTextInput.prototype, "background", {
+	get: function() {
+		return this._background;
+	},
+
+	set: function(v) {
+		this._background = v;
+		this.drawElements();
+	}
+});
+
+/**
+ * Determines if the background should be drawn behind the text.
+ * The color of the background is specified using the backgroundColor
+ * property.
+ * @property background
+ * @type Boolean
+ */
+Object.defineProperty(PixiTextInput.prototype, "placeholder", {
+	get: function() {
+		return this._placeholder;
+	},
+
+	set: function(v) {
+		this._placeholder = v;
+		this.syncValue();
+	}
+});
+
+/**
+ * Set text.
+ * @method setText
+ * @param {String} text The new text.
+ */
+PixiTextInput.prototype.setText = function(v) {
+	if(this._nativeTextInput) {
+		this._nativeTextInput.value = v;
+	}
+
+	this.text = v;
+}
+
+/**
+ * Trigger an event function if it exists.
+ * @method trigger
+ * @private
+ */
+PixiTextInput.prototype.trigger = function(fn, e) {
+	if (fn)
+		fn(e);
+}
+
+/**
+ * Get or create a native text input for mobile support
+ * @method getNativeTextInput
+ * @private
+ */
+PixiTextInput.prototype.getNativeTextInput = function(pw) {
+	var elmName = "PixiTextInput";
+	var elm = document.getElementById( elmName );
+
+	if ( !elm ) {
+		elm = document.createElement( "input" );
+		document.body.appendChild( elm );
+		elm.style.position = "fixed";
+		elm.style.top = "-100px";
+		elm.style.left = "-100px";
+
+		if ( pw ) {
+			elm.type = "password";
+		}
+	}
+
+	return elm;
+}
+
+/**
+ * Bind events for the native text input
+ * @method bindNativeTextInput
+ * @private
+ */
+PixiTextInput.prototype.bindNativeTextInput = function() {
+
+	if(this._nativeTextInput) {
+		this._nativeTextInput.addEventListener("keyup", function(e) {
+			window.pixiTextInputTarget.text = this.value;
+		});
+	}
+
+}
+
+if (typeof module !== 'undefined') {
+	module.exports = PixiTextInput;
+}

+ 13 - 0
src/Game/misc/Text.js

@@ -0,0 +1,13 @@
+import * as PIXI from 'pixi.js'
+class Text extends PIXI.Container{
+	constructor(text) {
+		super();
+		this.textNode = new PIXI.Text(text,{fontFamily : 'Arial', fontSize: 28, fill : 0x000000, align : 'center'});
+		this.textNode.anchor.set(0.5,0.5);
+		this.addChild(this.textNode);
+	}
+
+	setText = (args) => this.textNode.setText(args);
+}
+
+export default Text;

+ 18 - 0
src/Game/misc/TextInput.js

@@ -0,0 +1,18 @@
+import * as PIXI from 'pixi.js'
+import * as PixiTextInput from './PixiTextInput.js'
+
+class TextInput extends PIXI.Container{
+	constructor(text, width) {
+		super();
+		this.inputNode = new PixiTextInput(text,{fontFamily : 'Arial', fontSize: 28, fill : 0x000000, align : 'center'});
+		this.inputNode.width = width || 320;
+		this.inputNode.pivot.set(this.inputNode.width/2, this.inputNode.height/2);
+		this.addChild(this.inputNode);
+	}
+
+	value() {
+		return this.value;
+	}
+}
+
+export default TextInput;

+ 19 - 0
src/Game/views/LoginMenuConfig.js

@@ -0,0 +1,19 @@
+import Button from '../misc/Button.js'
+import TextInput from '../misc/TextInput.js'
+import Text from '../misc/Text.js'
+import App from '../app.js'
+
+
+const buttons = [];
+buttons.push(new Text("Welcome to Mafalda!"));
+buttons.push(new TextInput("Username"));
+buttons.push(new TextInput("Password"));
+let button = new Button("Join world");
+button.onClick(() => {
+	console.log(App);
+	App.router().go("Test");
+});
+
+buttons.push(button);
+
+export default buttons;

+ 3 - 21
src/Game/views/Menu.js

@@ -1,39 +1,21 @@
-import Button from '../misc/Button.js'
 import * as PIXI from 'pixi.js'
 
 const BUTTON_HEIGHT = 120;
 class Menu extends PIXI.Container{
-	constructor(app){
+	constructor(app, config){
 		super();
 		this.stage = app.stage;
-		this.buttons = this.createButtons();
+		this.buttons = require('./'+config).default || [];
 		this.calculatePositions();
 		this.buttons.forEach((e,i) => this.addChild(e));
 
 		this.position.set(app.screen.width/2, app.screen.height/2);
-		this.stage.addChild(this);
 	}
-
-	createButtons() {
-		const buttons = [];
-		
-		let button = new Button("HI!");
-		
-
-		buttons.push(button);
-
-		button = new Button("GJ");
-		
-		buttons.push(button);
-
-		return buttons;
-	}
-
 	calculatePositions() {
 		let length = this.buttons.length;
 		let top = length * BUTTON_HEIGHT/2;
 		this.buttons.forEach((b,i) => {
-			b.position.set(0,top - i*BUTTON_HEIGHT - BUTTON_HEIGHT/2);
+			b.position.set(0,-top + i*BUTTON_HEIGHT + BUTTON_HEIGHT/2);
 		});
 	}
 }

+ 14 - 0
src/Game/views/TestMenuConfig.js

@@ -0,0 +1,14 @@
+import Button from '../misc/Button.js'
+import TextInput from '../misc/TextInput.js'
+import Text from '../misc/Text.js'
+
+const buttons = [];
+buttons.push(new TextInput("Test input"));
+buttons.push(new Text("Welcome to Test Menu!"));
+let button = new Button("Test world");
+buttons.push(new TextInput("Test test "));
+button.onClick(() => alert("Test World! <3"));
+
+buttons.push(button);
+
+export default buttons;

+ 3 - 0
src/components/Game.jsx

@@ -7,6 +7,9 @@ class Game extends Component {
 	componentDidMount() {
        GameLayer.init();
 	}
+	componentWillUnmount() {
+       GameLayer.destroy();
+	}
 
 	goTo = (stateName) => {
 		this.props.resolves.$transition$.router.stateService.go(stateName);