简体   繁体   English

如何将事件监听器(点击)添加到 canvas object?

[英]How to add event listener(click) to a canvas object?

I am building a new Javascript game with canvas and I would like to add an event listener to each object.我正在使用 canvas 构建一个新的 Javascript 游戏,我想为每个 object 添加一个事件侦听器。 I want to draw a useful joystick (arrows) when the game is opened from a smartphone/tablet.当从智能手机/平板电脑打开游戏时,我想画一个有用的操纵杆(箭头)。 So, the player will be able to move the character by clicking each arrow.因此,玩家将能够通过单击每个箭头来移动角色。

This is what I have:这就是我所拥有的:

Game.js:游戏.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: 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;
    }
}

(Code is similar for Left, Right and Up classes. The only difference are their position (X and Y) and their picture in drawImage). (Left、Right 和 Up 类的代码相似。唯一的区别是它们的 position(X 和 Y)以及它们在 drawImage 中的图片)。

As you can see in my code, I have tried adding addEventListener("click") but when I test it in a web browser, it works when I click anywhere in the screen.正如您在我的代码中看到的那样,我尝试添加 addEventListener("click") 但是当我在 web 浏览器中对其进行测试时,当我单击屏幕中的任意位置时它可以工作。 However, I only want it to work when I click each object (Down, Left, Right and Up).但是,我只希望它在单击每个 object(下、左、右和上)时工作。

I have also tried with this.addEventListener but it did now work either.我也尝试过this.addEventListener但它现在也可以工作。

This what happens when I click Down:当我单击向下时会发生这种情况:

在此处输入图像描述

Also, I do not understand why it prints "click" so many times.另外,我不明白为什么它会多次打印“点击”。 I have clicked the down arrow just once!我只单击了一次向下箭头! There are like 600 prints like those!像这样的印刷品有600张! It should be just one from Down.js .它应该只是Down.js中的一个。

Can anyone help?任何人都可以帮忙吗?

The reason it is running click so many times is that you are adding the event listener in your draw function, which is being called every single frame, and once for each button.它运行 click 这么多次的原因是你在你的 draw function 中添加了事件监听器,它被每帧调用一次,每个按钮调用一次。 If the game is at 60fps and has been running for just one second, that's 240 event listeners that are all doing the same thing!如果游戏以 60fps 的速度运行并且只运行了一秒钟,那就是 240 个事件侦听器都在做同样的事情!

Event listeners don't go away, so you only need to add one.事件监听器不会 go 掉,所以你只需要添加一个。 Also, just having addEventListener() adds the event listener to the document object.此外,只需使用addEventListener()即可将事件侦听器添加到文档 object 中。 This isn't a problem since your canvas takes up the whole screen, but you can attach an event listener to the canvas specifically with this.canvas.addEventListener() (Inside the game class).这不是问题,因为您的 canvas 占据了整个屏幕,但是您可以将事件侦听器附加到 canvas 专门使用this.canvas.addEventListener() (在游戏内类)。 I think that would work best in the initialize function.我认为这在初始化 function 时效果最好。

Now, about having the click only register on the buttons: Unfortunately you can't add event listeners to objects that are not HTML nodes.现在,关于在按钮上仅注册单击:不幸的是,您无法将事件侦听器添加到不是 HTML 节点的对象。 The only way I've found to get around this is to add an event listener that runs every time you click on the canvas, and then to loop through all the buttons, checking if the click was within the bounds of the buttons.我发现解决此问题的唯一方法是添加一个事件侦听器,每次单击 canvas 时都会运行该事件侦听器,然后遍历所有按钮,检查单击是否在按钮的范围内。

The function in the event listener can have a parameter事件监听器中的function可以有一个参数

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();
                }
            }
        });
        //...
    }
    //...
}

Hopefully I didn't make any mistakes in this... You'll notice I replaced the "click" event with "mousedown" because the click event doesn't fire until you let go of the button, but mousedown fires when you press the button.希望我在这方面没有犯任何错误...您会注意到我将“click”事件替换为“mousedown”,因为单击事件在您让按钮的 go 触发之前不会触发,但是当您按下时会触发 mousedown按钮。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM