-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathBall.js
150 lines (111 loc) · 3.69 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
function Ball(position, color){
this.position = position;
this.velocity = new Vector2();
this.moving = false;
this.sprite = getBallSpriteByColor(color);
this.color = color;
this.visible = true;
}
Ball.prototype.update = function(delta){
if(!this.visible){
return;
}
this.position.addTo(this.velocity.mult(delta));
// Apply friction
this.velocity = this.velocity.mult(1 - CONSTANTS.frictionEnergyLoss);
if(this.velocity.length() < CONSTANTS.minVelocityLength){
this.velocity = new Vector2();
this.moving = false;
}
}
Ball.prototype.draw = function(){
if(!this.visible){
return;
}
Canvas.drawImage(this.sprite, this.position, CONSTANTS.ballOrigin);
}
Ball.prototype.shoot = function(power, rotation){
this.velocity = new Vector2(power * Math.cos(rotation), power * Math.sin(rotation));
this.moving = true;
}
Ball.prototype.collideWithBall = function(ball){
if(!this.visible || !ball.visible){
return;
}
// Find a normal vector
const n = this.position.subtract(ball.position);
// Find distance
const dist = n.length();
if(dist > CONSTANTS.ballDiameter){
return;
}
// Find minimum translation distance
const mtd = n.mult((CONSTANTS.ballDiameter - dist) / dist);
// Push-pull balls apart
this.position = this.position.add(mtd.mult(1/2));
ball.position = ball.position.subtract(mtd.mult(1/2));
// Find unit normal vector
const un = n.mult(1/n.length());
// Find unit tangent vector
const ut = new Vector2(-un.y, un.x);
// Project velocities onto the unit normal and unit tangent vectors
const v1n = un.dot(this.velocity);
const v1t = ut.dot(this.velocity);
const v2n = un.dot(ball.velocity);
const v2t = ut.dot(ball.velocity);
// Find new normal velocities
let v1nTag = v2n;
let v2nTag = v1n;
// Convert the scalar normal and tangential velocities into vectors
v1nTag = un.mult(v1nTag);
const v1tTag = ut.mult(v1t);
v2nTag = un.mult(v2nTag);
const v2tTag = ut.mult(v2t);
// Update velocities
this.velocity = v1nTag.add(v1tTag);
ball.velocity = v2nTag.add(v2tTag);
this.moving = true;
ball.moving = true;
}
Ball.prototype.handleBallInPocket = function(){
if(!this.visible){
return;
}
let inPocket = CONSTANTS.pockets.some(pocket => {
return this.position.distFrom(pocket) < CONSTANTS.pocketRadius;
});
if(!inPocket){
return;
}
this.visible = false;
this.moving = false;
}
Ball.prototype.collideWithTable = function(table){
if(!this.moving || !this.visible){
return;
}
let collided = false;
if(this.position.y <= table.TopY + CONSTANTS.ballRadius){
this.position.y = table.TopY + CONSTANTS.ballRadius;
this.velocity = new Vector2(this.velocity.x, -this.velocity.y);
collided = true;
}
if(this.position.x >= table.RightX - CONSTANTS.ballRadius){
this.position.x = table.RightX - CONSTANTS.ballRadius;
this.velocity = new Vector2(-this.velocity.x, this.velocity.y);
collided = true;
}
if(this.position.y >= table.BottomY - CONSTANTS.ballRadius){
this.position.y = table.BottomY - CONSTANTS.ballRadius;
this.velocity = new Vector2(this.velocity.x, -this.velocity.y);
collided = true;
}
if(this.position.x <= table.LeftX + CONSTANTS.ballRadius){
this.position.x = table.LeftX + CONSTANTS.ballRadius;
this.velocity = new Vector2(-this.velocity.x, this.velocity.y);
collided = true;
}
if(collided){
this.velocity = this.velocity.mult(1 - CONSTANTS.collisionEnergyLoss);
}
}