I'm writing a Snake game in TypeScript and have trouble defining a KeyListener (arrow keys for changing Snake direction).
I have a 4 layer architecture and key events are handled in the Gui Class. This holds the Snake object, draws the snake and handles key events.
I tried the normal way, but inside handleEvt the snake object is undefined.
document.addEventListener("keydown", handleEvt)
So I tried the fat arrow method, but now the function doesn't get called at all. I suspect that the key listener changed context and is not working on the window anymore
document.addEventListener("keydown", () => handleEvt)
Can anyone explain what the problem is here? It would be much appreciated!
Below is my Gui Class:
/// <reference path="../model/Snake.ts" />
/// <reference path="../model/Direction.ts" />
/// <reference path="../model/Part.ts" />
/// <reference path="../dao/Dao.ts" />
/// <reference path="../service/Service.ts" />
/// <reference path="../model/IPosObject.ts" />
module gui {
export class Gui {
snake:model.Snake;
canvas:HTMLCanvasElement;
ctx:CanvasRenderingContext2D;
loop:any;
lineWidth:number;
canvasSize:number;
loopSpeed:number;
unitLength:number;
constructor(snake:model.Snake) {
// init constants
this.snake = snake;
this.lineWidth = 3;
this.canvasSize = 200;
this.loopSpeed = 1000/60;
this.unitLength = 5;
// init canvas
this.canvas = document.getElementsByTagName("canvas")[0];
this.canvas.width = this.canvasSize;
this.canvas.height = this.canvasSize;
this.ctx = this.canvas.getContext("2d");
// Attach key event
// document.addEventListener("keydown", this.handleEvt);
document.addEventListener("keydown", () => this.handleEvt);
// activate game loop
this.loop = setInterval( () => this.gameLoop(), this.loopSpeed );
}
handleEvt(e):void {
var direction:model.Direction;
if (e) {
switch (e.which) {
case 37:
console.log("left");
direction = model.Direction.Left;
break;
case 38:
console.log("up");
direction = model.Direction.Up;
break;
case 39:
console.log("right");
direction = model.Direction.Right;
break;
case 40:
console.log("down");
direction = model.Direction.Down;
break;
}
this.snake.changeDirection(direction);
}
}
gameLoop():void {
if (this.snake) {
this.drawSnake();
}
}
drawSnake() {
// draw parts
}
}
}
I'm writing a Snake game in TypeScript and have trouble defining a KeyListener (arrow keys for changing Snake direction).
I have a 4 layer architecture and key events are handled in the Gui Class. This holds the Snake object, draws the snake and handles key events.
I tried the normal way, but inside handleEvt the snake object is undefined.
document.addEventListener("keydown", handleEvt)
So I tried the fat arrow method, but now the function doesn't get called at all. I suspect that the key listener changed context and is not working on the window anymore
document.addEventListener("keydown", () => handleEvt)
Can anyone explain what the problem is here? It would be much appreciated!
Below is my Gui Class:
/// <reference path="../model/Snake.ts" />
/// <reference path="../model/Direction.ts" />
/// <reference path="../model/Part.ts" />
/// <reference path="../dao/Dao.ts" />
/// <reference path="../service/Service.ts" />
/// <reference path="../model/IPosObject.ts" />
module gui {
export class Gui {
snake:model.Snake;
canvas:HTMLCanvasElement;
ctx:CanvasRenderingContext2D;
loop:any;
lineWidth:number;
canvasSize:number;
loopSpeed:number;
unitLength:number;
constructor(snake:model.Snake) {
// init constants
this.snake = snake;
this.lineWidth = 3;
this.canvasSize = 200;
this.loopSpeed = 1000/60;
this.unitLength = 5;
// init canvas
this.canvas = document.getElementsByTagName("canvas")[0];
this.canvas.width = this.canvasSize;
this.canvas.height = this.canvasSize;
this.ctx = this.canvas.getContext("2d");
// Attach key event
// document.addEventListener("keydown", this.handleEvt);
document.addEventListener("keydown", () => this.handleEvt);
// activate game loop
this.loop = setInterval( () => this.gameLoop(), this.loopSpeed );
}
handleEvt(e):void {
var direction:model.Direction;
if (e) {
switch (e.which) {
case 37:
console.log("left");
direction = model.Direction.Left;
break;
case 38:
console.log("up");
direction = model.Direction.Up;
break;
case 39:
console.log("right");
direction = model.Direction.Right;
break;
case 40:
console.log("down");
direction = model.Direction.Down;
break;
}
this.snake.changeDirection(direction);
}
}
gameLoop():void {
if (this.snake) {
this.drawSnake();
}
}
drawSnake() {
// draw parts
}
}
}
Share
Improve this question
asked Apr 11, 2015 at 8:47
olefrankolefrank
6,84014 gold badges69 silver badges94 bronze badges
1
- 1 This video will help you a bit : youtube./watch?v=tvocUcbCupA – basarat Commented Apr 11, 2015 at 10:35
1 Answer
Reset to default 6There are multiple solutions to this problem, you can fix it on your addEventListener side by doing the same as with you did with the setInterval. In the keyDown listener you aren't calling the handleEvt so change it to
() => this.handleEvt()
.
Another solution where you can use it like you did above is this:
document.addEventListener("keydown", this.handleEvt);
And declaring the handleEvt like this:
handleEvt = (e) => {
var direction:model.Direction;
...<snip>
}
Or another solution:
document.addEventListener("keydown", this.handleEvt.bind(this));
As you can see, there are different solutions and you can choose the one you like. The this
is lost because the function isn't called on a instance and that is normal (but sometimes confusing) JavaScript behaviour.