Javascript游戏,按下间隔使太空船射击

时间:2018-11-08 19:04:04

标签: javascript

我正在研究自己的游戏技能(主要是使用数组)来生成敌人,现在使用子弹将其击落。我能够在测试时设置项目符号,但是只有当我按下一个键(比如说空格键)并且在它们之间没有间隔时,它才可见,因此浏览器无法一次完成那么多任务。

有没有一种简单的方法可以使飞船发射子弹,并且它们之间有一定间隔(不会给浏览器加载太多时间),也许是在去敌人[i] .x / y位置以删除敌人时,子弹可以消失了吗?

这里是我目前拥有的尽可能多的已清理代码(HTML和JS文件。也有一些图像,并会提供游戏的URL以便在需要时进行检查-http://sarahkerrigan.biz/spaceship

<!DOCTYPE html>
<html>
  <head>
    <title>Space Ship</title>
  </head>
  <body>
   <h3>Space Ship</h3>

   <canvas id="canvas" width="1000" height="600"></canvas>

   <script src="spaceship.js"></script>
  </body>
</html>

这是spaceship.js文件:

var cvs = document.getElementById("canvas");
var ctx = cvs.getContext("2d");
//-------------------------------

// load images

var player = new Image();
var enemy = new Image();
var bullet = new Image();


player.src = "images/player.png";
enemy.src = "images/enemy.png";
bullet.src = "images/fire.png";
//-------------------------------

// vars
var score = 0;
var pause = 0;

var playerY = 300;
var playerX = 100;

var upPressed = false;
var downPressed = false;
var leftPressed = false;
var rightPressed = false;

// audio
var fire = new Audio();
var hit = new Audio();

fire.src = "sounds/fire.mp3";
hit.src = "sounds/hit.mp3";


//-------------------------------
// on key down
document.addEventListener("keydown", keyDownHandler);

function keyDownHandler(e) {
  if (e.keyCode == 87) {
    upPressed = true;
  }
  if (e.keyCode == 83) {
    downPressed = true;
  }
  if (e.keyCode == 65) {
    leftPressed = true;
  }
  if (e.keyCode == 68) {
    rightPressed = true;
  }
}

// on key up
document.addEventListener("keyup", keyUpHandler);

function keyUpHandler(e) {
  if (e.keyCode == 87) {
    upPressed = false;
  }
  if (e.keyCode == 83) {
    downPressed = false;
  }
  if (e.keyCode == 65) {
    leftPressed = false;
  }
  if (e.keyCode == 68) {
    rightPressed = false;
  }
}




//-------------------------------



function moveUp() {
 if (playerY <= canvas.height - canvas.height){
 }
 else{
  playerY -= 6;
 }
}

function moveDown() {
 if (playerY >= canvas.height - player.height){
 }
 else{
  playerY += 6;
 }
}

function moveLeft() {
 if (playerX <= canvas.width - canvas.width){
 }
 else{
  playerX -= 6;
 }
}

function moveRight() {
 if (playerX >= canvas.width - player.width){
 }
 else{
  playerX += 6;
 }
}




//-------------------------------
// Enemy coordinates

var enemies = [];

enemies[0] = {
  x: cvs.width,
  y: 0
};

//-------------------------------

// reload page

function reLoad() {
  location.reload(); // reload the page
}


//-------------------------------
// draw images

function draw() {

  ctx.fillStyle = "black";
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  if (upPressed === true) {
    moveUp();
  }
  if (downPressed === true) {
    moveDown();
  }
  if (leftPressed === true) {
    moveLeft();
  }
  if (rightPressed === true) {
    moveRight();
  }


//-------------------------------
  for (var i = 0; i < enemies.length; i++) {

    //draw the enemy
    ctx.drawImage(enemy, enemies[i].x, enemies[i].y);

    // enemy movement speed
    enemies[i].x -= 3;

    if (enemies[i].x == 880) {
      enemies.push({
        x: cvs.width,
        y: Math.floor(Math.random() * enemy.height) * 10 - enemy.height
      });
    }

    // detect collision

    // if enemy hits player
    if (playerX + player.width >= enemies[i].x && playerX <= enemies[i].x + enemy.width && (playerY <= enemies[i].y + enemy.height && playerY + player.height >= enemies[i].y)) {
      pause = 1;
    }
  }
//-------------------------------


  //draw the player
  ctx.drawImage(player, playerX, playerY);



  //draw score
  ctx.fillStyle = "#fff";
  ctx.font = "20px Verdana";
  ctx.fillText("Destroyed ships : " + score + "$", 10, cvs.height - 20);


  function onPause() {
    if (pause >= 1) {
      hit.play();
      ctx.fillStyle = "#df8a62";
      ctx.fillRect(150, 150, 280, 100);

      ctx.fillStyle = "#000";
      ctx.font = "20px Verdana";
      ctx.fillText("You died:", 165, 170);

      document.addEventListener("keydown", reLoad);
    } else if (pause <= 0) {
      requestAnimationFrame(draw);
    }
  }

  onPause();

}

draw();

2 个答案:

答案 0 :(得分:2)

您要使用时间间隔而不是侦听器。

var myVar = setInterval(timeCycle, 50);
function timeCycle() {
    //all the stuff you currently have listeners for.
}

这样,当时间间隔发生时,它将只执行一次按键。然后,如果您想更改射速,请添加以下内容:

setInterval(timeCycle, 50);
rateOfFire = 5;
shootCoolDown = 0;
function timeCycle() {
    if (shootPressed === true) {
        if(shootCoolDown === 0){
            shootCoolDown = rateOfFire;
            shoot();
        } 
    }
    if (shootCoolDown > 0){
        shootCoolDown --;
    }
}

这样,它将每5个游戏周期射击一次(在这种情况下,每秒射击4个回合)。

您可以做更多花哨的事情来创建一个增量时间系统,以根据执行时间周期的时间来更改模拟率,从而抵消时滞,但这往往更加复杂且容易弄乱。 ,所以我不建议初学者钻进那个兔子洞。

[编辑] 因此,我最近看到了有关deltaTime的几个问题,但是看不到任何有关如何实现它的好例子。因此,这是我一起提出的一个基本示例。要实现它,只需用游戏周期中发生的事情的实际代码替换GAME STUFF部分,然后通过delta()函数运行所有基于时间的值,它将把您的值从每秒转换为单位。每个currentFrame的单位。

My game us under a load of <input type="text" id="lag" value="100000000"> operations per frame.<br>
My speed is = <input type="text" id="speed" value="500"> px per second<br>
I moved <span id="adjusted"></span>px this frame.<br>
FPS: <span id="fps"></span>

<script>
function wrapDelta(lastTime){
   var d = new Date();
   var n = d.getSeconds()*1000 + d.getMilliseconds();
   if (lastTime >= n) {
        lastTime -= 60000;
   }
   return n - lastTime;
}

function delta(input){
   return input * deltaCoeff / 1000;
}

var d = new Date();
var ed = new Date();
var endTime =  d.getSeconds()*1000 + d.getMilliseconds();
var startTime =  d.getSeconds()*1000 + d.getMilliseconds();
var deltaCoeffMin = 25;
var deltaCoeff = deltaCoeffMin;

setInterval(function () {
    d = new Date();
    startTime =  d.getSeconds()*1000 + d.getMilliseconds();

    // START GAME STUFF
    var lag = Math.round(Math.sqrt(document.getElementById('lag').value)); //because comparing large numbers caused a wierd lag spike at from 9999999 to 10000000 
    var speed = document.getElementById('speed').value; 
    document.getElementById('adjusted').innerHTML = delta(speed);
    document.getElementById('fps').innerHTML = (1000/deltaCoeff).toFixed(2);
    var i; var j; var k; for (i=0; i<lag; i++){ for (j=0; j<lag; j++){ k = 1234567*1.1;}} //This is just a random math loop to simulate the lag cause by actual game stuff
    // END GAME STUFF

    ed = new Date();
    endTime = ed.getSeconds()*1000 + ed.getMilliseconds();
    deltaCoeff = endTime - startTime;
    if (deltaCoeff < deltaCoeffMin){deltaCoeff = deltaCoeffMin;}
  } , deltaCoeffMin);
</script>

答案 1 :(得分:1)

仅当计算机足够快时,对requestAnimationFrame的调用才会以显示器支持的速率运行绘图功能。如果代码运行缓慢,它将不时自动跳过对绘图函数的调用。因此,draw函数应该只包含渲染代码,而不能包含逻辑。

您应该首先将任何更新游戏状态的代码放入另一个称为update的函数中。将使用setInterval以一致的速率调用此函数:

function update() {
    // read inputs
    // move objects
    // detect collisions
    // etc.

    // render a new frame only if the browser is done drawing the previous one
    requestAnimationFrame(draw);
}

// run the update function 60 times per second
var updateInterval = setInterval(update, 1000 / 60);

存储updateInterval总是很好,这样我们就可以停止游戏在clearInterval(updateInterval)下完全运行,但是您可能永远不需要使用它。

现在您的游戏速度有些一致,您可以像这样设置射击的冷却时间:

if (fireCooldown > 0) {
  fireCooldown -= 1;
}

if (/* holding the fire key */ && fireCooldown === 0) {
  // create a projectile in front of the player ship
  fireCooldown = 30;
}

您需要先在某个地方声明该变量,然后在某个地方声明var fireCooldown = 0;,但这应该可以帮助您入门。

正如杰克·霍尔辛格(Jake Holzinger)在评论中所提到的,setInterval并非100%准确,因此更新功能的调用时间可能比预期的晚几毫秒。如果您想对时间进行完美计时,则必须使用Date对象或其他方式检查两次通话之间的时间,但是我怀疑这对于简单的射击游戏是必要的。