Игра 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>

А вот и файл spacehip.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();
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
554
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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 выстрела в секунду).

Есть и более необычные вещи, которые вы можете сделать, чтобы создать систему дельта-времени, чтобы компенсировать задержку, изменив скорость симуляции в зависимости от времени, которое требуется вашему timeCycle для выполнения, но это, как правило, намного сложнее и легко испортить, поэтому я не стал бы предлагать новичкам спускаться в кроличью нору.

[РЕДАКТИРОВАТЬ] Итак, недавно я видел несколько вопросов о deltaTime, но не вижу хороших примеров того, как его реализовать; Итак, вот базовый пример, который я собрал. Чтобы реализовать это, просто замените часть GAME STUFF своим реальным кодом того, что происходит в игровом цикле, и запустите все ваши временные значения с помощью функции delta (), и она преобразует ваши значения из единиц в секунду в единиц на текущий кадр.

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>

Оба предложения великолепны и дали мне лучшее представление о том, как обрабатывать события, для которых должны быть установлены интервалы. Спасибо! Я попробую его, как только у меня будет время поработать над ним, и обновлю его здесь с решением.

Todor 08.11.2018 21:00

Я заметил, что на самом деле довольно сложно найти примеры кода deltaTime; Итак, я добавляю один на тот случай, если вы или кто-то еще решит, что они хотят попробовать.

Nosajimiki 09.11.2018 18:57

Вызов requestAnimationFrame запустит функцию рисования только со скоростью, поддерживаемой монитором, и только если компьютер достаточно быстр. Если код работает медленно, он будет время от времени автоматически пропускать вызов функции рисования. Следовательно, функция рисования должна содержать только код отрисовки и никакой логики.

Сначала вы должны поместить любой код, обновляющий состояние игры, в другую функцию, называемую 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;, но это должно помочь вам начать работу.

Как упоминал Джейк Хольцингер в комментариях, setInterval не на 100% точен, и функция обновления может быть вызвана на несколько миллисекунд позже, чем ожидалось. Вам придется самостоятельно проверять время между двумя вызовами, используя объекты Date или другие средства, если вы хотите точно рассчитать время, но я сомневаюсь, что это необходимо для простой игры-шутера.

Не гарантируется, что setInterval будет работать с точными интервалами, обратный вызов будет находиться в очереди событий, пока не получит возможность выполнить. «Постоянная скорость игры» требует использования временной разницы между тактами цикла моделирования.

Jake Holzinger 08.11.2018 20:56

@JakeHolzinger Я знаю, и Носаджимики уже упоминал об этом в своем ответе, но я старался свести введение новых концепций к минимуму. Думаю, я мог бы отредактировать свою формулировку, чтобы сделать ее более тонкой.

Domino 08.11.2018 21:33

Другие вопросы по теме