Can't figure out where to draw image in Javascript code - javascript

I am having issues trying to place an image as an object for an "asteroid avoidance" game. I was able to get the game itself to work based on what was written in my book "Foundation: HTML5 Canvas for Games and Entertainment". I want to go one step beyond what was written in the book. I want to replace the triangle shaped ship with that of an image. However, I am unable to figure out where to put the code for this.draw. My professor showed us a way to do it. When I try to implement it into my code it doesn't want to work properly. May I ask for some advice on how to place the image as the ship?
Here is my working code from the book, before I made any this.draw edits:(http://jsbin.com/tukejopofo/1/)
$(document).ready(function() {
var canvas = $("#gameCanvas");
var context = canvas.get(0).getContext("2d");
//canvas dimensions
var canvasWidth = canvas.width();
var canvasHeight = canvas.height();
var playGame;
var asteroids;
var numAsteroids;
var player;
var score;
var scoreTimeout;
var arrowUp = 38;
var arrowRight = 39;
var arrowDown = 40;
var arrowLeft = 37;
//game UI
var ui = $("#gameUI");
var uiIntro = $("#gameIntro");
var uiStats = $("#gameStats");
var uiComplete = $("#gameComplete");
var uiPlay = $("#gamePlay");
var uiReset = $(".gameReset");
var uiScore = $(".gameScore");
var soundBackground = $("#gameSoundBackground").get(0);
var soundThrust = $("#gameSoundThrust").get(0);
var soundDeath = $("#gameSoundDeath").get(0);
var Asteroid = function(x, y, radius, vX) {
this.x = x;
this.y = y;
this.radius = radius;
this.vX = vX;
};
var Player = function(x, y) {
this.x = x;
this.y = y;
this.width = 24;
this.height = 24;
this.halfWidth = this.width / 2;
this.halfHeight = this.height / 2;
this.flameLength1 = 20;
this.flameLength2 = 20;
this.vX = 0;
this.vY = 0;
this.moveRight = false;
this.moveUp = false;
this.moveDown = false;
this.moveLeft = false;
};
//Reset and start the game
function startGame() {
//Reset game stats
uiScore.html("0");
uiStats.show();
//set up initial game settings
playGame = false;
asteroids = new Array();
numAsteroids = 10;
score = 0;
player = new Player(150, canvasHeight / 2, 50, 50);
for (var i = 0; i < numAsteroids; i++) {
var radius = 5 + (Math.random() * 10);
var x = canvasWidth + radius + Math.floor(Math.random() * canvasWidth);
var y = Math.floor(Math.random() * canvasHeight);
var vX = -5 - (Math.random() * 5);
asteroids.push(new Asteroid(x, y, radius, vX));
};
$(window).keydown(function(e) {
var keyCode = e.keyCode;
if (!playGame) {
playGame = true;
soundBackground.currentTime = 0;
soundBackground.play();
animate();
timer();
};
if (keyCode == arrowRight) {
player.moveRight = true;
if (soundThrust.paused) {
soundThrust.currentTime = 0;
soundThrust.play();
}
} else if (keyCode == arrowLeft) {
player.moveLeft = true;
} else if (keyCode == arrowUp) {
player.moveUp = true;
} else if (keyCode == arrowDown) {
player.moveDown = true;
}
});
$(window).keyup(function(e) {
var keyCode = e.keyCode;
if (!playGame) {
playGame = true;
animate();
};
if (keyCode == arrowRight) {
player.moveRight = false;
if (keyCode == arrowRight) {
player.moveRight = false;
soundThrust.pause();
}
} else if (keyCode == arrowUp) {
player.moveUp = false;
} else if (keyCode == arrowDown) {
player.moveDown = false;
} else if (keyCode == arrowLeft) {
player.moveLeft = false;
}
});
//start the animation loop
animate();
};
//initialize the game environment
function init() {
uiStats.hide();
uiComplete.hide();
uiPlay.click(function(e) {
e.preventDefault();
uiIntro.hide();
startGame();
});
uiReset.click(function(e) {
e.preventDefault();
uiComplete.hide();
$(window).unbind("keyup");
$(window).unbind("keydown");
soundThrust.pause();
soundBackground.pause();
clearTimeout(scoreTimeout);
startGame();
});
};
function timer() {
if (playGame) {
scoreTimeout = setTimeout(function() {
uiScore.html(++score);
if (score % 5 == 0) {
numAsteroids += 5;
}
timer();
}, 1000);
};
};
//Animation loop that does all the fun stuff
function animate() {
//Clear
context.clearRect(0, 0, canvasWidth, canvasHeight);
var asteroidsLength = asteroids.length;
for (var i = 0; i < asteroidsLength; i++) {
var tmpAsteroid = asteroids[i];
tmpAsteroid.x += tmpAsteroid.vX;
if (tmpAsteroid.x + tmpAsteroid.radius < 0) { //creates bounderies to prevent player from leaving the canvas
tmpAsteroid.radius = 5 + (Math.random() * 10);
tmpAsteroid.x = canvasWidth + tmpAsteroid.radius;
tmpAsteroid.y = Math.floor(Math.random() * canvasHeight);
tmpAsteroid.vX = -5 - (Math.random() * 5);
}
var dX = player.x - tmpAsteroid.x;
var dY = player.y - tmpAsteroid.y;
var distance = Math.sqrt((dX * dX) + (dY * dY));
if (distance < player.halfWidth + tmpAsteroid.radius) { //checks for collision
soundThrust.pause()
soundDeath.currentTime = 0;
soundDeath.play();
//Game over
playGame = false;
clearTimeout(scoreTimeout);
uiStats.hide();
uiComplete.show();
soundBackground.pause();
$(window).unbind("keyup"); //unbinds keys to stop player movement at the end of the game
$(window).unbind("keydown");
};
context.fillStyle = "rgb(255, 255, 255)";
context.beginPath();
context.arc(tmpAsteroid.x, tmpAsteroid.y, tmpAsteroid.radius, 0, Math.PI * 2, true);
context.fill();
};
player.vX = 0;
player.vY = 0;
if (player.moveRight) {
player.vX = 3;
};
if (player.moveLeft) {
player.vX = -3;
};
if (player.moveUp) {
player.vY = -3;
};
if (player.moveDown) {
player.vY = 3;
};
player.x += player.vX;
player.y += player.vY;
if (player.x - player.halfWidth < 20) {
player.x = 20 + player.halfWidth;
} else if (player.x + player.halfWidth > canvasWidth - 20) {
player.x = canvasWidth - 20 - player.halfWidth;
}
if (player.y - player.halfHeight < 20) {
player.y = 20 + player.halfHeight;
} else if (player.y + player.halfHeight > canvasHeight - 20) {
player.y = canvasHeight - 20 - player.halfHeight;
}
if (player.moveRight) {
context.save();
context.translate(player.x - player.halfWidth, player.y);
if (player.flameLength1 == 20) {
player.flameLength1 = 15;
(player.flameLength2 == 20)
player.flameLength2 = 15;
} else {
player.flameLength1 = 20;
player.flameLength2 = 20;
};
context.fillStyle = "orange";
context.beginPath();
context.moveTo(0, -12);
context.lineTo(-player.flameLength1, -7);
context.lineTo(0, -5);
context.closePath();
context.fill();
context.fillStyle = "orange";
context.beginPath();
context.moveTo(0, 12);
context.lineTo(-player.flameLength2, 7);
context.lineTo(0, 5);
context.closePath();
context.fill();
context.restore();
};
//draw ship
context.fillStyle = "rgb(255, 0, 0)";
context.beginPath();
context.moveTo(player.x + player.halfWidth, player.y);
context.lineTo(player.x - player.halfWidth, player.y - player.halfHeight);
context.lineTo(player.x - player.halfWidth, player.y + player.halfHeight);
context.closePath();
context.fill();
while (asteroids.length < numAsteroids) { //adds asteroids as the difficulty increases
var radius = 5 + (Math.random() * 10)
var x = Math.floor(Math.random() * canvasWidth) + canvasWidth + radius;
var y = Math.floor(Math.random() * canvasHeight);
var vX = -5 - (Math.random() * 5);
asteroids.push(new Asteroid(x, y, radius, vX));
}
if (playGame) {
//run the animation loop again in 33 milliseconds
setTimeout(animate, 24);
};
};
init();
});
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
width: 100%;
}
canvas {
display: block;
}
body {
background: #000;
color: #fff;
font-family: Verdana, Arial, sans-serif;
font-size: 18px;
}
h1 {
font-size: 30px;
}
h6 {
font-size: 15px;
}
p {
margin: 0 20px;
}
a {
color: #fff;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
a.button {
background: #185da8;
border-radius: 5px;
display: block;
font-size: 30px;
margin: 40px 0 0 350px;
padding: 10px;
width: 200px;
text-align: center;
}
a.button:hover {
background: #2488f5;
color: #fff;
text-decoration: none;
}
#game {
height: 600px;
left: 50%;
margin: -250px 0 0 -500px;
position: relative;
top: 50%;
width: 980px;
}
#gameCanvas {
background: #001022;
border: 5px solid green;
background-image: url(../images/space.jpg);
background-position: center top;
background-repeat: no-repeat;
background-size: cover;
}
#gameUI {
height: 600px;
position: absolute;
width: 980px;
}
#gameIntro,
#gameComplete {
background: rgba(0, 0, 0, 0.5);
margin: 100px 0 0 10px;
padding: 40px 0;
text-align: center;
}
#gameStats {
font-size: 14px;
margin: 20px 0;
}
#gameStats .gameReset {
margin: 20px 20px 0 0;
position: absolute;
right: 0;
top: 0;
}
<body>
<div id="game">
<div id="gameUI">
<div id="gameIntro">
<h1>Debris Fields of Spiral Galaxy</h1>
<h6>A <i>Galaxy Smuggler's Run</i> Game</h6>
<hr>
<p>You are Captain Amadaeus delivering goods to a dependent planet on the other side of a debris field</p>
<p>Click <i>"Play"</i> and then press any key to start.</p>
<p><a id="gamePlay" class="button" href="">Play!</a>
</p>
</div>
<div id="gameStats">
<p><b>Time: </b><span class="gameScore"></span> seconds</p>
<p><a class="gameReset" href="">Reset</a>
</p>
</div>
<div id="gameComplete">
<h1>Game Over!</h1>
<p>You survived for <span class="gameScore"></span> seconds.</p>
<p>Would you like to give it another go?</p>
<p><a class="gameReset button" href="">Play Again?</a>
</p>
</div>
</div>
<canvas id="gameCanvas" width="980" height="600">
</canvas>
<audio id="gameSoundBackground" loop>
<source src="sounds/background.ogg">
<source src="sounds/background.mp3">
</audio>
<audio id="gameSoundThrust" loop>
<source src="sounds/thrust.ogg">
<source src="sounds/thrust.mp3">
</audio>
<audio id="gameSoundDeath">
<source src="sounds/death.ogg">
<source src="sounds/death.mp3">
</audio>
</div>
</body>
and here is my Professor's code for drawing an image:(http://jsbin.com/rapayufafe/1/)
// JS file for the ship
function Ship() {
this.x = 100;
this.y = 100;
this.color = "yellow";
this.fillStyle = "white";
this.vx = 0;
this.vy = 0;
this.ax = 1;
this.ay = 1;
//function "move" that will add velocity to the position of the ship
this.move = function() {
this.x += this.vx;
this.y += this.vy;
}//end move function
//draw the ship
this.draw=function () {
//ship var
var imageObj = new Image();
imageObj.src = "images/ship.png";
//save the current state of the canvas
context.save();
//moving the point of origin (0,0) to the ships x and y coordinates
context.translate(this.x,this.y);
context.lineStyle = this.color;
context.fillStyle = this.fillStyle;
/*context.beginPath();
context.moveTo(25,0);
context.lineTo(-25,25)
context.lineTo(-25,-25)*/
//draw ship
context.drawImage(imageObj,-25,-25,50,50);
context.closePath();
context.stroke();
context.fill();
context.restore();
}//end of draw ship
}//end ship function
/*var asteroidsLength = asteroids.length;
for (var i = 0; i < asteroidsLength; i++) {
var tmpAsteroid = asteroids[i];
context.fillStyle = "gray";
context.beginPath();
context.arc(tmpAsteroid.x, tmpAsteroid.y, tmpAsteroid.radius, 0, Math.PI*2, true);
context.closePath();
context.fill();
};*/

As you can see in your starting code, you have a section looking like this:
//draw ship
context.fillStyle = "rgb(255, 0, 0)";
context.beginPath();
context.moveTo(player.x + player.halfWidth, player.y);
context.lineTo(player.x - player.halfWidth, player.y - player.halfHeight);
context.lineTo(player.x - player.halfWidth, player.y + player.halfHeight);
context.closePath();
context.fill();
Just replace that code with the code for drawing an image.
var imageObj = new Image();
imageObj.src = "images/ship.png";
context.drawImage(imageObj,player.x,player.y);
Although, I'd recommend declaring the imageObj and setting the source at the top of your code where you declare the rest of your variables so that you don't load the image every time you want to draw the ship.

Related

How to add Start Game and Play Again to canvas game?

I created game using Javascript following YouTube video game tutorial. Game works just fine, but I would like to add ability to enter nickname at the beginning of the game. After entering nickname and hitting play button the game would begin and nickname would display on the middle upper side of the screen. Then after loosing the game, window with score and play-again button should pop up. After clicking play-again button another game starts.
const canvas = document.getElementById('canvas1');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const collisionCanvas = document.getElementById('collisionCanvas');
const collisionCtx = collisionCanvas.getContext('2d');
collisionCanvas.width = window.innerWidth;
collisionCanvas.height = window.innerHeight;
//obsluga gry
let gameOver = false;
let score = 0;
ctx.font = '50px Impact';
let lives = 3;
let hit = false;
let clicked = false;
//setup spawnow
let timeToNextZombie = 0;
let zombieInterval = 400;
let lastTime = 0;
let zombies =[];
//myszka
let innerCursor = document.querySelector('.inner-cursor');
let outerCursor = document.querySelector('.outer-cursor');
document.addEventListener('mousemove', moveCursor)
function moveCursor(e){
let x = e.clientX;
let y = e.clientY;
innerCursor.style.left = `${x}px`;
innerCursor.style.top = `${y}px`;
outerCursor.style.left = `${x}px`;
outerCursor.style.top = `${y}px`;
}
class Zombie{
constructor(){
this.spriteWidth = 200; //szerkosc klatki zombie
this.spriteHeight = 312; //wyskosc klatki zombie
this.sizeModifier = Math.random()* 0.8 + 0.6; //mnożnik wielkości zombiaka
this.width = this.spriteWidth * this.sizeModifier;
this.height = this.spriteHeight * this.sizeModifier;
this.x = canvas.width;
this.y =Math.random() * (canvas.height -this.height); //spawn zombie od dolu do gory ekranu
this.directionX = Math.random() * 4 + 1; //predkosc zombiakow
if(Math.floor(Math.random() * 20) == 0) this.directionX = 10; //5% szans na szybkiego lopeza
this.markedForDeletion = false; //oznaczenie czy mozna usunac obiekt
this.image = new Image();
this.image.src = 'walkingdead.png';
this.frame = 0;
this.maxFrame = 8;
this.timeSinceFlap = 0;
this.flapInterval = Math.random()*50+50; //flipowanie kazdego inne
this.randomColors = [Math.floor(Math.random()*255), Math.floor(Math.random()*255), Math.floor(Math.random()*255)];
this.color = 'rgb(' + this.randomColors[0] + ',' + this.randomColors[1] + ',' + this.randomColors[2] + ')';
}
update(deltatime){
this.x -= this.directionX;
this.timeSinceFlap +=deltatime;
if (this.x < 0-this.width){
this.markedForDeletion = true;
} //zombiak jest poza zasiegiem
if (this.timeSinceFlap > this.flapInterval){
if (this.frame > this.maxFrame) this.frame = 0;
else this.frame++;
this.timeSinceFlap = 0;
}
if (this.x < 0 -this.width){
lives-=1;
if(lives == 0){
gameOver = true;
}
}
}
//rysowanie zombiaka
draw(){
collisionCtx.fillStyle = this.color;
collisionCtx.fillRect(this.x, this.y, this.width, this.height);
ctx.drawImage(this.image, this.frame * this.spriteWidth, 0, this.spriteWidth, this.spriteHeight, this.x, this.y, this.width, this.height);
}
}
function drawScore(){
//kordy scora
if(lives == 0){
ctx.font = '200px Impact';
ctx.fillText('☠️', 0, 170);
return;
}
ctx.fillStyle = 'white';
ctx.fillText('Score: ' + score, 55, 80);
if(lives == 3) ctx.fillText('❤ ❤ ❤', 55, 130);
if(lives == 2) ctx.fillText('❤ ❤', 55, 130);
if(lives == 1) ctx.fillText('❤', 55, 130);
}
function drawGameOver(){
drawScore();
ctx.font = "bold 100px serif";
ctx.textAlign = 'center';
ctx.fillStyle = 'red';
ctx.fillText("GAME OVER!", canvas.width/2, canvas.height/2)
ctx.fillText("Your score is " + score, canvas.width/2, 100 + canvas.height/2)
}
window.addEventListener('click', function(e){
const detectPixelColor = collisionCtx.getImageData(e.x, e.y, 1, 1);
const pc = detectPixelColor.data; //popieranie info o hitboxie zombie
zombies.forEach(object =>{
if(object.randomColors[0] === pc[0] && object.randomColors[1] === pc[1] && object.randomColors[2] === pc[2]){
object.markedForDeletion = true; //usunąć gościa z mapy
hit = true;
}
clicked = true;
})
});
//obsluga klatki
function animate(timestamp) {
if(clicked){
if(hit) score+=12
else score-=6;
clicked = false;
hit = false;
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
collisionCtx.clearRect(0, 0, canvas.width, canvas.height);
let deltatime = timestamp - lastTime;
lastTime = timestamp;
timeToNextZombie += deltatime;
if (timeToNextZombie > zombieInterval){
zombies.push(new Zombie()); //tworzenie nowego zombiaka
timeToNextZombie = 0;
zombies.sort(function(a, b){
return a.width - b.width; //sort zeby mniejsze zombiaki byly za wiekszymi
})
};
drawScore();
//dla kazdego zombiaka przesuwamy zombiaka, object to pojedynczy (obiekt) zombiaka
[...zombies].forEach(object => object.update(deltatime));
[...zombies].forEach(object => object.draw());
zombies = zombies.filter(object => !object.markedForDeletion); //usuwanie zombiakow poza screenem
if(!gameOver) requestAnimationFrame(animate);
else{
drawScore();
drawGameOver();
}
}
animate(0);
*{
cursor: none;
}
canvas{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url('board-bg.jpg');
}
#collisionCanvas{
opacity: 0;
}
.inner-cursor{
position: fixed;
width: 15px;
height: 15px;
transform: translate(-50%, -50%);
background-color: white !important;
mix-blend-mode: difference;
border-radius: 50%;
pointer-events: none;
}
.outer-cursor{
position: fixed;
width: 70px;
height: 70px;
transform: translate(-50%, -50%);
border: 5px solid white;
mix-blend-mode: difference;
border-radius: 50%;
pointer-events: none;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Zadanie 12</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas id="canvas2"></canvas>
<canvas id="collisionCanvas"></canvas>
<canvas id="canvas1"></canvas>
<div class="inner-cursor"></div>
<div class="outer-cursor"></div>
<script src="script.js"></script>
</body>
</html>
You have everything you need in that code...
let gameOver = false;
let zombies = [];
all we need is to change a bit your code to take advantage of those.
I'm not going to implement your "window with score and play-again button pop up" instead I'm going for a much simpler timeout to demonstrate how to restart your game.
The key point in your game that sets the "end" is the one below:
if (lives == 0) {
zombies = []
gameOver = true;
gameEnded = Date.now()
setTimeout(() => {
gameOver = false
lives = 3
}, 5000)
}
before you just had the gameOver now I'm doing a few more things, like that setTimeout that will restart the game in 5 seconds, restarting the game is just to set the gameOver back to false and give the user some lives.
Your function animate is where the drawing loop happens, I changed that a bit, now we no longer stop the loop but draw something else and we can add many conditions there:
function animate(timestamp) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (gameOver) {
drawGameOver();
} else if (abc < 20) {
drawABC();
} else if (def == "start_message") {
drawDEF();
} else {
...
}
requestAnimationFrame(animate)
}
Below is your simplified code with my additions
const canvas = document.getElementById('canvas1');
const ctx = canvas.getContext('2d');
canvas.width = canvas.height = 700;
let gameEnded = Date.now()
let gameOver = false;
let score = 0;
ctx.font = '50px Impact';
let lives = 3;
let hit = false;
let clicked = false;
let timeToNextZombie = 0;
let zombieInterval = 400;
let lastTime = 0;
let zombies = [];
class Zombie {
constructor() {
this.spriteWidth = 200; //szerkosc klatki zombie
this.spriteHeight = 312; //wyskosc klatki zombie
this.sizeModifier = Math.random() * 0.8 + 0.6; //mnożnik wielkości zombiaka
this.width = this.spriteWidth * this.sizeModifier;
this.height = this.spriteHeight * this.sizeModifier;
this.x = canvas.width;
this.y = Math.random() * (canvas.height - this.height); //spawn zombie od dolu do gory ekranu
this.directionX = Math.random() * 4 + 1; //predkosc zombiakow
if (Math.floor(Math.random() * 20) == 0) this.directionX = 10; //5% szans na szybkiego lopeza
this.markedForDeletion = false; //oznaczenie czy mozna usunac obiekt
//this.image = new Image();
//this.image.src = 'walkingdead.png';
this.frame = 0;
this.maxFrame = 8;
this.timeSinceFlap = 0;
this.flapInterval = Math.random() * 50 + 50; //flipowanie kazdego inne
}
update(deltatime) {
this.x -= this.directionX;
this.timeSinceFlap += deltatime;
if (this.x < 0 - this.width) {
this.markedForDeletion = true;
} //zombiak jest poza zasiegiem
if (this.timeSinceFlap > this.flapInterval) {
if (this.frame > this.maxFrame) this.frame = 0;
else this.frame++;
this.timeSinceFlap = 0;
}
if (this.x < 0 - this.width) {
lives -= 1;
if (lives == 0) {
zombies = []
gameOver = true;
gameEnded = Date.now()
setTimeout(() => {
gameOver = false
lives = 3
}, 5000)
}
}
}
draw() {
ctx.beginPath()
ctx.arc(this.x, this.y, 15, 0, 2 * Math.PI);
ctx.stroke()
}
}
function drawGameOver() {
ctx.beginPath()
ctx.font = "bold 100px serif";
ctx.textAlign = 'center';
ctx.fillStyle = 'red';
ctx.fillText("GAME OVER!", canvas.width / 2, canvas.height / 2)
ctx.fillText("Your score is " + score, canvas.width / 2, 100 + canvas.height / 2)
ctx.beginPath()
ctx.font = "bold 30px serif";
ctx.fillText("Game will restart in 5 seconds... " + String(Date.now()- gameEnded), canvas.width / 2, 100)
}
function animate(timestamp) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (gameOver) {
drawGameOver();
} else {
let deltatime = timestamp - lastTime;
lastTime = timestamp;
timeToNextZombie += deltatime;
if (timeToNextZombie > zombieInterval) {
zombies.push(new Zombie()); //tworzenie nowego zombiaka
timeToNextZombie = 0;
zombies.sort(function(a, b) {
return a.width - b.width; //sort zeby mniejsze zombiaki byly za wiekszymi
})
};
[...zombies].forEach(object => object.update(deltatime));
[...zombies].forEach(object => object.draw());
zombies = zombies.filter(object => !object.markedForDeletion);
}
requestAnimationFrame(animate)
}
animate(0);
<canvas id="canvas1"></canvas>

I cannot use context.canvas.height when testing against the position of an object

I have made a simple rocket with controls and I want it to stop when it hits the ground but for whatever reason the only number that I can use to test it against is 0. I have tried context.canvas.height - this.size.height because that is what I want it to be, but when I use that in the if statement the code does not work as desired. The goal is to be able to stop all of the rocket's movement when it hits the ground.
Here is my JavaScript code
(function () {
// the canvas constants
const canvas = document.getElementById('game');
const context = canvas.getContext('2d');
// setting the canvas size
context.canvas.width = window.innerWidth;
context.canvas.height = window.innerHeight;
// the game constants
const ROCKET_SIZE = { width: 20, height: 30 };
const ROCKET_POSITION = { x: 200, y: 200 };
const GRAVITY = 2;
const THRUST = 5;
const AFTERBURNER_THRUST = 20;
const INERTIAL_DAMPING = 0.98;
// the rocket ship class
class RocketShip {
constructor(size, position) {
this.color = 'white';
this.size = size;
this.position = position;
this.angle = 0;
this.engineOn = false;
this.afterburner = false;
this.inertialDampeners = false;
this.rotatingLeft = false;
this.rotatingRight = false;
this.velocity = {
x: 0,
y: 0,
};
}
draw() {
// the center of the rocket
const triangleCenterX = this.position.x + 0.5 * this.size.width;
const triangleCenterY = this.position.y + 0.5 * this.size.height;
context.save();
context.translate(triangleCenterX, triangleCenterY);
context.rotate(this.angle);
context.lineWidth = 1;
context.beginPath();
// drawing the delta rocket
context.moveTo(0, -this.size.height / 2);
context.lineTo(-this.size.width / 2, this.size.height / 2);
context.lineTo(this.size.width / 2, this.size.height / 2);
context.closePath();
context.strokeStyle = this.color;
context.stroke();
// drawing the engine if it is active
if (this.engineOn) {
const fireYPos = this.size.height / 2 + 5;
const fireXPos = this.size.width * 0.25;
context.beginPath();
context.moveTo(-fireXPos, fireYPos);
context.lineTo(fireXPos, fireYPos);
context.lineTo(0, fireYPos + Math.random() * 50);
context.lineTo(-fireXPos, fireYPos);
context.closePath();
context.fillStyle = 'orange';
context.fill();
}
// drawing the afterburner if it is active
if (this.afterburner) {
const fireYPos = this.size.height / 2 + 5;
const fireXPos = this.size.width * 0.25;
context.beginPath();
context.moveTo(-fireXPos, fireYPos);
context.lineTo(fireXPos, fireYPos);
context.lineTo(0, fireYPos + Math.random() * 100);
context.lineTo(-fireXPos, fireYPos);
context.closePath();
context.fillStyle = 'red';
context.fill();
}
context.restore();
}
moveRocket() {
// convert angle from degrees to radians
const degToRad = Math.PI / 180;
// changing the position of the rocket
this.position.x += this.velocity.x;
this.position.y += this.velocity.y;
// moving the rocket to the other side of the screen
if (this.position.x > context.canvas.width) {
this.position.x = 0;
}
if (this.position.x < 0) {
this.position.x = context.canvas.width;
}
if (this.position.y > context.canvas.height) {
this.position.y = 0;
}
if (this.position.y < 0) {
this.position.y = context.canvas.height;
}
// stopping the rocket if it hits the ground
if (this.position.y === context.canvas.height - this.size.height) {
this.velocity.y = -GRAVITY / 100;
this.velocity.x = 0;
}
// turning the rocket
if (this.rotatingLeft) {
this.angle -= degToRad;
}
if (this.rotatingRight) {
this.angle += degToRad;
}
// accelerating the rocket if the thrust is on
if (this.engineOn) {
this.velocity.x += (THRUST / 100) * Math.sin(this.angle);
this.velocity.y -= (THRUST / 100) * Math.cos(this.angle);
}
// accelerating the rocket if the afterburner is on
if (this.afterburner) {
this.velocity.x += (AFTERBURNER_THRUST / 100) * Math.sin(this.angle);
this.velocity.y -= (AFTERBURNER_THRUST / 100) * Math.cos(this.angle);
}
// decelerating the rocket if the inertial dampeners are on
if (this.inertialDampeners) {
this.velocity.x *= INERTIAL_DAMPING;
this.velocity.y *= INERTIAL_DAMPING;
}
// updating the rocket's velocity due to gravity
this.velocity.y += GRAVITY / 100;
}
}
const rocket = new RocketShip(ROCKET_SIZE, ROCKET_POSITION);
// handling the keyboard events
function handleKeyInput(event) {
const { keyCode, type } = event;
const isKeyDown = type === 'keydown';
if (keyCode === 37) {
rocket.rotatingLeft = isKeyDown;
}
if (keyCode === 39) {
rocket.rotatingRight = isKeyDown;
}
if (keyCode === 38) {
rocket.engineOn = isKeyDown;
}
if (keyCode === 32) {
rocket.afterburner = isKeyDown;
}
if (keyCode === 40) {
rocket.inertialDampeners = isKeyDown;
}
}
// resizing the screen
function onResize() {
context.canvas.width = window.innerWidth;
context.canvas.height = window.innerHeight;
}
function draw() {
// drawing space
context.fillStyle = '#111';
context.fillRect(0, 0, canvas.width, canvas.height);
rocket.moveRocket();
// drawing the rocket
rocket.draw();
// repeating the draw function
requestAnimationFrame(draw);
}
// adding event listeners to the webpage
document.addEventListener('keydown', handleKeyInput);
document.addEventListener('keyup', handleKeyInput);
document.addEventListener('resize', onResize);
// starting the game
draw();
})();
My HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Rocket</title>
<link rel=stylesheet href="styles/rocket2.css" >
</head>
<body id="body">
<canvas id="game"></canvas>
<script src="pscripts/rocket/rocket.js"></script>
<button class="info-btn">
Hello World
</button>
</body>
</html>
My CSS:
#body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
background-color: #111;
}
#game {
position: relative;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.info-btn {
opacity: 1;
position: absolute;
top: 2vh;
right: 2vw;
color: white;
background-color: dimgrey;
font-family: "Agency FB";
font-size: 2vh;
cursor: pointer;
}
.info-btn:hover {
background-color: #4f4f4f;
color: #c7c7c7;
}
.info {
background-color: #4f4f4f;
padding: 2%;
width: 98%;
height: 98%;
}
The code that I have been trying to use to stop the rocket when it reaches context.canvas.height - this.size.height is:
if (this.position.y === context.canvas.height - this.size.height) {
this.velocity.y = -GRAVITY / 100;
this.velocity.x = 0;
}
I am trying to check if the y position of the rocket is equal to the canvas height - the height of the rocket and if so I set the y velocity to the opposite of gravity over 100 so that it has no movement and I set the x velocity to 0.
Thank you to anyone who reads this and tries to help me.
Because you are using === your code will only work when they are equal which is almost never going to happen in an animation. The object could pass the given point between frames. You should use >=
if (this.position.y >= context.canvas.height - this.size.height) {
this.velocity.y = -GRAVITY / 100;
this.velocity.x = 0;
}

Remove objects in the canvas in certain coordinates

I would like to remove the balls already generated in the canvas on the click and decrease the counter on the bottom, but my function does not work. Here is my code concerning the part of the ball removal.
Is it possible to use a div to get the same result and to facilitate the removal of the balls? thank you
ball.onclick = function removeBalls(event) {
var x = event.clientX;
var y = event.clientY;
ctx.clearRect(x, y, 100, 50);
ctx.fillStyle = "#000000";
ctx.font = "20px Arial";
ctx.fillText("Balls Counter: " + balls.length - 1, 10, canvas.height - 10);
}
below I enclose my complete code
// GLOBAL VARIBLES
var gravity = 4;
var forceFactor = 0.3; //0.3 0.5
var mouseDown = false;
var balls = []; //hold all the balls
var mousePos = []; //hold the positions of the mouse
var ctx = canvas.getContext('2d');
var heightBrw = canvas.height = window.innerHeight;
var widthBrw = canvas.width = window.innerWidth;
var bounciness = 1; //0.9
window.onload = function gameCore() {
function onMouseDown(event) {
mouseDown = true;
mousePos["downX"] = event.pageX;
mousePos["downY"] = event.pageY;
}
canvas.onclick = function onMouseUp(event) {
mouseDown = false;
balls.push(new ball(mousePos["downX"], mousePos["downY"], (event.pageX - mousePos["downX"]) * forceFactor,
(event.pageY - mousePos["downY"]) * forceFactor, 5 + (Math.random() * 10), bounciness, random_color()));
ball
}
function onMouseMove(event) {
mousePos['currentX'] = event.pageX;
mousePos['currentY'] = event.pageY;
}
function resizeWindow(event) {
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;
}
function reduceBounciness(event) {
if (bounciness == 1) {
for (var i = 0; i < balls.length; i++) {
balls[i].b = bounciness = 0.9;
document.getElementById("btn-bounciness").value = "⤽ Bounciness";
}
} else {
for (var i = 0; i < balls.length; i++) {
balls[i].b = bounciness = 1;
document.getElementById("btn-bounciness").value = " ⤼ Bounciness";
}
}
return bounciness;
}
function reduceSpeed(event) {
for (var i = 0; i < balls.length; i++) {
balls[i].vx = velocityX = 20 + c;
balls[i].vy = velocityY = 20 + c;
}
}
function speedUp(event) {
for (var i = 0; i < balls.length; i++) {
balls[i].vx = velocityX = 120 + c;
balls[i].vy = velocityY = 120 + c;
}
}
function stopGravity(event) {
if (gravity == 4) {
for (var i = 0; i < balls.length; i++) {
balls[i].g = gravity = 0;
balls[i].vx = velocityX = 0;
balls[i].vy = velocityY = 0;
document.getElementById("btn-gravity").value = "►";
}
} else {
for (var i = 0; i < balls.length; i++) {
balls[i].g = gravity = 4;
balls[i].vx = velocityX = 100;
balls[i].vy = velocityY = 100;
document.getElementById("btn-gravity").value = "◾";
}
}
}
ball.onclick = function removeBalls(event) {
var x = event.clientX;
var y = event.clientY;
ctx.clearRect(x, y, 100, 50);
ctx.fillStyle = "#000000";
ctx.font = "20px Arial";
ctx.fillText("Balls Counter: " + balls.length - 1, 10, canvas.height - 10);
}
document.getElementById("btn-gravity").addEventListener("click", stopGravity);
document.getElementById("btn-speed-up").addEventListener("click", speedUp);
document.getElementById("btn-speed-down").addEventListener("click", reduceSpeed);
document.getElementById("btn-bounciness").addEventListener("click", reduceBounciness);
document.addEventListener("mousedown", onMouseDown);
document.addEventListener("mousemove", onMouseMove);
window.addEventListener('resize', resizeWindow);
}
// GRAPHICS CODE
function circle(x, y, r, c) { // x position, y position, r radius, c color
//draw a circle
ctx.beginPath(); //approfondire
ctx.arc(x, y, r, 0, Math.PI * 2, true);
ctx.closePath();
//fill
ctx.fillStyle = c;
ctx.fill();
//stroke
ctx.lineWidth = r * 0.1; //border of the ball radius * 0.1
ctx.strokeStyle = "#000000"; //color of the border
ctx.stroke();
}
function random_color() {
var letter = "0123456789ABCDEF".split(""); //exadecimal value for the colors
var color = "#"; //all the exadecimal colors starts with #
for (var i = 0; i < 6; i++) {
color = color + letter[Math.round(Math.random() * 15)];
}
return color;
}
function selectDirection(fromx, fromy, tox, toy) {
ctx.beginPath();
ctx.moveTo(fromx, fromy);
ctx.lineTo(tox, toy);
ctx.moveTo(tox, toy);
}
//per velocità invariata rimuovere bounciness
function draw_ball() {
this.vy = this.vy + gravity * 0.1; // v = a * t
this.x = this.x + this.vx * 0.1; // s = v * t
this.y = this.y + this.vy * 0.1;
if (this.x + this.r > canvas.width) {
this.x = canvas.width - this.r;
this.vx = this.vx * -1 * this.b;
}
if (this.x - this.r < 0) {
this.x = this.r;
this.vx = this.vx * -1 * this.b;
}
if (this.y + this.r > canvas.height) {
this.y = canvas.height - this.r;
this.vy = this.vy * -1 * this.b;
}
if (this.y - this.r < 0) {
this.y = this.r;
this.vy = this.vy * 1 * this.b;
}
circle(this.x, this.y, this.r, this.c);
}
// OBJECTS
function ball(positionX, positionY, velosityX, velosityY, radius, bounciness, color, gravity) {
this.x = positionX;
this.y = positionY;
this.vx = velosityX;
this.vy = velosityY;
this.r = radius;
this.b = bounciness;
this.c = color;
this.g = gravity;
this.draw = draw_ball;
}
// GAME LOOP
function game_loop() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (mouseDown == true) {
selectDirection(mousePos['downX'], mousePos['downY'], mousePos['currentX'], mousePos['currentY']);
}
for (var i = 0; i < balls.length; i++) {
balls[i].draw();
}
ctx.fillStyle = "#000000";
ctx.font = "20px Arial";
ctx.fillText("Balls Counter: " + balls.length, 10, canvas.height - 10);
}
setInterval(game_loop, 10);
* {
margin: 0px; padding: 0px;
}
html, body {
width: 100%; height: 100%;
}
#canvas {
display: block;
height: 95%;
border: 2px solid black;
width: 98%;
margin-left: 1%;
}
#btn-speed-up, #btn-speed-down, #btn-bounciness, #btn-gravity{
padding: 0.4%;
background-color: beige;
text-align: center;
font-size: 20px;
font-weight: 700;
float: right;
margin-right: 1%;
margin-top:0.5%;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Power Balls</title>
<link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
<canvas id="canvas"></canvas>
<input type="button" value="⤼ Bounciness" id="btn-bounciness"></input>
<input type="button" onclick="c+=10" value="+ Speed" id="btn-speed-up"></input>
<input type="button" value="◾" id="btn-gravity"></input>
<input type="button" onclick="c+= -10" value=" - Speed" id="btn-speed-down"></input>
<script src="js/main.js"></script>
</body>
</html>
I see two problems:
ball.onclick will not get triggered, as ball it is not a DOM object. Instead, you need to work with canvas.onclick. Check whether the user clicked on a ball or on empty space to decide whether to delete or create a ball.
To delete the ball, ctx.clearRect is not sufficient. This will clear the ball from the currently drawn frame, but the object still remains in the array balls and will therefore be drawn again in the next frame via balls[i].draw();. Instead, you need to remove the clicked ball entirely from the array, e. g. by using splice.
Otherwise, nice demo! :)
This cannot be done because the canvas is an immediate mode API. All you can do is draw over the top but this is not reliable.
https://en.wikipedia.org/wiki/Immediate_mode_(computer_graphics)
You will have to store each item in a separate data structure, then re-draw whenever a change occurs. In your case there is an array of balls, so you should remove the one that was clicked, before redrawing the entire array.
Each time you remove something, clear the canvas then re-draw each ball.
There are optimisations you can make if this is too slow.

How can i add a Start button to this function?

I'm trying to figure out how I can add a start button to play a javascript game by replacing the audio in the background. I came across this game, the way it works is as soon as you load the page the music plays in the background and the games already started. When I removed the audio link, the game paused after the players 3 lives are up, if I leave the audio in, then when the 3 lives are up you can see your points and a pop up message, can someone please help me understand this
here is a link to the game so you can look at the code and understand what I'm trying to say : https://jsfiddle.net/74nbrdak/embedded/result/
<div>
<canvas id="canvas" width="1000" height="500"></canvas>
</div>
<audio id="background-music" preload="auto" autoplay loop>
<source
src="https://dl.dropbox.com/s/5r3iu7kjsl0mx81/Wildfire%20Cut%20Loopable.wav" type="audio/wav">
function ShowGamesFinished() {
var message = gamesfinished[Math.floor(Math.random() * gamesfinished.length)];
document.getElementById("background-music").pause();
When I removed the audio link, the game paused after the players 3 lives are up, if I leave the audio in, then when the 3 lives are up you can see your points and a pop up message, can someone please help me understand this
So, In the second scenario when the audio element is on the page, the game works just as the creator intended.
In the first scenario when the audio element isn't on the page, the game works fine until the function that handles the game over is called. What causes the problem in that function is this line document.getElementById("background-music").pause();. Since the audio element doesn't exist, it throws an error and the game over screen isn't drawn. Hope that this helps
If you are using pure javascript Without any external libraries, you can initialize your canvas and on a click of the button you can start animating the canvas and your game starts.
let me know If you don't get my answer.
At first glance, removing the audio tag should not have any effect at all on the javascript. The audio plays upon openeing the page because the audio tag has the autoplay attribute.
All of the javascript code seems to be just within a script tag, so it will also autorun once the page gets opened. What you could try is wrapping the entire code from the fiddle into a function and just bind it to your button.
Something like:
<!DOCTYPE html>
<html lang="en">
<head>
<style>
h1 {
font-family: Architects Daughter;
text-align: center;
font-size: 48pt;
margin-top: 50px;
margin-bottom: 0px;
}
h2 {
font-family: Architects Daughter;
text-align: center;
font-size: 28pt;
margin-top: 0px;
margin-bottom: 50px;
}
span {
display: block;
font-family: Arial;
text-align: center;
margin-bottom: 2px;
}
div {
display: flex;
justify-content: space-around;
}
canvas {
border: 2px solid #CC3333;
}
</style>
</head>
<body>
<div>
<canvas id="canvas" width="640" height="360"></canvas>
</div>
<button id="start_game">Start</button>
<script>
var run_game = function() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var WIDTH = canvas.width;
var HEIGHT = canvas.height;
var updateTime = 20; // Milliseconds
var keys = [false, false, false];
var score = 0;
var kills = 0;
// Player Size = 50x18
var playerHealth = 3;
var playerX = WIDTH / 2;
var playerY = HEIGHT - 20;
var playerSpeed = 6;
var lazerSpeed = 16;
var lazerReloadDistance = playerY - 120;
var lazerLoaded = true;
var lazers = [];
var letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var maxEnemies = 12;
var enemySpeed = 4;
var enemies = [];
function Clear() {
ctx.fillStyle = "#404040";
ctx.fillRect(0, 0, WIDTH, HEIGHT);
}
function DrawHealth(health) {
ctx.fillStyle = "#E52B50";
ctx.shadowColor = "#E52B50";
ctx.shadowBlur = 15;
ctx.font = "18px Arial";
ctx.textAlign = "start";
var hearts = "";
if (health == 3) {
hearts = "<3 <3 <3";
}
else if (health == 2) {
hearts = "<3 <3 X";
}
else if (health == 1) {
hearts = "<3 X X";
}
else {
hearts = "X X X";
}
ctx.fillText(hearts, 10, 25);
}
function DrawScore() {
ctx.fillStyle = "#FFFF00";
ctx.shadowColor = "#FFFF00";
ctx.shadowBlur = 15;
ctx.font = "18px Arial";
ctx.textAlign = "end";
ctx.fillText(score, WIDTH - 10, 25);
}
function DrawPlayer(x, y) {
ctx.fillStyle = "#1E90FF";
ctx.shadowColor = "#1E90FF";
ctx.shadowBlur = 15;
ctx.font = "24px Arial";
ctx.textAlign = "center";
ctx.fillText("</^\\>", x, y);
}
function Lazer() {
this.x = playerX;
this.y = playerY - 38;
this.draw = function() {
ctx.fillStyle = "#FFFF00";
ctx.shadowColor = "#FFFF00";
ctx.shadowBlur = 15;
this.y -= lazerSpeed;
ctx.fillRect(this.x, this.y, 2, 18);
}
}
function DrawLazers() {
// Check if the last lazer fired is far enough away to fire another
if (lazers.length != 0) {
if (lazers[lazers.length - 1].y <= lazerReloadDistance) {
lazerLoaded = true;
}
}
else {
lazerLoaded = true;
}
for (var i = 0; i < lazers.length; i++) {
var currentLazer = lazers[i];
// Still on screen
if (currentLazer.y > -20) {
currentLazer.draw();
}
else {
lazers.splice(i, 1);
}
}
}
function Enemy(x) {
this.x = x;
this.y = 0;
this.health = Math.ceil(Math.random() * 4);
this.speed = enemySpeed / this.health;
var letterIndex = Math.floor(Math.random() * letters.length);
this.letter = letters.substr(letterIndex, 1);
this.size = 24 + (this.health * 4); // Font size based on health
ctx.font = this.size+"px Arial";
this.width = ctx.measureText(this.letter).width;
this.height = this.size * 0.75; // Approximate height;
this.draw = function() {
ctx.fillStyle = "#FF0040";
ctx.shadowColor = "#FF0040";
ctx.shadowBlur = 15;
ctx.font = this.size+"px Arial";
ctx.textAlign = "center";
this.y += this.speed;
ctx.fillText(this.letter, this.x, this.y);
}
}
function DrawEnemies() {
// Spawn new enemies
if (Math.random() <= 0.05 && enemies.length < maxEnemies) {
var randX = 40 + Math.floor(Math.random() * (WIDTH - 80));
enemies.push(new Enemy(randX));
}
for (var i = 0; i < enemies.length; i++) {
var currentEnemy = enemies[i];
if (currentEnemy.health <= 0) {
enemies.splice(i, 1);
score += 25;
kills++;
continue;
}
// Put enemies that passed the player back at the top
if (currentEnemy.y > HEIGHT + currentEnemy.height) {
currentEnemy.y = 0;
continue;
}
currentEnemy.draw();
}
}
var gameOverMessages = [
"You're in a better place",
"You're Cooked!",
"You gave it your all",
"At least you tried",
"You're Ruined!",
"You're Finished!"
];
function DrawGameOver() {
var message = gameOverMessages[Math.floor(Math.random() * gameOverMessages.length)];
// after deleting the audio element, this doesnt work anymore.
// document.getElementById("background-music").pause();
ctx.fillStyle = "#505050";
ctx.shadowColor = "#505050";
ctx.shadowBlur = 15;
ctx.fillRect(50, (HEIGHT / 2) - 100, WIDTH - 100, 200)
ctx.fillStyle = "#FFFFFF";
ctx.shadowColor = "#FFFFFF";
ctx.shadowBlur = 15;
ctx.textAlign = "center";
ctx.font = "36pt Arial";
ctx.fillText(message, WIDTH / 2, HEIGHT / 2 - 40);
ctx.textAlign = "end";
ctx.font = "18pt Arial";
ctx.fillText("Final Score - ", WIDTH / 2, HEIGHT / 2 + 30);
ctx.textAlign = "start";
ctx.fillStyle = "#FFFF00";
ctx.shadowColor = "#FFFF00";
ctx.fillText(score, WIDTH / 2, HEIGHT / 2 + 30);
ctx.fillStyle = "#FFFFFF";
ctx.shadowColor = "#FFFFFF";
ctx.textAlign = "end";
ctx.font = "18pt Arial";
ctx.fillText("Total Kills - ", WIDTH / 2, HEIGHT / 2 + 60);
ctx.textAlign = "start";
ctx.fillStyle = "#FF0040";
ctx.shadowColor = "#FF0040";
ctx.fillText(kills, WIDTH / 2, HEIGHT / 2 + 60);
}
////////////////////
// Core Functions //
////////////////////
var collidedEnemyIndex = -1;
function CheckCollision() {
for (var i = 0; i < enemies.length; i++) {
var currentEnemy = enemies[i];
// Check if enemy hits player. The 2 is to account for the text width of the player
if (
currentEnemy.x <= playerX - 2 + 25 + (currentEnemy.width / 2) &&
currentEnemy.x >= playerX - 2 - 25 - (currentEnemy.width / 2) &&
currentEnemy.y >= playerY - 18 &&
currentEnemy.y <= playerY + currentEnemy.height &&
collidedEnemyIndex != enemies.indexOf(currentEnemy)
)
{
collidedEnemyIndex = enemies.indexOf(currentEnemy);
playerHealth--;
}
// Reset the index of the enemy colliding with the player
if (collidedEnemyIndex == enemies.indexOf(currentEnemy) && currentEnemy.y < HEIGHT / 2) {
collidedEnemyIndex = -1;
}
for (var j = 0; j < lazers.length; j++) {
var currentLazer = lazers[j];
if (
currentLazer.x <= currentEnemy.x + (currentEnemy.width / 2) &&
currentLazer.x >= currentEnemy.x - (currentEnemy.width / 2) &&
currentLazer.y <= currentEnemy.y
)
{
currentEnemy.health--;
score += 10;
lazers.splice(lazers.indexOf(currentLazer), 1);
}
}
}
}
function HandleInput() {
if (keys[0] == true && keys[1] == false && playerX <= WIDTH - 30) {
playerX += playerSpeed;
}
if (keys[1] == true && keys[0] == false && playerX >= 30) {
playerX -= playerSpeed;
}
if (keys[2]) {
if (lazerLoaded) {
lazers.push(new Lazer());
lazerLoaded = false;
}
}
}
function KeysDown(e) {
e.preventDefault();
// Right
if (e.keyCode == 39) {
keys[0] = true;
}
// Left
else if (e.keyCode == 37) {
keys[1] = true;
}
// Up/Fire
if (e.keyCode == 38) {
keys[2] = true;
}
}
function KeysUp(e) {
// Right
if (e.keyCode == 39) {
keys[0] = false;
}
// Left
else if (e.keyCode == 37) {
keys[1] = false;
}
// Up/Fire
if (e.keyCode == 38) {
keys[2] = false;
}
}
document.addEventListener("keydown", KeysDown, true);
document.addEventListener("keyup", KeysUp, true);
function Update() {
Clear();
HandleInput();
CheckCollision();
DrawEnemies();
DrawLazers();
DrawPlayer(playerX, playerY);
DrawHealth(playerHealth);
DrawScore();
if (playerHealth <= 0) {
clearInterval(gameLoop);
DrawGameOver();
}
}
var gameLoop = setInterval(Update, updateTime);
};
document.querySelector( '#start_game' ).addEventListener( 'click', run_game );
</script>
</body>
</html>

Changing number of array elements during a simulation

I am trying to change the number of bouncing balls in a simulation. I am passing the required number using Socket.IO, but I'm struggling to change the number of balls. Here is the JavaScript:
var width = 100,
height = 200,
numBalls,
balls;
$(document).ready(function() {
var socket = io();
socket.on('message', function (data) {
console.log(data.count);
numBalls = data.count
});
$('#myCanvas').click(bounce);
// create an array of balls
balls = new Array(numBalls);
for(i = 0 ; i < numBalls ; i++){
balls[i] = new Ball();
}
});
function Ball(){
// random radius
this.radius = Math.floor(Math.random()*(10-5+1))+5;
// random x and y
this.x = Math.floor(Math.random()*(width-this.radius+1))+this.radius;
this.y = Math.floor(Math.random()*(width-this.radius+1))+this.radius;
// random direction, +1 or -1
this.dx = Math.floor(Math.random()*2) * 2 - 1;
this.dy = Math.floor(Math.random()*2) * 2 - 1;
//random colour, r, g or b
var rcol = Math.floor(Math.random()*3);
this.col = rcol==0 ? "red" :
rcol==1 ? "blue" : "green";
}
// draw the balls on the canvas
function draw(){
var canvas = document.getElementById("myCanvas");
// check if supported
if(canvas.getContext){
var ctx=canvas.getContext("2d");
//clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.globalAlpha = 0.5;
ctx.strokeStyle="black";
// draw each ball
for(i = 0; i < numBalls ; i++){
var ball = balls[i];
ctx.fillStyle=ball.col;
ctx.beginPath();
// check bounds
// change direction if hitting border
if(ball.x<=ball.radius ||
ball.x >= (width-ball.radius)){
ball.dx *= -1;
}
if(ball.y<=ball.radius ||
ball.y >= (height-ball.radius)){
ball.dy *= -1;
}
// move ball
ball.x += ball.dx;
ball.y += ball.dy;
// draw it
ctx.arc(ball.x, ball.y, ball.radius, 0, 2*Math.PI, false);
ctx.stroke();
ctx.fill();
}
}
else{
//canvas not supported
}
}
// calls draw every 10 millis
function bounce(){
setInterval(draw, 10);
}
Let's say newNumBalls is the new number of balls.
If newNumBalls is less than numBalls, you want to remove elements from balls. You can do that by taking a slice of balls and assigning it to balls.
If newNumBalls is greater than numBalls, you want to make new balls and add them to balls. You can do that with push.
The complete logic is this:
if (newNumBalls < numBalls) {
balls = balls.slice(0, newNumBalls);
} else {
for (var i = numBalls; i < newNumBalls; ++i) {
balls.push(new Ball());
}
}
numBalls = newNumBalls;
Below is a snippet that implements this logic.
var width,
height,
numBalls = 10,
balls;
$('#setNumBalls').click(function () {
var newNumBalls = parseInt($('#inputNumBalls').val(), 10);
if (newNumBalls < numBalls) {
balls = balls.slice(0, newNumBalls);
//$('#display').html('Removed ' + (numBalls - newNumBalls) + ' balls');
} else {
for (var i = numBalls; i < newNumBalls; ++i) {
balls.push(new Ball());
}
//$('#display').html('Added ' + (newNumBalls - numBalls) + ' new balls');
}
numBalls = newNumBalls;
});
$(document).ready(function() {
width = $('#myCanvas').width();
height = $('#myCanvas').height();
var canvas = $('#myCanvas')[0];
canvas.width = width;
canvas.height = height;
$('#inputNumBalls').val(numBalls);
// create an array of balls
balls = new Array(numBalls);
for(i = 0 ; i < numBalls ; i++){
balls[i] = new Ball();
}
bounce();
});
function Ball(){
// random radius
this.radius = Math.floor(Math.random()*(10-5+1))+5;
// random x and y
var margin = 2 * this.radius;
this.x = Math.floor(Math.random()*(width-margin))+margin/2;
this.y = Math.floor(Math.random()*(width-margin+1))+margin/2;
// random direction, +1 or -1
this.dx = Math.floor(Math.random()*2) * 2 - 1;
this.dy = Math.floor(Math.random()*2) * 2 - 1;
//random colour, r, g or b
var rcol = Math.floor(Math.random()*3);
this.col = rcol==0 ? "red" :
rcol==1 ? "blue" : "green";
}
// draw the balls on the canvas
function draw(){
var canvas = $('#myCanvas')[0];
// check if supported
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
//clear canvas
ctx.clearRect(0, 0, width, height);
ctx.globalAlpha = 0.5;
ctx.strokeStyle="black";
// draw each ball
for(var i = 0; i < numBalls ; i++){
var ball = balls[i];
ctx.fillStyle = ball.col;
ctx.beginPath();
// check bounds
// change direction if hitting border
if(ball.x <= ball.radius ||
ball.x >= (width - ball.radius)) {
ball.dx *= -1;
}
if(ball.y <= ball.radius ||
ball.y >= (height - ball.radius)) {
ball.dy *= -1;
}
// move ball
ball.x += ball.dx;
ball.y += ball.dy;
// draw it
ctx.arc(ball.x, ball.y, ball.radius, 0, 2*Math.PI, false);
ctx.stroke();
ctx.fill();
}
}
else{
//canvas not supported
}
}
// Calls draw frameRate times a second.
function bounce() {
var frameRate = 60;
setInterval(draw, 1000 / frameRate);
}
body {
font-family: sans-serif;
}
#myCanvas {
float: left;
margin: 0 10px 0 0;
width: 160px;
height: 160px;
border: 1px solid #888;
}
#inputNumBalls {
font-size: 18px;
padding: 5px 8px;
margin: 5px;
text-align: center;
outline: none;
}
.button {
display: inline;
cursor: pointer;
padding: 2px 8px;
border-radius: 5px;
border: 2px solid #888;
}
.button:hover {
background: #ffd;
border-color: #000;
}
#display {
width: 200px;
height: 50px;
padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<canvas id="myCanvas"> Canvas not supported. </canvas>
<div>
Number of balls:
<input type="text" id="inputNumBalls" size="3" />
<div class="button" id="setNumBalls">Set</div>
<div id="display"></div>
</div>

Categories