最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - KeyListener in TypeScript and "this" context - Stack Overflow

programmeradmin3浏览0评论

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
Add a ment  | 

1 Answer 1

Reset to default 6

There 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.

发布评论

评论列表(0)

  1. 暂无评论