Я разработал небольшую игру, в которой игрок должен "есть" только зеленые шары в HTML5-холсте, чтобы добиться успеха.
Я пришел в ту сторону, где, когда вы наведете мяч, его съедят. Но возникает ДЕЙСТВИТЕЛЬНО странное поведение. Вместо того, чтобы съедать только один мяч, ВЕСЬ ЛЮБОВЬ ИХ КАК СУЩЕСТВУЕТСЯ ИСКЛЮЧИТЕЛЬНО.
Вот мой код:
body {
overflow: hidden;
background: rgba(82, 80, 78, 0.75)
}
#gameCanvas {
border: 0.25em solid black;
background-color: rgba(255,235,205,0.5);
margin-top: 1.25vh;
}
* {
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-size: 100%;
vertical-align: baseline;
background: transparent;
}
#flexContainer {
margin-top: 0.5em;
font-family: Verdana;
font-size: 2.5em;
display: flex;
justify-content: space-around;
}
#flexContainer span{
background: rgba(255, 180, 0, 0.50);
transition-duration: 0.5s;
padding: 0.1em;
border-radius:0.25em;
}
#flexContainer span:hover {
background: rgba(255, 180, 0, 0.8);
transition-duration: 0.5s;
border-radius: 1em;
cursor:pointer;
}
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<link type="text/css" rel="stylesheet" href="EatTheBall.css" />
<meta charset="utf-8" />
<title>EatTheBall!</title>
</head>
<body>
<div id="flexContainer">
<span id="49" onclick="changeNumBalls();">Level 1</span>
<span id="30" onclick="changeNumBalls();">Level 2</span>
<span id="20" onclick="changeNumBalls();">Level 3</span>
<span id="10" onclick="changeNumBalls();">Level 4</span>
<span id="0" onclick="changeNumBalls();">Level 5</span>
</div>
<canvas id="gameCanvas"></canvas>
<!--Start of JavaScript code-->
<script>
var XPos = 0;
var YPos = 0;
var n = 40;
var gameCanvas = document.body.querySelector("#gameCanvas");
var ctx = gameCanvas.getContext("2d");
var colorArray = ["red", "orange", "yellow", "green", "blue", "indigo", "violet"];
var balls = [];
window.onload = function initial() {
gameCanvas.height = 0.9 * window.innerHeight;
gameCanvas.width = 0.995 * window.innerWidth;
window.addEventListener("resize", function (evt) {
gameCanvas.height = 0.9 * window.innerHeight;
gameCanvas.width = 0.995 * window.innerWidth;
gameCanvas.style.marginTop = (1.25 * window*innerHeight) +"vh";
})
movePlayer();
MainLoop();
addBalls();
}
function MainLoop() {
ctx.clearRect(0, 0, gameCanvas.width, gameCanvas.height);
drawBalls(balls);
animateBalls(balls);
requestAnimationFrame(MainLoop);
}
function addBalls() {
while (n < 50) {
n++;
var b = {
x: window.innerWidth / 2,
y: window.innerHeight / 2,
radius: Math.random() * 30 + 15,
speedX: -7.5 + Math.random() * 15,
speedY: -7.5 + Math.random() * 15,
color : colorArray[Math.round(Math.random() * 6)]
}
balls.push(b);
}
}
function drawBalls(ballArray) {
ballArray.forEach(function (b) {
drawOneBall(b);
});
drawPlayer();
}
function animateBalls(ballArray) {
ballArray.forEach(function (b) {
b.x += b.speedX;
b.y += b.speedY;
testCollisionBallWithWalls(b);
});
}
function drawOneBall(b) {
ctx.save();
ctx.beginPath();
ctx.arc(b.x, b.y, b.radius, 0, Math.PI * 2);
ctx.fillStyle = b.color;
ctx.fill();
ctx.restore();
}
function testCollisionBallWithWalls(b) {
if ((b.x + b.radius > gameCanvas.width) || (b.x - b.radius < 0)) {
b.speedX = -b.speedX;
};
if ((b.y + b.radius > gameCanvas.height) || (b.y - b.radius < 0)) {
b.speedY = -b.speedY;
};
if (XPos > b.x - b.radius && XPos < b.x + b.radius && YPos > b.y - b.radius && YPos < b.y + b.radius) {
balls.splice(b, 1);
}
if (XPos < b.x - b.radius && XPos > b.x + b.radius && YPos < b.y - b.radius && YPos > b.y + b.radius) {
balls.splice(b, 1);
}
}
function changeNumBalls() {
n = event.currentTarget.id;
balls = [];
addBalls();
drawBalls(balls);
animateBalls(balls);
}
function drawPlayer() {
ctx.save();
ctx.fillStyle = "red";
ctx.fillRect(XPos, YPos, 30, 30);
ctx.restore();
}
function movePlayer() {
gameCanvas.addEventListener("mousemove", function (evt) {
XPos = evt.clientX - 15;
YPos = evt.clientY - 100;
})
}
</script>
</body>
</html>
ВРЕМЯ ОБЪЯСНЕНИЯ КОДА!
Идея заключается в том, что я объявляю переменную с именем "balls" в начале и присваиваю ей значение пустого массива. Затем шары создаются с использованием цикла while. Цикл while продолжает добавлять новые литералы объектов, которые описывают свойства шара (ака, положение центра шара, длину радиуса и т.д.), В пустой массив. Затем я вызываю 2 функции, один на самом деле рисует шары, используя свойства в каждом объектном литерале, который был добавлен в массив. Другой используется для анимирования шаров. Я использовал метод forEach() для обеих функций.
Что касается игрока, я создал fillRect() в холсте. Я установил свойства x1 и y1 * в позицию курсора, используя canvas.addEventListener('mouseover',...)
Всякий раз, когда игрок перемещается в один из шаров, мяч автоматически исчезает с использованием метода array.splice(). ОДНАКО, этого не происходит. Вместо того, чтобы исчезнуть только один шар, как упоминалось ранее, более одного исчезают.
Я действительно понял, как именно возникла проблема. Когда мяч сталкивается с игроком, если вместо использования array.splice() вы просто показываете случайное сообщение в консоли (console.log (случайное дерьмо)), сообщение будет отображаться не только один раз, оно получится отображается несколько раз.
Метод splice() нуждается в индексе в качестве первого параметра, с которого следует начинать изменять массив. В этом случае balls.indexOf(b) может дать положение мяча в шарах массива. Поэтому он будет работать, если вы слегка измените функцию testCollisionBallWithWalls:
function testCollisionBallWithWalls(b) {
if ((b.x + b.radius > gameCanvas.width) || (b.x - b.radius < 0)) {
b.speedX = -b.speedX;
};
if ((b.y + b.radius > gameCanvas.height) || (b.y - b.radius < 0)) {
b.speedY = -b.speedY;
};
if (XPos > b.x - b.radius && XPos < b.x + b.radius && YPos > b.y -
b.radius && YPos < b.y + b.radius) {
balls.splice(balls.indexOf(b), 1);
}
}