Как нарисовать маркеры из проигрывателя в vanilla Javascript?

#javascript #html #function #html5-canvas

#javascript #HTML #функция #html5-canvas

Вопрос:

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

Любая помощь?

Вот мой код на данный момент.

Заранее благодарю вас.

 var project, ctx, img, img2, width, height, mid, midh, startPx, startPy, audio,interval,bulletStartPx,bulletStartPy;
var score = 0;

function setUp() {
 project = document.getElementById("project");
 ctx = project.getContext("2d");
 width = 505;
 height = 900;
 mid = width/2;
 midh = height/2;
 startPx = width/2-30;
 startPy = height-150;

 audio = new Audio("bgm.mp3");
 audio.play();

 img = new Image();
 img2 = new Image();
 img.src = "bg.png";
 img2.src = "fighterjet.png"
 img.onload = function(){
   ctx.shadowColor = "#ffffff";
   ctx.shadowBlur = 15;
   ctx.drawImage(img, 0, 0);
   ctx.drawImage(img2, startPx, startPy)
 }
 
 window.addEventListener("keydown", checkKeyPress);
}

function drawObject(x, y) {
  ctx.drawImage(img2, startPx, startPy)
}

function checkKeyPress(event) {
  if (event.keyCode == "87") {//W(UP)
    ctx.clearRect(0,0,width,height);
    if (startPy >= 20) {
    startPy -= 20;
    }
    ctx.drawImage(img, 0, 0);
    ctx.drawImage(img2, startPx, startPy)
  } else if (event.keyCode == "83") {//S(DOWN)
    ctx.clearRect(0,0,width,height);
    if (startPy <= 785) {
    startPy  = 20;
    }
    ctx.drawImage(img, 0, 0);
    ctx.drawImage(img2, startPx, startPy)
  } else if (event.keyCode == "65") {//A(LEFT)
    ctx.clearRect(0,0,width,height);
    if (startPx >= 0) {
    startPx -= 20;
    }
    ctx.drawImage(img, 0, 0);
    ctx.drawImage(img2, startPx, startPy)
  } else if (event.keyCode == "68") {//D(RIGHT)
    ctx.clearRect(0,0,width,height);
    if (startPx <= 410) {
    startPx  = 20;
    }
    ctx.drawImage(img, 0, 0);
    ctx.drawImage(img2, startPx, startPy)
  } else if (event.keyCode == "72") {
    for (let i = 0; i < 6; i  ) {
      bullets();
  }
}
}

function bullets() {
  return setInterval(function(){
          bulletStartPx = startPx 48;
          bulletStartPy = startPy-30;
          ctx.fillStyle = "gold"
          ctx.beginPath();
          ctx.arc(bulletStartPx,bulletStartPy,5,0,2*Math.PI);
          ctx.fill();
          score  = 25; }, 100);
}

function GameOver(){
  document.getElementById('bm').pause();
  ctx.font = '30px Courier New'
  ctx.filltext('GAME OVER', mid, midh)
  ctx.filltext('Your score was: ' score, mid, midh 40)
}

function showScore(){
  ctx.fillStyle = '#ff0000'
  ctx.font = '18px Courier New'
  ctx.text(score, width-10, 15)
}






/*
function bullet(){
  this.x = startPx;
	this.y = startPy - 10;

  this.draw = function() {
    ctx.fillStyle = "#b20808";
    ctx.shadowColor = "#b20808";
    ctx.shadowBlur = 15;
    this.y -= bulletSpeed;
    ctx.fillRect(this.x, this.y, 2, 8);
  }
}

function fireGun(){
if (event.keyCode == "32") {
   bullet();
   }
}*/  
 <!DOCTYPE html>
<html>
  <head>
    <title>Project</title>
    <meta charset="utf-8">
    <script src="project.js" type="text/javascript" defer></script>
  </head>
  <body>
    <h1>Arcade Shooter</h1>
    <fieldset>
    <legend><h2>Instructions:</h2></legend>
    <h3>Press W, A, S, D to Move</h3>
    <h3>Press Space Bar to Fire</h3>
    <h3>Goal: Survive as long as you can!</h3>
    </fieldset>
    <br>
    <canvas id="project" style="border-style: solid" width=505 height=900 ></canvas>
    <br>
      amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;amp;nbsp;
      <input id="start" type="button" value="START THE GAME" onclick="setUp()" style="width: 300px">
  </body>
</html>  

Комментарии:

1. Привет, если bullet() является конструктором объекта, он должен быть написан Bullet() { ... }

Ответ №1:

Вы же не хотите использовать setInterval каждый раз, когда запускаете маркеры. Вы хотите использовать один setInterval для всей игры, который вызывает функцию обновления или отрисовки для каждого игрового объекта. Например

 var game={
  //this is a list of items in the game I want to move around or do stuff
  //nothing there yet
  objects:[]
}
//this is a bullet object which can be created calling new bullet()
function Bullet(){
   //IM CHEATING HERE. DON'T DRAW TO THE DOM FOR GAMES
   //this is just a shortcut instead of drawing on a canvas
  this.object=document.createElement('div');
  this.object.style.width="10px";
  this.object.style.height="10px";
  this.object.style.position='absolute';
  this.object.style.top="100px";
  this.object.style.backgroundColor='red';
  document.body.appendChild(this.object)
  ///
  //these hold the bullet's current location on screen
  this.x=100;
  this.y=100;

  //this is the update function that gets called every frame
  this.update=function(){
     //I'm updating the bullet's y position.
    this.y-=10;
    if(this.y>0){
     
      //don't draw to the dom like this. use canvas like you were doing.
      this.object.style.top=this.y "px";
    }
  }
}

//now let's add a bullet to the game
game.objects.push(new bullet());

//the function that updates each of our objects
function runGame(){
  for(var i=0;i<game.objects.length;i  ){
      game.objects[i].update();
  }
}
//start the game
setInterval(runGame, 1000)  

ПРИМЕЧАНИЕ: НЕ рисуйте в DOM подобным образом. Используйте canvas, как вы делали. Я просто использовал dom в качестве ярлыка для демонстрации

Ответ №2:

1) вам нужно переопределить глобальную переменную, в которой вы будете отслеживать все :

 var gameData = {
    interval: null, // Controls the refresh
    redrawRequired: false, // Flag
    allBullets: [], // Moving bullets
    defaultBulletSpeed: 20 // Bullet speed
}
  

2) Проверяйте действие только в функции checkKeyPress (событие), включая действие fireGun :

 function checkKeyPress(event) {
    if (event.keyCode == "87") {//87 W(UP)
        if (startPy >= 20) {
            startPy -= 20;
            gameData.redrawRequired = true;
        }
    } else if (event.keyCode == "83") {//83 S(DOWN)
        if (startPy <= 785) {
            startPy  = 20;
            gameData.redrawRequired = true;
        }
    } else if (event.keyCode == "65") {//65 A(LEFT)
        if (startPx >= 0) {
            startPx -= 20;
            gameData.redrawRequired = true;
        }
    } else if (event.keyCode == "68") {//68 D(RIGHT)
        if (startPx <= 410) {
            startPx  = 20;
            gameData.redrawRequired = true;
        }
    } else if (event.keyCode == "72") { // 72 SPACEBAR ?? Actually H
        fireGun();
    }
}
  

3) Вот как вы определяете объект bullet и функцию firegun() :

 function Bullet() {
    // Object defining a bullet.
    this.x = startPx;
    this.y = startPy - 10;
    this.bulletSpeed = gameData.defaultBulletSpeed;
}

Bullet.prototype.draw = function () {
    // Draws the bullet on canvas...
    ctx.fillStyle = "#b20808";
    ctx.shadowColor = "#b20808";
    ctx.shadowBlur = 15;
    ctx.fillRect(this.x, this.y, 2, 8);
}

Bullet.prototype.move = function () {
    // Moves the bullet...
    this.y = this.y - this.bulletSpeed;
}


function fireGun() {
    var newBullet = new Bullet();
    gameData.allBullets.push(newBullet);
}
  

4) Затем вы решаете, когда перерисовывать холст, используя одну основную функцию (refreshGame) и другую функцию для проверки наличия маркеров для обновления (refreshBullets) :

 function refreshBullets() {
    var i = 0;
    var currentBullet;
    // Start by eliminating bullets out of the screen...
    while (i < gameData.allBullets.length) {
        currentBullet = gameData.allBullets[i];
        if (currentBullet.y < -10) {
            gameData.allBullets.splice(i, 1); // Remove the bullet outside of the screen.
        } else {
            currentBullet.move();
            gameData.redrawRequired = true;
            i  = 1; // Next bullet...
        }
    }
}


function refreshGame() {
    refreshBullets();
    if (gameData.redrawRequired) {
        ctx.clearRect(0,0,width,height);
        ctx.drawImage(img, 0, 0, width, height);
        ctx.drawImage(img2, startPx, startPy);

        for (var i = 0; i < gameData.allBullets.length; i  ) {
            gameData.allBullets[i].draw();
        }
    }
    gameData.redrawRequired = false;
}
  

5) И, наконец, вы инициализируете все, включая setInterval в функции setUp() :

 function setUp() {
    project = document.getElementById("project");
    ctx = project.getContext("2d");
    width = 505;
    height = 900;
    mid = width / 2;
    midh = height / 2;
    startPx = width / 2 - 30;
    startPy = height - 150;

    audio = new Audio("bgm.mp3");
    audio.play();

    img = new Image();
    img2 = new Image();
    img.src = "bg.png";
    img2.src = "fighterjet.png"
    img.onload = function() {
        ctx.shadowColor = "#ffffff";
        ctx.shadowBlur = 15;
        ctx.drawImage(img, 0, 0, width, height);
        ctx.drawImage(img2, startPx, startPy);
    }

    window.addEventListener("keydown", checkKeyPress);

    // Here ! And do something about that start button or the game will start over again...
    gameData.interval = window.setInterval(refreshGame, 100);
    document.getElementById("start").style.display = "none";
    project.focus();
}
  

Примечания :

  • Предполагается, что подход canvas с setInterval является плохим подходом из-за проблем с производительностью. Попробуйте найти «обновление интервала javascript с помощью canvas», есть другие способы решения проблемы. Переменная / свойство refreshRequired является всего лишь заполнителем для объяснения обходного пути. На самом деле, вам придется постоянно перерисовывать сцену, поскольку фон, цели и угрозы будут перемещаться ниже струи, и вы будете обновлять оценку в процессе.

  • Прежде чем писать код, вы должны спроектировать игру, каковы цели, персонажи, элементы управления, ограничения, уровни……. Бумага и карандаш — хорошее начало. Проблема в том, что когда вы начинаете писать код заранее, вы застреваете в тот момент, когда спрашиваете себя, как мне заставить пулю столкнуться с целью? А что, если я могу использовать ракеты вместо этого? В конце концов, ваш код станет тяжелым и потребует много процессора, потому что вы пытались решить проблему, создавая другую… Просто совет 😉

Комментарии:

1. Большое вам спасибо. Эти ответы немного прояснили ситуацию.