简体   繁体   English

按下后如何只发射一次键?

[英]How to make a key fire only once when pressed?

I'm making a simple JavaScript game (Space Invaders style) (Top-down space shooter) and I'm trying to make my character shoot a bullet per each 'space' key press. 我正在制作一个简单的JavaScript游戏(太空侵略者风格) (自上而下的太空射击游戏),并且我试图使我的角色每次按“空格”键时都会发射子弹。 How can I do that? 我怎样才能做到这一点?

I have tried multiple approaches, setting a flag, using onkeypress instead of keydown, Google searches (have also encountered this similar question yet it didn't help: Javascript onkeydown event fire only once? ) 我尝试了多种方法,设置了一个标志,使用onkeypress而不是keydown进行了Google搜索(也遇到过类似的问题,但这并没有帮助: Javascript onkeydown事件仅触发一次?

Below is an example of one solution I have tried. 以下是我尝试过的一种解决方案的示例。

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

Expected results: Key being fired only once. 预期结果:密钥仅发射一次。 Actual results: Key is being fired multiple times. 实际结果:多次触发密钥。

As @JaromandaX suggested, space = false; 正如@JaromandaX建议的那样, space = false; after p.shoot(); p.shoot(); will give you the desired result: 将给您想要的结果:

Reproducing the issue: 重现问题:

 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 /> 

EDIT: Added another isShot variable to keep track of shot fired and space key is down in requestAnimationFrame event: 编辑:添加了另一个isShot变量来跟踪射击,并且在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 /> 

There's really 3 states to a bullet - and, taking into consideration that in classic Space Invaders the player can only have one bullet in flight at a time, this makes things relatively simple 子弹实际上有3种状态-并且考虑到在经典的《太空侵略者》中,玩家一次只能飞行一颗子弹,因此事情变得相对简单

The bullet can be 子弹可以是

  • NONE - doesn't exist 无-不存在
  • FIRED - ie need to create one 点火-即需要创建一个
  • EXISTS - it's in flight 存在-在飞行中

The code to handle it is relatively simple too 处理它的代码也相对简单

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

I use fireBullet++ and fireBullet-- because I guess it's plausible that someone could press and release and press the spacebar within 16ms (single frame) :p 我使用fireBullet ++和fireBullet-因为我想有人可以在16ms(单帧)内按下并释放并按下空格键是合理的:p

You could also do 你也可以

function gameLoop(timeStamp) {
    if (fireBullet) {
        p.shoot();
        fireBullet--;
    }
    window.requestAnimationFrame(gameLoop);
}

that way you still handle multiple bullets OK, but only fire off one per frame - really depends on how you want to handle someone with a very fast trigger finger :p 这样,您仍然可以处理多发子弹,但每帧只能发射一颗子弹-确实取决于您要如何使用非常快速的触发手指来处理某人:p

Here you have two event, on each key press three are three even that get's fired 1. keydown (when user press the key but not yet release the key) 2. keypress (its fired after the keydown event) 3. keyup (When user release the key) If you want to fire only once for each keypress implement on of those if implement all of the three all three methods will fired. 在这里,你有两个活动,每个按键三个是三连那得到的烧制1 keydown (当用户按下按键,但尚未释放键)2. keypress (其keydown事件解雇后)3. keyup (当用户释放键),如果您只希望为每个按键实现触发一次,则在这三个方法中的全部实现都将被触发。 Additionally: for safety you can write e.preventDefault() . 另外:为了安全起见,您可以编写e.preventDefault()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM