Skip to content

Commit d1a42b8

Browse files
完成ch11/04的改写,但是无法解决误差累积的问题
1 parent 0f478ae commit d1a42b8

File tree

1 file changed

+168
-0
lines changed

1 file changed

+168
-0
lines changed
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<title>Bobbing 1</title>
6+
<link rel="stylesheet" href="../include/style.css">
7+
<style type="text/css">
8+
#canvas {
9+
background: #fff;
10+
}
11+
</style>
12+
</head>
13+
<body>
14+
<header>
15+
Example from <a href="http://amzn.com/1430236655?tag=html5anim-20"><em>Foundation HTML5 Animation with JavaScript</em></a>
16+
</header>
17+
<canvas id="canvas" width="400" height="400"></canvas>
18+
19+
<script type="module">
20+
import Ball from './classes/ball.js'
21+
22+
window.onload = function () {
23+
const canvas = document.getElementById('canvas'),
24+
context = canvas.getContext('2d'),
25+
{width, height} = canvas,
26+
centerPointY = height / 2,
27+
ballA = new Ball(80),
28+
ballB = new Ball(40),
29+
bouncing = -1.0;
30+
31+
ballA.mass = 2;
32+
ballA.x = canvas.width - 200;
33+
ballA.y = canvas.height - 200;
34+
ballA.vx = 5;
35+
ballA.vy = 5;
36+
37+
ballB.mass = 1;
38+
ballB.x = 100;
39+
ballB.y = 100;
40+
ballB.vx = 5;
41+
ballB.vy = 5;
42+
43+
const minDist = ballA.radius + ballB.radius;
44+
45+
function checkBoundary(ball) {
46+
const {x, y, radius} = ball;
47+
48+
if (x - radius < 0) {
49+
ball.x = radius;
50+
ball.vx *= bouncing;
51+
} else if (x + radius > width) {
52+
ball.x = width - radius;
53+
ball.vx *= bouncing;
54+
}
55+
56+
if (y - radius < 0) {
57+
ball.y = radius;
58+
ball.vy *= bouncing;
59+
} else if (y + radius > height) {
60+
ball.y = height - radius;
61+
ball.vy *= bouncing;
62+
}
63+
}
64+
65+
function hitProcess(m0, v0, m1, v1) {
66+
const totalV = v0 - v1;
67+
const v0Final = ((m0 - m1) * v0 + 2 * m1 * v1) /
68+
(m0 + m1);
69+
const v1Final = v0Final + totalV;
70+
71+
return {
72+
v0: v0Final,
73+
v1: v1Final
74+
}
75+
}
76+
77+
function rotate(x, y, sin, cos, reverse = false) {
78+
return {
79+
x: reverse ? (x * cos + y * sin) : (x * cos - y * sin),
80+
y: reverse ? (y * cos - y * sin) : (x * cos + y * sin)
81+
}
82+
}
83+
84+
function hitDetection(ballA, ballB) {
85+
// ballB 相对于 ballA旋转
86+
const dx = ballB.x - ballA.x,
87+
dy = ballB.y - ballA.y,
88+
dist = Math.sqrt(dx * dx + dy * dy);
89+
90+
if (dist >= minDist) {
91+
return;
92+
}
93+
94+
let angle = Math.atan2(dy, dx),
95+
sin = Math.sin(angle),
96+
cos = Math.cos(angle);
97+
98+
// rotate
99+
let posA = {x: 0, y: 0},
100+
posB = rotate(dx, dy, sin, cos, true),
101+
vA = rotate(ballA.vx, ballA.vy, sin, cos, true),
102+
vB = rotate(ballB.vx, ballB.vy, sin, cos, true);
103+
104+
let innerX = minDist - dist;
105+
106+
// make sure hit is just at interface
107+
if (innerX) {
108+
console.log('inner hit')
109+
// vA.x * t + vB.x * t = innerX
110+
// (vA.x + vB.x) * t = innerX;
111+
let t = innerX / (Math.abs(vA.x) + Math.abs(vB.x));
112+
let sA = Math.abs(vA.x * t),
113+
sB = Math.abs(vB.x * t);
114+
115+
posA.x -= sA;
116+
posB.x += sB;
117+
}
118+
119+
// hit
120+
let {v0: vAX, v1: vBX} = hitProcess(ballA.mass, vA.x, ballB.mass, vB.x);
121+
vA.x = vAX;
122+
vB.x = vBX;
123+
124+
// update position
125+
posA.x += vA.x;
126+
posB.x += vB.x;
127+
128+
// rotate position back
129+
let posAFinal = rotate(posA.x, posA.y, sin, cos),
130+
posBFinal = rotate(posB.x, posB.y, sin, cos);
131+
132+
// B先于A计算,避免A的值改动导致B计算不正确
133+
ballB.x = ballA.x + posBFinal.x;
134+
ballB.y = ballA.y + posBFinal.y;
135+
ballA.x = ballA.x + posAFinal.x;
136+
ballA.y = ballA.y + posAFinal.y;
137+
138+
// rotate velocities back
139+
let vAFinal = rotate(vA.x, vA.y, sin, cos),
140+
vBFinal = rotate(vB.x, vB.y, sin, cos);
141+
142+
ballA.vx = vAFinal.x;
143+
ballA.vy = vAFinal.y;
144+
ballB.vx = vBFinal.x;
145+
ballB.vy = vBFinal.y;
146+
}
147+
148+
(function draw(){
149+
window.requestAnimationFrame(draw);
150+
context.clearRect(0, 0, width, height);
151+
152+
ballA.x += ballA.vx;
153+
ballA.y += ballA.vy;
154+
ballB.x += ballB.vx;
155+
ballB.y += ballB.vy;
156+
157+
hitDetection(ballA, ballB);
158+
159+
checkBoundary(ballA);
160+
checkBoundary(ballB);
161+
162+
ballA.draw(context);
163+
ballB.draw(context);
164+
}())
165+
}
166+
</script>
167+
</body>
168+
</html>

0 commit comments

Comments
 (0)