The current code I have has 3 balls that are moving within the canvas but I also would like to add code where clicking on the canvas will display another circle (stationary). I tried the below code but currently stuck with the error I'm receiving. I think it's got something to do with the draw(c1) function but unsure how to have it fixed.
<div id="butDiv">
<input type='button' id='Begin' value='Start'>
<input type='button' id='resetCanvas' value='Reset'>
</div>
<canvas id='canvas1' onclick="draw()"></canvas>
<script>
const canvas = document.getElementById('canvas1');
const ctx = canvas.getContext('2d');
const width = canvas.width = 1050;
const height = canvas.height = 500;
ctx.fillStyle = 'grey';
ctx.fillRect(0, 0, width, height);
let rq;
function random(min, max) {
const num = Math.floor(Math.random() * (max - min + 1)) + min;
return num;
}
class Ball{
constructor(x, y, velX, velY, color, size){
this.x = x;
this.y = y;
this.velX = velX;
this.velY = velY;
this.color = color;
this.size = size;
}
draw(){
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
ctx.fill();
}
update(){
if ((this.x + this.size) >= width) {
this.velX = -(this.velX);
}
if ((this.x - this.size) <= 0) {
this.velX = -(this.velX);
}
if ((this.y + this.size) >= height) {
this.velY = -(this.velY);
}
if ((this.y - this.size) <= 0) {
this.velY = -(this.velY);
}
this.x += this.velX;
this.y += this.velY;
}
}
let balls = [];
const loop = () => {
while (balls.length < 3) {
let size = 35;
let ball = new Ball(
random(0 + size,width - size), random(0 + size,height - size),15,15,'yellow',size);
balls.push(ball);
}
ctx.fillStyle = 'grey';
ctx.fillRect(0, 0, width, height);
balls.forEach((i,a)=>{
i.draw();
i.update();
})
rq = requestAnimationFrame(loop);
}
function getCursorPosition(canvas, c1) {
// Gets click position
rect = canvas.getBoundingClientRect();
console.log('getcursorpos');
return {
x: c1.clickX - rect.left,
y: c1.clickY - rect.top
};
}
function draw(c1) {
getCursorPosition(canvas,c1);
var pos = getCursorPosition(canvas, c1);
var clickX = pos.x;
var clickY = pos.y;
var size1 = Math.floor((Math.Random() * 3) + 1);
ctx.fillStyle = "black";
ctx.beginPath();
ctx.arc(clickX, clickY, size1, 0, 2 * Math.PI);
ctx.fill();
}
document.getElementById('butDiv').addEventListener('click', (e)=> {
const tgt = e.target;
if (tgt.id === "Begin") {
if (tgt.value === "Start") {
loop()
tgt.value = "Pause";
}else {
cancelAnimationFrame(rq)
tgt.value = "Start";
}
}else if (tgt.id === "resetCanvas") {
cancelAnimationFrame(rq)
ctx.fillStyle = 'grey';
ctx.fillRect(0, 0, width, height);
}
})
I have a solution for you, I wrote everything you'll need in /* */ comments.
However it will only work if the game is stopped or paused, because when your game is running your canvas is always refreshing and you don't save the new dots, hence they will disappear on the next frame.
<div id="butDiv">
<input type='button' id='Begin' value='Start'>
<input type='button' id='resetCanvas' value='Reset'>
</div>
<canvas id='canvas1' onclick="draw()"></canvas>
<script>
const canvas = document.getElementById('canvas1');
const ctx = canvas.getContext('2d');
const width = canvas.width = 1050;
const height = canvas.height = 500;
ctx.fillStyle = 'grey';
ctx.fillRect(0, 0, width, height);
let rq;
/* otherwise it wont be passed */
canvas.onclick = (event) => {draw(event)};
function random(min, max) {
const num = Math.floor(Math.random() * (max - min + 1)) + min;
return num;
}
class Ball{
constructor(x, y, velX, velY, color, size){
this.x = x;
this.y = y;
this.velX = velX;
this.velY = velY;
this.color = color;
this.size = size;
}
draw(){
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
ctx.fill();
}
update(){
if ((this.x + this.size) >= width) {
this.velX = -(this.velX);
}
if ((this.x - this.size) <= 0) {
this.velX = -(this.velX);
}
if ((this.y + this.size) >= height) {
this.velY = -(this.velY);
}
if ((this.y - this.size) <= 0) {
this.velY = -(this.velY);
}
this.x += this.velX;
this.y += this.velY;
}
}
let balls = [];
const loop = () => {
while (balls.length < 3) {
let size = 35;
let ball = new Ball(
random(0 + size,width - size), random(0 + size,height - size),15,15,'yellow',size);
balls.push(ball);
}
ctx.fillStyle = 'grey';
ctx.fillRect(0, 0, width, height);
balls.forEach((i,a)=>{
i.draw();
i.update();
})
rq = requestAnimationFrame(loop);
}
function getCursorPosition(canvas, c1) {
// Gets click position
rect = canvas.getBoundingClientRect();
/* clickX and Y does not exist use clientX and Y */
return {
x: c1.offsetX,
y: c1.offsetY
};
}
function draw(c1) {
/* Why would you call it twice? */
//getCursorPosition(canvas,c1);
var pos = getCursorPosition(canvas, c1);
var clickX = pos.x;
var clickY = pos.y;
/* you had a typo here Random -> random */
var size1 = Math.floor((Math.random() * 3) + 1);
ctx.fillStyle = "black";
ctx.beginPath();
console.log(clickX, clickY, size1);
ctx.arc(clickX, clickY, size1, 0, 2 * Math.PI);
ctx.fill();
}
document.getElementById('butDiv').addEventListener('click', (e)=> {
const tgt = e.target;
if (tgt.id === "Begin") {
if (tgt.value === "Start") {
loop()
tgt.value = "Pause";
}else {
cancelAnimationFrame(rq)
tgt.value = "Start";
}
}else if (tgt.id === "resetCanvas") {
cancelAnimationFrame(rq)
ctx.fillStyle = 'grey';
ctx.fillRect(0, 0, width, height);
}
})
</script>
Edited version where it displays the dots even if the balls are moving:
<div id="butDiv">
<input type='button' id='Begin' value='Start'>
<input type='button' id='resetCanvas' value='Reset'>
</div>
<canvas id='canvas1' onclick="draw()"></canvas>
<script>
const canvas = document.getElementById('canvas1');
const ctx = canvas.getContext('2d');
const width = canvas.width = 1050;
const height = canvas.height = 500;
ctx.fillStyle = 'grey';
ctx.fillRect(0, 0, width, height);
let rq;
/* otherwise it wont be passed */
canvas.onclick = (event) => {draw(event)};
function random(min, max) {
const num = Math.floor(Math.random() * (max - min + 1)) + min;
return num;
}
class Ball{
constructor(x, y, velX, velY, color, size){
this.x = x;
this.y = y;
this.velX = velX;
this.velY = velY;
this.color = color;
this.size = size;
}
draw(){
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
ctx.fill();
}
update(){
if ((this.x + this.size) >= width) {
this.velX = -(this.velX);
}
if ((this.x - this.size) <= 0) {
this.velX = -(this.velX);
}
if ((this.y + this.size) >= height) {
this.velY = -(this.velY);
}
if ((this.y - this.size) <= 0) {
this.velY = -(this.velY);
}
this.x += this.velX;
this.y += this.velY;
}
}
// dot class - sorry for thinking that the dot was a ball object, my memory is converges to 0 :(
class Dot{
constructor(x, y, color, size){
this.x = x;
this.y = y;
this.color = color;
this.size = size;
}
draw(){
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
ctx.fill();
}
}
let dots = [];
let balls = [];
const loop = () => {
while (balls.length < 3) {
let size = 35;
let ball = new Ball(
random(0 + size,width - size), random(0 + size,height - size),15,15,'yellow',size);
balls.push(ball);
}
ctx.fillStyle = 'grey';
ctx.fillRect(0, 0, width, height);
balls.forEach((i,a)=>{
i.draw();
i.update();
})
// this is the suff that draws the dots, if you want them drawn under the balls just paste this to the behinning of the loop function
dots.forEach(dot => {
dot.draw();
});
rq = requestAnimationFrame(loop);
}
function getCursorPosition(canvas, c1) {
// Gets click position
rect = canvas.getBoundingClientRect();
/* clickX and Y does not exist use clientX and Y */
return {
x: c1.offsetX,
y: c1.offsetY
};
}
function draw(c1) {
/* Why would you call it twice? */
//getCursorPosition(canvas,c1);
var pos = getCursorPosition(canvas, c1);
/*var clickX = pos.x;
var clickY = pos.y;*/
/* you had a typo here Random -> random */
var size1 = Math.floor((Math.random() * 3) + 1);
dots.push(new Dot(pos.x, pos.y, "black", size1));
/*ctx.fillStyle = "black";
ctx.beginPath();
console.log(clickX, clickY, size1);
ctx.arc(clickX, clickY, size1, 0, 2 * Math.PI);
ctx.fill();*/
}
document.getElementById('butDiv').addEventListener('click', (e)=> {
const tgt = e.target;
if (tgt.id === "Begin") {
if (tgt.value === "Start") {
loop()
tgt.value = "Pause";
}else {
cancelAnimationFrame(rq)
tgt.value = "Start";
}
}else if (tgt.id === "resetCanvas") {
cancelAnimationFrame(rq)
ctx.fillStyle = 'grey';
ctx.fillRect(0, 0, width, height);
}
})
</script>
Related
Can you help with the code?
I'm creating a parkour game and everything went well but I got stuck on it:
as the cube will stand on the floor.
Here is my js code:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
//Налаштування
var width = canvas.width;
var height = canvas.height;
var gameOver = function () {
clearInterval(intervalId);
ctx.font = "60px Caurier";
ctx.textAlign = "cener";
ctx.textBaseline = "middle";
ctxfillText("GAME OVER", width / 2, height / 2);
};
var cicle = function (x, y, radius, fillCircle) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, false);
if (fillCircle) {
ctx.fill();
} else {
ctx.stroke();
}
};
//Людина
//намалювати
function Draw() {
this.x = 10;
this.y = 10;
}
Draw.prototype.draw = function () {
ctx.beginPath();
ctx.moveTo(this.x, this.y);
ctx.lineTo(this.x + 50, this.y);
ctx.lineTo(this.x + 50, this.y + 50);
ctx.lineTo(this.x, this.y + 50);
ctx.lineTo(this.x, this.y);
ctx.fill();
}
Draw.prototype.move = function () {
if (this.x < 0) {
this.x = 0;
} else if (this.x > 1250) {
this.x = 1250;
}
if (this.y < 0) {
this.y = 0;
} else if (this.y > 450) {
this.y = 450;
}
while (this.y < 450) {
this.y++;
}
}
Draw.prototype.setDirection = function (direction) {
if (direction === "left") {
this.x = this.x - 10;
} else if (direction === "right") {
this.x = this.x + 10;
} else if (direction === "up") {
this.y = this.y - 150;
}
}
var person = new Draw;
var keyActions = {
37: "left",
38: "up",
39: "right"
};
$("body").keydown(function (event) {
var direction = keyActions[event.keyCode];
person.setDirection(direction);
});
setInterval(function () {
ctx.clearRect(0, 0, 1300, 500);
person.draw();
person.move();
//карта
var floor = ctx.strokeStyle = "LimeGreen"; ctx.lineWidth = 4; ctx.strokeRect(0, 312, 1300, 362);
}, 30);
I tried a lot but it didn't work out.
For example, I tried this:
first the code checks whether the cube and the floor are in the same coordinates, if so it reflects, if not, then no.I want the cube to be able to walk on the floor which is painted green, and not pass through it.
I am trying to create a button object which can run a class function (show() in this case) that will change the button's color. The problem is I can only do this by calling show() repeatedly each time the color changes. The result is a ton of buttons being drawn on the screen, but I would like to only draw the button once. Is there a way around this? (Note: I have the button x position increasing to show the buttons being created)
let canvas = document.getElementById("JScanvas"),
c = canvas.getContext("2d");
let mousePosition = {
x: 0,
y: 0
};
// ignore, a few functions I might need for this to run
function buildRect(fillColor, outlineColor, outlineSize, x, y, w, h) {
if (fillColor && outlineColor) {
c.beginPath();
c.rect(x, y, w, h);
c.fillStyle = fillColor;
c.fill();
c.lineWidth = outlineSize;
c.strokeStyle = outlineColor;
c.stroke();
} else if (fillColor && !outlineColor) {
c.beginPath();
c.rect(x, y, w, h);
c.fillStyle = fillColor;
c.fill();
} else if (!fillColor && outlineColor) {
c.beginPath();
c.rect(x, y, w, h);
c.lineWidth = outlineSize;
c.strokeStyle = outlineColor;
c.stroke();
}
}
function write(str, x, y, color, txtSize, font) {
let size = txtSize.toString();
c.font = size + "px" + " " + font;
c.fillStyle = color;
c.fillText(str, x, y);
}
// end of useless functions
class button {
// mouse is {canvs: canvas, mClicked: t/f, mPosition: mousePosition{x, y}}
constructor(name, order, btnColor, x, y, w, h, txtColor, txtSize, m, f) {
this.name = name;
this.order = order;
this.btnColor = btnColor;
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.txtColor = txtColor;
this.txtSize = txtSize;
this.m = m;
this.f = f;
//change color when mouse over button
this.m.canvs.addEventListener("mousemove", (event) => {
console.log("hello there");
if (this.x < this.m.mPosition.x && this.m.mPosition.x < this.x + this.w && this.y < this.m.mPosition.y && this.m.mPosition.y < this.y + this.h) {
if (this.btnColor[0] != "grey") {
this.btnColor[0] = "grey";
this.x += 50;
this.show();
} else {
this.btnColor[0] = "red";
this.x += 50;
this.show();
}
}
});
}
show() {
if (!this.btnColor[0] && !this.btnColor[0]) {
buildRect("transparent", false, 1, this.x, this.y, this.w, this.h);
} else if (!this.btnColor[0]) {
buildRect(false, this.btnColor[1], 1, this.x, this.y, this.w, this.h);
} else if (!this.btnColor[1]) {
buildRect(this.btnColor[0], false, 1, this.x, this.y, this.w, this.h);
} else {
buildRect(this.btnColor[0], this.btnColor[1], 1, this.x, this.y, this.w, this.h);
}
c.fillStyle = this.txtColor;
let theString = String(this.txtSize) + "px Arial";
c.font = theString;
let width = Math.round(c.measureText(c.fillText(this.name, -1000, 0)).width);
if (width > this.w) {
let center = this.x + (this.w / 2);
let newSize = this.w / width;
c.font = String(this.txtSize * newSize);
let newWidth = Math.round(newSize * width);
c.textAlign = "center";
c.textBaseline = "middle";
c.fillText(this.name, this.x + (this.w / 2), this.y + (this.h / 2));
} else {
c.textAlign = "center";
c.textBaseline = "middle";
c.fillText(this.name, this.x + (this.w / 2), this.y + (this.h / 2));
}
}
clickButton(mouseX, mouseY) {
if (mouseX >= this.x && mouseX <= this.x + this.w && mouseY >= this.y && mouseY <= this.y + this.h) {
return true;
} else {
return false;
}
}
runf() {
this.f();
}
}
//getting mouse position
function getMousePos(canvas, evt) {
const rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
canvas.addEventListener("mousemove", (evt) => {
let r = getMousePos(canvas, event);
mousePosition.x = r.x, mousePosition.y = r.y;
});
let mouse = {
canvs: canvas,
mClicked: false,
mPosition: mousePosition
};
//button object to call: ("red" is the color of the button I am trying to change to grey)
let cookie = new button("cookie", 1, ["red", false], 50, 100, 150, 50, "black", 30, mouse, 2);
cookie.show();
<!DOCTYPE html>
<html>
<head>
<title>Playground</title>
</head>
<body>
<canvas width="1500" height="1500" id="JScanvas"></canvas>
</body>
</html>
I think you have over complicated your code...
Here is a simple example where we change the color when the mouse is over the rectangle
let canvas = document.getElementById("canvas")
let c = canvas.getContext("2d");
class button {
constructor(color, x, y, w, h) {
this.color = color;
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
draw(mouse) {
c.beginPath();
c.rect(this.x, this.y, this.w, this.h);
if (mouse.x >= this.x && mouse.x <= this.x + this.w &&
mouse.y >= this.y && mouse.y <= this.y + this.h) {
c.fillStyle = "gray";
} else {
c.fillStyle = this.color;
}
c.fill();
}
}
function getMousePos(evt) {
if (!evt) return { x: 0, y: 0 }
const rect = canvas.getBoundingClientRect();
return { x: evt.clientX - rect.left, y: evt.clientY - rect.top };
}
let buttons = []
buttons.push(new button("red", 50, 100, 40, 20))
buttons.push(new button("blue", 100, 50, 40, 20))
canvas.addEventListener("mousemove", mainDraw);
function mainDraw(evt) {
let mouse = getMousePos(evt)
c.clearRect(0, 0, canvas.width, canvas.height);
buttons.forEach((btn) => {
btn.draw(mouse)
})
}
mainDraw()
<canvas id="canvas" width="150" height="150"></canvas>
As you can see there is only one addEventListener and it is outside the class button, the logic is simple, we clean the entire canvas and draw everything on every event... that is how games do it, I'm sure that will work for what you are doing too.
I'm creating a game, and I need to draw) some elements at the top of the <canvas>, but the more elements appear, the more lag the page itself. I found this example where a lot of circles appear, but everything works fine - JSFiddle. Can someone tell me how to optimize my case?
"use strict";
/*Determing canvas*/
window.onload = () => {
const canvas = document.getElementById("canvas"),
ctx = canvas.getContext('2d'),
endTitle = document.getElementById('gameover');
let spawnRate = 300,
lastspawn = -1;
class Wall {
/*Getting values*/
constructor(x, y, width, height, speed) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.speed = speed;
}
/*Draw rectangle*/
draw() {
ctx.beginPath();
ctx.fillStyle = "#000000";
ctx.fillRect(this.x, this.y, this.width, this.height)
}
}
/*Making walls*/
let walls = [];
/*Spawn walls endlessly*/
function spawnWalls() {
const wall_x = Math.floor(Math.random() * (canvas.width - 20)) + 10
const wall_y = 0
for (let i = 0; i < 200; i++) {
walls.push(new Wall(wall_x, wall_y, 10, 10, 10))
}
}
/*Update game*/
function refresh() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
let time = Date.now()
if (time > (lastspawn + spawnRate)) {
lastspawn = time;
spawnWalls();
spawnRate -= 10;
}
walls.forEach(wall => wall.draw())
for (let j of walls) {
j.y += j.speed;
j.draw();
};
};
let interval = setInterval(refresh, 50);
Walls is too big.
It looks like you're never removing old walls, so they are continuing to be drawn well after they have been removed from the canvas. In your Refresh function, check if the wall has passed the canvas size and if so, remove that from the walls array.
EDIT:
I've added your 'remove' code from the comment.
Another easy win is to stop using new Date() because of who knows what, probably time zones and localization, dates are very expensive to instantiate. However modern browsers offer a performance API, and that can tell you the time since page load, which seems to have a substantial improvement on your existing performance.
"use strict";
/*Determing canvas*/
window.onload = () => {
const canvas = document.getElementById("canvas"),
ctx = canvas.getContext('2d'),
endTitle = document.getElementById('gameover');
let spawnRate = 300,
lastspawn = -1;
endTitle.style.display = "none";
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
/*Classes*/
class Player {
/*Get player info*/
constructor(x, y, width, height, speed) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.speed = speed;
}
/*Draw player*/
draw() {
ctx.beginPath();
ctx.fillStyle = "#000000";
ctx.fillRect(this.x, this.y, this.width, this.height);
}
/*Move player*/
move() {
}
};
class Wall {
/*Getting values*/
constructor(x, y, width, height, speed) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.speed = speed;
}
/*Draw rectangle*/
draw() {
ctx.beginPath();
ctx.fillStyle = "#000000";
ctx.fillRect(this.x, this.y, this.width, this.height)
}
}
/*Defining players*/
let player_01 = new Player(20, 70, 20, 20, 10);
let player_02 = new Player(50, 500, 20, 20, 10);
let players = [];
players.push(player_01);
/*Making walls*/
let walls = [];
/*Spawn Walls for infinity*/
function spawnWalls() {
const wall_x = Math.floor(Math.random() * (canvas.width - 20)) + 10
const wall_y = 0
for (let i = 0; i < 200; i++) {
walls.push(new Wall(wall_x, wall_y, 10, 10, 10))
}
}
/*Update game*/
function refresh() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
let time = performance.now()
if (time > (lastspawn + spawnRate)) {
lastspawn = time;
spawnWalls();
spawnRate -= 10;
}
walls.forEach(wall => wall.draw())
outOfWindow()
for (let i of players) {
i.draw();
};
for (let j of walls) {
if (j.y > canvas.height) {
walls.shift(j)
}
j.y += j.speed;
j.draw();
if (player_01.height + player_01.y > j.y && j.height + j.y > player_01.y && player_01.width + player_01.x > j.x && j.width + j.x > player_01.x) {
clearInterval(interval);
endTitle.style.display = "flex";
};
};
};
let interval = setInterval(refresh, 50);
/*Move players on keypress*/
for (let i of players) {
window.addEventListener("keydown", (event) => {
let key = event.key.toLowerCase();
if (key == "w") i.y -= i.speed;
else if (key == "s") i.y += i.speed;
else if (key == "a") i.x -= i.speed;
else if (key == "d") i.x += i.speed;
})
}
/*Check if player out of the window*/
function outOfWindow() {
for (let i of players) {
if (i.x < 0) i.x = 0;
else if (i.x + i.width > canvas.width) i.x = canvas.width - i.width;
else if (i.y < 0) i.y = 0;
else if (i.y + i.height > canvas.height) i.y = canvas.height - i.height;
}
}
}
#gameover {
position: absolute;
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
flex-direction: column;
background-color: rgba(0, 0, 0, .5);
}
<div id="gameover">
<h2>The Game Is Over</h2>
<button onclick="restart()">Try again!</button>
</div>
<canvas id="canvas"></canvas>
I'm trying to make 2 rows and 5 columns of bricks using an object, but It doesn't seem to be working. I tried looking it up and using arrays, but It still didn't seem to work.
The bricks have a class of Brick
Demo
Here's the JavaScript
let canvas = $("#canvas")[0];
let ctx = canvas.getContext("2d");
let mouseX = 0;
let mouseY = 0;
class Paddle {
constructor(x, y, w, h, color) {
this.x = canvas.width / 2 - 100 / 2;
this.y = canvas.height - 60;
this.w = 100;
this.h = 10;
this.color = "#fff";
}
draw() {
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.w, this.h);
}
}
class Ball {
constructor (x, y, r, speedX, speedY, color) {
this.x = canvas.width / 2 - 10 / 2;
this.y = canvas.height / 2 - 10 / 2;
this.r = 10;
this.speedX = 3;
this.speedY = 3;
this.color = "#fff";
}
draw() {
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
ctx.fill();
}
animate() {
this.x += this.speedX;
this.y += this.speedY;
}
collision() {
if(this.x >= canvas.width) {
this.speedX *= -1;
}
if(this.x <= 0) {
this.speedX *= -1;
}
if(this.y >= canvas.height) {
this.reset();
}
if(this.y <= 0) {
this.speedY *= -1;
}
let paddleTop = paddle.y;
let paddleBottom = paddleTop + paddle.h;
let paddleLeft = paddle.x;
let paddleRight = paddle.x + paddle.w;
if(ball.x >= paddleLeft &&
ball.x <= paddleRight &&
ball.y >= paddleTop &&
ball.y <= paddleBottom) {
ball.speedY *= -1;
ballControl();
}
}
reset() {
this.speedX = 3;
this.speedY = 3;
this.x = canvas.width / 2 - 10 / 2;
this.y = canvas.height / 2 - 10 / 2;
}
}
class Brick {
constructor(x, y, w, h, col, row, gap, color) {
this.x = 0;
this.y = 0;
this.w = 100;
this.h = 50;
this.col = 5; //# of brick columns
this.row = 2; //# of brick rows
this.gap = 2; //gap betweeb each brick
this.color = "#0000ff";
}
draw() {
for(let brickRow = 0; brickRow < this.row; brickRow++) {
for(let brickCol = 0; brickCol < this.col; brickCol++) {
ctx.fillStyle = this.color;
ctx.fillRect(this.x * brickCol, this.y * brickRow, this.w - this.gap, this.h - this.gap);
}
}
}
}
let paddle = new Paddle(this.x, this.y, this.w, this.h, this.color);
let ball = new Ball(this.x, this.y, this.r, this.speedX, this.speedY, this.color);
let brick = new Brick(this.x, this.y, this.w, this.h, this.col, this.row, this.gap, this.color);
// START
$(document).ready(() => {
let fps = 120;
setInterval(init, 1000 / fps);
$(canvas).bind("mousemove", paddleControl);
})
// INIT
let init = () => {
draw();
animate();
collision();
}
// DRAW
let draw = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
paddle.draw();
ball.draw();
brick.draw();
}
// ANIMATE
let animate = () => {
ball.animate();
}
// COLLISION
let collision = () => {
ball.collision();
}
// BALL CONTROL
let ballControl = () => {
let paddleCenter = paddle.x + paddle.w / 2;
let ballDistFromPaddleCenter = ball.x - paddleCenter;
ball.speedX = ballDistFromPaddleCenter * 0.15;
}
// PADDLE CONTROL
let paddleControl = (e) => {
let rect = canvas.getBoundingClientRect();
let root = document.documentElement;
mouseX = e.pageX - rect.left - root.scrollLeft;
mouseY = e.pageY - rect.top - root.scrollTop;
paddle.x = mouseX;
}
"Doesn't seem to work" is insufficient when describing your problem. You need to say what you expect and what you observe. Failing to do so has attracted 2 close votes for the reason that the question is unclear.
One of your problems is the way that you calculate the position of each brick.
Another potential problem is that you have one object representing all bricks, a better way would be for each brick to be it's own object - this will simplify collision detection (a lot!)
Your code also relies upon the script element appearing after all of the HTML - while functional, this is a broken paradigm. While it is good practise to put it after the html, so that the content is first rendered as soon as possible, having code that only works when it's put there is not so good. For instance - the classes wont initialise before the canvas has been located (since they rely on it's width - a better option would be to have them rely on a separate width variable, which is set to the width of the canvas during page init)
Couldn't get the fiddle to work, nor a snippet for that matter. But here's your code reworked a little. I can now see 2 rows of 5 blue bricks.
<!doctype html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<style>
#canvas {
position: absolute;
background-color: #000;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
}
</style>
<head>
<body>
<canvas id="canvas" width="600" height="500"></canvas>
<script>
var canvas, ctx, mouseX=0, mouseY=0;
canvas = $("#canvas")[0];
ctx = canvas.getContext("2d");
mouseX = 0;
mouseY = 0;
class Paddle
{
constructor(x, y, w, h, color)
{
this.x = canvas.width / 2 - 100 / 2;
this.y = canvas.height - 60;
this.w = 100;
this.h = 10;
this.color = "#fff";
}
draw()
{
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.w, this.h);
}
}
class Ball {
constructor (x, y, r, speedX, speedY, color) {
this.x = canvas.width / 2 - 10 / 2;
this.y = canvas.height / 2 - 10 / 2;
this.r = 10;
this.speedX = 3;
this.speedY = 3;
this.color = "#fff";
}
draw() {
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
ctx.fill();
}
animate() {
this.x += this.speedX;
this.y += this.speedY;
}
collision() {
if(this.x >= canvas.width) {
this.speedX *= -1;
}
if(this.x <= 0) {
this.speedX *= -1;
}
if(this.y >= canvas.height) {
this.reset();
}
if(this.y <= 0) {
this.speedY *= -1;
}
let paddleTop = paddle.y;
let paddleBottom = paddleTop + paddle.h;
let paddleLeft = paddle.x;
let paddleRight = paddle.x + paddle.w;
if(ball.x >= paddleLeft &&
ball.x <= paddleRight &&
ball.y >= paddleTop &&
ball.y <= paddleBottom) {
ball.speedY *= -1;
ballControl();
}
}
reset() {
this.speedX = 3;
this.speedY = 3;
this.x = canvas.width / 2 - 10 / 2;
this.y = canvas.height / 2 - 10 / 2;
}
}
class Brick {
constructor(x, y, w, h, col, row, gap, color) {
this.x = 0;
this.y = 0;
this.w = 100;
this.h = 50;
this.col = 5; //# of brick columns
this.row = 2; //# of brick rows
this.gap = 2; //gap betweeb each brick
this.color = "#0000ff";
}
draw() {
for(let brickRow = 0; brickRow < this.row; brickRow++)
{
for(let brickCol = 0; brickCol < this.col; brickCol++)
{
ctx.fillStyle = this.color;
ctx.fillRect( (this.w+this.gap) * brickCol, (this.h+this.gap) * brickRow, this.w, this.h );
}
}
}
}
let paddle = new Paddle(this.x, this.y, this.w, this.h, this.color);
let ball = new Ball(this.x, this.y, this.r, this.speedX, this.speedY, this.color);
let brick = new Brick(this.x, this.y, this.w, this.h, this.col, this.row, this.gap, this.color);
// START
$(document).ready(() => {
let fps = 120;
setInterval(init, 1000 / fps);
$(canvas).bind("mousemove", paddleControl);
})
// INIT
let init = () => {
draw();
animate();
collision();
}
// DRAW
let draw = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
paddle.draw();
ball.draw();
brick.draw();
}
// ANIMATE
let animate = () => {
ball.animate();
}
// COLLISION
let collision = () => {
ball.collision();
}
// BALL CONTROL
let ballControl = () => {
let paddleCenter = paddle.x + paddle.w / 2;
let ballDistFromPaddleCenter = ball.x - paddleCenter;
ball.speedX = ballDistFromPaddleCenter * 0.15;
}
// PADDLE CONTROL
let paddleControl = (e) => {
let rect = canvas.getBoundingClientRect();
let root = document.documentElement;
mouseX = e.pageX - rect.left - root.scrollLeft;
mouseY = e.pageY - rect.top - root.scrollTop;
paddle.x = mouseX;
}
</script>
</body>
</html>
Been trying to animate an object on canvas by putting it in an array but it wont seem to work.
Only have one object drawn at the moment but the thought is to add several more objects to the canvas hence the array.
Is there something wrong with the functions im using to draw and animate the object?
var draw;
function Canvas(canvas, ctx) {
this.canvas = canvas;
this.ctx = ctx;
}
function Direction(x, y) {
this.x = x;
this.y = y;
}
function Measures(cW, cH, radius, hR, degree, dirX, dirY, degree) {
this.cW = cW;
this.cH = cH;
this.radius = radius;
this.hR = hR;
this.dirX = dirX;
this.dirY = dirY;
this.degree = degree;
}
function Drawing(cW, cH, width, height, radius, hR, color) {
this.cW = canvas.width;
this.cH = canvas.height;
this.width = width;
this.height = height;
this.radius = height / 2;
this.hR = width - this.radius;
this.color = color;
this.render = function() {
ctx.fillStyle = this.color;
ctx.strokeStyle = this.color;
ctx.lineWidth = 1;
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.degree * Math.PI / 180);
ctx.translate(-this.x, -this.y);
ctx.beginPath();
ctx.moveTo(this.x, this.y);
ctx.lineTo(x + this.hR, this.y);
ctx.arc(this.x + this.hR, this.y + this.radius, this.radius, - Math.PI / 2, Math.PI / 2);
ctx.lineTo(this.x, this.y + height);
ctx.closePath();
ctx.fill();
ctx.stroke();
ctx.restore();
}
this.move = function(multiplier) {
var multiplier = 2;
var borders = 5;
if(this.dirX > 0 && this.x > this.cW - borders - width){
this.degree = 90;
this.dirX = 0;
this.dirY = 1;
this.x = cW - borders;
}
else if(this.dirY > 0 && this.y > this.cH - borders - width){
this.degree = 180;
this.dirX = -1;
this.dirY = 0;
this.y = this.cH - borders;
}
else if(this.dirX < 0 && this.x < borders + width){
this.degree = -90;
this.dirX = 0;
this.dirY = -1;
this.x = borders;
}
else if(this.dirY < 0 && this.y < borders + width){
this.degree = 0;
this.dirX = 1;
this.dirY = 0;
this.y = borders;
}
this.x += this.dirX * multiplier;
this.y += this.dirY * multiplier;
this.render();
}
}
function animate() {
ctx.clearRect(0, 0, this.cW, this.cH);
draw.forEach(function(object) {
object.render(2);
});
requestAnimationFrame(animate);
}
function init() {
this.canvas = document.getElementById("my_canvas");
this.ctx = canvas.getContext("2d");
this.degree = Math.PI / 2;
draw = [];
draw.push(new Drawing(5, 5, 80, 60, new Direction(1,0), "#E5E5E5"));
animate();
}
window.onload = init;
</script>
<canvas id="my_canvas" width="1000" height="800" style="background-color:#33CC33"></canvas>