-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathPhysics.js
More file actions
142 lines (132 loc) · 2.95 KB
/
Physics.js
File metadata and controls
142 lines (132 loc) · 2.95 KB
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
/**
*
*/
function Physics(jom)
{
var level_height = 30,
nodes = jom.nodes,
time = 0;
var blockWidth = 70, // width (in pixel) of each block in grid
blockHeight = 50, // height
grid = [],
gridWidth = 0, // number of blocks in horizontal
gridHeight = 0; // vertical
// initialize Grid
gridWidth = Math.ceil(jom.width / blockWidth);
gridHeight = Math.ceil(jom.height / blockHeight);
grid = new Array();
this.grid = grid;
for(var i=0; i< gridWidth * gridHeight; i++)
grid.push(new Object());
/// Private functions
var calGridId = function(x, y) {
// calculate Grid ID for (x,y)
id = (y / blockHeight) * gridWidth + (x / blockWidth);
if(id > gridHeight*gridWidth) id = gridHeight*gridWidth - 1;
if(id < 0) id = 0;
return parseInt(id);
};
var hit = function(a, b) {
// return true if a collides with b
if(a.x + a.width < b.x) return false;
if(b.x + b.width < a.x) return false;
if(a.y + a.height < b.y) return false;
if(b.y + b.height < a.y) return false;
return true;
};
var hitTest = function() {
// separate content into grids, do a hit test between only objects in the same grid
for(var i = 0; i < gridWidth * gridHeight; i++)
{
for(var index in grid[i])
{
for(var index2 in grid[i])
{
if(index == index2) continue;
var a = nodes[index], b = nodes[index2];
if(hit(a, b))
{
var t = Math.random()*0.1;
var ty = Math.random()*0.1;
if(a.x < b.x)
{
a.vx -= t;
b.vx += t;
} else {
a.vx += t;
b.vx -= t;
}
if(a.depth < b.depth)
{
a.vy -= ty;
b.vy += ty;
} else if(a.depth > b.depth)
{
a.vy += ty;
b.vy -= ty;
}
}
}
}
}
};
/// PUBLIC FUNCTIONs
this.simulate = function() {
time++;
// damping
if(time == 5)
{
for(var index in nodes)
{
var n = nodes[index];
n.vy *= 0.8;
n.vx *= 0.8;
}
time = 0;
}
// floating
// global left-right brownian
for(var index in nodes)
{
var n = nodes[index];
// Buoyancy
n.vy += (n.depth*level_height - n.y)*0.001 + (Math.random() * 0.05 - 0.025);
// Brownian with left-right limit
if(n.x < 0)
{
n.vx += 1;
} else if(n.x + n.width > jom.width) {
n.vx += -1;
} else {
n.vx += (Math.random() - 0.5) * 0.25;
}
}
// hit test
hitTest();
for(var index in nodes)
{
// update node position
var n = nodes[index];
n.x += n.vx;
n.y += n.vy;
// update grid membership
var newGridId = calGridId(n.x + n.width/2, n.y + n.height/2);
if('gridId' in n) // node already got gridID, then update
{
// gridID change?
if(n.gridId != newGridId)
{
// remove this node from old grid
delete grid[n.gridId][index];
// add to new grid
grid[newGridId][index] = true;
n.gridId = newGridId;
}
} else {
// add to new grid
grid[newGridId][index] = true;
n.gridId = newGridId;
}
}
};
}