Герой уже нарисован. Он смотрит на тебя с canvas и ничего не делает.
Это нормальный первый результат. Но в какой-то момент хочется нажать стрелку и увидеть, как он поехал. Так начинается движение персонажа на JavaScript canvas. Не с физики и не с игрового движка. С четырёх флагов, скорости и одного цикла.
Сначала запомни состояние клавиш
Самая простая ошибка — двигать героя прямо внутри keydown. Нажал клавишу — прибавил десять к x. Работает, пока не попробуешь удерживать кнопку. Дальше скорость зависит от того, как браузер повторяет событие.
Лучше разделить две вещи. Обработчик говорит: «стрелка зажата». Игровой цикл решает: «тогда каждый кадр двигаем героя».
const keys = {
left: false,
right: false,
up: false,
down: false
};
document.addEventListener('keydown', (event) => {
if (event.key === 'ArrowLeft') keys.left = true;
if (event.key === 'ArrowRight') keys.right = true;
if (event.key === 'ArrowUp') keys.up = true;
if (event.key === 'ArrowDown') keys.down = true;
});
document.addEventListener('keyup', (event) => {
if (event.key === 'ArrowLeft') keys.left = false;
if (event.key === 'ArrowRight') keys.right = false;
if (event.key === 'ArrowUp') keys.up = false;
if (event.key === 'ArrowDown') keys.down = false;
});
Скорость — обычное число
Положи скорость в объект героя. Например, 3 пикселя за кадр. Если зажата левая стрелка, уменьшаем x. Если правая — увеличиваем. С y то же самое.
Не ставь сразу скорость 20. Сначала важно увидеть сам принцип: клавиша меняет состояние, состояние меняет координату, координата меняет рисунок.
Где всё это происходит
В игровом цикле. Он очищает canvas, обновляет состояние героя, проверяет границы и рисует его заново. Без очистки за персонажем останется след. Без повторного вызова он так и останется на старой позиции.
function update() {
if (keys.left) hero.x -= hero.speed;
if (keys.right) hero.x += hero.speed;
if (keys.up) hero.y -= hero.speed;
if (keys.down) hero.y += hero.speed;
}
function loop() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
update();
keepInside();
drawHero();
requestAnimationFrame(loop);
}
loop();
Если хочешь отдельно разобраться, почему браузер вызывает кадры снова и снова, посмотри статью про игровой цикл.
Почему герой уезжает за край
Потому что число не знает, где заканчивается canvas. Для него можно спокойно продолжать движение в минус, пока на экране не останется пустота.
После обновления позиции прижми героя к границам. Радиус нужен затем, чтобы за край не уехала половина головы.
function keepInside() {
const r = hero.radius;
if (hero.x < r) hero.x = r;
if (hero.x > canvas.width - r) hero.x = canvas.width - r;
if (hero.y < r) hero.y = r;
if (hero.y > canvas.height - r) hero.y = canvas.height - r;
}
Что должно получиться
Стрелки двигают котика. Он не исчезает за краем. Ввод, движение и рисунок лежат в разных функциях. Это ещё не большая игра. Но уже не картинка. У тебя появился мир, который реагирует на действие.
Если героя пока нет, начни с урока «рисуем героя». Двигать понятнее то, что ты сначала собрал сам.
Книга по JavaScript для начинающих
«JavaScript с нуля: учимся программировать, создавая игры»Пошаговый формат с маленькими практическими задачами: от базового синтаксиса до первых игровых механик без перегруза теорией.
Читать книгу на ЛитРес →