-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
123 lines (104 loc) · 3.19 KB
/
index.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
import { Renderer2D, Vector2, BoundingBox, rand } from "./chaos.module.js"
import { Client } from "./src/client.js"
import { QuadTree, HashGrid, AabbTree, renderObj } from "./src/index.js"
let entityCount = 30
const GRID_NUMBER = 20
const renderer = new Renderer2D()
renderer.setViewport(innerWidth, innerHeight)
renderer.play()
renderer.bindTo("#can")
const canvasBound = new BoundingBox(
20, 20,
renderer.width - 20, renderer.height - 20
)
const bound = new BoundingBox(0, 0, renderer.width + 20, renderer.height + 20)
const spartialStructures = {
"Quad Tree": new QuadTree(bound, 3),
"AABB Tree": new AabbTree(),
"Hash Grid": new HashGrid(
renderer.width / GRID_NUMBER, renderer.height / GRID_NUMBER,
GRID_NUMBER,
GRID_NUMBER,
new Vector2(0, 0)
)
}
initSelection()
function initSelection() {
const selection = document.createElement("select")
selection.id = "options"
for (const name in spartialStructures) {
const opt = document.createElement("option")
opt.innerHTML = name
opt.value = name
selection.append(opt)
}
selection.onchange = (event) => {
const struct = spartialStructures[event.target.value]
demoGrid(struct, renderer, entityCount)
}
for (const name in spartialStructures) {
const struct = spartialStructures[name]
demoGrid(struct, renderer, entityCount)
break
}
document.body.append(selection)
}
function demoGrid(grid, renderer, number = 10) {
renderer.objects = []
const [velocity, bounds, clients] = createObjs(renderer.width - 100, renderer.height - 100, 50, 50, number)
renderer.add({
render(ctx) {
translate_bound(bounds, i => [velocity[i].x, velocity[i].y])
bounceoff(canvasBound, velocity, bounds)
grid.update(clients, bounds)
const collided = grid.getCollisionPairs(checker, clients)
.flatMap(e => [bounds[e.a], bounds[e.b]])
grid.draw(ctx)
ctx.strokeStyle = "white"
bounds.forEach(b => renderObj(ctx, b))
ctx.strokeStyle = "red"
//we are actually redrawing more than
//twice if the object is involved in
//more than one collision but it doesn't
//matter in a test.
collided.forEach(b => renderObj(ctx, b))
}
})
function checker(a, b) {
if (bounds[a.value].intersects(bounds[b.value])) return {
a: a.value,
b: b.value
}
return null
}
}
function createObjs(x, y, w, h, no) {
const map = [[], [], []]
for (let i = 0; i < no; i++) {
const nx = rand(100, x)
const ny = rand(100, y)
map[0].push(new Vector2(rand(-5, 5), rand(-5, 5)))
map[1].push(new BoundingBox(nx - w / 2, ny - h / 2, nx + w / 2, ny + h / 2))
map[2].push(new Client(map[0].length - 1, null))
}
return map
}
function translate_bound(bounds, func) {
for (let i = 0; i < bounds.length; i++) {
const [x, y] = func(i)
bounds[i].translate(
new Vector2(
x,
y
)
)
}
}
function bounceoff(bound, velocity, bounds) {
for (let i = 0; i < bounds.length; i++) {
if (bounds[i].min.x < bound.min.x || bounds[i].max.x > bound.max.x)
velocity[i].x = -velocity[i].x
if (bounds[i].min.y < bound.min.y || bounds[i].max.y > bound.max.y)
velocity[i].y = -velocity[i].y
}
}