Повторение анимации вылетающего блока

113
04 апреля 2021, 07:30

Я не понимаю, почему не выходит повторить анимацию. То есть при нажатии на пробел я ожидаю, что вылетит столько чёрных блочков, сколько нажатий было совершено, а происходит совсем не так почему-то

 const canvas = document.getElementById('man'); 
    let ctx = canvas.getContext('2d'); 
    const canvasBullet = document.getElementById('bullet'); 
    let ctxBullet = canvasBullet.getContext('2d'); 
    let speedBullet = 0; 
    let fightPressed = false; 
 
    ctx.fillStyle = 'red'; 
    ctx.fillRect(100, 100, 50, 50); 
 
    function fight() { 
        requestAnimationFrame(tickBullet); 
        console.log('baxxxx'); 
    } 
 
    function tickBullet() { 
        ctxBullet.clearRect(0, 0, canvas.width, canvas.height); 
        let xB = 150 + speedBullet; 
        ctxBullet.fillStyle = 'black'; 
        ctxBullet.fillRect(150 + speedBullet, 125, 10, 10); 
        speedBullet += 9; 
        if (xB > canvas.width) { 
            ctxBullet.clearRect(0, 0, canvas.width, canvas.height); 
        } 
        requestAnimationFrame(tickBullet); 
    } 
 
    function keyDown(e) { 
        if (e.keyCode === 32) fightPressed = true; 
    } 
 
    function keyUp(e) { 
        if (e.keyCode === 32) fightPressed = false; 
    } 
 
    document.addEventListener('keydown', keyDown, false); 
    document.addEventListener('keyup', keyUp, false); 
 
    function update() { 
        if (fightPressed) { 
            fightPressed = false; 
            fight(); 
        } 
    } 
 
    setInterval(update, 10);
    #man { 
        border: solid 1px; 
    }
<div style="position: relative;"> 
    <canvas id="man" width="500" height="400" style="position: absolute"></canvas> 
    <canvas id="bullet" width="500" height="400" style="position: absolute"></canvas> 
</div>

Answer 1
  • Начнем с того, что вы неправильно используете requestAnimationFrame. Его надо вешать бы на весь цикл игры, который будет отвечать за бесконечную петлю. Я его повесил на метод update. Что логично. Ознакомьтесь https://developer.mozilla.org/ru/docs/DOM/window.requestAnimationFrame. При этом setInterval не нужен. Зачем он, если у вас есть requestAnimationFrame?

  • У вас не могло физически вылететь столько "пуль", сколько раз вы нажали клавишу. У вас перерисовка одна. И координаты перерисовываются одни. Как вы при этом хотели сделать несколько? Для этого:

    • создается общий объект "bullet", у которого есть координаты
    • создается массив пуль, куда при каждом выстреле заносится новый объект, а при уход за экран - извлекается

    Уже непосредственно этим массивом и надо манипулировать и проходясь циклом, перерисовывать на холсте координаты каждого из объектов.

  • fightPressed не нужна. Т.к. при keyDown мы просто вызываем метод fight(), который заносит пулю в массив, который в свою очередь пробегается по всем элементам в своем методе

  • tickBullet мы запускаем всегда в основном цикле игры. Просто когда массив пуст - то не по чему будет пробегаться.
  • манипуляции let xB = 150 + speedBullet; ....speedBullet += 9; - бессмысленны. Если вы уж задаёте скорость, то вы определяете её сразу. Я её вынес в параметры объекта пули.

const canvas = document.getElementById('man'); 
let ctx = canvas.getContext('2d'); 
const canvasBullet = document.getElementById('bullet'); 
let ctxBullet = canvasBullet.getContext('2d'); 
let speedBullet = 5; 
//let fightPressed = false; 
 
let bullet = { 
  x:150, 
  y: 125, 
  width: 10, 
  height: 10, 
  speed: 5 
}; 
 
let bullets = []; 
 
ctx.fillStyle = 'red'; 
ctx.fillRect(100, 100, 50, 50); 
 
function fight() {         
    bullets.push(Object.create(bullet));                
} 
 
function tickBullet() {         
    bullets.forEach((el, i) => { 
        ctxBullet.clearRect(el.x, el.y, el.width, el.height); 
        el.x = el.x + el.speed; 
        ctxBullet.fillStyle = 'black'; 
        ctxBullet.fillRect(el.x, el.y, el.width, el.height);             
        if (el.x > canvas.width) { 
            ctxBullet.clearRect(el.x, el.x, el.width, el.height);                 
            bullets.splice(i, 1); 
        } 
    }); 
} 
 
function keyDown(e) {         
    if (e.keyCode === 32) { 
        fight();             
    } 
} 
 
function keyUp(e) {     
   // if (e.keyCode === 32) fightPressed = false; 
} 
 
document.addEventListener('keydown', keyDown, false); 
document.addEventListener('keyup', keyUp, false); 
 
function update() {             
    tickBullet(); 
    requestAnimationFrame(update); 
} 
 
function startGame() { 
    update(); 
} 
 
startGame();
#man { 
        border: solid 1px; 
    }
<div style="position: relative;"> 
    <canvas id="man" width="500" height="400" style="position: absolute"></canvas> 
    <canvas id="bullet" width="500" height="400" style="position: absolute"></canvas> 
</div>

READ ALSO
Скрыть/удалить из блока существующий элемент при появлении/добавлении нового

Скрыть/удалить из блока существующий элемент при появлении/добавлении нового

Имеем такие блокиВ подменю 2 Блок2 появляется новая строка, при ее появлении нужно убрать другую строку

95
Как изменить содержимое canvas?

Как изменить содержимое canvas?

На сайте есть светлая и темная темаДля каждой срабатывает свой фон

109
Странный казус в работе getline()

Странный казус в работе getline()

При i = 0 getline не работает, ввод запрашивает на 1 раз меньше чем требуетсяВ чём проблема работы getline() ?

112
Логические операции С++

Логические операции С++

Недавно начал изучать С++Выполняю упражнение на перевод температур по шкалам

78