Removing lag on rendering thousands of entities in JS canvas - javascript

I am a beginner in JS canvas. I wanna make a game but when rendering too many (Bricks) the game becomes unplayable. Most of the lag comes from draw function the part where bricks are drawn, From ctx.fill() and ctx.rect() function. I observed it with the chrome's performance devtool.
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var ballRadius = 10;
var x = canvas.width / 2;
var y = canvas.height - ballRadius;
var bulletX = x;
var bulletY = y;
var bullet2X = x;
var bullet2Y = y;
var dx = 2;
var dy = -2;
var paddleHeight = 0;
var paddleWidth = canvas.width;
var paddleX = (canvas.width - paddleWidth) / 2;
var rightPressed = false;
var leftPressed = false;
var brickRowCount = 50;
var brickColumnCount = 96;
var brickWidth = 5;
var brickHeight = 5;
var brickPadding = 0;
var brickOffsetTop = 0;
var brickOffsetLeft = 0;
var score = 0;
var damageDealth = 0;
var brickHealth = 1000;
var scoreEarned = 0;
window.bricks = [];
if (bricks.length == 0) {
bricks = [];
for (var c = 0; c < brickColumnCount; c++) {
bricks[c] = [];
for (var r = 0; r < brickRowCount; r++) {
bricks[c][r] = {
x: 0,
y: 0,
status: brickHealth
};
}
}
}
var resetLevel =
setInterval(() => {
var brickStatus = 0;
for (var row = 0; row < bricks.length; row++) {
bricks[row].forEach((status) => {
if (status.status > 1) {
brickStatus += 1;
}
})
}
if (brickStatus < 1) {
for (var row = 0; row < bricks.length; row++) {
for (var brick = 0; brick < bricks[row].length; brick++) {
if (bricks[row][brick].status < 1) {
brickHealth += 1;
bricks[row][brick].status = 1000
allBullets = [];
childBullets = [];
AOEBullets = [];
}
}
}
}
console.log(brickStatus);
console.log("BrickHealth: " + brickHealth)
}, 1000);
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
function keyDownHandler(e) {
if (e.key == "Right" || e.key == "ArrowRight" || e.key == "d") {
rightPressed = true;
} else if (e.key == "Left" || e.key == "ArrowLeft" || e.key == "a") {
leftPressed = true;
}
}
function keyUpHandler(e) {
if (e.key == "Right" || e.key == "ArrowRight" || e.key == "d") {
rightPressed = false;
} else if (e.key == "Left" || e.key == "ArrowLeft" || e.key == "a") {
leftPressed = false;
}
}
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
class MakeBullet {
constructor(x, y, radius, color, speedX, speedY, pierce, lifespan, damage) {
this.x = x;
this.y = y;
this.speedX = speedX;
this.speedY = speedY;
this.radius = radius;
this.color = color;
this.pierce = pierce;
this.lifespan = lifespan;
this.damage = damage;
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
}
update() {
this.draw();
this.x = this.x + this.speedX;
this.y = this.y + this.speedY;
}
}
window.allBullets = [];
window.childBullets = [];
window.AOEBullets = [];
document.addEventListener("mousemove", (event) => {
const angle = Math.atan2(event.clientY - y, event.clientX - x);
window.shootAngle = {
x: Math.cos(angle),
y: Math.sin(angle)
}
})
setInterval(() => {
if (allBullets.length < 101) {
allBullets.push(new MakeBullet(x, y, 3, "rgba(0, 149, 221, 0.9)", shootAngle.x + shootAngle.x * 12, shootAngle.y + shootAngle.y * 12, 8, 2, 25))
/* allBullets.push(new MakeBullet(x - 5, y, 3, "rgba(0, 149, 221, 0.9)", shootAngle.x + shootAngle.x * 12, shootAngle.y + shootAngle.y * 12, 8, 8, 50))
allBullets.push(new MakeBullet(x + 5, y, 3, "rgba(0, 149, 221, 0.9)", shootAngle.x + shootAngle.x * 12, shootAngle.y + shootAngle.y * 12, 8, 8, 25)) */
}
}, 75)
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function drawBricks() {
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
if (bricks[c][r].status > 0) {
var brickX = (c * (brickWidth + brickPadding)) + brickOffsetLeft;
var brickY = (r * (brickHeight + brickPadding)) + brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
}
}
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBricks();
drawBall();
drawPaddle();
childBullets.forEach((childBullet) => {
if (childBullet.lifespan > 0) {
childBullet.update();
childBullet.draw();
if (childBullet.x + childBullet.speedX > canvas.width - childBullet.radius || childBullet.x + childBullet.speedX < childBullet.radius) {
childBullet.speedX = -childBullet.speedX;
}
if (childBullet.y + childBullet.speedY > canvas.width - childBullet.radius || childBullet.y + childBullet.speedY < childBullet.radius) {
childBullet.speedY = -childBullet.speedY;
} else if (childBullet.y + childBullet.speedY > canvas.height - childBullet.radius) {
if (childBullet.x > paddleX && childBullet.x < paddleX + paddleWidth) {
if (childBullet.y = childBullet.y - paddleHeight) {
childBullet.speedY = -childBullet.speedY;
}
}
}
}
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
var b = bricks[c][r];
if (b.status > 0) {
if (childBullet.x > b.x && childBullet.x < b.x + brickWidth && childBullet.y > b.y && childBullet.y < b.y + brickHeight) {
b.status -= childBullet.damage;
childBullet.pierce -= 1
var randomScore = Math.floor(Math.random() * 5);
score += randomScore;
scoreEarned += randomScore;
damageDealth += childBullet.damage;
}
}
}
}
})
AOEBullets.forEach((AOEBullet) => {
if (AOEBullet.lifespan > 0) {
AOEBullet.update();
AOEBullet.draw();
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
var b = bricks[c][r];
if (b.status > 0) {
if (AOEBullet.x + AOEBullet.radius > b.x + brickWidth && AOEBullet.x - AOEBullet.radius < b.x + brickWidth && AOEBullet.y + AOEBullet.radius > b.y + brickHeight && AOEBullet.y - AOEBullet.radius < b.y + brickHeight) {
b.status -= AOEBullet.damage;
AOEBullet.pierce -= 1
var randomScore = Math.floor(Math.random() * 10);
score += randomScore;
scoreEarned += randomScore;
damageDealth += AOEBullet.damage;
}
}
}
}
}
})
if (shootAngle !== undefined) {
allBullets.forEach((bullet) => {
if (bullet.lifespan > 0) {
if (bullet.pierce > 0) {
bullet.update();
bullet.draw();
window.BulletX = bullet.x;
window.BulletY = bullet.y;
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
var b = bricks[c][r];
if (b.status > 0) {
if (bullet.x > b.x && bullet.x < b.x + brickWidth && bullet.y > b.y && bullet.y < b.y + brickHeight) {
b.status -= bullet.damage;
bullet.pierce -= 1;
var randomScore = Math.floor(Math.random() * 100);
score += randomScore;
scoreEarned += randomScore;
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 25, "rgba(0,149,221, 0.024)", 0, 0, 5, 0.4, 1.4))
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 50, "rgba(0,149,221, 0.018)", 0, 0, 5, 0.3, 0.7))
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 75, "rgba(0,149,221, 0.016)", 0, 0, 5, 0.2, 0.5))
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 100, "rgba(0,149,221, 0.012)", 0, 0, 5, 0.1, 0.2))
damageDealth += bullet.damage;
}
if (bullet.x > b.x && bullet.x < b.x + brickWidth && bullet.y > b.y && bullet.y < b.y + brickHeight) {
b.status -= bullet.damage;
}
if (bullet.x > b.x && bullet.x < b.x + brickWidth && bullet.y > b.y && bullet.y < b.y + brickHeight) {
b.status -= bullet.damage;
}
if (bullet.x > b.x && bullet.x < b.x + brickWidth && bullet.y > b.y && bullet.y < b.y + brickHeight) {
b.status -= bullet.damage;
}
}
}
}
if (bullet.x + bullet.speedX > canvas.width - bullet.radius || bullet.x + bullet.speedX < bullet.radius) {
bullet.speedX = -bullet.speedX;
}
if (bullet.y + bullet.speedY > canvas.width - bullet.radius || bullet.y + bullet.speedY < bullet.radius) {
bullet.speedY = -bullet.speedY;
} else if (bullet.y + bullet.speedY > canvas.height - bullet.radius) {
if (bullet.x > paddleX && bullet.x < paddleX + paddleWidth) {
if (bullet.y = bullet.y - paddleHeight) {
bullet.speedY = -bullet.speedY;
}
}
}
}
}
})
}
if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) {
dx = -dx;
}
if (y + dy < ballRadius) {
dy = -dy;
} else if (y + dy > canvas.height - ballRadius) {
if (x > paddleX && x < paddleX + paddleWidth) {
if (y = y - paddleHeight) {
dy = -dy;
}
} else {
document.location.reload();
clearInterval(interval); // Needed for Chrome to end game
}
}
if (rightPressed && x < canvas.width - ballRadius) {
x += 7;
} else if (leftPressed && x > 0 + ballRadius) {
x -= 7;
}
// x += dx;
//y += dy;
}
var interval = setInterval(draw, 10);
setInterval(() => {
allBullets.forEach((bullet) => {
for (var i = 0; i < 1; i++) {
var angle = 2 * Math.PI * Math.random();
var randomx = bullet.speedX * Math.cos(angle);
var randomy = bullet.speedY * Math.sin(angle);
if (bullet.lifespan < 1) {
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 25, "rgba(0,149,221, 0.024)", 0, 0, 5, 0.4, 0.24))
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 50, "rgba(0,149,221, 0.018)", 0, 0, 5, 0.3, 0.16))
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 75, "rgba(0,149,221, 0.016)", 0, 0, 5, 0.2, 0.08))
AOEBullets.push(new MakeBullet(bullet.x, bullet.y, 100, "rgba(0,149,221, 0.012)", 0, 0, 5, 0.1, 0.04))
if (childBullets.length < 51) {
childBullets.push(new MakeBullet(bullet.x, bullet.y, 2, "#0095DD", randomx + randomx * Math.floor(Math.random() * 2), randomy + randomy * Math.floor(Math.random() * 2), 5, 5, 1))
}
}
if (bullet.pierce < 1) {
if (childBullets.length < 51) {
childBullets.push(new MakeBullet(bullet.x, bullet.y, 2, "#0095DD", randomx + randomx * Math.floor(Math.random() * 5), randomy + randomy * Math.floor(Math.random() * 5), 5, 5, 1))
}
}
}
})
}, 1)
var lifeSpan = setInterval(() => {
allBullets.forEach((bullet) => {
bullet.lifespan -= 0.1;
})
childBullets.forEach((bullet) => {
bullet.lifespan -= 0.1;
})
AOEBullets.forEach((bullet) => {
bullet.lifespan -= 0.1;
})
}, 100)
setInterval(() => {
for (var i = 0; i < allBullets.length; i++) {
if (allBullets[i].pierce < 1 || allBullets[i].lifespan < 1) {
allBullets.splice(allBullets.indexOf[i], 1)
}
}
}, 50)
setInterval(() => {
for (var i = 0; i < childBullets.length; i++) {
if (childBullets[i].pierce < 1 || childBullets[i].lifespan < 0) {
childBullets.splice(childBullets.indexOf[i], 1)
}
}
}, 5000)
setInterval(() => {
for (var i = 0; i < AOEBullets.length; i++) {
if (AOEBullets[i].pierce < 1 || AOEBullets[i].lifespan < 0) {
AOEBullets.splice(AOEBullets.indexOf[i], 1)
}
}
}, 5000)
setInterval(() => {
for (var i = 0; i < 8; i++) {
allBullets.push(new MakeBullet(x, y, 10, "#0095DD", shootAngle.x + shootAngle.x * 12, shootAngle.y + shootAngle.y * 12, 10, 3, 5))
allBullets.push(new MakeBullet(x + 10, y, 10, "#0095DD", shootAngle.x + shootAngle.x * 12, shootAngle.y + shootAngle.y * 12, 10, 3, 5))
allBullets.push(new MakeBullet(x - 10, y, 10, "#0095DD", shootAngle.x + shootAngle.x * 12, shootAngle.y + shootAngle.y * 12, 10, 3, 5))
}
}, 30000)
setInterval(() => {
document.getElementsByClassName("scrore")[0].innerText = "Score: " + score;
}, 100)
setInterval(() => {
document.getElementsByClassName("scoreEarned")[0].innerText = "Score Earned: " + scoreEarned;
scoreEarned = 0;
}, 1000)
var damage = setInterval(() => {
document.getElementsByClassName("damageDealth")[0].innerText = "Damage: " + damageDealth.toFixed(1);
damageDealth = 0;
}, 1000)
<canvas id="myCanvas" height="320" width="480" style="background-color: #eee"></canvas>
<p class="scrore" style="color: rgba(0, 149, 221, 0.9); font-family: 'Hammersmith One';">Score: 0</p>
<p class="scoreEarned" style="color: rgba(0, 149, 221, 0.9); font-family: 'Hammersmith One';">Score Earned: 0</p>
<p class="damageDealth" style="color: rgba(0, 149, 221, 0.9); font-family: 'Hammersmith One';">Damage: 0</p>

One idea to speed up the drawing is to prepare the next frame to be shown on an invisible canvas. Then blip the invisible canvas to the canvas shown to the player in one go.
// drawing surface
var visibleCanvas_; // (HTML5 canvas) serves as playfield, visible for user
var visibleCtx2d_; // (HTML5 canvas 2D context) context of visible canvas
// optimization: if drawing with fillRect(), draw on hidden canvas
var hiddenCanvas_; // (HTML5 canvas) invisible canvas on which shapes are drawn each step
var hiddenCtx2d_; // (HTML5 canvas 2D context) context of invisible canvas
function createHiddenCanvas_(mainCanvas) {
hiddenCanvas_= document.createElement("canvas");
hiddenCanvas_.width = mainCanvas.width;
hiddenCanvas_.height = mainCanvas.height;
hiddenCtx2d_= hiddenCanvas_.getContext("2d");
// other settings that do not change while drawing, e.g. brick color
// hiddenCtx2d_.strokeStyle = ...;
// hiddenCtx2d_.fillStyle = ...;
}
// must be called once at startup of the game
function init_() {
visibleCanvas_ = document.getElementById('myCanvas');
visibleCtx2d_= visibleCanvas_.getContext('2d');
createHiddenCanvas_(visibleCanvas_);
}
// to be called before we start building the next frame
function startDraw_() {
// clear hidden canvas
hiddenCtx2d_.clearRect(0, 0, hiddenCanvas_.width, hiddenCanvas_.height);
}
// draws single brick for next frame on hidden canvas
function drawBrick_(brickX, brickY, brickWidth, brickHeight) {
hiddenCtx2d_.fillRect(brickX, brickY, brickWidth, brickHeight);
}
// to be called after we finish building the next frame and want to display it
function finishDraw_() {
// clear visible canvas
visibleCtx2d_.clearRect(0, 0, visibleCanvas_.width, visibleCanvas_.height);
// blip hidden canvas on visible canvas
visibleCtx2d_.drawImage(hiddenCanvas_, 0, 0);
}
Draw all shapes for the next frame between startDraw_ and finishDraw_.
You should also look into window.requestAnimationFrame to manage when the next frame is drawn.

Related

P5.js game crashes due to TypeError for a missing element in an array

OK, so I run into this problem where my program regularly crashes mid-game due to a TypeError: Uncaught TypeError: bullets[i] is undefined
The error occurs in the function where I check for every variable in the bullets and the enemies array if there is a collision.
This is the Source Code of this small school project I created, and I've been trying to troubleshoot this particular bug for hours at a time now. If anyone were able to help me that would be amazing as I can't quite grasp what the problem could be other than their occurring a collision when an element has already been spliced. But since the draw() function in P5.js runs 60 times per second that shouldn't really happen as regularly as it does, so I don't understand how this even can be an issue.
function setup() {
createCanvas(displayWidth - 20, displayHeight - 20);
angleMode(DEGREES);
rectMode(CENTER);
ellipseMode(CENTER);
playerX = width / 2;
playerY = height / 2;
}
let playerX = 0;
let playerY = 0;
let angle = 0;
let timer = 120;
let time = 0;
let v = 2;
let cooldown = 20;
let color = 50;
let hit = 0;
var bullets = [];
var enemies_easy = [];
var enemies_hard = [];
var score = 0;
var highscore = 0;
var gameover = false;
var gamestarted = false;
var nexthard = 5;
var currentenemy = 0;
function draw() {
if (!gamestarted) {
push();
textAlign(CENTER);
background('black');
translate(displayWidth / 2, displayHeight / 2);
textSize(width / 50);
fill('white');
text('Welcome!', 0, -100);
text('Controls:', 0, 0);
text('Fullscreen: F Moving: W, A, S, D Restart: R Shooting: Left Mouse Button Start: Space Bar', 0, 100);
pop();
if (keyIsDown(32)) {
bullets = [];
gamestarted = true;
}
} else {
if (!gameover) {
//calculates shot enemies_easy
bulletcollision();
//shoots if weapon cooldown is expired
background('black');
cooldown--;
activategun();
//draw hero
angle = atan2(mouseY - playerY, mouseX - playerX) + 90;
push();
fill('blue');
translate(playerX, playerY);
rotate(angle);
ellipse(0, 0, 40, 40);
//draw gun
fill('grey');
rect(0, 0 - 25, 10, 20);
pop();
//move hero
move();
//creates enemies with increasing difficulty
time++;
difficulty();
spawnenemy_easy();
spawnenemy_hard();
//shows score on screen
showscore();
//draw crosshair
noCursor();
push();
fill('white');
stroke('white');
line(mouseX, mouseY, mouseX + 20, mouseY);
line(mouseX, mouseY, mouseX - 20, mouseY);
line(mouseX, mouseY, mouseX, mouseY + 20);
line(mouseX, mouseY, mouseX, mouseY - 20);
pop();
//checks for game over
playercollision();
} else {
if (keyIsDown(82)) {
bullets = [];
enemies_easy = [];
enemies_hard = [];
timer = 120;
time = 0;
cooldown = 20;
score = 0;
playerX = width / 2;
playerY = height / 2;
v = 2;
gameover = false;
}
}
}
}
class bullet {
constructor() {
this.x = playerX;
this.y = playerY;
this.angle = createVector(mouseX - playerX, mouseY - playerY);
this.angle.normalize();
}
drawbullet() {
push();
fill('white');
ellipse(this.x, this.y, 10, 10);
pop();
this.y = this.y + 10 * this.angle.y;
this.x = this.x + 10 * this.angle.x;
}
}
class enemy_easy {
constructor() {
this.x = random(-1000, width + 1000);
if (this.x > width || this.x < 0) {
if (this.x > width) {
this.x = width;
this.y = random(0, height + 1);
}
if (this.x < 0) {
this.x = 0;
this.y = random(0, height + 1);
} else {}
} else {
let i = floor(random(0, 2));
this.y = i * height;
}
}
drawenemy_easy() {
push();
this.angle = createVector(this.x - playerX, this.y - playerY);
this.angle.normalize();
fill('red');
ellipse(this.x, this.y, 30, 30);
rotate(angle);
pop();
this.x = this.x - v * this.angle.x; // * random(0, 5);
this.y = this.y - v * this.angle.y; // * random(0, 5);
}
}
class enemy_hard {
constructor() {
this.x = random(-1000, width + 1000);
if (this.x > width || this.x < 0) {
if (this.x > width) {
this.x = width;
this.y = random(0, height + 1);
}
if (this.x < 0) {
this.x = 0;
this.y = random(0, height + 1);
} else {}
} else {
let i = floor(random(0, 2));
this.y = i * height;
}
}
drawenemy_hard() {
push();
this.angle = createVector(this.x - playerX, this.y - playerY);
this.angle.normalize();
fill('purple');
ellipse(this.x, this.y, 30, 30);
rotate(angle);
pop();
this.x = this.x - v * this.angle.x; // * random(0, 5);
this.y = this.y - v * this.angle.y; // * random(0, 5);
}
}
function keyPressed() {
//fullscreen Taste F: https://www.geeksforgeeks.org/p5-js-fullscreen-function/
if (keyCode === 70) {
let fs = fullscreen();
fullscreen(!fs);
}
}
function move() {
if (keyIsDown(83) && playerY <= height - 22) {
playerY = playerY + 4;
}
if (keyIsDown(87) && playerY >= 22) {
playerY = playerY - 4;
}
if (keyIsDown(68) && playerX <= width - 22) {
playerX = playerX + 4;
}
if (keyIsDown(65) && playerX >= 22) {
playerX = playerX - 4;
}
}
function activategun() {
for (var i = 0; i < bullets.length; i++) {
bullets[i].drawbullet();
if (bullets[i].x <= 0 || bullets[i].y <= 0 || bullets[i].x >= width || bullets[i].y >= height) {
bullets.splice(i, 1);
}
}
}
function mousePressed() {
if (cooldown < 0) {
bullets.push(new bullet());
cooldown = 20;
}
}
function spawnenemy_easy() {
for (var i = 0; i < enemies_easy.length; i++) {
enemies_easy[i].drawenemy_easy();
}
}
function spawnenemy_hard() {
for (var i = 0; i < enemies_hard.length; i++) {
enemies_hard[i].drawenemy_hard();
}
}
function newenemy() {
if (currentenemy < nexthard) {
enemies_easy.push(new enemy_easy());
currentenemy++;
} else {
enemies_hard.push(new enemy_hard());
currentenemy = 0;
nexthard = random(2, 6);
}
}
function bulletcollision() {
for (var i = 0; i < bullets.length; i++) {
for (var e = 0; e < enemies_easy.length; e++) {
var distance = createVector(bullets[i].x - enemies_easy[e].x, bullets[i].y - enemies_easy[e].y);
if (distance.mag() <= 18) {
bullets.splice(i, 1);
enemies_easy.splice(e, 1);
score++;
if (score > highscore) {
highscore++;
}
}
}
for (var e = 0; e < enemies_hard.length; e++) {
var distance = createVector(bullets[i].x - enemies_hard[e].x, bullets[i].y - enemies_hard[e].y);
if (distance.mag() <= 18) {
bullets.splice(i, 1);
hit++;
if (hit == 2) {
enemies_hard.splice(e, 1);
score++;
if (score > highscore) {
highscore++;
}
hit = 0;
}
}
}
}
}
function playercollision() {
for (var i = 0; i < enemies_easy.length; i++) {
var distance = createVector(enemies_easy[i].x - playerX, enemies_easy[i].y - playerY);
if (distance.mag() <= 25) {
push();
background(abs(255 * sin(random(0, 255))), 255 * sin(random(0, 255)), 255 * sin(random(0, 255)));
fill('white');
textAlign(CENTER);
textSize(width / 40);
translate(width / 2, height / 2);
text("Game Over!", 0, -100);
text("Score: " + score, 0, 0);
text("High Score: " + highscore, 0, 100);
pop();
return gameover = true;
}
}
for (var i = 0; i < enemies_hard.length; i++) {
var distance = createVector(enemies_hard[i].x - playerX, enemies_hard[i].y - playerY);
if (distance.mag() <= 25) {
push();
background(abs(255 * sin(random(0, 255))), 255 * sin(random(0, 255)), 255 * sin(random(0, 255)));
fill('white');
textAlign(CENTER);
textSize(width / 40);
translate(width / 2, height / 2);
text("Game Over!", 0, -100);
text("Score: " + score, 0, 0);
text("High Score: " + highscore, 0, 100);
pop();
return gameover = true;
}
}
}
function difficulty() {
if (time >= timer) {
newenemy();
time = 0;
timer = timer * 0.99;
v = v * 1.02;
}
}
function showscore() {
push();
fill('white');
textSize(width / 55);
textAlign(CENTER);
text('Score: ' + score, 100, 100);
pop();
}
Does anyone know how I could fix this issue or if I even can?
Any help is appreciated!
The problem is that you are removing bullets from the array as you iterate through the array. Use while-loop instead of the for-loop:
function bulletcollision() {
let i = 0;
while (i < bullets.length) {
let bullet_hit = false;
for (var e = 0; e < enemies_easy.length; e++) {
var distance = createVector(bullets[i].x - enemies_easy[e].x, bullets[i].y - enemies_easy[e].y);
if (distance.mag() <= 18) {
bullet_hit = true;
destroy_enemy(enemies_easy, e);
}
}
for (var e = 0; e < enemies_hard.length; e++) {
var distance = createVector(bullets[i].x - enemies_hard[e].x, bullets[i].y - enemies_hard[e].y);
if (distance.mag() <= 18) {
bullet_hit = true;
hit++;
if (hit == 2) {
destroy_enemy(enemies_hard, e);
hit = 0;
}
}
}
if (bullet_hit) {
bullets.splice(i, 1);
} else {
i ++;
}
}
}
function destroy_enemy(enemies, e) {
enemies.splice(e, 1);
score++;
highscore = Math.max(highscore, score);
}
See also Looping through array and removing items, without breaking for loop.

How to change opacity in Javascript for object

Found code here for metaballs using vanilla javascript. Is there a way I can change the opacity of the metaballs? I think it should be a quick fix but im not too sure. I tried changing to CSS class bubbles but that didnt work so im assuming in needs to be in the Javascript. Anything helps, thanks.
Found code here for metaballs using vanilla javascript. Is there a way I can change the opacity of the metaballs? I think it should be a quick fix but im not too sure. I tried changing to CSS class bubbles but that didnt work so im assuming in needs to be in the Javascript. Anything helps, thanks.
;(function() {
"use strict";
var lava0;
var ge1doot = {
screen: {
elem: null,
callback: null,
ctx: null,
width: 0,
height: 0,
left: 0,
top: 0,
init: function (id, callback, initRes) {
this.elem = document.getElementById(id);
this.callback = callback || null;
if (this.elem.tagName == "CANVAS") this.ctx = this.elem.getContext("2d");
window.addEventListener('resize', function () {
this.resize();
}.bind(this), false);
this.elem.onselectstart = function () { return false; }
this.elem.ondrag = function () { return false; }
initRes && this.resize();
return this;
},
resize: function () {
var o = this.elem;
this.width = o.offsetWidth;
this.height = o.offsetHeight;
for (this.left = 0, this.top = 0; o != null; o = o.offsetParent) {
this.left += o.offsetLeft;
this.top += o.offsetTop;
}
if (this.ctx) {
this.elem.width = this.width;
this.elem.height = this.height;
}
this.callback && this.callback();
}
}
}
// Point constructor
var Point = function(x, y) {
this.x = x;
this.y = y;
this.magnitude = x * x + y * y;
this.computed = 0;
this.force = 0;
};
Point.prototype.add = function(p) {
return new Point(this.x + p.x, this.y + p.y);
};
// Ball constructor
var Ball = function(parent) {
var min = .1;
var max = 1.5;
this.vel = new Point(
(Math.random() > 0.5 ? 1 : -1) * (0.2 + Math.random() * 0.25), (Math.random() > 0.5 ? 1 : -1) * (0.2 + Math.random())
);
this.pos = new Point(
parent.width * 0.2 + Math.random() * parent.width * 0.6,
parent.height * 0.2 + Math.random() * parent.height * 0.6
);
this.size = (parent.wh / 15) + ( Math.random() * (max - min) + min ) * (parent.wh / 15);
this.width = parent.width;
this.height = parent.height;
};
// move balls
Ball.prototype.move = function() {
// bounce borders
if (this.pos.x >= this.width - this.size) {
if (this.vel.x > 0) this.vel.x = -this.vel.x;
this.pos.x = this.width - this.size;
} else if (this.pos.x <= this.size) {
if (this.vel.x < 0) this.vel.x = -this.vel.x;
this.pos.x = this.size;
}
if (this.pos.y >= this.height - this.size) {
if (this.vel.y > 0) this.vel.y = -this.vel.y;
this.pos.y = this.height - this.size;
} else if (this.pos.y <= this.size) {
if (this.vel.y < 0) this.vel.y = -this.vel.y;
this.pos.y = this.size;
}
// velocity
this.pos = this.pos.add(this.vel);
};
// lavalamp constructor
var LavaLamp = function(width, height, numBalls, c0, c1) {
this.step = 5;
this.width = width;
this.height = height;
this.wh = Math.min(width, height);
this.sx = Math.floor(this.width / this.step);
this.sy = Math.floor(this.height / this.step);
this.paint = false;
this.metaFill = createRadialGradient(width, height, width, c0, c1);
this.plx = [0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0];
this.ply = [0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1];
this.mscases = [0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 0, 2, 1, 1, 0];
this.ix = [1, 0, -1, 0, 0, 1, 0, -1, -1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1];
this.grid = [];
this.balls = [];
this.iter = 0;
this.sign = 1;
// init grid
for (var i = 0; i < (this.sx + 2) * (this.sy + 2); i++) {
this.grid[i] = new Point(
(i % (this.sx + 2)) * this.step, (Math.floor(i / (this.sx + 2))) * this.step
)
}
// create metaballs
for (var k = 0; k < numBalls; k++) {
this.balls[k] = new Ball(this);
}
};
// compute cell force
LavaLamp.prototype.computeForce = function(x, y, idx) {
var force;
var id = idx || x + y * (this.sx + 2);
if (x === 0 || y === 0 || x === this.sx || y === this.sy) {
force = 0.6 * this.sign;
} else {
force = 0;
var cell = this.grid[id];
var i = 0;
var ball;
while (ball = this.balls[i++]) {
force += ball.size * ball.size / (-2 * cell.x * ball.pos.x - 2 * cell.y * ball.pos.y + ball.pos.magnitude + cell.magnitude);
}
force *= this.sign
}
this.grid[id].force = force;
return force;
};
// compute cell
LavaLamp.prototype.marchingSquares = function(next) {
var x = next[0];
var y = next[1];
var pdir = next[2];
var id = x + y * (this.sx + 2);
if (this.grid[id].computed === this.iter) {
return false;
}
var dir, mscase = 0;
// neighbors force
for (var i = 0; i < 4; i++) {
var idn = (x + this.ix[i + 12]) + (y + this.ix[i + 16]) * (this.sx + 2);
var force = this.grid[idn].force;
if ((force > 0 && this.sign < 0) || (force < 0 && this.sign > 0) || !force) {
// compute force if not in buffer
force = this.computeForce(
x + this.ix[i + 12],
y + this.ix[i + 16],
idn
);
}
if (Math.abs(force) > 1) mscase += Math.pow(2, i);
}
if (mscase === 15) {
// inside
return [x, y - 1, false];
} else {
// ambiguous cases
if (mscase === 5) dir = (pdir === 2) ? 3 : 1;
else if (mscase === 10) dir = (pdir === 3) ? 0 : 2;
else {
// lookup
dir = this.mscases[mscase];
this.grid[id].computed = this.iter;
}
// draw line
var ix = this.step / (
Math.abs(Math.abs(this.grid[(x + this.plx[4 * dir + 2]) + (y + this.ply[4 * dir + 2]) * (this.sx + 2)].force) - 1) /
Math.abs(Math.abs(this.grid[(x + this.plx[4 * dir + 3]) + (y + this.ply[4 * dir + 3]) * (this.sx + 2)].force) - 1) + 1
);
ctx.lineTo(
this.grid[(x + this.plx[4 * dir]) + (y + this.ply[4 * dir]) * (this.sx + 2)].x + this.ix[dir] * ix,
this.grid[(x + this.plx[4 * dir + 1]) + (y + this.ply[4 * dir + 1]) * (this.sx + 2)].y + this.ix[dir + 4] * ix
);
this.paint = true;
// next
return [
x + this.ix[dir + 4],
y + this.ix[dir + 8],
dir
];
}
};
LavaLamp.prototype.renderMetaballs = function() {
var i = 0, ball;
while (ball = this.balls[i++]) ball.move();
// reset grid
this.iter++;
this.sign = -this.sign;
this.paint = false;
ctx.fillStyle = this.metaFill;
ctx.beginPath();
// compute metaballs
i = 0;
//ctx.shadowBlur = 50;
//ctx.shadowColor = "green";
while (ball = this.balls[i++]) {
// first cell
var next = [
Math.round(ball.pos.x / this.step),
Math.round(ball.pos.y / this.step), false
];
// marching squares
do {
next = this.marchingSquares(next);
} while (next);
// fill and close path
if (this.paint) {
ctx.fill();
ctx.closePath();
ctx.beginPath();
this.paint = false;
}
}
};
// gradients
var createRadialGradient = function(w, h, r, c0, c1) {
var gradient = ctx.createRadialGradient(
w / 1, h / 1, 0,
w / 1, h / 1, r
);
gradient.addColorStop(0, c0);
gradient.addColorStop(1, c1);
};
// main loop
var run = function() {
requestAnimationFrame(run);
ctx.clearRect(0, 0, screen.width, screen.height);
lava0.renderMetaballs();
};
// canvas
var screen = ge1doot.screen.init("bubble", null, true),
ctx = screen.ctx;
screen.resize();
// create LavaLamps
lava0 = new LavaLamp(screen.width, screen.height, 6, "#FF9298", "#E4008E");
run();
})();
body {
margin: 0;
}
.wrap {
overflow: hidden;
position: relative;
height: 100vh;
}
canvas {
width: 100%;
height: 100%;
}
<div class="wrap">
<canvas id="bubble"></canvas>
</div>
You can do it by changing the context alpha channel with RGBA (see at the very bottom ctx.fillStyle = 'rgba(0, 0, 255, 0.5)' // NEW! where 0.5 is the level of opacity - see ) :
;
(function() {
'use strict'
var lava0
var ge1doot = {
screen: {
elem: null,
callback: null,
ctx: null,
width: 0,
height: 0,
left: 0,
top: 0,
init: function(id, callback, initRes) {
this.elem = document.getElementById(id)
this.callback = callback || null
if (this.elem.tagName == 'CANVAS') this.ctx = this.elem.getContext('2d')
window.addEventListener(
'resize',
function() {
this.resize()
}.bind(this),
false
)
this.elem.onselectstart = function() {
return false
}
this.elem.ondrag = function() {
return false
}
initRes && this.resize()
return this
},
resize: function() {
var o = this.elem
this.width = o.offsetWidth
this.height = o.offsetHeight
for (this.left = 0, this.top = 0; o != null; o = o.offsetParent) {
this.left += o.offsetLeft
this.top += o.offsetTop
}
if (this.ctx) {
this.elem.width = this.width
this.elem.height = this.height
}
this.callback && this.callback()
},
},
}
// Point constructor
var Point = function(x, y) {
this.x = x
this.y = y
this.magnitude = x * x + y * y
this.computed = 0
this.force = 0
}
Point.prototype.add = function(p) {
return new Point(this.x + p.x, this.y + p.y)
}
// Ball constructor
var Ball = function(parent) {
var min = 0.1
var max = 1.5
this.vel = new Point(
(Math.random() > 0.5 ? 1 : -1) * (0.2 + Math.random() * 0.25),
(Math.random() > 0.5 ? 1 : -1) * (0.2 + Math.random())
)
this.pos = new Point(
parent.width * 0.2 + Math.random() * parent.width * 0.6,
parent.height * 0.2 + Math.random() * parent.height * 0.6
)
this.size = parent.wh / 15 + (Math.random() * (max - min) + min) * (parent.wh / 15)
this.width = parent.width
this.height = parent.height
}
// move balls
Ball.prototype.move = function() {
// bounce borders
if (this.pos.x >= this.width - this.size) {
if (this.vel.x > 0) this.vel.x = -this.vel.x
this.pos.x = this.width - this.size
} else if (this.pos.x <= this.size) {
if (this.vel.x < 0) this.vel.x = -this.vel.x
this.pos.x = this.size
}
if (this.pos.y >= this.height - this.size) {
if (this.vel.y > 0) this.vel.y = -this.vel.y
this.pos.y = this.height - this.size
} else if (this.pos.y <= this.size) {
if (this.vel.y < 0) this.vel.y = -this.vel.y
this.pos.y = this.size
}
// velocity
this.pos = this.pos.add(this.vel)
}
// lavalamp constructor
var LavaLamp = function(width, height, numBalls, c0, c1) {
this.step = 5
this.width = width
this.height = height
this.wh = Math.min(width, height)
this.sx = Math.floor(this.width / this.step)
this.sy = Math.floor(this.height / this.step)
this.paint = false
this.metaFill = createRadialGradient(width, height, width, c0, c1)
this.plx = [0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0]
this.ply = [0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1]
this.mscases = [0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 0, 2, 1, 1, 0]
this.ix = [1, 0, -1, 0, 0, 1, 0, -1, -1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1]
this.grid = []
this.balls = []
this.iter = 0
this.sign = 1
// init grid
for (var i = 0; i < (this.sx + 2) * (this.sy + 2); i++) {
this.grid[i] = new Point((i % (this.sx + 2)) * this.step, Math.floor(i / (this.sx + 2)) * this.step)
}
// create metaballs
for (var k = 0; k < numBalls; k++) {
this.balls[k] = new Ball(this)
}
}
// compute cell force
LavaLamp.prototype.computeForce = function(x, y, idx) {
var force
var id = idx || x + y * (this.sx + 2)
if (x === 0 || y === 0 || x === this.sx || y === this.sy) {
force = 0.6 * this.sign
} else {
force = 0
var cell = this.grid[id]
var i = 0
var ball
while ((ball = this.balls[i++])) {
force +=
(ball.size * ball.size) /
(-2 * cell.x * ball.pos.x - 2 * cell.y * ball.pos.y + ball.pos.magnitude + cell.magnitude)
}
force *= this.sign
}
this.grid[id].force = force
return force
}
// compute cell
LavaLamp.prototype.marchingSquares = function(next) {
var x = next[0]
var y = next[1]
var pdir = next[2]
var id = x + y * (this.sx + 2)
if (this.grid[id].computed === this.iter) {
return false
}
var dir,
mscase = 0
// neighbors force
for (var i = 0; i < 4; i++) {
var idn = x + this.ix[i + 12] + (y + this.ix[i + 16]) * (this.sx + 2)
var force = this.grid[idn].force
if ((force > 0 && this.sign < 0) || (force < 0 && this.sign > 0) || !force) {
// compute force if not in buffer
force = this.computeForce(x + this.ix[i + 12], y + this.ix[i + 16], idn)
}
if (Math.abs(force) > 1) mscase += Math.pow(2, i)
}
if (mscase === 15) {
// inside
return [x, y - 1, false]
} else {
// ambiguous cases
if (mscase === 5) dir = pdir === 2 ? 3 : 1
else if (mscase === 10) dir = pdir === 3 ? 0 : 2
else {
// lookup
dir = this.mscases[mscase]
this.grid[id].computed = this.iter
}
// draw line
var ix =
this.step /
(Math.abs(
Math.abs(this.grid[x + this.plx[4 * dir + 2] + (y + this.ply[4 * dir + 2]) * (this.sx + 2)].force) - 1
) /
Math.abs(
Math.abs(this.grid[x + this.plx[4 * dir + 3] + (y + this.ply[4 * dir + 3]) * (this.sx + 2)].force) - 1
) +
1)
ctx.lineTo(
this.grid[x + this.plx[4 * dir] + (y + this.ply[4 * dir]) * (this.sx + 2)].x + this.ix[dir] * ix,
this.grid[x + this.plx[4 * dir + 1] + (y + this.ply[4 * dir + 1]) * (this.sx + 2)].y + this.ix[dir + 4] * ix
)
this.paint = true
// next
return [x + this.ix[dir + 4], y + this.ix[dir + 8], dir]
}
}
LavaLamp.prototype.renderMetaballs = function() {
var i = 0,
ball
while ((ball = this.balls[i++])) ball.move()
// reset grid
this.iter++
this.sign = -this.sign
this.paint = false
ctx.fillStyle = this.metaFill
ctx.beginPath()
// compute metaballs
i = 0
//ctx.shadowBlur = 50;
//ctx.shadowColor = "green";
while ((ball = this.balls[i++])) {
// first cell
var next = [Math.round(ball.pos.x / this.step), Math.round(ball.pos.y / this.step), false]
// marching squares
do {
next = this.marchingSquares(next)
} while (next)
// fill and close path
if (this.paint) {
ctx.fill()
ctx.closePath()
ctx.beginPath()
this.paint = false
}
}
}
// gradients
var createRadialGradient = function(w, h, r, c0, c1) {
var gradient = ctx.createRadialGradient(w / 1, h / 1, 0, w / 1, h / 1, r)
gradient.addColorStop(0, c0)
gradient.addColorStop(1, c1)
}
// main loop
var run = function() {
requestAnimationFrame(run)
ctx.clearRect(0, 0, screen.width, screen.height)
ctx.fillStyle = 'rgba(0, 0, 255, 0.5)' // NEW!
lava0.renderMetaballs()
}
// canvas
var screen = ge1doot.screen.init('bubble', null, true),
ctx = screen.ctx
screen.resize()
// create LavaLamps
lava0 = new LavaLamp(screen.width, screen.height, 6, '#FF9298', '#E4008E')
run()
})()
body {
margin: 0;
}
.wrap {
overflow: hidden;
position: relative;
height: 100vh;
}
canvas {
width: 100%;
height: 100%;
}
<div class="wrap">
<canvas id="bubble"></canvas>
</div>
Your Lava constructor takes two colors, these can be modified to fit your color needs. By using rgba() versions of your colors, you can set the alpha (ie the opacity) or your bubbles/meatballs. However, before you do that, you need to return the gradient created in createRadialGradient so that the colors can be used:
var createRadialGradient = function(w, h, r, c0, c1) {
// ... code ...
return gradient; // add this line
};
Now you can modify how you call your constructor:
// rgba versions of your colors -----------------------\/
lava0 = new LavaLamp(screen.width, screen.height, 6, "rgba(255, 146, 152, 0.5)", "rgba(228, 0, 142, 0.5)");
;(function() {
"use strict";
var lava0;
var ge1doot = {
screen: {
elem: null,
callback: null,
ctx: null,
width: 0,
height: 0,
left: 0,
top: 0,
init: function (id, callback, initRes) {
this.elem = document.getElementById(id);
this.callback = callback || null;
if (this.elem.tagName == "CANVAS") this.ctx = this.elem.getContext("2d");
window.addEventListener('resize', function () {
this.resize();
}.bind(this), false);
this.elem.onselectstart = function () { return false; }
this.elem.ondrag = function () { return false; }
initRes && this.resize();
return this;
},
resize: function () {
var o = this.elem;
this.width = o.offsetWidth;
this.height = o.offsetHeight;
for (this.left = 0, this.top = 0; o != null; o = o.offsetParent) {
this.left += o.offsetLeft;
this.top += o.offsetTop;
}
if (this.ctx) {
this.elem.width = this.width;
this.elem.height = this.height;
}
this.callback && this.callback();
}
}
}
// Point constructor
var Point = function(x, y) {
this.x = x;
this.y = y;
this.magnitude = x * x + y * y;
this.computed = 0;
this.force = 0;
};
Point.prototype.add = function(p) {
return new Point(this.x + p.x, this.y + p.y);
};
// Ball constructor
var Ball = function(parent) {
var min = .1;
var max = 1.5;
this.vel = new Point(
(Math.random() > 0.5 ? 1 : -1) * (0.2 + Math.random() * 0.25), (Math.random() > 0.5 ? 1 : -1) * (0.2 + Math.random())
);
this.pos = new Point(
parent.width * 0.2 + Math.random() * parent.width * 0.6,
parent.height * 0.2 + Math.random() * parent.height * 0.6
);
this.size = (parent.wh / 15) + ( Math.random() * (max - min) + min ) * (parent.wh / 15);
this.width = parent.width;
this.height = parent.height;
};
// move balls
Ball.prototype.move = function() {
// bounce borders
if (this.pos.x >= this.width - this.size) {
if (this.vel.x > 0) this.vel.x = -this.vel.x;
this.pos.x = this.width - this.size;
} else if (this.pos.x <= this.size) {
if (this.vel.x < 0) this.vel.x = -this.vel.x;
this.pos.x = this.size;
}
if (this.pos.y >= this.height - this.size) {
if (this.vel.y > 0) this.vel.y = -this.vel.y;
this.pos.y = this.height - this.size;
} else if (this.pos.y <= this.size) {
if (this.vel.y < 0) this.vel.y = -this.vel.y;
this.pos.y = this.size;
}
// velocity
this.pos = this.pos.add(this.vel);
};
// lavalamp constructor
var LavaLamp = function(width, height, numBalls, c0, c1) {
this.step = 5;
this.width = width;
this.height = height;
this.wh = Math.min(width, height);
this.sx = Math.floor(this.width / this.step);
this.sy = Math.floor(this.height / this.step);
this.paint = false;
this.metaFill = createRadialGradient(width, height, width, c0, c1);
this.plx = [0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0];
this.ply = [0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1];
this.mscases = [0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 0, 2, 1, 1, 0];
this.ix = [1, 0, -1, 0, 0, 1, 0, -1, -1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1];
this.grid = [];
this.balls = [];
this.iter = 0;
this.sign = 1;
// init grid
for (var i = 0; i < (this.sx + 2) * (this.sy + 2); i++) {
this.grid[i] = new Point(
(i % (this.sx + 2)) * this.step, (Math.floor(i / (this.sx + 2))) * this.step
)
}
// create metaballs
for (var k = 0; k < numBalls; k++) {
this.balls[k] = new Ball(this);
}
};
// compute cell force
LavaLamp.prototype.computeForce = function(x, y, idx) {
var force;
var id = idx || x + y * (this.sx + 2);
if (x === 0 || y === 0 || x === this.sx || y === this.sy) {
force = 0.6 * this.sign;
} else {
force = 0;
var cell = this.grid[id];
var i = 0;
var ball;
while (ball = this.balls[i++]) {
force += ball.size * ball.size / (-2 * cell.x * ball.pos.x - 2 * cell.y * ball.pos.y + ball.pos.magnitude + cell.magnitude);
}
force *= this.sign
}
this.grid[id].force = force;
return force;
};
// compute cell
LavaLamp.prototype.marchingSquares = function(next) {
var x = next[0];
var y = next[1];
var pdir = next[2];
var id = x + y * (this.sx + 2);
if (this.grid[id].computed === this.iter) {
return false;
}
var dir, mscase = 0;
// neighbors force
for (var i = 0; i < 4; i++) {
var idn = (x + this.ix[i + 12]) + (y + this.ix[i + 16]) * (this.sx + 2);
var force = this.grid[idn].force;
if ((force > 0 && this.sign < 0) || (force < 0 && this.sign > 0) || !force) {
// compute force if not in buffer
force = this.computeForce(
x + this.ix[i + 12],
y + this.ix[i + 16],
idn
);
}
if (Math.abs(force) > 1) mscase += Math.pow(2, i);
}
if (mscase === 15) {
// inside
return [x, y - 1, false];
} else {
// ambiguous cases
if (mscase === 5) dir = (pdir === 2) ? 3 : 1;
else if (mscase === 10) dir = (pdir === 3) ? 0 : 2;
else {
// lookup
dir = this.mscases[mscase];
this.grid[id].computed = this.iter;
}
// draw line
var ix = this.step / (
Math.abs(Math.abs(this.grid[(x + this.plx[4 * dir + 2]) + (y + this.ply[4 * dir + 2]) * (this.sx + 2)].force) - 1) /
Math.abs(Math.abs(this.grid[(x + this.plx[4 * dir + 3]) + (y + this.ply[4 * dir + 3]) * (this.sx + 2)].force) - 1) + 1
);
ctx.lineTo(
this.grid[(x + this.plx[4 * dir]) + (y + this.ply[4 * dir]) * (this.sx + 2)].x + this.ix[dir] * ix,
this.grid[(x + this.plx[4 * dir + 1]) + (y + this.ply[4 * dir + 1]) * (this.sx + 2)].y + this.ix[dir + 4] * ix
);
this.paint = true;
// next
return [
x + this.ix[dir + 4],
y + this.ix[dir + 8],
dir
];
}
};
LavaLamp.prototype.renderMetaballs = function() {
var i = 0, ball;
while (ball = this.balls[i++]) ball.move();
// reset grid
this.iter++;
this.sign = -this.sign;
this.paint = false;
ctx.fillStyle = this.metaFill;
ctx.beginPath();
// compute metaballs
i = 0;
//ctx.shadowBlur = 50;
//ctx.shadowColor = "green";
while (ball = this.balls[i++]) {
// first cell
var next = [
Math.round(ball.pos.x / this.step),
Math.round(ball.pos.y / this.step), false
];
// marching squares
do {
next = this.marchingSquares(next);
} while (next);
// fill and close path
if (this.paint) {
ctx.fill();
ctx.closePath();
ctx.beginPath();
this.paint = false;
}
}
};
// gradients
var createRadialGradient = function(w, h, r, c0, c1) {
var gradient = ctx.createRadialGradient(
w / 1, h / 1, 0,
w / 1, h / 1, r
);
gradient.addColorStop(0, c0);
gradient.addColorStop(1, c1);
return gradient;
};
// main loop
var run = function() {
requestAnimationFrame(run);
ctx.clearRect(0, 0, screen.width, screen.height);
lava0.renderMetaballs();
};
// canvas
var screen = ge1doot.screen.init("bubble", null, true),
ctx = screen.ctx;
screen.resize();
// create LavaLamps
lava0 = new LavaLamp(screen.width, screen.height, 6, "rgba(255, 146, 152, 0.5)", "rgba(228, 0, 142, 0.5)");
run();
})();
body {
margin: 0;
}
.wrap {
overflow: hidden;
position: relative;
height: 100vh;
}
canvas {
width: 100%;
height: 100%;
}
<div class="wrap">
<canvas id="bubble"></canvas>
</div>

Unexpected Result when Resolving Collision in JavaScript

I've been making a simple game just with the HTML5 canvas and plain JavaScript. Most recently I tried adding a feature to shoot bullets which would then destroy obstacles but I've come upon a problem. Whenever you shoot a bullet it doesn't move until another is shot. Even when it starts moving and collides with one of the obstacles nothing happens. I've done some troubleshooting and I can't seem to get to the bottom of it. Any help and/or suggestions would be greatly appreciated.
Collision handling code:
for(var i = 0; i < this.bullets.length - 1; i++) { // -1 is present because whenever I remove it I get an error. I have a feeling this may be related to the order of how everything updates, will be fixed
this.bullets[i].x += this.bullets[i].speed;
if(this.bullets[i].x > cvs.width) {
this.bullets.splice(i, 1);
}
for(var j = 0; j < obstacles.length - 1; j++) { // Same here
if(rectanglesColliding(this.bullets[i], obstacles[j])) {
console.log("Collision");
}
}
}
Full player object:
var player = {
score: 0,
x: 50,
y: 150,
radius: 10,
jumping: false,
bullets: [],
velocityX: 0,
velocityY: 1,
angle: 90,
update: function() {
this.draw();
this.score++;
if(this.y + this.radius + 2 > cvs.height - 50 && this.jumping === false || this.y - this.radius + 2 < 0 + 50 && this.jumping === true) {
this.velocityY = 0;
} else if(this.jumping === false){
this.velocityY = 4;
} else {
this.velocityY = -4;
}
obstacles.forEach((obstacle) => {
if(colliding(this, obstacle)) {
gameEnded = true;
}
});
this.x += this.velocityX;
this.y += this.velocityY;
for(var i = 0; i < this.bullets.length - 1; i++) { // -1 is present because whenever I remove it I get an error. I have a feeling this may be related to the order of how everything updates, will be fixed
this.bullets[i].x += this.bullets[i].speed;
if(this.bullets[i].x > cvs.width) {
this.bullets.splice(i, 1);
}
for(var j = 0; j < obstacles.length - 1; j++) { // Same here
if(rectanglesColliding(this.bullets[i], obstacles[j])) {
console.log("Collision");
}
}
}
},
draw: function() {
this.bullets.forEach((bullet) => {
ctx.fillStyle = 'green';
ctx.fillRect(bullet.x, bullet.y, 7, 2);
});
ctx.fillStyle = 'blue';
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
ctx.fill();
}
};
Collision Detection Function:
function rectanglesColliding(rect1, rect2) {
if(rect1.x < rect2.x + rect2.width &&
rect1.x + rect1.width > rect2.x && // Found on Mozilla.com: https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection
rect1.y < rect2.y + rect2.height &&
rect1.y + rect1.height > rect2.y) return true;
else return false;
}
Shoot Function:
function shoot() {
player.bullets.push({ x: player.x + 10, y: player.y, speed: 6 });
}
Object of the game:
Survive as long as you can by avoiding the obstacles.
Controls:
Space: Go up
W: Shoot Bullet
Full code snippet:
var cvs = document.getElementById('canvas');
var ctx = cvs.getContext("2d");
var gameEnded = false;
var player = {
score: 0,
x: 50,
y: 150,
radius: 10,
jumping: false,
bullets: [],
velocityX: 0,
velocityY: 1,
angle: 90,
update: function() {
this.draw();
this.score++;
if(this.y + this.radius + 2 > cvs.height - 50 && this.jumping === false || this.y - this.radius + 2 < 0 + 50 && this.jumping === true) {
this.velocityY = 0;
} else if(this.jumping === false){
this.velocityY = 4;
} else {
this.velocityY = -4;
}
obstacles.forEach((obstacle) => {
if(colliding(this, obstacle)) {
gameEnded = true;
}
});
this.x += this.velocityX;
this.y += this.velocityY;
for(var i = 0; i < this.bullets.length - 1; i++) {
this.bullets[i].x += this.bullets[i].speed;
if(this.bullets[i].x > cvs.width) {
this.bullets.splice(i, 1);
}
for(var j = 0; j < obstacles.length - 1; j++) {
if(rectanglesColliding(this.bullets[i], obstacles[j])) {
console.log("Collision");
// obstacles.splice(i, 1);
}
}
}
},
draw: function() {
this.bullets.forEach((bullet) => {
ctx.fillStyle = 'green';
ctx.fillRect(bullet.x, bullet.y, 7, 2);
});
ctx.fillStyle = 'blue';
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
ctx.fill();
}
};
var obstacles = [{ x: 150, y: 60, width: 10, height: 20 }];
document.addEventListener('keydown', (event) => {
if(event.key === ' ') {
player.jumping = true;
}
if(event.key === 'w') {
shoot();
}
});
document.addEventListener('keyup', (event) => {
if(event.key === ' ') {
player.jumping = false;
}
});
function randomIntFromRange(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
function getWidth() {
return Math.max(
document.body.scrollWidth,
document.documentElement.scrollWidth,
document.body.offsetWidth,
document.documentElement.offsetWidth,
document.documentElement.clientWidth
);
}
function getHeight() {
return Math.max(
document.body.scrollHeight,
document.documentElement.scrollHeight,
document.body.offsetHeight,
document.documentElement.offsetHeight,
document.documentElement.clientHeight
);
}
function colliding(circle, rect) {
var distX = Math.abs(circle.x - rect.x - rect.width / 2);
var distY = Math.abs(circle.y - rect.y - rect.height / 2);
if(distX > (rect.width / 2 + circle.radius)) return false;
if(distY > (rect.height / 2 + circle.radius)) return false;
if(distX <= (rect.width / 2)) return true;
if(distY <= (rect.height / 2)) return true;
}
function rectanglesColliding(rect1, rect2) {
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) {
return true;
}
}
function distance(x1, y1, x2, y2) {
const xDist = x2 - x1;
const yDist = y2 - y1;
return Math.sqrt(Math.pow(xDist, 2) + Math.pow(yDist, 2));
}
function shoot() {
player.bullets.push({ x: player.x + 10, y: player.y, speed: 6 });
}
function generateObstacle() {
var obstacle = {
x: obstacles[0].x + randomIntFromRange(cvs.width - 100, cvs.width + 70),
y: 0 + randomIntFromRange(20, 550),
width: randomIntFromRange(25, 35),
height: randomIntFromRange(10, 25)
};
for(var i = 0; i < obstacles.length; i++) {
if(distance(obstacle.x, obstacle.y, obstacles[i].x, obstacles[i].y) < 65) {
obstacle = {
x: obstacles[0].x + randomIntFromRange(cvs.width - 100, cvs.width + 70),
y: 0 + randomIntFromRange(20, 550),
width: randomIntFromRange(25, 35),
height: randomIntFromRange(10, 25)
};
i = -1;
}
}
obstacles.push({ x: obstacle.x, y: obstacle.y, width: obstacle.width, height: obstacle.height });
}
function removeBadObstacles() {
for(var i = 0; i < obstacles.length; i++) {
if(obstacles[i].x < 0) {
obstacles.splice(i, 1);
}
}
}
function updateObstacles() {
if(obstacles[obstacles.length - 1].x < cvs.width + 5) {
generateObstacle();
generateObstacle();
}
obstacles.forEach((obstacle) => {
obstacle.x -= 10;
ctx.fillStyle = 'red';
ctx.fillRect(obstacle.x, obstacle.y, obstacle.width, obstacle.height);
});
}
function init() {
cvs.width = getWidth();
cvs.height = getHeight();
update();
}
function update() {
if(gameEnded) {
ctx.font = '50px Verdana';
return ctx.fillText('Game Over', 110, cvs.height / 2);
}
requestAnimationFrame(update);
removeBadObstacles();
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, cvs.width, cvs.height);
updateObstacles();
player.update();
ctx.font = '30px Impact';
ctx.fillText("Score: " + player.score, 20, 40);
}
init();
<!DOCTYPE html>
<html>
<head>
<title>Game</title>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="text/javascript" src="./JS/main.js"></script>
</body>
</html>
when iterate through a array, the last item is at length-1 (which mean you should use < length, not < length-1)
the remove code should be obstacles.splice(j, 1); (i is the index for bullet)
you do not assign size to bullet (and you may also want to use this size when draw)
var cvs = document.getElementById('canvas');
var ctx = cvs.getContext("2d");
var gameEnded = false;
var player = {
score: 0,
x: 50,
y: 150,
radius: 10,
jumping: false,
bullets: [],
velocityX: 0,
velocityY: 1,
angle: 90,
update: function() {
this.draw();
this.score++;
if(this.y + this.radius + 2 > cvs.height - 50 && this.jumping === false || this.y - this.radius + 2 < 0 + 50 && this.jumping === true) {
this.velocityY = 0;
} else if(this.jumping === false){
this.velocityY = 4;
} else {
this.velocityY = -4;
}
obstacles.forEach((obstacle) => {
if(colliding(this, obstacle)) {
gameEnded = true;
}
});
this.x += this.velocityX;
this.y += this.velocityY;
for(var i = 0; i < this.bullets.length; i++) {//<==============
this.bullets[i].x += this.bullets[i].speed;
if(this.bullets[i].x > cvs.width) {
this.bullets.splice(i, 1);
}
for(var j = 0; j < obstacles.length; j++) {//<==============
if(rectanglesColliding(this.bullets[i], obstacles[j])) {
console.log("Collision");
obstacles.splice(j, 1);//<==============
}
}
}
},
draw: function() {
this.bullets.forEach((bullet) => {
ctx.fillStyle = 'green';
ctx.fillRect(bullet.x, bullet.y, 7, 2);
});
ctx.fillStyle = 'blue';
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
ctx.fill();
}
};
var obstacles = [{ x: 150, y: 60, width: 10, height: 20 }];
document.addEventListener('keydown', (event) => {
if(event.key === ' ') {
player.jumping = true;
}
if(event.key === 'w') {
shoot();
}
});
document.addEventListener('keyup', (event) => {
if(event.key === ' ') {
player.jumping = false;
}
});
function randomIntFromRange(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
function getWidth() {
return Math.max(
document.body.scrollWidth,
document.documentElement.scrollWidth,
document.body.offsetWidth,
document.documentElement.offsetWidth,
document.documentElement.clientWidth
);
}
function getHeight() {
return Math.max(
document.body.scrollHeight,
document.documentElement.scrollHeight,
document.body.offsetHeight,
document.documentElement.offsetHeight,
document.documentElement.clientHeight
);
}
function colliding(circle, rect) {
var distX = Math.abs(circle.x - rect.x - rect.width / 2);
var distY = Math.abs(circle.y - rect.y - rect.height / 2);
if(distX > (rect.width / 2 + circle.radius)) return false;
if(distY > (rect.height / 2 + circle.radius)) return false;
if(distX <= (rect.width / 2)) return true;
if(distY <= (rect.height / 2)) return true;
}
function rectanglesColliding(rect1, rect2) {
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) {
return true;
}
}
function distance(x1, y1, x2, y2) {
const xDist = x2 - x1;
const yDist = y2 - y1;
return Math.sqrt(Math.pow(xDist, 2) + Math.pow(yDist, 2));
}
function shoot() {
player.bullets.push({ x: player.x + 10, y: player.y, speed: 6, width: 7, height: 6 }); //<====================
}
function generateObstacle() {
var obstacle = {
x: obstacles[0].x + randomIntFromRange(cvs.width - 100, cvs.width + 70),
y: 0 + randomIntFromRange(20, 550),
width: randomIntFromRange(25, 35),
height: randomIntFromRange(10, 25)
};
for(var i = 0; i < obstacles.length; i++) {
if(distance(obstacle.x, obstacle.y, obstacles[i].x, obstacles[i].y) < 65) {
obstacle = {
x: obstacles[0].x + randomIntFromRange(cvs.width - 100, cvs.width + 70),
y: 0 + randomIntFromRange(20, 550),
width: randomIntFromRange(25, 35),
height: randomIntFromRange(10, 25)
};
i = -1;
}
}
obstacles.push({ x: obstacle.x, y: obstacle.y, width: obstacle.width, height: obstacle.height });
}
function removeBadObstacles() {
for(var i = 0; i < obstacles.length; i++) {
if(obstacles[i].x < 0) {
obstacles.splice(i, 1);
}
}
}
function updateObstacles() {
if(obstacles[obstacles.length - 1].x < cvs.width + 5) {
generateObstacle();
generateObstacle();
}
obstacles.forEach((obstacle) => {
obstacle.x -= 10;
ctx.fillStyle = 'red';
ctx.fillRect(obstacle.x, obstacle.y, obstacle.width, obstacle.height);
});
}
function init() {
cvs.width = getWidth();
cvs.height = getHeight();
update();
}
function update() {
if(gameEnded) {
ctx.font = '50px Verdana';
return ctx.fillText('Game Over', 110, cvs.height / 2);
}
requestAnimationFrame(update);
removeBadObstacles();
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, cvs.width, cvs.height);
updateObstacles();
player.update();
ctx.font = '30px Impact';
ctx.fillText("Score: " + player.score, 20, 40);
}
init();
<!DOCTYPE html>
<html>
<head>
<title>Game</title>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="text/javascript" src="./JS/main.js"></script>
</body>
</html>

Duplicate randomly multiple objects inside a javascript for loop

I found this platform game on the Internet and I modified it a bit:
<canvas id="canvas" widht=1000 height=400></canvas>
<script>
(function () {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 1000,
height = 400,
player = {
x: width / 2,
y: height - 15,
width: 5,
height: 5,
speed: 3,
velX: 0,
velY: 0,
jumping: false,
grounded: false
},
keys = [],
friction = 0.8,
gravity = 0.3;
var boxes = [];
// dimensions
a = Math.floor((Math.random() * 20) + 1);
for (i = 0; i < a; i++) {
random1 = Math.floor((Math.random() * 1000) + 1);
random2 = Math.floor((Math.random() * 400) + 1);
random3 = Math.floor((Math.random() * 200) + 1);
random4 = Math.floor((Math.random() * 200) + 1);
boxes.push({
x: random1,
y: random2,
width: random3,
height: random4
}
boxes.push({
x: 0,
y: 0,
width: 10,
height: height
});
boxes.push({
x: 0,
y: height - 2,
width: width,
height: 50
});
boxes.push({
x: width - 10,
y: 0,
width: 50,
height: height
});
canvas.width = width;
canvas.height = height;
function update() {
// check keys
if (keys[38] || keys[32]) {
// up arrow or space
if (!player.jumping && player.grounded) {
player.jumping = true;
player.grounded = false;
player.velY = -player.speed * 2;
}
}
if (keys[39]) {
// right arrow
if (player.velX < player.speed) {
player.velX++;
}
}
if (keys[37]) {
// left arrow
if (player.velX > -player.speed) {
player.velX--;
}
}
player.velX *= friction;
player.velY += gravity;
ctx.clearRect(0, 0, width, height);
ctx.fillStyle = "black";
ctx.beginPath();
player.grounded = false;
for (var i = 0; i < boxes.length; i++) {
ctx.rect(boxes[i].x, boxes[i].y, boxes[i].width, boxes[i].height);
var dir = colCheck(player, boxes[i]);
if (dir === "l" || dir === "r") {
player.velX = 0;
player.jumping = false;
} else if (dir === "b") {
player.grounded = true;
player.jumping = false;
} else if (dir === "t") {
player.velY *= -1;
}
}
if(player.grounded){
player.velY = 0;
}
player.x += player.velX;
player.y += player.velY;
ctx.fill();
ctx.fillStyle = "red";
ctx.fillRect(player.x, player.y, player.width, player.height);
requestAnimationFrame(update);
}
function colCheck(shapeA, shapeB) {
// get the vectors to check against
var vX = (shapeA.x + (shapeA.width / 2)) - (shapeB.x + (shapeB.width / 2)),
vY = (shapeA.y + (shapeA.height / 2)) - (shapeB.y + (shapeB.height / 2)),
// add the half widths and half heights of the objects
hWidths = (shapeA.width / 2) + (shapeB.width / 2),
hHeights = (shapeA.height / 2) + (shapeB.height / 2),
colDir = null;
// if the x and y vector are less than the half width or half height, they we must be inside the object, causing a collision
if (Math.abs(vX) < hWidths && Math.abs(vY) < hHeights) {
// figures out on which side we are colliding (top, bottom, left, or right)
var oX = hWidths - Math.abs(vX),
oY = hHeights - Math.abs(vY);
if (oX >= oY) {
if (vY > 0) {
colDir = "t";
shapeA.y += oY;
} else {
colDir = "b";
shapeA.y -= oY;
}
} else {
if (vX > 0) {
colDir = "l";
shapeA.x += oX;
} else {
colDir = "r";
shapeA.x -= oX;
}
}
}
return colDir;
}
document.body.addEventListener("keydown", function (e) {
keys[e.keyCode] = true;
});
document.body.addEventListener("keyup", function (e) {
keys[e.keyCode] = false;
});
window.addEventListener("load", function () {
update();
});
</script>
The problem is in the for loop when I want to create multiple boxes with random width, height, position but that didn't work. How could I do that?
In you code there are two syntax error. first one is you didn't close for loop and second one is inside for loop first push operation was not close properly.
i have update code.
(function () {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 1000,
height = 400,
player = {
x: width / 2,
y: height - 15,
width: 5,
height: 5,
speed: 3,
velX: 0,
velY: 0,
jumping: false,
grounded: false
},
keys = [],
friction = 0.8,
gravity = 0.3;
var boxes = [];
// dimensions
a = Math.floor((Math.random() * 20) + 1);
for (i = 0; i < a; i++) {
random1 = Math.floor((Math.random() * 1000) + 1);
random2 = Math.floor((Math.random() * 400) + 1);
random3 = Math.floor((Math.random() * 200) + 1);
random4 = Math.floor((Math.random() * 200) + 1);
boxes.push({
x: random1,
y: random2,
width: random3,
height: random4
});
boxes.push({
x: 0,
y: 0,
width: 10,
height: height
});
boxes.push({
x: 0,
y: height - 2,
width: width,
height: 50
});
boxes.push({
x: width - 10,
y: 0,
width: 50,
height: height
});
canvas.width = width;
canvas.height = height;
}
function update() {
// check keys
if (keys[38] || keys[32]) {
// up arrow or space
if (!player.jumping && player.grounded) {
player.jumping = true;
player.grounded = false;
player.velY = -player.speed * 2;
}
}
if (keys[39]) {
// right arrow
if (player.velX < player.speed) {
player.velX++;
}
}
if (keys[37]) {
// left arrow
if (player.velX > -player.speed) {
player.velX--;
}
}
player.velX *= friction;
player.velY += gravity;
ctx.clearRect(0, 0, width, height);
ctx.fillStyle = "black";
ctx.beginPath();
player.grounded = false;
for (var i = 0; i < boxes.length; i++) {
ctx.rect(boxes[i].x, boxes[i].y, boxes[i].width, boxes[i].height);
var dir = colCheck(player, boxes[i]);
if (dir === "l" || dir === "r") {
player.velX = 0;
player.jumping = false;
} else if (dir === "b") {
player.grounded = true;
player.jumping = false;
} else if (dir === "t") {
player.velY *= -1;
}
}
if(player.grounded){
player.velY = 0;
}
player.x += player.velX;
player.y += player.velY;
ctx.fill();
ctx.fillStyle = "red";
ctx.fillRect(player.x, player.y, player.width, player.height);
requestAnimationFrame(update);
}
function colCheck(shapeA, shapeB) {
// get the vectors to check against
var vX = (shapeA.x + (shapeA.width / 2)) - (shapeB.x + (shapeB.width / 2)),
vY = (shapeA.y + (shapeA.height / 2)) - (shapeB.y + (shapeB.height / 2)),
// add the half widths and half heights of the objects
hWidths = (shapeA.width / 2) + (shapeB.width / 2),
hHeights = (shapeA.height / 2) + (shapeB.height / 2),
colDir = null;
// if the x and y vector are less than the half width or half height, they we must be inside the object, causing a collision
if (Math.abs(vX) < hWidths && Math.abs(vY) < hHeights) {
// figures out on which side we are colliding (top, bottom, left, or right)
var oX = hWidths - Math.abs(vX),
oY = hHeights - Math.abs(vY);
if (oX >= oY) {
if (vY > 0) {
colDir = "t";
shapeA.y += oY;
} else {
colDir = "b";
shapeA.y -= oY;
}
} else {
if (vX > 0) {
colDir = "l";
shapeA.x += oX;
} else {
colDir = "r";
shapeA.x -= oX;
}
}
}
return colDir;
}
document.body.addEventListener("keydown", function (e) {
keys[e.keyCode] = true;
});
document.body.addEventListener("keyup", function (e) {
keys[e.keyCode] = false;
});
window.addEventListener("load", function () {
update();
});
<canvas id="canvas" widht=1000 height=400></canvas>

How do I get one singel array inside a for-loop?

i have a simpel game but when the red ball hits the blue ball while in motion the SPLICING desen't work i get the error form the movement script. I think the best solution to this problem is to registrer a collition when only the red ball hits the blu ball. can somone help me whith that?
To se a demo clik the linkDEMO press R to restart
Code:
var canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
var tileldig = Math.floor((Math.random() * 300) + 1);
var tekst = document.getElementById("tekst")
var log = document.getElementById("log")
var highlog = document.getElementById("highlog")
var kuler = [{
r: 10,
x: canvas.width / 2,
y: canvas.height - 100,
f: "red",
dy: 0
}, ];
var fiender = [{
r: 20,
x: tileldig,
y: -20,
vx: 0,
vy: 1,
}, ];
//var snd = new Audio("Skudd.m4a");
var poeng = 0;
var highscore = 0;
var høyre = 0;
var venstre = 0;
var opp = 0;
var ned = 0;
var restart = 0;
var død = 0;
document.onkeydown = function tast(e) {
if (e.keyCode == 39) { // høyre
høyre = 1;
}
if (e.keyCode == 37) { // venstre
venstre = 1;
}
if (e.keyCode == 38) { // opp
opp = 1;
}
if (e.keyCode == 40) { // ned
ned = 1;
}
if (e.keyCode == 32) {
newskudd();
// snd.play();
console.log("hit space")
}
if (e.keyCode == 82) {
init();
log.innerHTML += ("Poeng: " + poeng)
poeng = 0;
}
}
document.onkeyup = function tast2(e) {
if (e.keyCode == 39) { // høyre
høyre = 0;
}
if (e.keyCode == 37) { // venstre
venstre = 0;
}
if (e.keyCode == 38) { // opp
opp = 0;
}
if (e.keyCode == 40) { // ned
ned = 0;
}
}
function spill() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < kuler.length; i++) {
kuler[i].x += 0;
kuler[i].y += kuler[i].dy;
ctx.fillStyle = kuler[i].f;
ctx.beginPath();
ctx.arc(kuler[i].x, kuler[i].y, kuler[i].r, 2 * Math.PI, 0);
ctx.closePath();
ctx.fill();
if (kuler[0].x >= canvas.width - kuler[0].r) {
kuler[0].x = canvas.width - kuler[0].r
};
if (kuler[0].x <= 0 + kuler[0].r) {
kuler[0].x = 0 + kuler[0].r
};
if (kuler[0].y >= canvas.height - kuler[0].r) {
kuler[0].y = canvas.height - kuler[0].r
};
if (kuler[0].y <= 0 + kuler[0].r) {
kuler[0].y = 0 + kuler[0].r
};
for (var j = 0; j < fiender.length; j++) {
ctx.fillStyle = "blue";
ctx.beginPath();
ctx.arc(fiender[j].x, fiender[j].y, fiender[j].r, 2 * Math.PI, 0);
ctx.closePath();
ctx.fill();
if (fiender[j].x >= canvas.width - fiender[j].r) {
fiender[j].x = canvas.width - fiender[j].r;
};
if (fiender[j].x <= 0 + fiender[j].r) {
fiender[j].x = 0 + fiender[j].r;
};
if (fiender[j].vy >= 2) {
fiender[j].vy = 2;
};
var distanceFromCenters = Math.sqrt(Math.pow(Math.abs(fiender[j].x - kuler[i].x), 2) + Math.pow(Math.abs(fiender[j].y - kuler[i].y), 2)); // you have a collision
if (distanceFromCenters <= (fiender[j].r + kuler[i].r)) {
fiender.splice(j, 1);
kuler.splice(i, 1);
poeng += 1;
restart = 1;
} else if (fiender[j].y > canvas.height) {
fiender.splice(j, 1)
}
if (j > 1) {
fiender.splice(j, 1)
}
log.innerHTML = ("<br>" + "Score denne runden: " + poeng + "</br>" + "<br>" + "Highscore: " + highscore + "</br>")
if (poeng >= highscore) {
log.innerHTML += ("<br>" + "Ny Highscore: " + highscore + "</br>")
highscore = poeng;
}
}
}
for (var j = 0; j < fiender.length; j++) {
fiender[j].y += fiender[j].vy;
}
if (venstre == 1) {
kuler[0].x -= 4;
}
if (høyre == 1) {
kuler[0].x += 4;;
}
if (opp == 1) {
kuler[0].y -= 4;
}
if (ned == 1) {
kuler[0].y += 4;
}
requestAnimationFrame(spill);
return;
}
document.onload = spill();
function newskudd() {
var nyttskudd = {
x: kuler[0].x,
y: kuler[0].y,
r: 5,
dy: -5,
f: "white"
};
kuler.push(nyttskudd);
};
setInterval(function() {
fiender.push({
r: 20,
x: Math.floor((Math.random() * 300) + 1),
y: -20,
vx: 0,
vy: 1,
f: "green"
});
}, 1000);
function init() {
kuler = [{
r: 10,
x: canvas.width / 2,
y: canvas.height - 100,
f: "red",
dy: 0
}, ];
fiender = [{
r: 20,
x: tileldig,
y: -20,
vx: 0,
vy: 1,
}, ];
}

Categories

Resources