How can I restart my function? - javascript

I have made a simple game but when its game over the game is just over, I want it to restart when I press ENTER. Can someone help me with this?
I do not want to reload the site but only the function.
When I press enter now the speed increases.
You can se the the game by clicking the link DEMO press ENTER to start the game
Code:
var canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
var tileldig = Math.floor((Math.random() * 300) + 1);
var tekst = document.getElementById("tekst")
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 høyre = 0;
var venstre = 0;
var opp = 0;
var ned = 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 == 13) {
spill();
}
}
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;
} else if (fiender[j].y > canvas.height) {
fiender.splice(j, 1)
}
if (j > 1) {
fiender.splice(j, 1)
}
tekst.innerHTML = ("Poeng: " + 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;
}
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);

An easy way to do this would be to simply refresh the page with location.reload() when a key is pressed.
You could also create a gameIsInProgress variable to change to false when the game ends, and test for that value before allowing the page to reload.

First, initialize then run spill ...
if (e.keyCode == 13) {
init();
spill();
}
Here's an init ...
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,
}, ];
poeng = 0;
høyre = 0;
venstre = 0;
opp = 0;
ned = 0;
}
Running here ... jsFiddle

Related

add delay to iteraction

I'm building an animation with multiple drawn circles going left to right. However, the animation starts at the same time for all circles, and I need them to have a timed interval (for example 1 second) between each other. Any idea on how to manage this?
I've tried setInterval without success.
The drawing of circles is as follows:
function isPrime(num) {
for(var i = 2; i < num; i++)
if(num % i === 0) return false;
return num > 1;
}
const settings = {
width: 300,
height: 930,
radius: 13,
gap: 5,
circles: 30,
};
const canvas = document.getElementById("canvas");
canvas.width = settings.width;
canvas.height = settings.height;
const ctx = canvas.getContext("2d");
var randomNumber = [];
const circles = [...Array(settings.circles).keys()].map((i) => ({
number: randomNumber[i],
x: settings.radius,
y: settings.radius + (settings.radius * 2 + settings.gap) * i,
radius: settings.radius,
dx: 100, // This is the speed in pixels per second
dy: 0,
isPrime: isPrime(randomNumber[i]),
}));
function drawCircle(circle) {
i = 0;
if (circle.number > 0 && circle.number <= 10) {
ctx.strokeStyle = "#0b0bf1";
} else if (circle.number > 10 && circle.number <= 20) {
ctx.strokeStyle = "#f10b0b";
} else if (circle.number > 20 && circle.number <= 30) {
ctx.strokeStyle = "#0bf163";
} else if (circle.number > 30 && circle.number <= 40) {
ctx.strokeStyle = "#f1da0b";
} else if (circle.number > 40 && circle.number <= 50) {
ctx.strokeStyle = "#950bf1";
} else if (circle.number > 50 && circle.number <= 60) {
ctx.strokeStyle = "#0bf1e5";
}
ctx.beginPath();
ctx.arc(circle.x, circle.y, circle.radius, 0, Math.PI * 2, false);
ctx.stroke();
ctx.fillText(circle.number, circle.x - 5, circle.y + 3);
}
function updateCircle(circle, dt) {
circle.x = clamp(
circle.x + circle.dx * dt,
circle.radius + 1,
settings.width - circle.radius - 1
);
circle.y = clamp(
circle.y + circle.dy * dt,
circle.radius + 1,
settings.height - circle.radius - 1
);
}
function animate() {
ctx.clearRect(0, 0, settings.width, settings.height);
circles.forEach(drawCircle);
requestAnimationFrame(animate);
}
animate();
update((dt) => circles.forEach((circle) => updateCircle(circle, dt)), 50);
I think you want to do like
let i = 0, l = circles.length;
let intv = setInterval(()=>{
drawCircle(circles[i++]);
if(i === l){
clearInterval(intv); intv = undefined;
}
}, 100); // change interval as desired
instead of circles.forEach(drawCircle);.
That requestAnimationFrame looks pretty useless like that too.

Restarting my draw function does not work

I have a game in which there si a rocket. When rockets health is 0 the game over screen should appear and when any key is pressed the game should restart.
I tried using redraw and loop keywords in p5.js
let x = 240;
let x1 = 258;
let score = 0;
let health = 5;
let opelsins = [];
let ecllipseOpelsin = [];
let monsterimg;
let meteorimg;
let inGameSound;
let opelsinimg;
let gameOverSound;
let backgroundsun;
let gameoverScreen;
function collideRectangleCircle(rx, ry, rw, rh, cx, cy, cr)
{
return rx+rw > cx-cr && cx+cr > rx && ry+rh > cy-cr && cy+cr > ry;
}
function Opelsin() {
this.x = random(40,560);
this.y = random(-200,-190);
this.speed = random(3,10);
this.fall = function() {
this.y = this.y + this.speed;
if (this.y > height) {
this.y = random(-200,-100);
this.x = random(40,560);
this.speed = random(3, 10);
}
};
this.show = function() {
fill(255)
ellipse(this.x + 15,this.y + 34, 10, 10)
image(opelsinimg,this.x,this.y, 40, 40)
};
}
function opelsinmodel() {
this.x = random(0,600);
this.y = random(-300,-310);
this.speed = random(3,10);
this.show = function() { ellipse(this.x,this.y, 20, 20) };
}
function setup() {
createCanvas(600, 400);
frameRate(300)
inGameSound.setVolume(1);
inGameSound.loop();
interval = setInterval(scoreCount, 500);
}
function gameOver() {
textSize(20);
text("GAME OVER", 250, 200);
text("SCORE: " + score, 270, 220);
fill(255);
}
function newGame() {
if (keyIsPressed === true) {
//redraw();
loop();
}
}
function preload() {
soundFormats('m4a')
monsterimg = loadImage('assets/monster.png');
opelsinimg = loadImage('assets/opelsin.png');
inGameSound = loadSound('assets/spaceBotInGameMusic.m4a');
gameOverSound = loadSound('assets/gameOverInGameSound.m4a');
backgroundsun = loadImage('assets/backgroundsun.jpg');
gameoverScreen = loadImage('assets/gameoverScreen.png');
}
function scoreCount() {
score++;
}
function draw() {
// background(11, 72, 170);
image(backgroundsun, 0, 0, 700, 400);
if (score == 0) {
for (let i = 0; i < 5; i ++) {
opelsins[i] = new Opelsin();
ecllipseOpelsin[i] = new opelsinmodel();
}
} if (score == 50) {
for (let i = 0; i < 10; i ++) {
opelsins[i] = new Opelsin();
ecllipseOpelsin[i] = new opelsinmodel();
}
}
if (score == 100) {
for (let i = 0; i < 15; i ++) {
opelsins[i] = new Opelsin();
ecllipseOpelsin[i] = new opelsinmodel();
}
}
if (score == 150) {
for (let i = 0; i < 20; i ++) {
opelsins[i] = new Opelsin();
ecllipseOpelsin[i] = new opelsinmodel();
}
}
if (score == 200) {
for (let i = 0; i < 25; i ++) {
opelsins[i] = new Opelsin();
ecllipseOpelsin[i] = new opelsinmodel();
}
}
if (keyIsDown(LEFT_ARROW) && x > -14) {
x -= 5;
}
if (keyIsDown(RIGHT_ARROW) && x < 550) {
x += 5;
}
if (keyIsDown(LEFT_ARROW) && x1 > 9) {
x1 -= 5;
}
if (keyIsDown(RIGHT_ARROW) && x1 < 565) {
x1 += 5;
}
fill(255, 255, 0)
rect(x1, 345, 20, 20)
image(monsterimg,x,310,60,60)
for (let opelsin of opelsins) {
opelsin.fall();
opelsin.show();
}
textSize(20);
text("Health: " + health, 10, 20);
fill(255);
textSize(20);
text("Score: " + score, 10, 40);
fill(255);
for (let opelsin of opelsins) {
hit = collideRectCircle(x1, 335, 20, 30, opelsin.x, opelsin.y, 40);
if(hit == true) {
health -= 1;
opelsin.y = height+1;
if (health == 0) {
inGameSound.stop();
gameOverSound.setVolume(1);
gameOverSound.loop();
image(gameoverScreen, 0, 0, 600, 400);
gameOver();
noLoop();
newGame();
}
}
}
}
What I expect is when the game over screen appears and then when the random key is pressed the game should restart.
The issue is that the game loop is stopped by noLoop() when the game is over. The loop is never restarted.
Set a state (e.g waitRestart) when the game is over (instead of newGame()):
let waitRestart = false;
function draw() {
// [...]
for (let opelsin of opelsins) {
hit = collideRectCircle(x1, 335, 20, 30, opelsin.x, opelsin.y, 40);
if(hit == true) {
health -= 1;
opelsin.y = height+1;
if (health == 0) {
inGameSound.stop();
gameOverSound.setVolume(1);
gameOverSound.loop();
image(gameoverScreen, 0, 0, 600, 400);
gameOver();
noLoop();
// newGame(); <----- delete
waitRestart = true; // <----- wait for restart
}
}
}
}
Add a keyPressed() callback instead of the newGame() function, which restarts the game and set all initial states like health and score:
function keyPressed() {
if (waitRestart) {
waitRestart = false;
score = 0;
health = 5;
loop();
}
}

Remove an item that is drawn on to a canvas from an array. Where each item has a different purpose

I'm currently making a game and I am at the point where I'm trying to implement powerups. For the power ups I use a for loop that creates an object which allows me to give them different characteristics.
var type;
Powerups = [];
for(var j = 0; j < 325; j++) {
if (type="undefined"){
type = "scoreUp";
} else if(type="scoreUp"){
type = "horizonUp"
} else if (type="horizonUp"){
type = "newBall"
} else if (type="newBall") {
type = "scoreUp"
}
Powerups.push({
"x": randInt(20,360),
"y": 345 + (j * 240),
"width": 10,
"type": type
})
}
I then use rect circle collision that allows me to detect if the player collides with a powerup. If it does, the following line of code runs Powerups.splice(j, 1)
One thing that I've noticed is that the powerups never change and always increase score when a collision occurs. I think that this is because of the code that I use to remove the power up when colliding.
Is there a way where I could make it work as intended
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var isMenu = true;
var isPlaying = false;
var testing = true;
var gameOver = false;
var pause;
var pressingLeft = false;
var pressingRight = false;
var pressingP = false;
var Platforms = [];
var Powerups = [];
var difficulty = 1;
var playerGravity = 1;
var Player = { color: "red", radius: 7.5, stepY: 1.5, x: 175, y: 75 };
var Score = 0;
var speed = 1;
var type;
var moveR = 2;
var moveL = 2;
function PlayerColliding(circle, rect) {
var distX = Math.abs(circle.x - rect.x - rect.width / 2);
var distY = Math.abs(circle.y - rect.y - 20 / 2);
if (distX > (rect.width / 2 + circle.radius) && (distX) - 70 < (rect.width / 2 + circle.radius)) return false;
if (distY > (20 / 2 + circle.radius)) return false;
if (distX <= (rect.width / 2)) return true;
if (distY >= (20 / 2)) return true;
var dx = distX - rect.width / 2;
var dy = distY - 20 / 2;
return (dx * dx + dy * dy <= (circle.radius * circle.radius));
}
function PowerColliding(circle, rect) {
var distX = Math.abs(circle.x - rect.x - rect.width / 2);
var distY = Math.abs(circle.y - rect.y - 20 / 2);
if (distX > (rect.width / 2 + circle.radius)) return false;
if (distY > (20 / 2 + circle.radius)) return false;
if (distX <= (rect.width / 2)) return true;
if (distY >= (20 / 2)) return true;
var dx = distX - rect.width / 2;
var dy = distY - 20 / 2;
return (dx * dx + dy * dy <= (circle.radius * circle.radius));
}
function drawBackground(Player) {
ctx.fillStyle = "black"; ctx.fillRect(0, 0, canvas.width, canvas.height);
if (isMenu && !isPlaying) {
Score = 0;
createText("60px monospace", "white", "FallDown", 45, 130);
createText("34px Arial", "white", "PLAY", 130, 240);
createText("34px Arial", "white", "LEADERBOARD", 50, 300);
createText("34px Arial", "white", "SETTINGS", 90, 360);
createText("34px Arial", "white", "INFO", 130, 420);
}
if(isMenu && isPlaying) {
createText("60px monospace", "white", "Game Mode", 40, 130);
createText("34px Arial", "white", "CLASSIC", 110, 240);
createText("34px Arial", "white", "VERSUS", 113.5, 300);
}
else if(pause) {
isPlaying = false;
createText("60px monospace", "white", "PAUSED", 90, 130);
createText("34px Arial", "white", "RESUME", 115, 260);
createText("34px Arial", "white", "SETTINGS", 100, 340);
createText("34px Arial", "white", "QUIT", 145, 420);
}
else if(!isMenu && isPlaying) {
if (testing) {
Platforms = [];
for (var i = 0; i < 1300; i++) {
Platforms.push({
"x": 10,
"y": 300 + (i * 60),
"width": (Math.random() * canvas.width) - 60
});
}
testing = false;
Powerups = [];
for(var j = 0; j < 325; j++) {
if (type="undefined"){
type = "scoreUp";
} else if(type="scoreUp"){
type = "horizonUp"
} else if (type="horizonUp"){
type = "newBall"
} else if (type="newBall") {
type = "scoreUp"
}
Powerups.push({
"x": randInt(20,360),
"y": 345 + (j * 240),
"width": 10,
"type": type
})
}
}
if(Player.y<=0) {
restartGame()
}
var playerCollided;
for (var i in Platforms) {
ctx.fillStyle = "#00ffff";
ctx.fillRect(10, Platforms[i].y, Platforms[i].width, 20);
var totalTest = Platforms[i].width + 60;
ctx.fillRect(totalTest + 30, Platforms[i].y, canvas.width - totalTest, 20);
Platforms[i].y -= 1;
if (!playerCollided) {
if (PlayerColliding(Player, Platforms[i])) {
playerGravity = -1;
playerCollided = true;
} else {
playerGravity = 2.5;
}
}
}
var powerCollided;
for (var j in Powerups) {
ctx.fillStyle = "#ff00ff";
ctx.fillRect(Powerups[j].x, Powerups[j].y, Powerups[j].width, 10);
Powerups[j].y -= 1;
if (!powerCollided) {
if (PowerColliding(Player, Powerups[j])) {
powerCollided = true;
Powerups.splice(j, 1)
if(type="scoreUp") {
Score += 75
} else if (type="horizonUp") {
moveR+= 0.5;
moveL+=0.5;
console.log("hup")
}
}
}
}
displayScore();
detectBorderCollision();
detectPlayerCollision();
drawPlayer();
drawBorder();
}
if (Platforms.length === 7) Platforms = [];
}
function displayScore() {
ctx.beginPath();
Score +=1;
ctx.font = "15px arial black";
ctx.fillStyle = 'white';
ctx.strokeStyle = 'black';
ctx.fillText(Score, 180, 50);
ctx.lineWidth = 0.25;
ctx.strokeText(Score, 180, 50);
ctx.fill();
ctx.stroke();
ctx.closePath();
}
function detectBorderCollision() {
if (Player.x > 370 - Player.radius) {
Player.x = 370 - Player.radius;
} else if (Player.x < 3.8 + Player.radius * 2) {
Player.x = 3.8 + Player.radius * 2
}
}
function detectPlayerCollision() {
}
function randInt(min, max) {
return ~~(Math.random() * (max - min + 1) + min);
}
function drawPlayer() {
ctx.beginPath();
ctx.fillStyle = Player.color;
ctx.arc(Player.x, Player.y, Player.radius, 0, 2 * Math.PI);
ctx.fill();
ctx.closePath();
Player.y += playerGravity;
if (pressingRight) {
Player.x += 2;
} else if (pressingLeft) {
Player.x -= 2;
}
/*
ctx.fillStyle = "#00ffff"; ctx.fillRect(10, 160, 300, 20); */ }
function drawBorder() {
ctx.beginPath();
ctx.strokeStyle = "#00ffff";
ctx.lineWidth = 10;
ctx.moveTo(5, 0);
ctx.lineTo(5, 640);
ctx.moveTo(375, 0);
ctx.lineTo(375, 640);
ctx.stroke();
ctx.closePath();
}
function createText(font, color, value, posX, posY) {
ctx.font = font;
ctx.fillStyle = color;
ctx.fillText(value, posX, posY)
}
function isInside(realX, realY, x1, x2, y1, y2) {
return (realX > x1 && realX < x2) && (realY > y1 && realY < y2)
}
function drawGame() {
drawBackground(Player);
}
function startDrawing() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawGame();
requestAnimationFrame(startDrawing);
}
function restartGame() {
isPlaying = false;
isMenu = true;
pause = false;
Player.y= 75;
Player.x = 175
Platforms = [];
var Score = 1;
testing = true;
pressingLeft = false;
pressingRight = false;
var moveR = 2;
var moveL = 2;
}
function Init() {
requestAnimationFrame(startDrawing);
canvas.addEventListener("click", function(evt) {
var rect = canvas.getBoundingClientRect();
var mouseX = evt.clientX - rect.left;
var mouseY = evt.clientY - rect.top;
if (isMenu && !isPlaying) {
if (isInside(mouseX, mouseY, 115, 230, 220, 270)) {
isPlaying = true;
isMenu = false;
} else if (isInside(mouseX, mouseY, 35, 320, 300, 345)) {
console.log("Leaderboard");
} else if (isInside(mouseX, mouseY, 75, 270, 380, 430)) {
console.log("Settings");
}
} else if (pause) {
if(isInside(mouseX, mouseY, 110, 270, 230, 260)) {
pause = false;
isPlaying = true;
} else if (isInside(mouseX, mouseY, 95, 270, 310, 345)) {
console.log('settings')
} else if (isInside(mouseX, mouseY, 140, 230, 390, 425)) {
console.log('quit')
restartGame();
}
}
});
window.addEventListener("keydown", function(evt) {
if (!isMenu && isPlaying || pause) {
if (evt.keyCode === 39) { // right
pressingRight = true;
} else if (evt.keyCode === 37) { // left
pressingLeft = true;
} else if (evt.keyCode === 80) {
pressingP = true;
pause = !pause;
if(!pause) {
isPlaying = true;
}
}
}
});
window.addEventListener("keyup", function(evt) {
if (!isMenu && isPlaying) {
if (evt.keyCode === 39) { // right
pressingRight = false;
} else if (evt.keyCode === 37) { // left
pressingLeft = false;
}
}
});
}
Init();
<html>
<head>
<title>Falldown</title>
</head>
<body>
<canvas id="canvas" width = "380" height= "640"></canvas>
<script src="beta.js"></script>
</body>
</html>

How to manage multiple ball animations?

I have made a program that is supposed to make several balls move along a path. So far, I have only been able to make one ball successfully traverse the course because whenever I add another ball (from the array of balls) it begins to flicker and spasmodically disappears. I would appreciate any assistance in solving this problem.
JS bin
<!DOCTYPE html>
<html>
<head>
<style>
* {
padding: 0;
margin: 0;
}
canvas {
background: #eee;
display: block;
margin: 0 auto;
}
</style>
</head>
<body>
<canvas id="Circuit" width="500" height="320"></canvas>
<script>
var dad = [];
var canvas = document.getElementById("Circuit");
var ctx = canvas.getContext("2d");
var bool = false;
var dx1 = 2;
var dx2 = -2;
var dy1 = 0;
var dy2 = 2;
var memes = [{
x: 0,
y: 100,
}, {
x: 0,
y: 100,
}, {
x: 0,
y: 100,
}, {
x: 0,
y: 100,
}];
function drawCircle(index) {
ctx.beginPath();
ctx.arc(memes[index].x, memes[index].y, 10, 0, Math.PI * 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function draw(index) {
if (index == 0) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
if (memes[index].x < 490 && memes[index].y < 291 && !bool) {
drawCircle(index);
memes[index].x += dx1;
memes[index].y += dy1;
}
else if (memes[index].x == 490) {
drawCircle(index);
memes[index].x += 1;
}
else if (memes[index].x > 490 && memes[index].y < 291) {
drawCircle(index);
memes[index].y += dy2;
}
else if (memes[index].y == 291) {
drawCircle(index);
memes[index].y += 1;
}
else if (memes[index].y > 291 && memes[index].x > 2) {
drawCircle(index);
bool = true;
memes[index].x -= 2;
}
else if (memes[index].x == 2 && memes[index].y > 291) {
drawCircle(index);
memes[index].x -= 1;
}
else if (memes[index].x < 2) {
drawCircle(index);
memes[index].y -= dy2;
if (memes[index].y < 100) {
clearInterval(dad[index]);
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
}
ctx.strokeStyle = "red";
ctx.strokeRect(2, 101, 490, 190);
ctx.strokeStyle = "blue";
ctx.strokeRect(2, 82, 40, 40);
}
setTimeout(function() {
setTimeout(function() {
dad[1] = setInterval(function() {
draw(1);
}, 20);
}, 1000);
dad[0] = setInterval(function() {
draw(0);
}, 20);
}, 1000);
</script>
</body>
</html>
The flicker happens when the second ball tries to render the frame. You have two sprites (animating things) clearing and drawing the frame. You also have multiple timers and when animating you usually want a nextFrame function that handles movement of the sprites and drawing the frame.
The sprites array is a list of things that need to be moved and drawn. I added some properties to the meme sprites so you can see that their state needs to be internal like with the "bool" value. Without that you end up effecting the other balls. You'll need to figure out how to remove sprites when they're no longer in play.
var dad = [];
var canvas = document.getElementById("Circuit");
var ctx = canvas.getContext("2d");
var bool = false;
var dx1 = 2;
var dx2 = -2;
var dy1 = 0;
var dy2 = 2;
var memes = [{
x: 0,
y: 100,
color: "#0095DD",
draw: drawMeme,
move: moveMeme,
vx: 1.2,
vy: 1.5,
}, {
x: 0,
y: 100,
vx: 1.5,
vy: 1,
color: "#DD9500",
draw: drawMeme,
move: moveMeme
}, {
x: 0,
y: 100,
vx: 2,
vy: 1,
color: "#FF0000",
draw: drawMeme,
move: moveMeme
}, {
x: 0,
y: 100,
vx: 3,
vy: 2,
color: "#009999",
draw: drawMeme,
move: moveMeme
}];
function drawMeme(meme) {
ctx.beginPath();
ctx.arc(meme.x, meme.y, 10, 0, Math.PI * 2);
ctx.fillStyle = meme.color;
ctx.fill();
ctx.closePath();
}
var sprites = [];
function nextFrame () {
ctx.clearRect(0, 0, canvas.width, canvas.height);
var len = sprites.length;
for (var i = 0; i < len; i++) {
var sprite = sprites[i];
sprite.move(sprite);
sprite.draw(sprite);
}
ctx.strokeStyle = "red";
ctx.strokeRect(2, 101, 490, 190);
ctx.strokeStyle = "blue";
ctx.strokeRect(2, 82, 40, 40);
requestAnimationFrame(nextFrame);
}
function moveMeme(meme) {
if (meme.x < 490 && meme.y < 291 && !meme.bool) {
meme.x += dx1 * meme.vx;
meme.y += dy1 * meme.vy;
}
else if (meme.x == 490) {
meme.x += 1 * meme.vx;
}
else if (meme.x > 490 && meme.y < 291) {
meme.y += dy2 * meme.vy;
}
else if (meme.y == 291) {
meme.y += 1 * meme.vy;
}
else if (meme.y > 291 && meme.x > 2) {
meme.bool = true;
meme.x -= 2 * meme.vx;
}
else if (meme.x == 2 && meme.y > 291) {
meme.x -= 1 * meme.vx;
}
else if (meme.x < 2) {
meme.y -= dy2 * meme.vy;
if (meme.y < 100) {
// stop drawing this sprite
meme.draw = function(){};
meme.delete = 1; // for a cleanup function
}
}
}
nextFrame();
function startMeme(index) {
var meme = memes[index];
sprites.push(meme);
}
setTimeout(function() {
setTimeout(function() {
startMeme(1);
}, 1000);
startMeme(0);
startMeme(2);
startMeme(3);
}, 1000);
<canvas id="Circuit" width="500" height="320"></canvas>

Memory leak in JavaScript

What's the memory leak in the following script?
function postars(canvas) {
var _this = this,
ctx = canvas.getContext('2d');
_this.config = {
star: {
color: '#ffffff'
},
line: {
color: '#ffffff',
width: 0.1
},
position: {
x: canvas.width * 0.5,
y: canvas.height * 0.5
},
velocity: 0.1,
length: 100,
distance: 120,
radius: 150,
stars: []
};
function Star() {
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
this.vx = (_this.config.velocity - (Math.random() * 0.5));
this.vy = (_this.config.velocity - (Math.random() * 0.5));
this.radius = Math.random();
}
Star.prototype = {
create: function() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
ctx.fill();
},
animate: function() {
var i;
for (i = 0; i < _this.config.length; i++) {
var star = _this.config.stars[i];
if (star.y < 0 || star.y > canvas.height) {
star.vx = star.vx;
star.vy = -star.vy;
} else if (star.x < 0 || star.x > canvas.width) {
star.vx = -star.vx;
star.vy = star.vy;
}
star.x += star.vx;
star.y += star.vy;
}
},
line: function() {
var length = _this.config.length,
iStar, jStar, i, j;
for (i = 0; i < length; i++) {
for (j = 0; j < length; j++) {
iStar = _this.config.stars[i];
jStar = _this.config.stars[j];
if ((iStar.x - jStar.x) < _this.config.distance && (iStar.y - jStar.y) < _this.config.distance && (iStar.x - jStar.x) > -_this.config.distance && (iStar.y - jStar.y) > -_this.config.distance) {
if ((iStar.x - _this.config.position.x) < _this.config.radius && (iStar.y - _this.config.position.y) < _this.config.radius && (iStar.x - _this.config.position.x) > -_this.config.radius && (iStar.y - _this.config.position.y) > -_this.config.radius) {
ctx.beginPath();
ctx.moveTo(iStar.x, iStar.y);
ctx.lineTo(jStar.x, jStar.y);
ctx.stroke();
ctx.closePath();
}
}
}
}
}
};
_this.createStars = function() {
var length = _this.config.length,
star, i;
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (i = 0; i < length; i++) {
_this.config.stars.push(new Star());
star = _this.config.stars[i];
star.create();
}
star.line();
star.animate();
};
_this.setCanvas = function() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
};
_this.setContext = function() {
ctx.fillStyle = _this.config.star.color;
ctx.strokeStyle = _this.config.line.color;
ctx.lineWidth = _this.config.line.width;
};
_this.loop = function(callback) {
callback();
reqAnimFrame(function() {
_this.loop(function() {
callback();
});
});
};
_this.bind = function() {
$(window).on('mousemove', function(e) {
_this.config.position.x = e.pageX;
_this.config.position.y = e.pageY;
});
};
_this.init = function() {
_this.setCanvas();
_this.setContext();
_this.loop(function() {
_this.createStars();
});
_this.bind();
};
return _this;
}
var reqAnimFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) {
window.setTimeout(callback, 1000 / 60);
};
It's working for a few hours and then Chrome crashes (displays an error page saying something went wrong) or outputs "stack overflow" to console.
The answer is not to use new Star() in a function's parameter, instead of that do:
var newStar = new Star()
_this.config.stars.push(newStar)
newStar = null
And to modify the code not to create new stars continously.

Categories