What is the best way to handle multiple key events in Javascript?

前端 未结 4 2040
半阙折子戏
半阙折子戏 2021-02-08 11:24

Pressing space bar in game will make a character shoot, pressing space bar when a confirmation box is shown will make this box disappear and pressing space bar in a highscore fo

相关标签:
4条回答
  • 2021-02-08 11:35

    Attach event listeners to individual elements instead of the entire document.

    document.getElementById('highscore').onkeypress = function(keyEvent) {
          if (is_spacebar(keyEvent)) //Do something...
    };
    
    document.getElementById('game').onkeypress = function(keyEvent) {
          if (is_spacebar(keyEvent)) //Do something else...
    };
    

    This is a simplistic example. You will probably have to deal with event bubbling which can be controlled when using addEventListener() to attach functions to events. Given browser (IE) compatibility issues involving this, some JS library should be used to deal with events.

    0 讨论(0)
  • 2021-02-08 11:38

    There are a few ways, typically involving code-branching for IE's ‘special’ event model.

    One way is to stop keypresses handled further down from bubbling up to the document key handler:

    confirmationbox.onkeydown = function(event) {
        if (event === undefined) event = window.event;
    
        // do something with event.keyCode
    
        if ('stopPropagation' in event) // standards browsers
            event.stopPropagation();
        else if ('cancelBubble' in event) // IE before version 9
            event.cancelBubble = true;
    };
    
    document.onkeydown = ... // will not be called for keydowns inside confirmationbox
    

    Another way would be to check the event target element to see if it's in the box:

    document.onkeydown = function(event) {
        if (event === undefined) event = window.event;
        var target = 'target' in event ? event.target : event.srcElement; // srcElement is for IE<9
    
        if (target === containerbox || isDescendantOf(target, containerbox) {
            // do containerbox stuff
        } else {
            // do other stuff
        }
    };
    
    function isDescendantOf(element, ancestor) {
        while (element = element.parentNode)
            if (element === ancestor)
                return true;
        return false;
    }
    
    0 讨论(0)
  • 2021-02-08 11:49

    Functions are first-class objects in javascript, which makes them really powerful. Because of this, your problem can be solved very elegantly.

    // the whole thing can be encapsulated 
    // into an object actually
    
    function spaceBarHandler() {
      var state = spaceBarHandler.state;
      var actions = spaceBarHandler.actions;
    
        // execute function if exists
        if (actions[state]) {
          actions[state]();
        }
    }
    
    // spaceBar actions
    spaceBarHandler.actions = {
      shoot: function() {
        // bang bang
      },
      removeBox: function() {
        // do it...
      }
    };
    
    // change current state from outside
    // we are in the game
    spaceBarHandler.state = "shoot";
    
    // change current state from outside
    // confirmation box is shown 
    spaceBarHandler.state = "removeBox";
    

    All these cases will be handled by one function. If you want to extend with another case, you just add another function to the actions object. Notice how the whole thing is encapsulated into one object.

    0 讨论(0)
  • 2021-02-08 11:57

    you could instead add and remove the event listener as needed.

    let's assume you're using a javascript framework (if you're not, then you probably should be considering the amount of JS code involved in a game like this)

    using PrototypeJS:

    when game starts,

    document.observe("keydown",shootHandler());
    

    when the message box is created,

    function createBox(text) {
        ...snip
    
        document.observe("keydown",closeBox());
        document.fire("game:pause");
    }
    

    and, for example

    var paused = false;
    
    function shoothandler() {
       if (!paused) {
           alert("pew! pew!");
       }
    }
    
    function closeBox() {
        $('messagebox').remove();
        document.fire("game:unpaused");
        document.stopObserving("keydown",closeBox());
    }
    
    document.observe("game:paused", function() { paused = true;});
    document.observe("game:unpaused", function() { paused = false;});
    document.observe("game:over", function() { document.stopObserving("keydown",shootHandler());});
    

    I haven't included the high score screen but the theory is the same.

    As you can see, I also used custom events to notify the pause status. The same event could also be fire by a puase button in the interface, etc...

    0 讨论(0)
提交回复
热议问题