0

我正在用画布构建一个新的 Javascript 游戏,我想为每个对象添加一个事件监听器。当从智能手机/平板电脑打开游戏时,我想画一个有用的操纵杆(箭头)。因此,玩家将能够通过单击每个箭头来移动角色。

这就是我所拥有的:

游戏.js:

class Game {
    constructor() {
        this.touchDevice = false;
        this.joystickDown = new Down();
        this.joystickLeft = new Left();
        this.joystickRight = new Right();
        this.joystickUp = new Up();
        this.imgDownArrow = new Image();
        this.imgLeftArrow = new Image();
        this.imgRightArrow = new Image();
        this.imgUpArrow = new Image();
        this.gameStruct = new Object();
        this.gameLoaded = true;
        this.gameOver = false;
    }
}

    initialize(width = 640, height = 480) {
        console.log("Game initialized");
        this.canvas = document.getElementById("canvas");
        this.canvas.width = width;
        this.canvas.height= height;

        if(this.canvas && this.canvas.getContext) {
            this.ctx = this.canvas.getContext("2d");
            if(this.ctx) {
                this.ctx.strokeStyle="#000";

                this.gameStruct.ctx = this.ctx;
                this.gameStruct.canvas = this.canvas;

                function is_touch_device() {  
                    try {  
                      document.createEvent("TouchEvent");
                      return true;  
                    } catch (e) {  
                      return false;  
                    }  
                  }

                this.touchDevice = is_touch_device();

                if(this.touchDevice) {                  
                    this.imgDownArrow.src = "img/joystick/arrow_down.png";
                    this.imgLeftArrow.src = "img/joystick/arrow_left.png";
                    this.imgRightArrow.src = "img/joystick/arrow_right.png";
                    this.imgUpArrow.src = "img/joystick/arrow_up.png";

                    this.gameStruct.imgDownArrow = this.imgDownArrow;
                    this.gameStruct.imgLeftArrow = this.imgLeftArrow;
                    this.gameStruct.imgRightArrow = this.imgRightArrow;
                    this.gameStruct.imgUpArrow = this.imgUpArrow;

                    this.joystickDown.initialize(this.gameStruct);
                    this.joystickLeft.initialize(this.gameStruct);
                    this.joystickRight.initialize(this.gameStruct);
                    this.joystickUp.initialize(this.gameStruct);                    
                }

            } else 
                alert("error_context");
            }
    }

    animate() {
        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);

        if(!this.gameOver) {
            this.player.draw();
            if(this.touchDevice) {
                this.joystickDown.draw();
                this.joystickLeft.draw();
                this.joystickRight.draw();
                this.joystickUp.draw();
            }
        }
        window.requestAnimationFrame(this.animate.bind(this));
    }

Down.js:

class Down {
    constructor() {
    }

    initialize(gameStruct) {

        this.gameStruct = gameStruct;
        this.ctx = gameStruct.ctx;
        this.width = gameStruct.canvas.width / 15;
        this.height = gameStruct.canvas.width / 15;
        this.x = (gameStruct.canvas.width) - (this.width*2);
        this.y = gameStruct.canvas.height-this.height;
        this.limitTop = 0;
        this.limitBottom = gameStruct.canvas.height;
        this.limitLeft = 0;
        this.limitRight = gameStruct.canvas.width;
        this.shiftX = this.width / 8;
        this.shiftY = this.height / 8;
        console.log("Joystick initialized");
        return this;
    }

    draw() {
        this.ctx.drawImage(this.gameStruct.imgDownArrow, this.x, this.y, this.width, this.height);
        addEventListener("click", function() {
            console.log("clicked");
        });
        return this.gameStruct;
    }
}

(Left、Right 和 Up 类的代码类似。唯一的区别是它们的位置(X 和 Y)以及它们在 drawImage 中的图片)。

正如您在我的代码中看到的那样,我尝试添加 addEventListener("click") 但是当我在网络浏览器中对其进行测试时,当我单击屏幕中的任意位置时它会起作用。但是,我只希望它在单击每个对象(下、左、右和上)时工作。

我也尝试过,this.addEventListener但现在也可以了。

当我单击向下时会发生这种情况:

在此处输入图像描述

另外,我不明白为什么它会多次打印“点击”。我只单击了一次向下箭头!像这样的印刷品有600张!它应该只是一个来自Down.js.

任何人都可以帮忙吗?

4

1 回答 1

0

它运行 click 这么多次的原因是您在绘制函数中添加了事件侦听器,该函数每帧调用一次,每个按钮调用一次。如果游戏以 60fps 的速度运行并且只运行了一秒钟,那就是 240 个事件侦听器都在做同样的事情!

事件侦听器不会消失,因此您只需添加一个。此外,只需addEventListener()将事件侦听器添加到文档对象。这不是问题,因为您的画布占据了整个屏幕,但您可以专门使用this.canvas.addEventListener()(在游戏类中)将事件侦听器附加到画布。我认为这在初始化函数中效果最好。

现在,关于仅在按钮上注册单击:不幸的是,您不能将事件侦听器添加到不是 HTML 节点的对象。我发现解决此问题的唯一方法是添加一个事件侦听器,每次单击画布时都会运行该事件侦听器,然后循环遍历所有按钮,检查单击是否在按钮的范围内。

事件监听器中的函数可以有参数

class Game {
    //...
    initialize() {
        //...

        // I put the buttons in an array so that you can loop through them.
        let buttons = [this.joystickDown, this.joystickUp, this.joystickLeft, this.joystickRight];
        this.canvas.addEventListener('mousedown', function(evt) {
            // The X and Y coordinates of the mouse, relative to the top left corner
            let x = evt.clientX;
            let y = evt.clientY;

            for (let button of buttons) {
                // checkClick is a method you'll have to add to the joystick classes. It'll
                // take in X and Y coordinates and tell if they are within the button.
                if (button.checkClick(x, y)) {
                    // This is a method you'll have on the joystick classes to handle the click.
                    button.handleClick();
                }
            }
        });
        //...
    }
    //...
}

希望我没有在这方面犯任何错误...您会注意到我将“click”事件替换为“mousedown”,因为在您松开按钮之前单击事件不会触发,但是当您按下时会触发 mousedown按钮。

于 2020-05-03T14:19:41.753 回答