While learning js I made this one. It is working (moving) on computer with tracking mouse position but i couldnt integrate it to smart phones. I want it to move with touch constantly. I guess i need to use touch event, can anyone help me about this? Also I am a new learner, If you see any ridiculous mistake and inform me I will be so gratefull!
Its not working on safari
// setup canvas
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const width = canvas.width = window.innerWidth;
const height = canvas.height = window.innerHeight;
let Audio1 = new Audio("a.wav")
// function to generate random number
function random(min, max) {
const num = Math.floor(Math.random() * (max - min + 1)) + min;
return num;
}
class Shape {
constructor(x, y, velX, velY, size, color, exists) {
this.x = x;
this.y = y;
this.velX = velX;
this.velY = velY;
this.color = color;
this.size = size;
this.exists = exists;
}
}
class Ball extends Shape {
constructor(x, y, velX, velY, size, color, exists) {
super(x, y, velX, velY, size, color, exists)
}
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;
}
collisionDetect() {
for (let j = 0; j < balls.length; j++) {
if (!(this === balls[j]) && balls[j].exists) {
const dx = this.x - balls[j].x;
const dy = this.y - balls[j].y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < this.size + balls[j].size) {
balls[j].color = 'rgb(' + random(0, 255) + ',' + random(0, 255) + ',' + random(0, 255) + ')';
this.color = 'rgb(' + random(0, 255) + ',' + random(0, 255) + ',' + random(0, 255) + ')';
this.velX = -(this.velX) + 1;
this.velY = -(this.velY);
balls[j].velX = (balls[j].velX);
balls[j].velY = (balls[j].velY)
}
}
}
}
}
let balls = [];
let i = balls.length;
for (i = 0; i < 10; i++) {
let size = random(2, 10);
let ball = new Ball(
// ball position always drawn at least one ball width
// away from the edge of the canvas, to avoid drawing errors
random(0 + size, width - size),
random(0 + size, height - size),
random(-9, 9),
random(-9, 9),
size,
'rgb(' + random(0, 255) + ',' + random(0, 255) + ',' + random(0, 255) + ')', true
);
balls.push(ball);
}
let dir = -10;
var pctOpen = 100;
class EvilCircle extends Shape {
constructor(x, y, velX, velY, size) {
super(x, y, velX, velY, size)
}
draw(pctOpen) {
// Convert percent open to a float
var fltOpen = pctOpen / 100;
// An arc which stops at a specific percent to allow for the
// open mouth to be drawn
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, (fltOpen * 0.2) * Math.PI, (2 - fltOpen * 0.2) * Math.PI);
// The line leading back to the center and then closing the
// path to finish the open mouth.
ctx.lineTo(this.x, this.y);
ctx.closePath();
// Fill pacman's head yellow
ctx.fillStyle = "#FF0";
ctx.fill();
// Outline the head
ctx.strokeStyle = '#000';
ctx.stroke();
// A circle for the eye
var angle = Math.PI * (0.3 + fltOpen * 0.2),
xDelta = (this.x + (this.size / 4)),
yDelta = (this.y - (this.size / 2));
ctx.beginPath();
ctx.arc(xDelta, yDelta, this.size / 5, 0, 2 * Math.PI);
ctx.fillStyle = "#000";
ctx.fill();
// Outline the eye
ctx.strokeStyle = '#FFF';
ctx.stroke();
}
checkBounds() {
if ((this.x + this.size) >= width) {
this.x = width - this.size;
}
if ((this.x - this.size) <= 0) {
this.x = this.size;
}
if ((this.y + this.size) >= height) {
this.y = height - this.size;
}
if ((this.y - this.size) <= 0) {
this.y = this.size;
}
}
setControls() {
this.x = window.event.clientX;
this.y = window.event.clientY;
}
setControls2() {
this.x = Touch.clientX;
this.y = Touch.clientY;
}
collisionDetect() {
for (let j = 0; j < balls.length; j++) {
if (!(this === balls[j]) && balls[j].exists) {
const dx = this.x - balls[j].x;
const dy = this.y - balls[j].y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < this.size + balls[j].size) {
balls[j].exists = false;
this.size += balls[j].size;
balls.splice(j, 1);
Audio1.play()
}
}
}
}
}
let EvilCircle1 = new EvilCircle(15, 15, 10, 10, 10);
document.querySelector('canvas').onmousemove = function () { EvilCircle1.setControls() };
document.querySelector('canvas').addEventListener("touchstart", EvilCircle1.setControls2())
document.querySelector('canvas').addEventListener("touchmove", EvilCircle1.setControls2())
document.querySelector('canvas').addEventListener("touchend", EvilCircle1.setControls2())
function loop() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.25)';
ctx.fillRect(0, 0, width, height);
for (let i = 0; i < balls.length; i++) {
balls[i].draw();
balls[i].update();
balls[i].collisionDetect();
}
EvilCircle1.draw(pctOpen += dir);
if (pctOpen % 100 == 0) {
dir = -dir;
}
EvilCircle1.checkBounds();
EvilCircle1.collisionDetect()
requestAnimationFrame(loop);
}
loop();
html, body {
margin: 0;
cursor: none;
}
html {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
height: 100%;
}
body {
overflow: hidden;
height: inherit;
}
h1 {
font-size: 22;
letter-spacing: -1px;
position: absolute;
margin: 0;
top: 20px;
left: 42.5%;
color: white;
}
<!DOCTYPE html>
<html>
<head>
<link rel="shortcut icon" href="#">
<meta charset="utf-8">
<title>Bouncing balls</title>
<link rel="stylesheet" href="egee.css">
</head>
<body>
<h1>Are you high?</h1>
<canvas></canvas>
<script src="eg.js"></script>
</body>
</html>
This:
document.querySelector('canvas').addEventListener("touchstart", EvilCircle1.setControls2())
Is calling the value returned by EvilCircle1.setControls(), not the function. You should instead be using:
document.querySelector('canvas').addEventListener("touchstart", EvilCircle1.setControls2)
// setup canvas
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const width = canvas.width = window.innerWidth;
const height = canvas.height = window.innerHeight;
let Audio1 = new Audio("a.wav")
// function to generate random number
function random(min, max) {
const num = Math.floor(Math.random() * (max - min + 1)) + min;
return num;
}
class Shape {
constructor(x, y, velX, velY, size, color, exists) {
this.x = x;
this.y = y;
this.velX = velX;
this.velY = velY;
this.color = color;
this.size = size;
this.exists = exists;
}
}
class Ball extends Shape {
constructor(x, y, velX, velY, size, color, exists) {
super(x, y, velX, velY, size, color, exists)
}
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;
}
collisionDetect() {
for (let j = 0; j < balls.length; j++) {
if (!(this === balls[j]) && balls[j].exists) {
const dx = this.x - balls[j].x;
const dy = this.y - balls[j].y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < this.size + balls[j].size) {
balls[j].color = 'rgb(' + random(0, 255) + ',' + random(0, 255) + ',' + random(0, 255) + ')';
this.color = 'rgb(' + random(0, 255) + ',' + random(0, 255) + ',' + random(0, 255) + ')';
this.velX = -(this.velX) + 1;
this.velY = -(this.velY);
balls[j].velX = (balls[j].velX);
balls[j].velY = (balls[j].velY)
}
}
}
}
}
let balls = [];
let i = balls.length;
for (i = 0; i < 10; i++) {
let size = random(2, 10);
let ball = new Ball(
// ball position always drawn at least one ball width
// away from the edge of the canvas, to avoid drawing errors
random(0 + size, width - size),
random(0 + size, height - size),
random(-9, 9),
random(-9, 9),
size,
'rgb(' + random(0, 255) + ',' + random(0, 255) + ',' + random(0, 255) + ')', true
);
balls.push(ball);
}
let dir = -10;
var pctOpen = 100;
class EvilCircle extends Shape {
constructor(x, y, velX, velY, size) {
super(x, y, velX, velY, size)
}
draw(pctOpen) {
// Convert percent open to a float
var fltOpen = pctOpen / 100;
// An arc which stops at a specific percent to allow for the
// open mouth to be drawn
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, (fltOpen * 0.2) * Math.PI, (2 - fltOpen * 0.2) * Math.PI);
// The line leading back to the center and then closing the
// path to finish the open mouth.
ctx.lineTo(this.x, this.y);
ctx.closePath();
// Fill pacman's head yellow
ctx.fillStyle = "#FF0";
ctx.fill();
// Outline the head
ctx.strokeStyle = '#000';
ctx.stroke();
// A circle for the eye
var angle = Math.PI * (0.3 + fltOpen * 0.2),
xDelta = (this.x + (this.size / 4)),
yDelta = (this.y - (this.size / 2));
ctx.beginPath();
ctx.arc(xDelta, yDelta, this.size / 5, 0, 2 * Math.PI);
ctx.fillStyle = "#000";
ctx.fill();
// Outline the eye
ctx.strokeStyle = '#FFF';
ctx.stroke();
}
checkBounds() {
if ((this.x + this.size) >= width) {
this.x = width - this.size;
}
if ((this.x - this.size) <= 0) {
this.x = this.size;
}
if ((this.y + this.size) >= height) {
this.y = height - this.size;
}
if ((this.y - this.size) <= 0) {
this.y = this.size;
}
}
setControls() {
this.x = window.event.clientX;
this.y = window.event.clientY;
}
setControls2() {
this.x = Touch.clientX;
this.y = Touch.clientY;
}
collisionDetect() {
for (let j = 0; j < balls.length; j++) {
if (!(this === balls[j]) && balls[j].exists) {
const dx = this.x - balls[j].x;
const dy = this.y - balls[j].y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < this.size + balls[j].size) {
balls[j].exists = false;
this.size += balls[j].size;
balls.splice(j, 1);
Audio1.play()
}
}
}
}
}
let EvilCircle1 = new EvilCircle(15, 15, 10, 10, 10);
document.querySelector('canvas').onmousemove = function() {
EvilCircle1.setControls()
};
document.querySelector('canvas').addEventListener("touchstart", EvilCircle1.setControls2)
document.querySelector('canvas').addEventListener("touchmove", EvilCircle1.setControls2)
document.querySelector('canvas').addEventListener("touchend", EvilCircle1.setControls2)
function loop() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.25)';
ctx.fillRect(0, 0, width, height);
for (let i = 0; i < balls.length; i++) {
balls[i].draw();
balls[i].update();
balls[i].collisionDetect();
}
EvilCircle1.draw(pctOpen += dir);
if (pctOpen % 100 == 0) {
dir = -dir;
}
EvilCircle1.checkBounds();
EvilCircle1.collisionDetect()
requestAnimationFrame(loop);
}
loop();
html,
body {
margin: 0;
cursor: none;
}
html {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
height: 100%;
}
body {
overflow: hidden;
height: inherit;
}
h1 {
font-size: 22;
letter-spacing: -1px;
position: absolute;
margin: 0;
top: 20px;
left: 42.5%;
color: white;
}
<!DOCTYPE html>
<html>
<head>
<link rel="shortcut icon" href="#">
<meta charset="utf-8">
<title>Bouncing balls</title>
<link rel="stylesheet" href="egee.css">
</head>
<body>
<h1>Are you high?</h1>
<canvas></canvas>
<script src="eg.js"></script>
</body>
</html>
Related
I have created a full demonstration of the problem I'm experiencing below:
const rng = (min, max) => Math.random() * (max - min + 1) + min;
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.strokeStyle = "#000";
ctx.lineWidth = 4;
ctx.fillStyle = "#ff0000";
function drawCircle(c) {
ctx.beginPath();
ctx.arc(c.x, c.y, c.r, 0, 2 * Math.PI);
ctx.stroke();
ctx.fill();
}
class Circle {
constructor(x, y, r) {
this.x = x;
this.y = y;
this.r = r;
this.vX = 0;
this.vY = 0;
}
}
const circles = [];
for (let i = 0; i < 300; i++) {
circles.push(new Circle(rng(0, canvas.width), rng(0, canvas.height), rng(12, 14)));
}
function processCollision(c1, c2) {
const deltaX = c2.x - c1.x;
const deltaY = c2.y - c1.y;
const sumRadius = c1.r + c2.r;
const centerDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (centerDistance === 0 || centerDistance > sumRadius) { return; } // not colliding
const circleDistance = centerDistance - sumRadius;
const aX = deltaX / centerDistance;
const aY = deltaY / centerDistance;
const force = 5;
c1.vX += aX * circleDistance * force;
c1.vY += aY * circleDistance * force;
}
function update() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (const c of circles) {
c.vX = (canvas.width / 2) - c.x; // move towards center x
c.vY = (canvas.height / 2) - c.y; // move towards center y
}
for (const c1 of circles) {
for (const c2 of circles) {
c1 !== c2 && processCollision(c1, c2);
}
}
for (const c of circles) {
c.x += c.vX * (1 / 60);
c.y += c.vY * (1 / 60);
drawCircle(c);
}
}
setInterval(update, 16.6666);
<canvas width="600" height="600" style="border:1px solid #d3d3d3;">
Notice how all the circles gravitate around the center. However, they are all heavily colliding with one another. I would like to modify the processCollision function such that the circles no longer significantly overlap one another and instead are roughly evenly spread around the center point.
I tried increasing the force variable, but unfortunately while this does indeed cause greater spread, it also creates lot of shaky and jerky movement. The solution must be smooth, similar to the example above. I have been messing with this for weeks but unfortunately cannot seem to come to a solution.
This seems to behave the way you probably want (or close to it)... It uses a control theory model combined with a physics model, and one needs to tweak the constants k0, k1, strength, buffer, step_size...
const rng = (min, max) => Math.random() * (max - min + 1) + min;
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
ctx.strokeStyle = '#000';
ctx.lineWidth = 4;
ctx.fillStyle = '#ff0000';
const k0 = 1.5;
const k1 = 5;
const strength = 1000000;
const buffer = 2;
class Disc {
constructor(x, y, r) {
this.x = x;
this.y = y;
this.r = r;
this.vX = 0;
this.vY = 0;
return;
}
drawDisc(ctx) {
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI);
ctx.stroke();
ctx.fill();
return;
}
addVelocity(step_size) {
this.x = this.x + step_size * this.vX;
this.y = this.y + step_size * this.vY;
return;
}
addAcceleration(aX, aY, step_size) {
this.vX = this.vX + step_size * aX;
this.vY = this.vY + step_size * aY;
return;
}
applyCentralAcceleration(step_size) {
const accelX = -k1 * this.vX - k0 * (this.x - canvas.width / 2);
const accelY = -k1 * this.vY - k0 * (this.y - canvas.height / 2);
this.addAcceleration(accelX, accelY, step_size);
return;
}
applyInteractionAcceleration(that, step_size) {
let dX = this.x - that.x;
let dY = this.y - that.y;
const dist = dX * dX + dY * dY;
const magnitude = strength / (dist - (this.r + buffer + that.r) ** 2) ** 2;
dX = magnitude * dX;
dY = magnitude * dY;
this.addAcceleration(dX, dY, step_size);
return;
}
}
class System {
constructor(numDiscs) {
this.n = numDiscs;
this.discs = [];
for (let i = 0; i < numDiscs; i++) {
this.discs.push(
new Disc(rng(0, canvas.width), rng(0, canvas.height), rng(6, 7))
);
}
return;
}
applyCentralAcceleration(step_size) {
for (let i = 0; i < this.n; i++) {
this.discs[i].applyCentralAcceleration(step_size);
}
}
applyInteractionAcceleration(step_size) {
for (let i = 0; i < this.n; i++) {
for (let j = 0; j < this.n; j++) {
if (i === j) {
continue;
}
this.discs[i].applyInteractionAcceleration(this.discs[j], step_size);
}
}
}
applyVelocity(step_size) {
for (let i = 0; i < this.n; i++) {
this.discs[i].addVelocity(step_size);
}
}
updateSystemState(step_size) {
this.applyCentralAcceleration(step_size);
this.applyInteractionAcceleration(step_size);
this.applyVelocity(step_size);
return;
}
drawSystemDiscs() {
for (let i = 0; i < this.n; i++) {
this.discs[i].drawDisc(ctx);
}
}
}
systemOfDiscs = new System(50);
function update() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
const step_size = 1 / 100;
systemOfDiscs.updateSystemState(step_size);
systemOfDiscs.drawSystemDiscs();
return;
}
setInterval(update, 16.6666);
<canvas width="300" height="300" style="border: 1px solid #d3d3d3"></canvas>
Here's my code:
<!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>Johnny's Potential Homepage</title>
<style type="text/css">
#font-face {
font-family: Abel Regular;
src: url("fonts/Abel-Regular.ttf");
}
body {
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="text/javascript">
class Circle {
constructor(x, y, radius) {
this.x = x;
this.y = y;
this.destinationX = x;
this.destinationY = y;
this.originalRadius = radius;
this.radius = radius/2;
this.contentAlpha = 0;
this.displayDelay = 50;
this.displayDelayTicker = 0;
}
update() {
var offset = Math.sqrt(Math.sqrt(Math.pow(this.x-mouseX, 2)+(Math.pow(this.y-mouseY, 2))));
var angle = -Math.atan2(this.x-mouseX, this.y-mouseY) - Math.PI/2;
this.destinationX = canvas.width / 2 + offset * Math.cos(angle);
this.destinationY = canvas.height / 2 + offset * Math.sin(angle);
this.fixCollisions();
this.x += (this.destinationX - this.x) / 10;
this.y += (this.destinationY - this.y) / 10;
this.radius += (this.originalRadius - this.radius) / 10;
if (this.displayDelayTicker >= this.displayDelay) {
this.contentAlpha += (1 - this.contentAlpha) / 10;
}
this.displayDelayTicker = Math.min(this.displayDelay, this.displayDelayTicker+1);
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI*2);
ctx.fillStyle = "#000";
ctx.filter = "blur(120px)";
ctx.fill();
ctx.filter = "blur(0px)";
ctx.fillStyle = "rgba(0, 0, 0, 0.8)";
ctx.fill();
}
fixCollisions() {
for (var i = 0; i < circles.length; i++) {
if (circles[i] != this) {
var angle = getAngle([this.x, this.y], [circles[i].x, circles[i].y]);
var dist = ((this.radius + circles[i].radius)/2 + padding);
// Distribute
this.destinationX += Math.cos(-angle) * dist;
this.destinationY += Math.sin(-angle) * dist;
}
}
}
}
class Centerpiece extends Circle {
constructor(x, y, radius) {
super(x, y, radius);
this.time = 0;
this.readTime = "";
this.readSeconds = "";
}
update() {
super.update();
var date = new Date();
var destTime = date.getHours()*3600 + date.getMinutes()*60 + date.getSeconds();
if (this.displayDelayTicker >= this.displayDelay) {
this.time += (destTime - this.time) / 10;
}
var hours = Math.floor(this.time / 3600);
if (hours > 12) {
hours -= 12;
}
var minutes = (this.time/60) % 60;
minutes = Math.floor(minutes);
if (minutes < 10) {
minutes = "0" + minutes;
}
var seconds = (this.time) % 60;
seconds = Math.floor(seconds);
if (seconds < 10) {
seconds = "0" + seconds;
}
this.readTime = hours + ":" + minutes;
this.readSeconds = seconds;
}
draw() {
super.draw();
ctx.font = "14px Abel Regular";
var secondsWidth = ctx.measureText(this.readSeconds).width;
ctx.font = "21px Abel Regular";
var timeWidth = ctx.measureText(this.readTime).width;
ctx.textAlign = "center";
ctx.fillStyle = "rgba(255, 255, 255, " + this.contentAlpha + ")";
ctx.fillText(this.readTime, this.x - secondsWidth/2 -1, this.y);
ctx.font = "14px Abel Regular";
ctx.fillText(this.readSeconds, this.x + timeWidth/2 + 1, this.y);
}
}
var canvas = document.getElementById("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var ctx = canvas.getContext("2d");
var circles = [];
var mouseX = canvas.width/2;
var mouseY = canvas.height/2;
var scale = 1.0;
var scrollAmount = 0;
var padding = Math.sqrt(getDistance([0, 0], [canvas.width/2, canvas.height/2]));
circles.push(new Centerpiece(canvas.width/2, canvas.height/2, 120));
circles.push(new Centerpiece(canvas.width/2, canvas.height/2, 100));
circles.push(new Centerpiece(canvas.width/2, canvas.height/2, 80));
circles.push(new Centerpiece(canvas.width/2, canvas.height/2, 90));
window.onresize = function() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var padding = Math.sqrt(getDistance([0, 0], [canvas.width/2, canvas.height/2])) + 10;
}
window.onmousemove = function(e) {
mouseX = e.clientX;
mouseY = e.clientY;
}
window.onwheel = function(e) {
scrollAmount -= Math.min(Math.max(-0.5, e.deltaY), 0.5);
scale = (Math.log10(Math.min(2, Math.max(0.5, scrollAmount + 1)))) + 1;
console.log(scrollAmount + " " + scale);
}
function getDistance(a, b) {
return (Math.sqrt((b[0]-a[0])*(b[0]-a[0])-(b[1]-a[1])*(b[1]-a[1])));
}
function getAngle(a, b) {
return Math.atan2(b[1] - a[1], b[0] - a[0]);
}
function loop() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < circles.length; i++) {
circles[i].update();
}
for (var i = 0; i < circles.length; i++) {
circles[i].draw();
}
requestAnimationFrame(loop);
}
loop();
</script>
</body>
</html>
My goal is to have the circles "glob" together in the middle, yet not collide. Take a look at the fixCollisions() function and see if there's a way to update things so the circles spread evenly across the x and y axis.
Also, I'm not sure why it bugs out at the beginning.
I think this does what you need, if I understood correctly. I commented out some lines and changed some others. I removed the mouse following part because I did not get to fix that and it causes a problem by resetting the position of the blobs every time it updates.
Then I changed the way the blobs are made to be attracted to each other but not allowing them to overlap.
I also simplified the way the sines and cosines are calculated. You don't actually need to first find the angle and the take the cosine and sine of the angle since you already have these when dividing the x and y displacements by the distance. That is in actual fact dividing the opposite and the adjacent sides by the hypotenuse, which is actually the definition of a sine and cosine.
<!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>Johnny's Potential Homepage</title>
<style type="text/css">
#font-face {
font-family: Abel Regular;
src: url("fonts/Abel-Regular.ttf");
}
body {
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="text/javascript">
class Circle {
constructor(x, y, radius) {
this.x = x;
this.y = y;
this.destinationX = x;
this.destinationY = y;
this.originalRadius = radius;
this.radius = radius/2;
this.contentAlpha = 0;
this.displayDelay = 50;
this.displayDelayTicker = 0;
}
update() {
var offset = Math.sqrt(Math.sqrt(Math.pow(this.x-mouseX, 2)+(Math.pow(this.y-mouseY, 2))));
var angle = -Math.atan2(this.x-mouseX, this.y-mouseY) - Math.PI/2;
//this.destinationX = canvas.width / 2 + offset * Math.cos(angle);
//this.destinationY = canvas.height / 2 + offset * Math.sin(angle);
this.fixCollisions();
this.x += (this.destinationX - this.x) / 10;
this.y += (this.destinationY - this.y) / 10;
// removed this.radius += (this.originalRadius - this.radius) / 10;
// changed
this.x += Math.min( 1 * ( canvas.width / 2 - this.x ),1 );
this.y += Math.min( 1 * ( canvas.height / 2 - this.y ),1 );
if (this.displayDelayTicker >= this.displayDelay) {
this.contentAlpha += (1 - this.contentAlpha) / 10;
}
this.displayDelayTicker = Math.min(this.displayDelay, this.displayDelayTicker+1);
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI*2);
ctx.fillStyle = "#000";
ctx.filter = "blur(120px)";
ctx.fill();
ctx.filter = "blur(0px)";
ctx.fillStyle = "rgba(0, 0, 0, 0.8)";
ctx.fill();
}
fixCollisions() {
for (var i = 0; i < circles.length; i++)
{
if (circles[i] != this) {
//var angle = getAngle([this.x, this.y], [circles[i].x, circles[i].y]);
//var dist = ((this.radius + circles[i].radius)/2 + padding);
var minDist = ((this.radius + circles[i].radius));
var dist = Math.sqrt( (this.x-circles[i].x)*(this.x-circles[i].x) + (this.y-circles[i].y)*(this.y-circles[i].y) )
// Distribute
if ( dist < minDist) // overlapping so push away
{
this.destinationX += 100 * (( this.x - circles[i].x) / minDist ) / ( dist + 1 );
this.destinationY += 100 * (( this.y - circles[i].y) / minDist ) / ( dist + 1 );
}
if ( dist > minDist) // overlapping so push away
{
this.destinationX += -0.001 * (( this.x - circles[i].x) / minDist ) * dist;
this.destinationY += -0.001 * (( this.y - circles[i].y) / minDist ) * dist;
}
}
}
}
}
class Centerpiece extends Circle {
constructor(x, y, radius) {
super(x, y, radius);
this.time = 0;
this.readTime = "";
this.readSeconds = "";
}
update() {
super.update();
var date = new Date();
var destTime = date.getHours()*3600 + date.getMinutes()*60 + date.getSeconds();
if (this.displayDelayTicker >= this.displayDelay) {
this.time += (destTime - this.time) / 10;
}
var hours = Math.floor(this.time / 3600);
if (hours > 12) {
hours -= 12;
}
var minutes = (this.time/60) % 60;
minutes = Math.floor(minutes);
if (minutes < 10) {
minutes = "0" + minutes;
}
var seconds = (this.time) % 60;
seconds = Math.floor(seconds);
if (seconds < 10) {
seconds = "0" + seconds;
}
this.readTime = hours + ":" + minutes;
this.readSeconds = seconds;
}
draw() {
super.draw();
ctx.font = "14px Abel Regular";
var secondsWidth = ctx.measureText(this.readSeconds).width;
ctx.font = "21px Abel Regular";
var timeWidth = ctx.measureText(this.readTime).width;
ctx.textAlign = "center";
ctx.fillStyle = "rgba(255, 255, 255, " + this.contentAlpha + ")";
ctx.fillText(this.readTime, this.x - secondsWidth/2 -1, this.y);
ctx.font = "14px Abel Regular";
ctx.fillText(this.readSeconds, this.x + timeWidth/2 + 1, this.y);
}
}
var canvas = document.getElementById("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var ctx = canvas.getContext("2d");
var circles = [];
var mouseX = canvas.width/2;
var mouseY = canvas.height/2;
var scale = 1.0;
var scrollAmount = 0;
var padding = Math.sqrt(getDistance([0, 0], [canvas.width/2, canvas.height/2]));
circles.push(new Centerpiece(0.27 * canvas.width, 0.67 * canvas.height/2, 120));
circles.push(new Centerpiece(0.98 * canvas.width, 0.23 * canvas.height/2, 100));
circles.push(new Centerpiece(0.46 * canvas.width, 0.15 * canvas.height/2, 80));
circles.push(new Centerpiece(0.37 * canvas.width, 0.29 * canvas.height/2, 90));
window.onresize = function() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var padding = Math.sqrt(getDistance([0, 0], [canvas.width/2, canvas.height/2])) + 10;
}
window.onmousemove = function(e) {
mouseX = e.clientX;
mouseY = e.clientY;
}
window.onwheel = function(e) {
scrollAmount -= Math.min(Math.max(-0.5, e.deltaY), 0.5);
scale = (Math.log10(Math.min(2, Math.max(0.5, scrollAmount + 1)))) + 1;
console.log(scrollAmount + " " + scale);
}
function getDistance(a, b) {
return (Math.sqrt((b[0]-a[0])*(b[0]-a[0])-(b[1]-a[1])*(b[1]-a[1])));
}
function getAngle(a, b) {
return Math.atan2(b[1] - a[1], b[0] - a[0]);
}
function loop() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < circles.length; i++) {
circles[i].update();
}
for (var i = 0; i < circles.length; i++) {
circles[i].draw();
}
requestAnimationFrame(loop);
}
loop();
</script>
</body>
</html>
I'm creating a code where 3 balls will bounce when a button is clicked. I have a code I found in the internet and added the start button but clicking it multiple times speed up the balls. Also, I tried adding a reset button that will clear out the canvas but can't make it work. Sharing both the HTML and JS code.
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const width = canvas.width = 1000;
const height = canvas.height = 500;
ctx.fillStyle = 'grey';
ctx.fillRect(0, 0, width, height);
function random(min, max) {
const num = Math.floor(Math.random() * (max - min + 1)) + min;
return num;
}
function Ball(x, y, velX, velY, color, size) {
this.x = x;
this.y = y;
this.velX = velX;
this.velY = velY;
this.color = color;
this.size = size;
}
Ball.prototype.draw = function() {
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
ctx.fill();
}
Ball.prototype.update = function() {
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 = [];
function loop() {
while (balls.length < 3) {
let size = 35;
let ball = new Ball(
random(0 + size, width - size), random(0 + size, height - size), 5, 5, 'yellow', size);
balls.push(ball);
}
ctx.fillStyle = 'grey';
ctx.fillRect(0, 0, width, height);
for (let i = 0; i < balls.length; i++) {
balls[i].draw();
balls[i].update();
}
requestAnimationFrame(loop);
}
document.getElementById('Begin').addEventListener('click',loop);
<input type='button' id='Begin' value='start'>
<canvas id='myCanvas'></canvas>
You need to store the requestAnimationFrame in a var and use cancelAnimationFrame to stop
I added a div to hold the buttons and now delegate from that div so only one event handler is needed.
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const width = canvas.width = 1000;
const height = canvas.height = 500;
ctx.fillStyle = 'grey';
ctx.fillRect(0, 0, width, height);
let rq; // this we can use to request and cancel
function random(min, max) {
const num = Math.floor(Math.random() * (max - min + 1)) + min;
return num;
}
function Ball(x, y, velX, velY, color, size) {
this.x = x;
this.y = y;
this.velX = velX;
this.velY = velY;
this.color = color;
this.size = size;
}
Ball.prototype.draw = function() {
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
ctx.fill();
}
Ball.prototype.update = function() {
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 = [];
function loop() {
while (balls.length < 3) {
let size = 35;
let ball = new Ball(
random(0 + size, width - size), random(0 + size, height - size), 5, 5, 'yellow', size);
balls.push(ball);
}
ctx.fillStyle = 'grey';
ctx.fillRect(0, 0, width, height);
for (let i = 0; i < balls.length; i++) {
balls[i].draw();
balls[i].update();
}
rq = requestAnimationFrame(loop);
}
document.getElementById('butDiv').addEventListener('click', function(e) {
const tgt = e.target;
if (tgt.id === "Begin") {
if (tgt.value === "start") {
loop()
tgt.value = "stop";
document.getElementById("resetCanvas").classList.add("hide");
} else {
cancelAnimationFrame(rq)
this.value = "start";
document.getElementById("resetCanvas").classList.remove("hide");
}
} else if (tgt.id === "resetCanvas") {
cancelAnimationFrame(rq)
ctx.fillStyle = 'grey';
ctx.fillRect(0, 0, width, height);
document.getElementById("Begin").value="start";
tgt.classList.add("hide");
}
})
.hide {
display: none;
}
<div id="butDiv">
<input type='button' id='Begin' value='start'> <input type='button' class="hide" id='resetCanvas' value='reset'>
</div>
<canvas id='myCanvas'></canvas>
I have run into a problem with my program, which essentially moves 100 figures on a browser window and changes their direction if the user presses a key down. In order to determine if a user has pressed a key, I used an event listener, but the problem is that the event listener only works for two of the figures on the screen. I can only change the direction of two figures, while the other figures continue to move around the screen and not respond to user input. I have attached all of my code below, and I would really appreciate if someone could help me figure out the problem! Thanks!
let canvas = document.querySelector("canvas")
canvas.width = window.innerWidth
canvas.height = window.innerHeight
// console.log(innerWidth)
// console.log(innerHeight)
let c = canvas.getContext("2d")
let changeDirection = undefined
let repeatone = 0
let repeattwo = 0
window.addEventListener('keydown', function(event) {
repeatone = 0
repeattwo = 0
changeDirection = true
console.log(changeDirection)
})
window.addEventListener('keyup', function(event) {
changeDirection = false
console.log(changeDirection);
})
function random_rgba() {
var o = Math.round,
r = Math.random,
s = 255;
return 'rgba(' + o(r() * s) + ',' + o(r() * s) + ',' + o(r() * s) + ',' + r().toFixed(1) + ')';
}
// c.arc(xCircle, yCircle, radius, 0, Math.PI * 2, false)
function Circle(x, y, dx, dy, radius, color) {
this.x = x
this.y = y
this.dx = dx
this.dy = dy
this.radius = radius
this.color = color
this.draw = function() {
// c.strokeStyle = this.color
c.beginPath()
c.strokeStyle = this.color
c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false)
c.stroke()
}
this.update = function() {
repeatone += 1
if (changeDirection === true && repeatone <= 1) {
this.dx = -this.dx
this.dy = -this.dy
if (this.x >= innerWidth - this.radius) {
this.dx = -this.dx
} else if (this.x <= 0) {
this.dx = -this.dx
}
if (this.y >= innerHeight - this.radius) {
this.dy = -this.dy
} else if (this.y <= 0) {
this.dy = -this.dy
}
this.x += this.dx
this.y += this.dy
this.draw()
} else if (changeDirection === false || repeatone > 1) {
if (this.x >= innerWidth - this.radius) {
this.dx = -this.dx
} else if (this.x <= 0) {
this.dx = -this.dx
}
if (this.y >= innerHeight - this.radius) {
this.dy = -this.dy
} else if (this.y <= 0) {
this.dy = -this.dy
}
this.x += this.dx
this.y += this.dy
this.draw()
}
}
}
function Rectangle(x, y, dx, dy, height, width, color) {
this.x = x
this.y = y
this.dx = dx
this.dy = dy
this.height = height
this.width = width
this.color = color
this.draw = function() {
c.beginPath()
c.fillStyle = this.color
c.fillRect(this.x, this.y, this.width, this.height)
}
this.update = function() {
repeattwo += 1
if (changeDirection === true && repeattwo <= 1) {
this.dx = -this.dx
this.dy = -this.dy
if (this.x >= innerWidth - this.width) {
this.dx = -this.dx
} else if (this.x <= 0) {
this.dx = -this.dx
}
if (this.y >= innerHeight - this.height) {
this.dy = -this.dy
} else if (this.y <= 0) {
this.dy = -this.dy
}
this.x += this.dx
this.y += this.dy
this.draw()
} else if (changeDirection === false || repeattwo > 1) {
if (this.x >= innerWidth - this.width) {
this.dx = -this.dx
} else if (this.x <= 0) {
this.dx = -this.dx
}
if (this.y >= innerHeight - this.height) {
this.dy = -this.dy
} else if (this.y <= 0) {
this.dy = -this.dy
}
this.x += this.dx
this.y += this.dy
this.draw()
}
}
}
// let x = Math.floor((Math.random() * innerWidth) + 1)
// let dx = Math.floor((Math.random() * 10) + 1)
// let y = Math.floor((Math.random() * innerHeight) + 1)
// let dy = Math.floor((Math.random() * 10) + 1)
//
// console.log("X Value " + x)
// console.log("Y Value " + y)
// console.log("X Velocity Value " + dx)
// console.log("Y Velocity Value " + dy)
//
let rectangleArray = []
let circleArray = []
for (var i = 0; i < 50; i++) {
let xRect = Math.floor((Math.random() * innerWidth) + 1)
let dxRect = Math.floor((Math.random() * 10) + 1)
let yRect = Math.floor((Math.random() * innerHeight) + 1)
let dyRect = Math.floor((Math.random() * 10) + 1)
let heightRect = Math.floor((Math.random() * 250) + 1)
let widthRect = Math.floor((Math.random() * 250) + 1)
let colorRect = random_rgba()
let xCircle = Math.floor((Math.random() * innerWidth) + 1)
let dxCircle = Math.floor((Math.random() * 10) + 1)
let yCircle = Math.floor((Math.random() * innerHeight) + 1)
let dyCircle = Math.floor((Math.random() * 10) + 1)
let heightCircle = Math.floor((Math.random() * 250) + 1)
let widthCircle = Math.floor((Math.random() * 250) + 1)
let colorCircle = random_rgba()
let radiusCircle = Math.floor((Math.random() * 100) + 1)
rectangleArray.push(new Rectangle(xRect, yRect, dxRect, dyRect, heightRect, widthRect, colorRect))
circleArray.push(new Circle(xCircle, yCircle, dxCircle, dyCircle, radiusCircle, colorCircle))
}
console.log(circleArray)
console.log(rectangleArray)
function animate() {
requestAnimationFrame(animate)
c.clearRect(0, 0, innerWidth, innerHeight)
for (var i = 0; i < rectangleArray.length; i++) {
rectangleArray[i].draw()
rectangleArray[i].update()
}
for (var i = 0; i < circleArray.length; i++) {
circleArray[i].draw()
circleArray[i].update()
}
}
animate()
<canvas></canvas>
You had a lot of code, I remove a lot of it...
Take a look at the new logic under the addEventListener
Troubleshooting cases like this the first thing I do is reduce the scope:
you had 100 figures, I took it down to 6
your animation was too fast, I reduced the speed.
lot's of random stuff on the code that created the figures, I hard-coded some of that.
you had changeDirection, repeatone & repeattwo, I could not figure out what you needed those for so I remove them.
let canvas = document.querySelector("canvas")
canvas.width = canvas.height = innerWidth = innerHeight = 300
let c = canvas.getContext("2d")
window.addEventListener('keydown', function(event) {
for (var i = 0; i < rectangleArray.length; i++) {
rectangleArray[i].dx *= -1
rectangleArray[i].dy *= -1
}
for (var i = 0; i < circleArray.length; i++) {
circleArray[i].dx *= -1
circleArray[i].dy *= -1
}
})
function random_rgba() {
var o = Math.round,
r = Math.random,
s = 255;
return 'rgba(' + o(r() * s) + ',' + o(r() * s) + ',' + o(r() * s) + ',' + r().toFixed(1) + ')';
}
// c.arc(xCircle, yCircle, radius, 0, Math.PI * 2, false)
function Circle(x, y, dx, dy, radius, color) {
this.x = x
this.y = y
this.dx = dx
this.dy = dy
this.radius = radius
this.color = color
this.draw = function() {
// c.strokeStyle = this.color
c.beginPath()
c.strokeStyle = this.color
c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false)
c.stroke()
}
this.update = function() {
if (this.x >= innerWidth - this.radius) {
this.dx = -this.dx
} else if (this.x <= this.radius) {
this.dx = -this.dx
}
if (this.y >= innerHeight - this.radius) {
this.dy = -this.dy
} else if (this.y <= this.radius) {
this.dy = -this.dy
}
this.x += this.dx
this.y += this.dy
this.draw()
}
}
function Rectangle(x, y, dx, dy, height, width, color) {
this.x = x
this.y = y
this.dx = dx
this.dy = dy
this.height = height
this.width = width
this.color = color
this.draw = function() {
c.beginPath()
c.fillStyle = this.color
c.fillRect(this.x, this.y, this.width, this.height)
}
this.update = function() {
if (this.x >= innerWidth - this.width) {
this.dx = -this.dx
} else if (this.x <= 0) {
this.dx = -this.dx
}
if (this.y >= innerHeight - this.height) {
this.dy = -this.dy
} else if (this.y <= 0) {
this.dy = -this.dy
}
this.x += this.dx
this.y += this.dy
this.draw()
}
}
function randSpeed() {
return (Math.random() - 0.5) * 5
}
let rectangleArray = []
let circleArray = []
for (var i = 0; i < 3; i++) {
let heightRect = Math.floor((Math.random() * 100) + 1)
let widthRect = Math.floor((Math.random() * 100) + 1)
rectangleArray.push(new Rectangle(80, 80, randSpeed(), randSpeed(), heightRect, widthRect, random_rgba()))
let radiusCircle = Math.floor((Math.random() * 50) + 1)
circleArray.push(new Circle(80, 80, randSpeed(), randSpeed(), radiusCircle, random_rgba()))
}
function animate() {
requestAnimationFrame(animate)
c.clearRect(0, 0, innerWidth, innerHeight)
for (var i = 0; i < rectangleArray.length; i++) {
rectangleArray[i].draw()
rectangleArray[i].update()
}
for (var i = 0; i < circleArray.length; i++) {
circleArray[i].draw()
circleArray[i].update()
}
}
animate()
<canvas></canvas>
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.