通过按键移动元素(多个)

发布于 2024-12-02 15:07:59 字数 608 浏览 1 评论 0原文

对角线移动不起作用,并在左长按/右同时发出问题,

但是在双击按键时,船变得疯狂!

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

×眷恋的温暖 2024-12-09 15:07:59

我搞乱了类似的事情,这是我遇到的一个有效的解决方案。

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

延迟的问题似乎是大多数浏览器将采用第一个输入(在 keyDown 上)然后他们在一遍又一遍地运行这些功能之前有半秒的延迟。如果我们不记得按下按键时的功能,而是有一个时间间隔检查一个关联数组,在该数组中存储按下的键,这似乎可以平滑移动。它还允许同时按下多个键,这意味着对角线移动。然后我们将使用 keyup 事件删除相应的键。

在此解决方案中,您有两种方法来管理正在移动的元素的速度。

  1. 间隔的更新频率。 (上面的演示中为 20 毫秒)
  2. 平面每次移动的像素数。 (上面演示中的 5)

我发现 20 毫秒的间隔频率可以让您实现相当平滑的运动。

我意识到这是一个非常古老的线程,但我想无论如何我都会做出贡献。

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.

夕色琉璃 2024-12-09 15:07:59

关于该间隔,

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);

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);
梅窗月明清似水 2024-12-09 15:07:59

在游戏开发中,最好在键盘周围创建一个包装器。
这样的包装器应该实现以下内容:

  • 当按下一个键时,使用 Event.preventDefault() 来防止浏览器执行默认操作(例如,在箭头键上滚动页面),
  • 防止自动按键重复(在~1s 长按)检查 keydown 事件是否不是 Event.repeat
  • 使用数组或 Set 来存储所有活动(按下)键的 Event。关键
  • 使用对象或 Map 来定义我们想要
  • 在游戏循环内为特定键名 (Event.key) 触发的函数操作,迭代该组按下的键并调用相关操作

函数修复对角玩家移动,您可以通过两种方式实现,使用旋转角度,或者将玩家对角移动 1 / Math.sqrt(2) (大约 ~ 0.7071代码>) 距离。在下面的示例中,我将使用角度(以弧度为单位):

const player = {
  el: document.querySelector("#player"),
  x: 100, y: 50,
  dirX: 0, dirY: 0,
  velX: 0, velY: 0,
  power: 2, angle: 0,
  move() {
    if (this.dirX || this.dirY) {
      this.angle = Math.atan2(this.dirY, this.dirX);
      this.velX = Math.cos(this.angle) * this.power;
      this.velY = Math.sin(this.angle) * this.power;
      this.x += this.velX;
      this.y += this.velY;
      this.dirX = this.dirY = 0; // Reset directions
    }
    this.el.style.translate = `${this.x}px ${this.y}px`;
    this.el.style.rotate = `${this.angle}rad`;
  }
};

const keyboard = {
  actions: new Map(Object.entries({
    ArrowLeft  () { player.dirX = -1; },
    ArrowRight () { player.dirX =  1; },
    ArrowUp    () { player.dirY = -1; },
    ArrowDown  () { player.dirY =  1; },
    // add more key actions here
  })),
  keys: new Set(),
  handle(evt) {
    if (evt.repeat || !this.actions.has(evt.key)) return;
    evt.preventDefault();
    this.keys[evt.type === "keydown" ? "add" : "delete"](evt.key);
  },
  callActions() {
    for (let key of this.keys) this.actions.get(key)();
  }
};

addEventListener("keydown", (evt) => keyboard.handle(evt));
addEventListener("keyup", (evt) => keyboard.handle(evt));

const engine = () => {
  keyboard.callActions();
  player.move();
  requestAnimationFrame(engine);
};

engine();
#player{
  position: absolute;
  left: 0;  top: 0;
  width: 20px;  height: 20px;
  background: #0bf;  border-radius: 50%;
}
Click here to focus and use arrow keys to move:
<div id="player">→</div>

In game development it's best to create a wrapper around the keyboard.
Such wrapper should implement the following:

  • when a key is pressed use Event.preventDefault() to prevent the browser doing default stuff (like i.e. page scrolling on arrow keys)
  • prevent the automatic key-repeat (after a ~1s long-press) check if the keydown event is not an Event.repeat
  • use an array or Set to store all the active (pressed) key's Event.key
  • use an object or Map to define the function actions that we want to trigger for a specific key-name (Event.key)
  • inside the game loop iterate that Set of pressed keys and call the related action function

To fix the diagonal player movement, you can do it in wo ways, using an angle of rotation, or move the player diagonally by 1 / Math.sqrt(2) (approximately ~ 0.7071) distance. In the following example I'll use angles (in radians):

const player = {
  el: document.querySelector("#player"),
  x: 100, y: 50,
  dirX: 0, dirY: 0,
  velX: 0, velY: 0,
  power: 2, angle: 0,
  move() {
    if (this.dirX || this.dirY) {
      this.angle = Math.atan2(this.dirY, this.dirX);
      this.velX = Math.cos(this.angle) * this.power;
      this.velY = Math.sin(this.angle) * this.power;
      this.x += this.velX;
      this.y += this.velY;
      this.dirX = this.dirY = 0; // Reset directions
    }
    this.el.style.translate = `${this.x}px ${this.y}px`;
    this.el.style.rotate = `${this.angle}rad`;
  }
};

const keyboard = {
  actions: new Map(Object.entries({
    ArrowLeft  () { player.dirX = -1; },
    ArrowRight () { player.dirX =  1; },
    ArrowUp    () { player.dirY = -1; },
    ArrowDown  () { player.dirY =  1; },
    // add more key actions here
  })),
  keys: new Set(),
  handle(evt) {
    if (evt.repeat || !this.actions.has(evt.key)) return;
    evt.preventDefault();
    this.keys[evt.type === "keydown" ? "add" : "delete"](evt.key);
  },
  callActions() {
    for (let key of this.keys) this.actions.get(key)();
  }
};

addEventListener("keydown", (evt) => keyboard.handle(evt));
addEventListener("keyup", (evt) => keyboard.handle(evt));

const engine = () => {
  keyboard.callActions();
  player.move();
  requestAnimationFrame(engine);
};

engine();
#player{
  position: absolute;
  left: 0;  top: 0;
  width: 20px;  height: 20px;
  background: #0bf;  border-radius: 50%;
}
Click here to focus and use arrow keys to move:
<div id="player">→</div>

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文