-
Notifications
You must be signed in to change notification settings - Fork 0
/
bouncing-ball.html
183 lines (157 loc) · 4.99 KB
/
bouncing-ball.html
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Bouncing Ball</title>
<meta name="description" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="content-frame-styles.css" />
</head>
<body>
<script type="module">
import {
World,
System,
TagComponent
} from "//unpkg.com/[email protected]/build/ecsy.module.js";
// Initialize canvas
let canvas = document.querySelector("canvas");
let canvasWidth = (canvas.width = window.innerWidth);
let canvasHeight = (canvas.height = window.innerHeight);
let ctx = canvas.getContext("2d");
window.addEventListener(
"resize",
() => {
canvasWidth = canvas.width = window.innerWidth;
canvasHeight = canvas.height = window.innerHeight;
},
false
);
//----------------------
// Components
//----------------------
// Velocity component
class Velocity {
constructor() {
this.x = this.y = 0;
}
}
// Position component
class Position {
constructor() {
this.x = this.y = 0;
}
}
// Ball component
class Ball {
constructor() {
this.color = "#000";
this.radius = 30;
}
}
// Renderable component
class Renderable extends TagComponent {}
//----------------------
// Systems
//----------------------
// MovableSystem
class MovableSystem extends System {
// This method will get called on every frame by default
execute(delta, time) {
// Iterate through all the entities on the query
this.queries.moving.results.forEach(entity => {
const velocity = entity.getMutableComponent(Velocity);
const position = entity.getMutableComponent(Position);
const ball = entity.getMutableComponent(Ball);
position.x += velocity.x * delta;
position.y += velocity.y * delta;
if (
position.x + ball.radius > canvasWidth ||
position.x < 0 + ball.radius
) {
velocity.x = velocity.x * -1;
}
if (
position.y + ball.radius > canvasHeight ||
position.y < 0 + ball.radius
) {
velocity.y = velocity.y * -1;
}
});
}
}
// Define a query of entities that have "Velocity" and "Position" components
MovableSystem.queries = {
moving: {
components: [Velocity, Position, Ball]
}
};
// RendererSystem
class RendererSystem extends System {
// This method will get called on every frame by default
execute(delta, time) {
ctx.globalAlpha = 1;
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
// Iterate through all the entities on the query
this.queries.renderables.results.forEach(entity => {
const position = entity.getComponent(Position);
const ball = entity.getMutableComponent(Ball);
// draw circle
ctx.fillStyle = "#000";
ctx.beginPath();
ctx.arc(
position.x,
position.y,
ball.radius,
0,
2 * Math.PI,
false
);
ctx.fill();
});
}
}
// Define a query of entities that have "Renderable" and "Ball" components
RendererSystem.queries = {
renderables: { components: [Renderable, Ball] }
};
// Create world and register the systems on it
const world = new World();
world.registerSystem(MovableSystem).registerSystem(RendererSystem);
// Some helper functions when creating the components
function getRandomVelocity() {
return {
x: 0.5 * (2 * Math.random() - 1),
y: 0.5 * (2 * Math.random() - 1)
};
}
function getRandomPosition() {
return {
x: Math.random() * canvasWidth,
y: Math.random() * canvasHeight
};
}
world
.createEntity()
.addComponent(Velocity, getRandomVelocity())
.addComponent(Ball)
.addComponent(Position, getRandomPosition())
.addComponent(Renderable);
// Run!
function run() {
// Compute delta and elapsed time
const time = performance.now();
const delta = time - lastTime;
// Run all the systems
world.execute(delta, time);
lastTime = time;
requestAnimationFrame(run);
}
let lastTime = performance.now();
run();
</script>
<canvas></canvas>
</body>
</html>