-
Notifications
You must be signed in to change notification settings - Fork 0
/
Ball.js
156 lines (126 loc) · 4.01 KB
/
Ball.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import Vector from './Vector.js';
function Ball(x, y, radius, dx, dy, color) {
var self = this;
self.position = new Vector(x, y);
self.radius = radius;
self.mass = mass(radius, 1);
self.velocity = new Vector(dx, dy);
self.color = color;
self.bounds = bounds;
self.plot = plot;
self.tick = tick;
self.resolveRectangleCollision = resolveRectangleCollision;
self.isColliding = isColliding;
self.resolveBallCollision = resolveBallCollision;
self.isBallColliding = isBallColliding;
self.resolveBallIntersection = resolveBallIntersection;
self.resolveBallCollisionVelocities = resolveBallCollisionVelocities;
function mass(radius, density) {
var volume = 4 * Math.PI * radius * radius * radius / 3;
return volume * density;
}
function bounds() {
return {
x0: this.position.x - this.radius,
y0: this.position.y - this.radius,
x1: this.position.x + this.radius,
y1: this.position.y + this.radius
};
}
function plot(context) {
context.fillStyle = this.color;
context.beginPath();
context.ellipse(this.position.x, this.position.y, this.radius, this.radius, 0, 0, 2 * Math.PI);
context.fill();
}
function tick(dt) {
this.position.x += this.velocity.x * dt;
this.position.y += this.velocity.y * dt;
}
function resolveRectangleCollision(rectangle) {
var bounds = this.bounds();
var rectangleBounds = {
x0: rectangle.x,
y0: rectangle.y,
x1: rectangle.x + rectangle.width,
y1: rectangle.y + rectangle.height
};
if (bounds.x0 < rectangleBounds.x0) {
this.velocity.x = -this.velocity.x;
this.position.x += rectangleBounds.x0 - bounds.x0;
}
if (bounds.x1 > rectangleBounds.x1) {
this.velocity.x = -this.velocity.x;
this.position.x += rectangleBounds.x1 - bounds.x1;
}
if (bounds.y0 < rectangleBounds.y0) {
this.velocity.y = -this.velocity.y;
this.position.y += rectangleBounds.y0 - bounds.y0;
}
if (bounds.y1 > rectangleBounds.y1) {
this.velocity.y = -this.velocity.y;
this.position.y += rectangleBounds.y1 - bounds.y1;
}
}
function isColliding(objectBounds) {
var bounds = this.bounds();
return bounds.x0 < objectBounds.x1
&& bounds.x1 > objectBounds.x0
&& bounds.y0 < objectBounds.y1
&& bounds.y1 > objectBounds.y0;
}
function resolveBallCollision(ball) {
if (!this.isBallColliding(ball)) {
return;
}
// backtrack to point of collision
var dt = this.resolveBallIntersection(ball);
// calculate new velocities after collision
this.resolveBallCollisionVelocities(ball);
// forward by amount backtracked when resolving intersection
this.tick(-dt);
ball.tick(-dt);
}
function isBallColliding(ball) {
if (!this.isColliding(ball.bounds())) {
return false;
}
var d = this.position.sub(ball.position);
return d.mod() <= this.radius + ball.radius;
}
function resolveBallIntersection(ball) {
// solving |p2 - p1| = r1 + r2 for t
var dp = this.position.sub(ball.position);
var dv = this.velocity.sub(ball.velocity);
var r = this.radius + ball.radius;
// gives quadratic
var a = dv.dot();
var b = 2 * dp.dot(dv);
var c = dp.dot() - r * r;
// with earliest t
var t = (-b - Math.sqrt(b * b - 4 * a * c)) / (2 * a);
// backtrack to point of intersection
this.tick(t);
ball.tick(t);
return t;
}
function resolveBallCollisionVelocities(ball) {
// obtain unit vector in direction of collision
var d = this.position.sub(ball.position).unit();
// calculate velocity components in direction of collision
// reduces problem to one dimension
var u1 = this.velocity.dot(d);
var u2 = ball.velocity.dot(d);
// calculate new velocity components in direction of collision
// using conservation of momentum and conservation of kenetic energy
var m1 = this.mass;
var m2 = ball.mass;
var m = m1 + m2;
var v1 = (m1 - m2) * u1 / m + (2 * m2 * u2) / m;
var v2 = (2 * m1 * u1) / m + (m2 - m1) * u2 / m;
// apply change in velocity
this.velocity = this.velocity.add(d.scale(v1 - u1));
ball.velocity = ball.velocity.add(d.scale(v2 - u2));
}
}
export default Ball;