Search code examples
javascriptperformancegame-development

Event listener delay when key held


Ive made a fairly simple movement script for a web based game I am making and I noticed that when a key is held down, it runs the movements once, waits a while, then starts moving continuously. I assume this is a thing that's done by browsers to stop users from accidentally typing thousands of letters when holding a key down for too long, but is there any way to disable this?

This is a method used in my "Game" class which has all the functions needed for the game too run

movement(player) {
    let movements = {
        up: false,
        down: false,
        left: false,
        right: false,
        speed: 0,
        maxSpeed: 10,
        lastMove: null
    }

    function controls(e) {
        const key = e.key;
        if (key == "w") {
            e.preventDefault();
            movements.up = true;
        }
        if (key == "s") {
            e.preventDefault();
            movements.down = true;
        }
        if (key == "a") {
            e.preventDefault();
            movements.left = true;
        }
        if (key == "d") {
            e.preventDefault();
            movements.right = true;
        }
    }

    function movement(x) {
        let direction = null;

        if (movements.up) direction = "up";
        else if (movements.down) direction = "down";
        else if (movements.left) direction = "left";
        else if (movements.right) direction = "right";

        if (direction) {
            if (direction == "up" || direction == "down") {
                player.src = `${x.data.entities.player.image}${direction}.png`;
                player.style.top = `${parseInt(player.style.top) + (direction == "up" ? -1 : 1) * movements.speed}px`;
            } else {
                player.src = `${x.data.entities.player.image}${direction}.png`;
                player.style.left = `${parseInt(player.style.left) + (direction == "left" ? -1 : 1) * movements.speed}px`;
            }
            movements.lastMove = direction;
        }

        if (direction && movements.speed < movements.maxSpeed) {
            movements.speed++;
        }

        if (direction) {
            movements.up = false;
            movements.down = false;
            movements.left = false;
            movements.right = false;
        }

        requestAnimationFrame(() => movement(x));
    }


    requestAnimationFrame(() => movement(this));
    document.addEventListener("keydown", (e) => {
        controls(e);
    });
}

Solution

  • A well known approach to minimize the dependency on OS and hardware is to handle yourself the keys state (up or down). Then you can just tell when key is down by looking at this dictionary object.

    var obj_down = {}
    var direction
    
    window.addEventListener("keydown", function(ev) {
      obj_down[ev.key] = true;
    })
    
    window.addEventListener("keyup", function(ev) {
      delete obj_down[ev.key];
    })
    
    
    function loop() {
      var keys = Object.keys(obj_down)
      output.innerText = "" + keys
    
      // for example:
      if (obj_down["ArrowDown"]) {
        direction = "down"
      }
      requestAnimationFrame(loop)
    }
    loop()
    Keys that are currently down: 
    <div id="output"></div>