I try to create reverse gravity, and I have an issue after I click several times on the button "physics" : it is supposed to restart with the default values, but after 10 times, the balls go too fast and I don't understand why. The function works fine the first time, but then it starts to accelerate each time you click on "physics".
https://codepen.io/Arthur222/pen/QWOgMXq
let isOn = 0;
let canvas = document.getElementById("canvas");
if (canvas.getContext('2d') == null ) alert("erreur javascript");
let ctx = canvas.getContext('2d');
let velocity=1, force=1, mass = 1, radius=30;
let lastTs;
//FCN
window.addEventListener('load', ()=>{
resize();
window.addEventListener('resize', resize);
createBalls();
drawBalls();
});
// PHYSICS
let balls = [];
function createBalls(){
for ( let i=0; i<6; i ){
let x = radius (i*radius*2);
if (i>0) x = radius (i*(radius 10)*2);
let vel = Math.random();
let ball = {x:x, y:250, xBase:x, yBase:250, velocity:vel, velocityBase:vel, radius:30, active:true}
balls.push(ball);
}
}
function startPhy1(){
if (isOn == 1){
console.log("canvas.width, canvas.height : " canvas.width, canvas.height);
ctx.clearRect(0,0,canvas.width, canvas.height);
balls.forEach(element => {
element.y = element.yBase;
element.active = true;
element.velocity = element.velocityBase;
});
}
isOn = 1;
lastTs = getTimestamp();
runPhy();
draw();
}
function runPhy(){
let t = (getTimestamp() - lastTs)/1000;
balls.forEach(element => {
if ( element.active ){ //still below
element.y -= element.velocity * t;
element.velocity = ( force / mass ) * t;
if ( element.y <= element.radius 10 ){//already on top
element.active = false;
element.y = element.radius;//stay on top
}
}
});
requestAnimationFrame(runPhy);
}
function getTimestamp() {
return new Date().getTime();
}
// DRAW
function draw(){
drawBalls();
requestAnimationFrame(draw);
}
function drawBalls(){
ctx.clearRect(0,0,canvas.width, canvas.height);
for (let i=0; i< balls.length; i ){
ctx.beginPath();
ctx.arc(balls[i].x, balls[i].y, balls[i].radius, 0, 2 * Math.PI, false);
ctx.strokeStyle = "green";
ctx.lineWidth = 2;
ctx.stroke();
}
}
function resize(){
ctx.canvas.width = window.innerWidth*0.7;
ctx.canvas.height = window.innerHeight*0.9;
}
CodePudding user response:
I think the problem with your code is that you are requesting the animation frame every time that the button is clicked.
I tried fixing your code without success, that's why I coded this one. Try it:
const canvas = document.getElementById('root')
const btn = document.getElementById('btn')
const ctx = canvas.getContext('2d')
const circleImage = new Image()
circleImage.src = 'https://i.stack.imgur.com/CdziF.png'
var piece = {
image: circleImage,
x: 100,
y: 250,
width: 50
}
var speed = 0
var max = 10
function gameLoop(){
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.drawImage(piece.image, piece.x, piece.y)
speed < max ? speed = 0.1 : null
if(piece.y > 0){
piece.y -= speed
piece.y < 0 ? piece.y = 0 : null // Position correction
}
window.requestAnimationFrame(gameLoop) // Needed to keep looping
}
function start(){
if(btn.value === 'start'){
btn.value = 'restart'
circleImage.onload = window.requestAnimationFrame(gameLoop) // Start gameLoop()
}
if(btn.value === 'restart'){
speed = 0
piece.y = 250
}
}
btn.addEventListener('click', start) // When btn is clicked execute start()
<input id="btn" type="button" value="start" />
<p>
<canvas id="root" height="300" width="300" style="border:1px solid grey">
And see here what happens when the request animation frame is requested everytime the a button is clicked:
const canvas = document.getElementById('root')
const btn = document.getElementById('btn')
const ctx = canvas.getContext('2d')
const circleImage = new Image()
circleImage.src = 'https://i.stack.imgur.com/CdziF.png'
var piece = {
image: circleImage,
x: 100,
y: 250,
width: 50
}
var speed = 0
var max = 10
function gameLoop(){
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.drawImage(piece.image, piece.x, piece.y)
speed < max ? speed = 0.1 : null
if(piece.y > 0){
piece.y -= speed
piece.y < 0 ? piece.y = 0 : null // Position correction
}
window.requestAnimationFrame(gameLoop) // Needed to keep looping
}
function start(){
if(btn.value === 'start'){
speed = 0
piece.y = 250
circleImage.onload = window.requestAnimationFrame(gameLoop) // Start gameLoop()
}
}
btn.addEventListener('click', start) // When btn is clicked execute start()
<input id="btn" type="button" value="start" />
<p>
<canvas id="root" height="300" width="300" style="border:1px solid grey">