Анімація, розваги. Організація віртуального світу аркадної гри.
Фронтенд розробка JavaScript. -> Організація віртуального світу аркадної гри.
Аркадна гра.
[посилання на репозиторій] (https://github.com/zdimon/simple-arcade)
Пересування об’єкта по горизонталі.
Завдання: переміщати внутрішній блок відносного зовнішнього горизонталі нескінченно взад-вперед.
Рішення.
Визначимо 2 блоки на сторінці.
<div class="out">
<div class="in" id="ball">
</div>
</div>
Стилі.
.out {
width: 200px;
height: 200px;
position: relative;
border: 1px solid silver;
}
.in {
width: 30px;
height: 30px;
border-radius: 50%;
background-color: red;
position: absolute;
}
Визначимо нескінченний таймер.
var timerFunc = function() {
console.log($.now());
id = setTimeout(timerFunc, 1000);
}
var id = setTimeout(timerFunc, 1000);
Визначимо об’єкт кульки з елементом та напрямок руху.
$( document ).ready(() => {
var ball = {
el: $('#ball'),
move: 'right'
};
var timerFunc = function() {
id = setTimeout(timerFunc, 1000);
ball.el.css({'left' : parseInt(ball.el.position().left+5) + 'px'});
}
var id = setTimeout(timerFunc, 1000);
}
);
Відпрацюємо два напрямки руху.
var timerFunc = function() {
id = setTimeout(timerFunc, 100);
if(ball.move === 'right') {
var newCoord = parseInt(ball.el.position().left+5);
} else {
var newCoord = parseInt(ball.el.position().left-5);
}
ball.el.css({'left' : newCoord + 'px'});
if (newCoord>200) {
ball.move = 'left';
}
if (newCoord<0) {
ball.move = 'right'
}
}
Проблема виникне, коли у нас буде багато об’єктів, при такому підході ми будемо змушені для кожного встановлювати свій таймер і коли їх стане багато, це буде дуже незручно.
Тому логічніше визначити спеціальну функцію – життєвий цикл, яку запустити з інтервалом та в ній пересувати всі об’єкти на сторінці.
$( document ).ready(() => {
var ball2 = {
el: $('#ball2'),
move: 'right'
};
function gameLoop()
{
console.log(parseInt($.now()));
setTimeout(gameLoop,100);
}
gameLoop();
}
);
Зробимо для гри один єдиний блок.
<div class="out" id="gameApp"> </div>
Далі створимо 3 функції:
clear – для очищення ігрового поля
draw - для промальовування всіх елементів
calc - для перерахунку координат елементів
І викличемо їх у життєвому циклі подій.
function clear() {
}
function calc() {
}
function draw() {
}
function gameLoop()
{
// change position based on speed
//moveSelection();
console.log(parseInt($.now()));
calc();
clear();
draw();
setTimeout(gameLoop,100);
}
Далі закинемо усі об’єкти гри в один об’єкт.
var gameApp = {
balls: [
{x: 0, y: 30},
{x: 30, y: 100},
]
}
Опишемо функцію очищення.
function clear() {
$("#game").clear();
}
Функція промальовування.
function draw() {
for (let ball of gameApp.balls) {
$('#gameApp').append(`<div class="ball" style="top:${ball.y}px; left:${ball.x}px">`);
}
}
Функція перерахунку координат об’єктів.
function calc() {
for (let ball of gameApp.balls) {
if(ball.x>170) ball.move = 'left';
if (ball.x<30) ball.move = 'right';
if(ball.move === 'left') ball.x = ball.x - 4;
if(ball.move === 'right') ball.x = ball.x + 4;
}
}
Рухаємо об’єкт гармати натисканням стрілок.
Додамо стилі для гармати.
.canon {
height: 25px;
width: 5px;
background-color: black;
position: absolute;
}
Додамо координату гармати та статус натискання клавіш стрілок в об’єкт гри.
var gameApp = {
balls: [
{x: 0, y: 30, move: 'right'},
{x: 70, y: 100, move: 'left'},
],
cannon_x: 100,
key_left: 'up',
key_right: 'up'
}
Додамо до промальовування.
function draw() {
for (let ball of gameApp.balls) {
$('#gameApp').append(`<div class="ball" style="top:${ball.y}px; left:${ball.x}px">`);
}
$('#gameApp').append(`<div class="canon" style="top:170px; left:${gameApp.cannon_x}px">`);
}
Відстежуємо натискання кнопок стрілок.
$(document).on('keyup', function( e ) {
if(e.keyCode === 39) gameApp.key_right = 'up'
if(e.keyCode === 37) gameApp.key_left = 'up'
})
$(document).on('keydown', function( e ) {
if(e.keyCode === 39) gameApp.key_right = 'down'
if(e.keyCode === 37) gameApp.key_left = 'down'
})
Додаємо перерахунок координат гармати.
function calc() {
for (let ball of gameApp.balls) {
if(ball.x>170) ball.move = 'left';
if (ball.x<0) ball.move = 'right';
if(ball.move === 'left') ball.x = ball.x - 4;
if(ball.move === 'right') ball.x = ball.x + 4;
}
if(gameApp.key_left === 'down') gameApp.cannon_x = gameApp.cannon_x - 4;
if(gameApp.key_right === 'down') gameApp.cannon_x = gameApp.cannon_x + 4;
}
Робимо обмеження руху гармати за розмірами екрану.
if(gameApp.key_left === 'down') (gameApp.cannon_x>0)? gameApp.cannon_x = gameApp.cannon_x - 4: gameApp.cannon_x = 0;
if(gameApp.key_right === 'down') (gameApp.cannon_x<190)? gameApp.cannon_x = gameApp.cannon_x + 4: gameApp.cannon_x=190;
Додамо кульки в об’єкт гри.
var gameApp = {
....
bullets: []
}
Відпрацюємо натискання на пробіл.
$(document).on('keydown', (e) => {
...
if(e.keyCode === 32) {
gameApp.bullets.push({x: gameApp.canon_x, y: 185})
}
...
})
Змінюємо координати куль і прибираємо їх із масиву при виході межі ігрового поля.
for (let bullet of gameApp.bullets){
bullet.y -= 2;
if(bullet.y<0) gameApp.bullets.splice(gameApp.bullets.indexOf(bullet),1);
}
Приклад визначення колізії.
var rect1 = {x: 5, y: 5, width: 50, height: 50}
var rect2 = {x: 20, y: 10, width: 10, height: 10}
if (rect1.x < rect2.x + rect2.width &&
rect1.x + rect1.width > rect2.x &&
rect1.y < rect2.y + rect2.height &&
rect1.y + rect1.height > rect2.y) {
// collision detected!
}
Фронтенд розробка JavaScript. -> Домашнє завдання.
Домашнє завдання.
Відпрацювати колізію куль із кульками. Забирати всі кульки при зіткненні.
Кулі при зіткненні залишати та продовжувати їх рух.
Зробити автоматичну появу нових кульок із випадковою координатою x і рухати їх зверху донизу.
Відпрацювати колізію кульок з гарматою та завершити гру.
Вважати кількість збитих куль.