forked from playcanvas/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcomponent.js
More file actions
236 lines (212 loc) · 10.1 KB
/
component.js
File metadata and controls
236 lines (212 loc) · 10.1 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
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
pc.extend(pc, function () {
/**
* @component
* @name pc.CollisionComponent
* @description Create a new CollisionComponent
* @class A collision volume. use this in conjunction with a {@link pc.RigidBodyComponent} to make a collision volume that can be simulated using the physics engine.
* <p>If the {@link pc.Entity} does not have a {@link pc.RigidBodyComponent} then this collision volume will act as a trigger volume. When an entity with a dynamic
* or kinematic body enters or leaves an entity with a trigger volume, both entities will receive trigger events.
* <p>The following table shows all the events that can be fired between two Entities:
* <table class="table table-striped table-condensed">
* <tr><td></td><td><strong>Rigid Body (Static)</strong></td><td><strong>Rigid Body (Dynamic or Kinematic)</strong></td><td><strong>Trigger Volume</strong></td></tr>
* <tr>
* <td><strong>Rigid Body (Static)</strong></td>
* <td>-</td>
* <td><ul class="list-group">
* <li class="list-group-item">contact</li>
* <li class="list-group-item">collisionstart</li>
* <li class="list-group-item">collisionend</li>
* </td>
* <td>-</td>
* </tr>
* <tr>
* <td><strong>Rigid Body (Dynamic or Kinematic)</strong></td>
* <td><ul class="list-group">
* <li class="list-group-item">contact</li>
* <li class="list-group-item">collisionstart</li>
* <li class="list-group-item">collisionend</li>
* </td>
* <td><ul class="list-group">
* <li class="list-group-item">contact</li>
* <li class="list-group-item">collisionstart</li>
* <li class="list-group-item">collisionend</li>
* </td>
* <td><ul class="list-group">
* <li class="list-group-item">triggerenter</li>
* <li class="list-group-item">triggerleave</li>
* </td>
* </tr>
* <tr>
* <td><strong>Trigger Volume</strong></td>
* <td>-</td>
* <td><ul class="list-group">
* <li class="list-group-item">triggerenter</li>
* <li class="list-group-item">triggerleave</li>
* </td>
* <td>-</td>
* </tr>
* </table>
* </p>
* @param {pc.CollisionComponentSystem} system The ComponentSystem that created this Component
* @param {pc.Entity} entity The Entity that this Component is attached to.
* @property {String} type The type of the collision volume. Defaults to 'box'. Can be one of the following:
* <ul>
* <li><strong>box</strong>: A box-shaped collision volume.</li>
* <li><strong>sphere</strong>: A sphere-shaped collision volume.</li>
* <li><strong>capsule</strong>: A capsule-shaped collision volume.</li>
* <li><strong>cylinder</strong>: A cylinder-shaped collision volume.</li>
* <li><strong>mesh</strong>: A collision volume that uses a model asset as its shape.</li>
* </ul>
* @property {pc.Vec3} halfExtents The half-extents of the box-shaped collision volume in the x, y and z axes. Defaults to [0.5, 0.5, 0.5]
* @property {Number} radius The radius of the sphere, capsule or cylinder-shaped collision volumes. Defaults to 0.5
* @property {Number} axis The local space axis with which the capsule or cylinder-shaped collision volume's length is aligned. 0 for X, 1 for Y and 2 for Z. Defaults to 1 (Y-axis).
* @property {Number} height The total height of the capsule or cylinder-shaped collision volume from tip to tip. Defaults to 2.
* @property {pc.Asset} asset The asset for the model of the mesh collision volume - can also be an asset id.
* @property {pc.Model} model The model that is added to the scene graph for the mesh collision volume.
* @extends pc.Component
*/
// Events Documentation
/**
* @event
* @name pc.CollisionComponent#contact
* @description The 'contact' event is fired when a contact occurs between two rigid bodies
* @param {pc.ContactResult} result Details of the contact between the two rigid bodies.
*/
/**
* @event
* @name pc.CollisionComponent#collisionstart
* @description The 'collisionstart' event is fired when two rigid bodies start touching.
* @param {pc.ContactResult} result Details of the contact between the two Entities.
*/
/**
* @event
* @name pc.CollisionComponent#collisionend
* @description The 'collisionend' event is fired two rigid-bodies stop touching.
* @param {pc.Entity} other The {@link pc.Entity} that stopped touching this collision volume.
*/
/**
* @event
* @name pc.CollisionComponent#triggerenter
* @description The 'triggerenter' event is fired when a rigid body enters a trigger volume.
* a {@link pc.RigidBodyComponent} attached.
* @param {pc.Entity} other The {@link pc.Entity} that entered this collision volume.
*/
/**
* @event
* @name pc.CollisionComponent#triggerleave
* @description The 'triggerleave' event is fired when a rigid body exits a trigger volume.
* a {@link pc.RigidBodyComponent} attached.
* @param {pc.Entity} other The {@link pc.Entity} that exited this collision volume.
*/
var CollisionComponent = function CollisionComponent (system, entity) {
this.on('set_type', this.onSetType, this);
this.on('set_halfExtents', this.onSetHalfExtents, this);
this.on('set_radius', this.onSetRadius, this);
this.on('set_height', this.onSetHeight, this);
this.on('set_axis', this.onSetAxis, this);
this.on("set_asset", this.onSetAsset, this);
this.on("set_model", this.onSetModel, this);
};
CollisionComponent = pc.inherits(CollisionComponent, pc.Component);
pc.extend(CollisionComponent.prototype, {
onSetType: function (name, oldValue, newValue) {
if (oldValue !== newValue) {
this.system.changeType(this, oldValue, newValue);
}
},
onSetHalfExtents: function (name, oldValue, newValue) {
if (this.data.initialized && this.data.type === 'box') {
this.system.recreatePhysicalShapes(this);
}
},
onSetRadius: function (name, oldValue, newValue) {
if (this.data.initialized && (this.data.type === 'sphere' || this.data.type === 'capsule' || this.data.type === 'cylinder')) {
this.system.recreatePhysicalShapes(this);
}
},
onSetHeight: function (name, oldValue, newValue) {
if (this.data.initialized && (this.data.type === 'capsule' || this.data.type === 'cylinder')) {
this.system.recreatePhysicalShapes(this);
}
},
onSetAxis: function (name, oldValue, newValue) {
if (this.data.initialized && (this.data.type === 'capsule' || this.data.type === 'cylinder')) {
this.system.recreatePhysicalShapes(this);
}
},
onSetAsset: function (name, oldValue, newValue) {
var asset;
var assets = this.system.app.assets;
if (oldValue) {
// Remove old listeners
asset = assets.get(oldValue);
if (asset) {
asset.off('remove', this.onAssetRemoved, this);
}
}
if (newValue) {
if (newValue instanceof pc.Asset) {
this.data.asset = newValue.id;
}
asset = assets.get(this.data.asset);
if (asset) {
// make sure we don't subscribe twice
asset.off('remove', this.onAssetRemoved, this);
asset.on('remove', this.onAssetRemoved, this);
}
}
if (this.data.initialized && this.data.type === 'mesh') {
if (! newValue) {
// if asset is null set model to null
// so that it's going to be removed from the simulation
this.data.model = null;
}
this.system.recreatePhysicalShapes(this);
}
},
onSetModel: function (name, oldValue, newValue) {
if (this.data.initialized && this.data.type === 'mesh') {
// recreate physical shapes skipping loading the model
// from the 'asset' as the model passed in newValue might
// have been created procedurally
this.system.implementations.mesh.doRecreatePhysicalShape(this);
}
},
onAssetRemoved: function (asset) {
asset.off('remove', this.onAssetRemoved, this);
if (this.data.asset === asset.id) {
this.asset = null;
}
},
onEnable: function () {
CollisionComponent._super.onEnable.call(this);
if (this.data.type === 'mesh' && this.data.asset && this.data.initialized) {
var asset = this.system.app.assets.get(this.data.asset);
// recreate the collision shape if the model asset is not loaded
// or the shape does not exist
if (asset && (!asset.resource || !this.data.shape)) {
this.system.recreatePhysicalShapes(this);
return;
}
}
if (this.entity.trigger) {
this.entity.trigger.enable();
} else if (this.entity.rigidbody) {
if (this.entity.rigidbody.enabled) {
this.entity.rigidbody.enableSimulation();
}
}
},
onDisable: function () {
CollisionComponent._super.onDisable.call(this);
if (this.entity.trigger) {
this.entity.trigger.disable();
} else if (this.entity.rigidbody) {
this.entity.rigidbody.disableSimulation();
}
}
});
return {
CollisionComponent: CollisionComponent
};
}());