碰撞弹球2.0,小球点击后四处迸射,因为球更小,没有设置为消失,模拟得更真实,观察得可以更全面。
代码:
<!DOCTYPE html>
<html>
<head>
<title>Bouncing Balls 2.0</title>
<style>
body {
margin: 0;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
window.onload = function(){
alert("click anywhere to spawn a ball.")
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
canvas.width = innerWidth;
canvas.height = innerHeight;
circles = [];
gravity = 0.4;
maxGravity = 100;
bounceReduce = 0.5;
document.addEventListener("click", (e) => {
x = e.x;
y = e.y;
circles.push(new Projectile(x, y, 5));
});
class Projectile{
constructor(x, y, s){
this.x = x;
this.y = y;
this.s = s;
this.gX = Math.floor(Math.random()*20-10);
this.gY = Math.floor(Math.random()*15-15);
}
draw(){
ctx.beginPath();
ctx.fillStyle = "rgb(255,255,255)";
ctx.arc(this.x, this.y, this.s, 0, Math.PI*2);
ctx.fill();
ctx.closePath();
}
update(){
this.x += this.gX;
this.y += this.gY;
}
gravity(){
if (this.y < canvas.height - this.s){
if (this.gY <= maxGravity){
this.gY += gravity;
}
}
else{
this.y = canvas.height - this.s
if (this.gY > bounceReduce){
this.gY = (this.gY*bounceReduce) * -1;
}
else {
this.gY = 0;
}
}
if (this.x < 0 + this.s){
this.x = 0 + this.s;
this.gX = (this.gX/2) * -1;
}
else if (this.x > canvas.width - this.s){
this.x = canvas.width - this.s
this.gX = (this.gX/2) * -1;
}
if (this.gX >= .3){
this.gX -= .01;
}
else if (this.gX <= -.3){
this.gX += .01;
}
else {
this.gX = 0;
}
}
}
function main(){
ctx.beginPath();
ctx.fillStyle = "rgba(0,0,0,0.3)";
ctx.rect(0,0,canvas.width,canvas.height);
ctx.fill();
ctx.closePath();
circles.forEach((circle, index) => {
circle.gravity();
circle.update();
circle.draw();
if (circle.s <= .1){
circles.splice(index, 1)
}
});
requestAnimationFrame(main);
}
main();
}
</script>
</body>
</html>
核心逻辑:
gravity() 方法是 Projectile 类中的一个重要方法,用于模拟球体受到重力的影响。下面是对该方法的解释:
1. 功能
gravity() 方法模拟了球体在重力作用下的运动,包括向下加速、碰撞检测以及反弹效果。
2. 详细解释
- 如果球体的垂直位置 y 小于画布的高度减去球体半径 this.s,说明球体还没有触底,则继续受到重力的作用,垂直速度 this.gY 逐渐增加,即 this.gY += gravity;。
- 如果球体触底(即 y 大于等于画布的高度减去球体半径),则将球体的垂直位置设为画布底部,并且给球体一个向上的速度,即 this.gY = (this.gY * bounceReduce) * -1;,其中 bounceReduce 是一个反弹系数,用于模拟碰撞时的能量损失。
- 如果球体触到画布的左右边界,即 x 小于等于 0 或大于等于画布的宽度减去球体半径,那么球体将被限制在边界内,速度将被减小,同时方向改变,即 this.gX = (this.gX/2) * -1;。
- 最后,根据球体的水平速度 this.gX 的大小调整水平方向的速度,以模拟球体运动时逐渐减速的效果。
3. 注意事项
- 在球体触底时,需要检查球体的垂直速度,如果速度小于某个阈值(例如 1),则说明球体已经停止运动,此时应该停止给球体施加重力,避免无限制地进行反弹。
- 在球体触底时,可以逐渐减小球体的垂直速度,以模拟摩擦或能量损失的效果。
视频演示:
碰撞弹球2.0