forked from jeromeetienne/threex.colliders
-
Notifications
You must be signed in to change notification settings - Fork 1
/
threex.collidersystem.js
150 lines (131 loc) · 4.6 KB
/
threex.collidersystem.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
var THREEx = THREEx || {}
//////////////////////////////////////////////////////////////////////////////////
// Comment //
//////////////////////////////////////////////////////////////////////////////////
THREEx.ColliderSystem = function(){
//////////////////////////////////////////////////////////////////////////////////
// Comment //
//////////////////////////////////////////////////////////////////////////////////
/**
* compute collisions states and notify events appropriatly
* @param {THREEx.Collider[]} colliders - array of colliders
*/
this.computeAndNotify = function(colliders){
// purge states from the colliders which are no more there
purgeState(colliders)
// compute and notify contacts between colliders
notifyContacts(colliders)
}
//////////////////////////////////////////////////////////////////////////////////
// handle colliding states
//////////////////////////////////////////////////////////////////////////////////
var states = {}
this._states = states
function getStateLabel(collider1, collider2){
if( collider1.id < collider2.id )
var stateLabel = collider1.id + '-' + collider2.id
else
var stateLabel = collider2.id + '-' + collider1.id
return stateLabel
}
//////////////////////////////////////////////////////////////////////////////////
// Comment //
//////////////////////////////////////////////////////////////////////////////////
/**
* purge states
* - go thru all states
* - any states which isnt both in colliders, remove it
* - if only one of both colliders is still present, notify contactRemoved(contactId)
*
* @param {THREE.Collider[]} colliders - base to purge state
*/
function purgeState(colliders){
// remove pending states for removed collider
Object.keys(states).forEach(function(stateLabel){
// get leftColliderId
var leftColliderId = parseInt(stateLabel.match(/^([0-9]+)-/)[1])
var rightColliderId = parseInt(stateLabel.match(/-([0-9]+)$/)[1])
// get colliders based on their id
var leftCollider = findById(colliders, leftColliderId)
var rightCollider = findById(colliders, rightColliderId)
// handle differently depending on their presence
if( leftCollider !== null && rightCollider !== null ){
// both still present, do nothing
return
}else if( leftCollider !== null && rightCollider === null ){
// right collider got removed
leftCollider.dispatchEvent('contactRemoved', rightColliderId)
}else if( leftCollider === null && rightCollider !== null ){
// left collider got removed
rightCollider.dispatchEvent('contactRemoved', leftColliderId)
}else{
// both got removed
}
// update states
delete states[stateLabel]
})
return
function findById(colliders, colliderId){
for( var i = 0; i < colliders.length; i++ ){
if( colliders[i].id === colliderId ){
return colliders[i]
}
}
return null
}
}
//////////////////////////////////////////////////////////////////////////////////
// Comment //
//////////////////////////////////////////////////////////////////////////////////
/**
* Compute the collision and immediatly notify the listener
*
* @param {THREE.Collider[]} colliders - base to purge state
*/
function notifyContacts(colliders){
for(var i = 0; i < colliders.length; i++){
var collider1 = colliders[i]
for(var j = i+1; j < colliders.length; j++){
var collider2 = colliders[j]
// stay if they do collide
var doCollide = collider1.collideWith(collider2)
// get previous state
var stateLabel = getStateLabel(collider1, collider2)
var stateExisted= states[stateLabel] ? true : false
// process depending do Collide
if( doCollide ){
// update states
states[stateLabel] = 'dummy'
// notify proper events
if( stateExisted === true ){
dispatchEvent(collider1, collider2, 'contactStay')
}else{
dispatchEvent(collider1, collider2, 'contactEnter')
}
}else{
// update states
delete states[stateLabel]
// notify proper events
if( stateExisted === true ){
dispatchEvent(collider1, collider2, 'contactExit')
}
}
}
}
// console.log('post notify states', Object.keys(states).length)
return
function dispatchEvent(collider1, collider2, eventName){
// console.log('dispatchEvent', eventName, 'between', collider1.id, 'and', collider2.id)
// send event to collider1
collider1.dispatchEvent(eventName, collider2, collider1)
// send event to collider2
collider2.dispatchEvent(eventName, collider1, collider2)
}
}
/**
* reset the events states
*/
this.reset = function(){
states = {}
}
}