I have the following code which bounces multiple balls along the screen, making use of physics, and the gravity of jupiter divided by 10 for testing purposes.
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext('2d');
//jupiter's gravity divided by 10 for testing purposes
g = 24.79/10;
canvas.width = window.innerWidth - 50;
canvas.height = window.innerHeight - 22.5;
bounciness = (1/2)
var spawnrate = 16;
var inertia = 0.00075;
var gravity = g/25;
players = []
then = new Date()/1000;
moved = false;
function getPosition(event){
mouseX = event.clientX;
mouseY = event.clientY;
if(moved == false){
update();
moved = true;
}
}
function addCircle(){
players.push({x: mouseX, y: mouseY, color: '#000000', radius: 10, velY: 0, velX: 2, jumped: false, jump: 0.02, max: 0});
}
first = new Date();
function update(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
t = new Date() - first;
now = new Date() / 1000;
if(now-then >= 1/spawnrate){
then = now;
addCircle();
}
for(var c = 0; c < players.length; c++){
circle = players[c];
circle.y+=circle.velY;
circle.x+=circle.velX;
circle.velX-=inertia;
circle.velY+=gravity;
if(Math.abs(circle.velY) > Math.abs(circle.max)){
circle.max = circle.velY;
}
if(circle.y + circle.radius/2 > canvas.height){
circle.velY*=-Math.sqrt(bounciness);
}
updateCircle(circle);
if(circle.x > canvas.width){
players.splice(c, 1);
}
}
setTimeout(update, 10);
}
function drawLine(x1, y1, x2, y2){
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
}
function updateCircle(player){
ctx.fillStyle = player.color;
ctx.beginPath();
ctx.arc(player.x, player.y, player.radius, 0, Math.PI * 2);
ctx.fill();
}
window.addEventListener("mousemove", getPosition, false);
if(moved == true){
update();
}
#canvas{
display: block;
}
<!DOCTYPE html>
<html>
<head>
<title>Bounce</title>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
</html>
However, after I move the mouse around, I notice that some of the balls seem to stick to the bottom of the screen.
I have been working on this for the past 8 hours, only to be dumbfounded. The code is relatively simple, so I don't think it's any obvious mistake.
Your problem is the collison detection:
if (circle.y + circle.radius/2 > canvas.height) { circle.velY*=-Math.sqrt(bounciness); }
This just inverts the velocity, but does not adjust the position. Which means that when you drop your balls from certain heights, they can get stuck in the ground - they have entered it by a certain depth, but in the next frame their reduced velocity is no more enough to take them out of the ground, and gets inverted right again taking them a bit deeper in the ground…
You can solve this fairly easy by making sure that their vertical position never gets "negative", or even completely bounce the ball away from the ground:
var inGround = circle.y + circle.radius - canvas.height;
if (inGround >= 0) {
circle.velY *= -Math.sqrt(bounciness);
circle.y -= 2*inGround;
}
Try the updated snippet demo:
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext('2d');
//jupiter's gravity divided by 10 for testing purposes
g = 24.79/10;
canvas.width = window.innerWidth - 50;
canvas.height = window.innerHeight - 22.5;
bounciness = (1/2)
var spawnrate = 16;
var inertia = 0.00075;
var gravity = g/25;
players = []
then = new Date()/1000;
moved = false;
function getPosition(event){
mouseX = event.clientX;
mouseY = event.clientY;
if(moved == false){
update();
moved = true;
}
}
function addCircle(){
players.push({x: mouseX, y: mouseY, color: '#000000', radius: 10, velY: 0, velX: 2, jumped: false, jump: 0.02, max: 0});
}
first = new Date();
function update(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
t = new Date() - first;
now = new Date() / 1000;
if(now-then >= 1/spawnrate){
then = now;
addCircle();
}
for(var c = 0; c < players.length; c++){
circle = players[c];
circle.y+=circle.velY;
circle.x+=circle.velX;
circle.velX-=inertia;
circle.velY+=gravity;
if(Math.abs(circle.velY) > Math.abs(circle.max)){
circle.max = circle.velY;
}
var inGround = circle.y + circle.radius - canvas.height;
if(inGround >= 0){
circle.velY *= -Math.sqrt(bounciness);
circle.y -= 2*inGround;
}
updateCircle(circle);
if(circle.x > canvas.width){
players.splice(c, 1);
}
}
setTimeout(update, 10);
}
function drawLine(x1, y1, x2, y2){
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
}
function updateCircle(player){
ctx.fillStyle = player.color;
ctx.beginPath();
ctx.arc(player.x, player.y, player.radius, 0, Math.PI * 2);
ctx.fill();
}
window.addEventListener("mousemove", getPosition, false);
if(moved == true){
update();
}
#canvas{
display: block;
}
<!DOCTYPE html>
<html>
<head>
<title>Bounce</title>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
</html>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With