如何在按下时只触发一次按键?
How to make a key fire only once when pressed?
我正在制作一个简单的 JavaScript 游戏 (Space Invaders 风格)(自上而下 space 射击游戏)并且我'我试图让我的角色每按一次 'space' 键就发射一颗子弹。我该怎么做?
我尝试了多种方法,设置标志,使用 onkeypress 而不是 keydown,Google 搜索(也遇到过类似的问题但没有帮助:Javascript onkeydown event fire only once?)
下面是我尝试过的一种解决方案的示例。
document.onkeydown = function(e)
{
if(e.keyCode == 32 && space == false)
{
space = true;
}
}
document.onkeyup = function(e)
{
if(e.keyCode == 32) space = false;
}
window.requestAnimationFrame(gameLoop);
function gameLoop(timeStamp)
{ if(space === true)
{
p.shoot();
}
window.requestAnimationFrame(gameLoop);
}
预期结果:密钥仅触发一次。
实际结果:密钥被触发多次。
这里有两个事件,每次按下三个键,即使被触发也是三个事件
1. keydown
(当用户按下键但尚未释放键时)
2. keypress
(在按键事件后触发)
3. keyup
(当用户松开按键时)
如果您只想为每个按键触发一次
如果实现所有这三种方法,将触发所有三种方法。
另外:为了安全起见,你可以写 e.preventDefault()
.
按照@JaromandaX的建议,space = false;
在p.shoot();
之后会给你想要的结果:
重现问题:
var space = false;
var element = document.querySelector('input');
element.onkeydown = function(e) {
if (!space && e.keyCode == 32) {
space = true;
console.log('event fired');
}
};
element.onkeyup = function(e) {
if (e.keyCode == 32)
space = false;
}
window.requestAnimationFrame(gameLoop);
function gameLoop(timeStamp) {
if (space == true) {
console.log('shoot');
}
window.requestAnimationFrame(gameLoop);
}
<input />
编辑:添加了另一个 isShot
变量来跟踪射击和 space 键在 requestAnimationFrame
事件中按下:
var space = false;
var element = document.querySelector('input');
var isShot = false;
element.onkeydown = function(e) {
if (!space && e.keyCode == 32) {
space = true;
console.log('event fired');
}
};
element.onkeyup = function(e) {
if (e.keyCode == 32) {
space = isShot = false;
}
}
window.requestAnimationFrame(gameLoop);
function gameLoop(timeStamp) {
if (space && !isShot) {
console.log('shoot');
isShot = true;
}
window.requestAnimationFrame(gameLoop);
}
<input />
一颗子弹实际上有 3 种状态 - 而且,考虑到在经典 Space 入侵者中,玩家一次只能发射一颗子弹,这让事情变得相对简单
子弹可以
- NONE - 不存在
- FIRED - 即需要创建一个
- 存在 - 正在飞行
处理的代码也比较简单
var BulletState = {
NONE: 0,
FIRED: 1,
EXISTS: 2
};
var bullet = BulletState.NONE;
document.onkeydown = function(e) {
if (e.keyCode == 32 && bullet === BulletState.NONE) {
bullet = BulletState.FIRED;
}
}
window.requestAnimationFrame(gameLoop);
function gameLoop(timeStamp) {
if (bullet === BulletState.FIRED) {
bullet = BulletState.EXISTS;
p.shoot(); // p.shoot needs to set bullet = BulletState.NONE when the bullet expires
}
window.requestAnimationFrame(gameLoop);
}
document.onkeyup = function(e)
{
// not required at all
}
edit: To fire a bullet every press of spacebar (allowing multiple bullets)
var space = false;
var fireBullet = 0;
document.onkeydown = function(e) {
if (e.keyCode == 32 && !e.repeat && !space) {
fireBullet++;
space = true;
}
}
window.requestAnimationFrame(gameLoop);
function gameLoop(timeStamp) {
while (fireBullet) {
p.shoot();
fireBullet--;
}
window.requestAnimationFrame(gameLoop);
}
document.onkeyup = function(e)
{
space = false;
}
我使用 fireBullet++ 和 fireBullet-- 因为我想有人可以在 16 毫秒(单帧)内按下和释放并按下空格键是合理的:p
你也可以
function gameLoop(timeStamp) {
if (fireBullet) {
p.shoot();
fireBullet--;
}
window.requestAnimationFrame(gameLoop);
}
这样你仍然可以处理多发子弹,但每帧只发射一发 - 这真的取决于你想如何处理扳机手指非常快的人 :p
我正在制作一个简单的 JavaScript 游戏 (Space Invaders 风格)(自上而下 space 射击游戏)并且我'我试图让我的角色每按一次 'space' 键就发射一颗子弹。我该怎么做?
我尝试了多种方法,设置标志,使用 onkeypress 而不是 keydown,Google 搜索(也遇到过类似的问题但没有帮助:Javascript onkeydown event fire only once?)
下面是我尝试过的一种解决方案的示例。
document.onkeydown = function(e)
{
if(e.keyCode == 32 && space == false)
{
space = true;
}
}
document.onkeyup = function(e)
{
if(e.keyCode == 32) space = false;
}
window.requestAnimationFrame(gameLoop);
function gameLoop(timeStamp)
{ if(space === true)
{
p.shoot();
}
window.requestAnimationFrame(gameLoop);
}
预期结果:密钥仅触发一次。 实际结果:密钥被触发多次。
这里有两个事件,每次按下三个键,即使被触发也是三个事件
1. keydown
(当用户按下键但尚未释放键时)
2. keypress
(在按键事件后触发)
3. keyup
(当用户松开按键时)
如果您只想为每个按键触发一次
如果实现所有这三种方法,将触发所有三种方法。
另外:为了安全起见,你可以写 e.preventDefault()
.
按照@JaromandaX的建议,space = false;
在p.shoot();
之后会给你想要的结果:
重现问题:
var space = false;
var element = document.querySelector('input');
element.onkeydown = function(e) {
if (!space && e.keyCode == 32) {
space = true;
console.log('event fired');
}
};
element.onkeyup = function(e) {
if (e.keyCode == 32)
space = false;
}
window.requestAnimationFrame(gameLoop);
function gameLoop(timeStamp) {
if (space == true) {
console.log('shoot');
}
window.requestAnimationFrame(gameLoop);
}
<input />
编辑:添加了另一个 isShot
变量来跟踪射击和 space 键在 requestAnimationFrame
事件中按下:
var space = false;
var element = document.querySelector('input');
var isShot = false;
element.onkeydown = function(e) {
if (!space && e.keyCode == 32) {
space = true;
console.log('event fired');
}
};
element.onkeyup = function(e) {
if (e.keyCode == 32) {
space = isShot = false;
}
}
window.requestAnimationFrame(gameLoop);
function gameLoop(timeStamp) {
if (space && !isShot) {
console.log('shoot');
isShot = true;
}
window.requestAnimationFrame(gameLoop);
}
<input />
一颗子弹实际上有 3 种状态 - 而且,考虑到在经典 Space 入侵者中,玩家一次只能发射一颗子弹,这让事情变得相对简单
子弹可以
- NONE - 不存在
- FIRED - 即需要创建一个
- 存在 - 正在飞行
处理的代码也比较简单
var BulletState = {
NONE: 0,
FIRED: 1,
EXISTS: 2
};
var bullet = BulletState.NONE;
document.onkeydown = function(e) {
if (e.keyCode == 32 && bullet === BulletState.NONE) {
bullet = BulletState.FIRED;
}
}
window.requestAnimationFrame(gameLoop);
function gameLoop(timeStamp) {
if (bullet === BulletState.FIRED) {
bullet = BulletState.EXISTS;
p.shoot(); // p.shoot needs to set bullet = BulletState.NONE when the bullet expires
}
window.requestAnimationFrame(gameLoop);
}
document.onkeyup = function(e)
{
// not required at all
}
edit: To fire a bullet every press of spacebar (allowing multiple bullets)
var space = false;
var fireBullet = 0;
document.onkeydown = function(e) {
if (e.keyCode == 32 && !e.repeat && !space) {
fireBullet++;
space = true;
}
}
window.requestAnimationFrame(gameLoop);
function gameLoop(timeStamp) {
while (fireBullet) {
p.shoot();
fireBullet--;
}
window.requestAnimationFrame(gameLoop);
}
document.onkeyup = function(e)
{
space = false;
}
我使用 fireBullet++ 和 fireBullet-- 因为我想有人可以在 16 毫秒(单帧)内按下和释放并按下空格键是合理的:p
你也可以
function gameLoop(timeStamp) {
if (fireBullet) {
p.shoot();
fireBullet--;
}
window.requestAnimationFrame(gameLoop);
}
这样你仍然可以处理多发子弹,但每帧只发射一发 - 这真的取决于你想如何处理扳机手指非常快的人 :p