move element with keypress (multiple)

2019-03-08 22:10发布

Diagonal move not working and issue on left-longPress/right simultaneous

But on double keypress the ship goes crazy!

$(document).bind('keydown', function(e) {
    var box = $("#plane"),
        left = 37,
        up = 38,
        right = 39,
        down = 40

    if (e.keyCode == left) {
        box.animate({left: "-=5000"},3000);
    }
    if (e.keyCode == up) {
        box.animate({top: "-=5000"},3000);
    }
    if (e.keyCode == right) {
        box.animate({left:"+=5000"},3000);
    }
    if (e.keyCode == down) {
        box.animate({top: "+=5000"},3000);
    }
});
$(document).bind('keyup', function() {
    $('#plane').stop();
});

4条回答
手持菜刀,她持情操
2楼-- · 2019-03-08 22:29

Relying on keyboard events to move an element will make it dependent on the OS key-interval delay. Instead, use the game interval and check the pressed keys stored inside an Object

On keydown keyup events, if the keyCode returned by event.which is >=37 && <=40 means arrow keys were used. Store inside a K (keys) Object a boolean value for key-number property.

Interval:

Inside a window.requestAnimationFrame increase or decrease the x, y position of your element if a key-number property (inside our K object) is true (if(K[37])).

Diagonal movement:

Moving an element diagonally using simultaneously i.e. the and needs a compensation for the diagonal distance: 1 / Math.sqrt(2) (0.7071..)

const Player = {
  el: document.getElementById('player'),
  x: 200,
  y: 100,
  speed: 2,
  move() {
    this.el.style.transform = `translate(${this.x}px, ${this.y}px)`;
  }
};

const K = {
  fn(ev) {
    const k = ev.which;
    if (k >= 37 && k <= 40) {
      ev.preventDefault();
      K[k] = ev.type === "keydown"; // If is arrow
    }
  }
};

const update = () => {
  let dist = K[38] && (K[37] || K[39]) || K[40] && (K[37] || K[39]) ? 0.707 : 1;
  dist *= Player.speed;
  if (K[37]) Player.x -= dist;
  if (K[38]) Player.y -= dist;
  if (K[39]) Player.x += dist;
  if (K[40]) Player.y += dist;
  Player.move();
}

document.addEventListener('keydown', K.fn);
document.addEventListener('keyup', K.fn);

(function engine() {
  update();
  window.requestAnimationFrame(engine);
}());
#player{
  position: absolute;
  left: 0;  top: 0;
  width: 20px;  height: 20px;
  background: #000;  border-radius: 50%;
}
Click here to focus, and use arrows
<div id="player"></div>

查看更多
仙女界的扛把子
3楼-- · 2019-03-08 22:41

about that interval,

http://jsfiddle.net/fbFuW/21/

var leftDown, rightDown, upDown, downDown,leftKey,upKey,rightKey,downKey;
    var box = $("#plane");

function keye(e) {
    console.log(e.keyCode);
    var $key = e.keyCode;

    $(document).keydown(function(e) {
        if (e.keyCode == left && $key != left) leftDown = true;
        if (e.keyCode == right && $key != right) rightDown = true;
        if (e.keyCode == down && $key != down) downDown = true;
        if (e.keyCode == up && $key != up) upDown = true;
    }).keyup(function(e) {
        if (e.keyCode == left) leftDown = false;
        if (e.keyCode == right) rightDown = false;
        if (e.keyCode == down) downDown = false;
        if (e.keyCode == up) upDown = false;
    });
    if (e.keyCode == left) {
        leftKey = true;
    }

    if (e.keyCode == up) {
        upKey = true;
    }
    if (e.keyCode == right) {
        rightKey = true;
    }
    if (e.keyCode == down) {
        downKey = true;
    }

}

$("body").keydown(function(){
   keye(event); 
});


$("body").keyup(function(e){
       if (e.keyCode == left) {
        leftKey = false;
    }

    if (e.keyCode == up) {
        upKey = false;
    }
    if (e.keyCode == right) {
        rightKey = false;
    }
    if (e.keyCode == down) {
        downKey = false;
    }
});

setInterval(function() {
    if (leftDown) {
        box.css('left', '-=5');
    }

    if (rightDown) {
        box.css('left', '+=5');
    }

    if (downDown) {
        box.css('top', '+=5');
    }

    if (upDown) {
        box.css('top', '-=5');
    }

    if (upKey) {
        box.css("top", "-=5");
    }
    if (rightKey) {
        box.css("left", "+=5");
    }
    if (downKey) {
        box.css("top", "+=5");
    }
    if (leftKey) {
        box.css("left", "-=5");
    }


},20);
查看更多
【Aperson】
4楼-- · 2019-03-08 22:45

I messed around with a similar thing and here's a solution I came across that works.

setInterval(movePlane, 20);
var keys = {}

$(document).keydown(function(e) {
    keys[e.keyCode] = true;
});

$(document).keyup(function(e) {
    delete keys[e.keyCode];
});

function movePlane() {
    for (var direction in keys) {
        if (!keys.hasOwnProperty(direction)) continue;
        if (direction == 37) {
            $("#plane").animate({left: "-=5"}, 0);                
        }
        if (direction == 38) {
            $("#plane").animate({top: "-=5"}, 0);  
        }
        if (direction == 39) {
            $("#plane").animate({left: "+=5"}, 0);  
        }
        if (direction == 40) {
            $("#plane").animate({top: "+=5"}, 0);  
        }
    }
}

Demo

The problem with the delay seems to be that most browsers will take the first input (on keyDown) and then they have half a second delay before running the functions over and over. If we don't recall the function on keydown, but rather have an interval checking an associative array where we store what keys are being held down, that seems to smooth out movement. It also allows for multiple keys to be pressed at once, which means diagonal movement. Then we'll remove the respective keys by using the keyup event.

In this solution you have two ways of managing the speed of the element you're moving.

  1. The update frequency of the interval. (20ms in the demo above)
  2. The pixel count per move of the plane. (5 in the demo above)

I find that 20 ms on the interval frequency gives you fairly smooth movement.

I realize that this is a really old thread, but I figured I'd contribute anyway.

查看更多
Evening l夕情丶
5楼-- · 2019-03-08 22:51

How about this using jquery animate. It almost prevent delayed movement.

See demo

查看更多
登录 后发表回答