-
-
Notifications
You must be signed in to change notification settings - Fork 215
Expand file tree
/
Copy pathsrc_engineObject.js.html
More file actions
534 lines (476 loc) · 46.8 KB
/
src_engineObject.js.html
File metadata and controls
534 lines (476 loc) · 46.8 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
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
<!DOCTYPE html><html lang="en" style="font-size:16px"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="./static/favicon.png"><meta name="description" content="LittleJS is a lightweight HTML5 game engine with fast WebGL rendering, physics, particles, sound, and more!"><meta name="keywords" content="javascript, game engine, html5, webgl, 2d, game development, indie games"><meta name="author" content="Frank Force"><meta property="og:title" content="LittleJS - The Tiny JavaScript Game Engine"><meta property="og:description" content="Lightweight HTML5 game engine with WebGL rendering, physics, and sound"><meta property="og:type" content="website"><title>Source: src/engineObject.js</title><!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]--><script src="scripts/third-party/hljs.js" defer="defer"></script><script src="scripts/third-party/hljs-line-num.js" defer="defer"></script><script src="scripts/third-party/popper.js" defer="defer"></script><script src="scripts/third-party/tippy.js" defer="defer"></script><script src="scripts/third-party/tocbot.min.js"></script><script>var baseURL="/",locationPathname="";baseURL=(baseURL=(baseURL="https://killedbyapixel.github.io/LittleJS/docs/").replace(/https?:\/\//i,"")).substr(baseURL.indexOf("/"))</script><link rel="stylesheet" href="styles/clean-jsdoc-theme.min.css"><svg aria-hidden="true" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:none"><defs><symbol id="copy-icon" viewbox="0 0 488.3 488.3"><g><path d="M314.25,85.4h-227c-21.3,0-38.6,17.3-38.6,38.6v325.7c0,21.3,17.3,38.6,38.6,38.6h227c21.3,0,38.6-17.3,38.6-38.6V124 C352.75,102.7,335.45,85.4,314.25,85.4z M325.75,449.6c0,6.4-5.2,11.6-11.6,11.6h-227c-6.4,0-11.6-5.2-11.6-11.6V124 c0-6.4,5.2-11.6,11.6-11.6h227c6.4,0,11.6,5.2,11.6,11.6V449.6z"/><path d="M401.05,0h-227c-21.3,0-38.6,17.3-38.6,38.6c0,7.5,6,13.5,13.5,13.5s13.5-6,13.5-13.5c0-6.4,5.2-11.6,11.6-11.6h227 c6.4,0,11.6,5.2,11.6,11.6v325.7c0,6.4-5.2,11.6-11.6,11.6c-7.5,0-13.5,6-13.5,13.5s6,13.5,13.5,13.5c21.3,0,38.6-17.3,38.6-38.6 V38.6C439.65,17.3,422.35,0,401.05,0z"/></g></symbol><symbol id="search-icon" viewBox="0 0 512 512"><g><g><path d="M225.474,0C101.151,0,0,101.151,0,225.474c0,124.33,101.151,225.474,225.474,225.474 c124.33,0,225.474-101.144,225.474-225.474C450.948,101.151,349.804,0,225.474,0z M225.474,409.323 c-101.373,0-183.848-82.475-183.848-183.848S124.101,41.626,225.474,41.626s183.848,82.475,183.848,183.848 S326.847,409.323,225.474,409.323z"/></g></g><g><g><path d="M505.902,476.472L386.574,357.144c-8.131-8.131-21.299-8.131-29.43,0c-8.131,8.124-8.131,21.306,0,29.43l119.328,119.328 c4.065,4.065,9.387,6.098,14.715,6.098c5.321,0,10.649-2.033,14.715-6.098C514.033,497.778,514.033,484.596,505.902,476.472z"/></g></g></symbol><symbol id="font-size-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11.246 15H4.754l-2 5H.6L7 4h2l6.4 16h-2.154l-2-5zm-.8-2L8 6.885 5.554 13h4.892zM21 12.535V12h2v8h-2v-.535a4 4 0 1 1 0-6.93zM19 18a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></symbol><symbol id="add-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z"/></symbol><symbol id="minus-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M5 11h14v2H5z"/></symbol><symbol id="dark-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2h.1A6.979 6.979 0 0 0 10 7zm-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938 7.999 7.999 0 0 0 4 12z"/></symbol><symbol id="light-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z"/></symbol><symbol id="reset-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M18.537 19.567A9.961 9.961 0 0 1 12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10c0 2.136-.67 4.116-1.81 5.74L17 12h3a8 8 0 1 0-2.46 5.772l.997 1.795z"/></symbol><symbol id="down-icon" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M12.7803 6.21967C13.0732 6.51256 13.0732 6.98744 12.7803 7.28033L8.53033 11.5303C8.23744 11.8232 7.76256 11.8232 7.46967 11.5303L3.21967 7.28033C2.92678 6.98744 2.92678 6.51256 3.21967 6.21967C3.51256 5.92678 3.98744 5.92678 4.28033 6.21967L8 9.93934L11.7197 6.21967C12.0126 5.92678 12.4874 5.92678 12.7803 6.21967Z"></path></symbol><symbol id="codepen-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M16.5 13.202L13 15.535v3.596L19.197 15 16.5 13.202zM14.697 12L12 10.202 9.303 12 12 13.798 14.697 12zM20 10.869L18.303 12 20 13.131V10.87zM19.197 9L13 4.869v3.596l3.5 2.333L19.197 9zM7.5 10.798L11 8.465V4.869L4.803 9 7.5 10.798zM4.803 15L11 19.131v-3.596l-3.5-2.333L4.803 15zM4 13.131L5.697 12 4 10.869v2.262zM2 9a1 1 0 0 1 .445-.832l9-6a1 1 0 0 1 1.11 0l9 6A1 1 0 0 1 22 9v6a1 1 0 0 1-.445.832l-9 6a1 1 0 0 1-1.11 0l-9-6A1 1 0 0 1 2 15V9z"/></symbol><symbol id="close-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></symbol><symbol id="menu-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M3 4h18v2H3V4zm0 7h18v2H3v-2zm0 7h18v2H3v-2z"/></symbol></defs></svg></head><body data-theme="dark"><div class="sidebar-container"><div class="sidebar" id="sidebar"><a href="/" class="sidebar-title sidebar-title-anchor">LittleJS - The Tiny JavaScript Game Engine That Can!</a><div class="sidebar-items-container"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-classes"><div>Classes</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="Audio.Sound.html">Sound</a></div><div class="sidebar-section-children"><a href="Audio.SoundInstance.html">SoundInstance</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dDistanceJoint.html">Box2dDistanceJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dFrictionJoint.html">Box2dFrictionJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dGearJoint.html">Box2dGearJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dJoint.html">Box2dJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dKinematicObject.html">Box2dKinematicObject</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dMotorJoint.html">Box2dMotorJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dObject.html">Box2dObject</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dPinJoint.html">Box2dPinJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dPlugin.html">Box2dPlugin</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dPrismaticJoint.html">Box2dPrismaticJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dPulleyJoint.html">Box2dPulleyJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dRevoluteJoint.html">Box2dRevoluteJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dRopeJoint.html">Box2dRopeJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dStaticObject.html">Box2dStaticObject</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dTargetJoint.html">Box2dTargetJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dTileLayer.html">Box2dTileLayer</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dWeldJoint.html">Box2dWeldJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dWheelJoint.html">Box2dWheelJoint</a></div><div class="sidebar-section-children"><a href="Box2dRaycastResult.html">Box2dRaycastResult</a></div><div class="sidebar-section-children"><a href="Draw.FontImage.html">FontImage</a></div><div class="sidebar-section-children"><a href="Draw.TextureInfo.html">TextureInfo</a></div><div class="sidebar-section-children"><a href="Draw.TileInfo.html">TileInfo</a></div><div class="sidebar-section-children"><a href="Engine.Color.html">Color</a></div><div class="sidebar-section-children"><a href="Engine.EngineObject.html">EngineObject</a></div><div class="sidebar-section-children"><a href="Engine.RandomGenerator.html">RandomGenerator</a></div><div class="sidebar-section-children"><a href="Engine.Timer.html">Timer</a></div><div class="sidebar-section-children"><a href="Engine.Vector2.html">Vector2</a></div><div class="sidebar-section-children"><a href="Medals.Medal.html">Medal</a></div><div class="sidebar-section-children"><a href="Newgrounds.NewgroundsMedal.html">NewgroundsMedal</a></div><div class="sidebar-section-children"><a href="Newgrounds.NewgroundsPlugin.html">NewgroundsPlugin</a></div><div class="sidebar-section-children"><a href="Particles.Particle.html">Particle</a></div><div class="sidebar-section-children"><a href="Particles.ParticleEmitter.html">ParticleEmitter</a></div><div class="sidebar-section-children"><a href="PostProcess.PostProcessPlugin.html">PostProcessPlugin</a></div><div class="sidebar-section-children"><a href="TileLayers.CanvasLayer.html">CanvasLayer</a></div><div class="sidebar-section-children"><a href="TileLayers.TileCollisionLayer.html">TileCollisionLayer</a></div><div class="sidebar-section-children"><a href="TileLayers.TileLayer.html">TileLayer</a></div><div class="sidebar-section-children"><a href="TileLayers.TileLayerData.html">TileLayerData</a></div><div class="sidebar-section-children"><a href="UISystem.UIButton.html">UIButton</a></div><div class="sidebar-section-children"><a href="UISystem.UICheckbox.html">UICheckbox</a></div><div class="sidebar-section-children"><a href="UISystem.UIObject.html">UIObject</a></div><div class="sidebar-section-children"><a href="UISystem.UIScrollbar.html">UIScrollbar</a></div><div class="sidebar-section-children"><a href="UISystem.UISystemPlugin.html">UISystemPlugin</a></div><div class="sidebar-section-children"><a href="UISystem.UIText.html">UIText</a></div><div class="sidebar-section-children"><a href="UISystem.UITile.html">UITile</a></div><div class="sidebar-section-children"><a href="UISystem.UIVideo.html">UIVideo</a></div><div class="sidebar-section-children"><a href="ZzFXM.ZzFXMusic.html">ZzFXMusic</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-namespaces"><div>Namespaces</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="Audio.html">Audio</a></div><div class="sidebar-section-children"><a href="Box2D.html">Box2D</a></div><div class="sidebar-section-children"><a href="Debug.html">Debug</a></div><div class="sidebar-section-children"><a href="Draw.html">Draw</a></div><div class="sidebar-section-children"><a href="DrawUtilities.html">DrawUtilities</a></div><div class="sidebar-section-children"><a href="Engine.html">Engine</a></div><div class="sidebar-section-children"><a href="Input.html">Input</a></div><div class="sidebar-section-children"><a href="Math.html">Math</a></div><div class="sidebar-section-children"><a href="Medals.html">Medals</a></div><div class="sidebar-section-children"><a href="Newgrounds.html">Newgrounds</a></div><div class="sidebar-section-children"><a href="Particles.html">Particles</a></div><div class="sidebar-section-children"><a href="PostProcess.html">PostProcess</a></div><div class="sidebar-section-children"><a href="Random.html">Random</a></div><div class="sidebar-section-children"><a href="Settings.html">Settings</a></div><div class="sidebar-section-children"><a href="TileLayers.html">TileLayers</a></div><div class="sidebar-section-children"><a href="UISystem.html">UISystem</a></div><div class="sidebar-section-children"><a href="Utilities.html">Utilities</a></div><div class="sidebar-section-children"><a href="WebGL.html">WebGL</a></div><div class="sidebar-section-children"><a href="ZzFXM.html">ZzFXM</a></div></div></div></div></div><div class="navbar-container" id="VuAckcnZhf"><nav class="navbar"><div class="navbar-left-items"><div class="navbar-item"><a id="" href="https://github.com/KilledByAPixel/LittleJS" target="_blank">GitHub</a></div><div class="navbar-item"><a id="" href="https://killedbyapixel.github.io/LittleJS/examples/" target="_blank">Examples</a></div><div class="navbar-item"><a id="" href="https://github.com/KilledByAPixel/LittleJS/blob/main/FAQ.md" target="_blank">FAQ</a></div></div><div class="navbar-right-items"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#light-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div><nav></nav></nav></div><div class="toc-container"><div class="toc-content"><span class="bold">On this page</span><div id="eed4d2a0bfd64539bb9df78095dec881"></div></div></div><div class="body-wrapper"><div class="main-content"><div class="main-wrapper"><section id="source-page" class="source-page"><header><h1 id="title" class="has-anchor">src_engineObject.js</h1></header><article><pre class="prettyprint source lang-js"><code>/**
* LittleJS Object System
* - EngineObject is the base class for all game objects
* - Handles automatic updating, rendering, physics, and collision
* - Supports parent-child hierarchies with transform inheritance
* - 2D physics with velocity, acceleration, damping, and gravity
* - Collision system with tiles and other objects
* - Renders sprites from tile sheets with color and rotation
* - Objects sorted by renderOrder for layered rendering
*/
'use strict';
/**
* LittleJS Object Base Object Class
* - Top level object class used by the engine
* - Automatically adds self to object list
* - Will be updated and rendered each frame
* - Renders as a sprite from a tilesheet by default
* - Can have color and additive color applied
* - 2D Physics and collision system
* - Sorted by renderOrder
* - Objects can have children attached
* - Parents are updated before children, and set child transform
* - Call destroy() to get rid of objects
*
* The physics system used by objects is simple and fast with some caveats...
* - Collision uses the axis aligned size, the object's rotation angle is only for rendering
* - Objects are guaranteed to not intersect tile collision from physics
* - If an object starts or is moved inside tile collision, it will not collide with that tile
* - Collision for objects can be set to be solid to block other objects
* - Objects may get pushed into overlapping other solid objects, if so they will push away
* - Solid objects are more performance intensive and should be used sparingly
* @memberof Engine
* @example
* // create an engine object, normally you would first extend the class with your own
* const pos = vec2(2,3);
* const object = new EngineObject(pos);
*/
class EngineObject
{
/** Create an engine object and adds it to the list of objects
* @param {Vector2} [pos=vec2()] - World space position of the object
* @param {Vector2} [size=vec2(1)] - World space size of the object
* @param {TileInfo} [tileInfo] - Tile info to render object (undefined is untextured)
* @param {number} [angle] - Angle the object is rotated by
* @param {Color} [color=WHITE] - Color to apply to tile when rendered
* @param {number} [renderOrder] - Objects sorted by renderOrder before being rendered
*/
constructor(pos=vec2(), size=vec2(1), tileInfo, angle=0, color=WHITE, renderOrder=0)
{
// check passed in params
ASSERT(isVector2(pos), 'object pos must be a vec2');
ASSERT(isVector2(size), 'object size must be a vec2');
ASSERT(!tileInfo || tileInfo instanceof TileInfo, 'object tileInfo should be a TileInfo or undefined');
ASSERT(typeof angle === 'number' && isFinite(angle), 'object angle should be a number');
ASSERT(isColor(color), 'object color should be a valid rgba color');
ASSERT(typeof renderOrder === 'number', 'object renderOrder should be a number');
/** @property {Vector2} - World space position of the object */
this.pos = pos.copy();
/** @property {Vector2} - World space width and height of the object */
this.size = size.copy();
/** @property {Vector2} - Size of object used for drawing, uses size if not set */
this.drawSize = undefined;
/** @property {TileInfo} - Tile info to render object (undefined is untextured) */
this.tileInfo = tileInfo;
/** @property {number} - Angle to rotate the object */
this.angle = angle;
/** @property {Color} - Color to apply when rendered */
this.color = color.copy();
/** @property {Color} - Additive color to apply when rendered */
this.additiveColor = undefined;
/** @property {boolean} - Should it flip along y axis when rendered */
this.mirror = false;
/** @property {boolean} - Has object been destroyed? */
this.destroyed = false;
// physical properties
/** @property {number} - How heavy the object is, static if 0 */
this.mass = objectDefaultMass;
/** @property {number} - How much to slow down velocity each frame (0-1) */
this.damping = objectDefaultDamping;
/** @property {number} - How much to slow down rotation each frame (0-1) */
this.angleDamping = objectDefaultAngleDamping;
/** @property {number} - How bouncy the object is when colliding (0-1) */
this.restitution = objectDefaultRestitution;
/** @property {number} - How much friction to apply when sliding (0-1) */
this.friction = objectDefaultFriction;
/** @property {number} - How much to scale gravity by for this object */
this.gravityScale = 1;
/** @property {number} - Objects are sorted by render order */
this.renderOrder = renderOrder;
/** @property {Vector2} - Velocity of the object */
this.velocity = vec2();
/** @property {number} - Angular velocity of the object */
this.angleVelocity = 0;
/** @property {number} - Track when object was created */
this.spawnTime = time;
/** @property {Array<EngineObject>} - List of children of this object */
this.children = [];
/** @property {boolean} - Limit object speed along x and y axis */
this.clampSpeed = true;
/** @property {EngineObject} - Object we are standing on, if any */
this.groundObject = undefined;
// parent child system
/** @property {EngineObject} - Parent of object if in local space */
this.parent = undefined;
/** @property {Vector2} - Local position if child */
this.localPos = vec2();
/** @property {number} - Local angle if child */
this.localAngle = 0;
// collision flags
/** @property {boolean} - Object collides with the tile collision */
this.collideTiles = false;
/** @property {boolean} - Object collides with solid objects */
this.collideSolidObjects = false;
/** @property {boolean} - Object collides with and blocks other objects */
this.isSolid = false;
/** @property {boolean} - Object collides with raycasts */
this.collideRaycast = false;
// add to list of objects
engineObjects.push(this);
}
/** Update the object transform, called automatically by engine even when paused */
updateTransforms()
{
const parent = this.parent;
if (parent)
{
// copy parent pos/angle
const mirror = parent.getMirrorSign();
this.pos = this.localPos.multiply(vec2(mirror,1)).rotate(parent.angle).add(parent.pos);
this.angle = mirror*this.localAngle + parent.angle;
}
// update children
for (const child of this.children)
child.updateTransforms();
}
/** Update the object physics, called automatically by engine once each frame. Can be overridden to stop or change how physics works for an object. */
updatePhysics()
{
// child objects do not have physics
ASSERT(!this.parent);
if (this.clampSpeed)
{
// limit max speed to prevent missing collisions
this.velocity.x = clamp(this.velocity.x, -objectMaxSpeed, objectMaxSpeed);
this.velocity.y = clamp(this.velocity.y, -objectMaxSpeed, objectMaxSpeed);
}
// apply physics
const oldPos = this.pos.copy();
this.velocity.x *= this.damping;
this.velocity.y *= this.damping;
if (this.mass)
{
// apply gravity only if it has mass
this.velocity.x += gravity.x * this.gravityScale;
this.velocity.y += gravity.y * this.gravityScale;
}
this.pos.x += this.velocity.x;
this.pos.y += this.velocity.y;
this.angle += this.angleVelocity *= this.angleDamping;
// physics sanity checks
ASSERT(this.angleDamping >= 0 && this.angleDamping <= 1);
ASSERT(this.damping >= 0 && this.damping <= 1);
// don't do collision for static objects or if solver disabled
if (!enablePhysicsSolver || !this.mass) return;
const wasFalling = this.velocity.y < 0 && gravity.y < 0 || this.velocity.y > 0 && gravity.y > 0;
if (this.groundObject)
{
// apply friction in local space of ground object
const friction = max(this.friction, this.groundObject.friction);
const groundSpeed = this.groundObject.velocity.x;
this.velocity.x = groundSpeed + (this.velocity.x - groundSpeed) * friction;
this.groundObject = undefined;
}
if (this.collideSolidObjects)
{
// check collisions against solid objects
const epsilon = .001; // necessary to push slightly outside of the collision
for (const o of engineObjectsCollide)
{
// skip destroyed, child objects, or self collision
if (o.destroyed || o.parent || o === this) continue;
// non solid objects don't collide with each other
if (!this.isSolid && !o.isSolid) continue;
// check collision
if (!this.isOverlappingObject(o)) continue;
// notify objects of collision and check if should be resolved
const collide1 = this.collideWithObject(o);
const collide2 = o.collideWithObject(this);
if (!collide1 || !collide2) continue;
if (isOverlapping(oldPos, this.size, o.pos, o.size))
{
// if already was touching, try to push away
const deltaPos = oldPos.subtract(o.pos);
const length = deltaPos.length();
const pushAwayAccel = .001; // push away if already overlapping
const velocity = length < .01 ? randVec2(pushAwayAccel) : deltaPos.scale(pushAwayAccel/length);
this.velocity = this.velocity.add(velocity);
if (o.mass) // push away if not fixed
o.velocity = o.velocity.subtract(velocity);
debugPhysics && debugOverlap(this.pos, this.size, o.pos, o.size, '#f00');
continue;
}
// check for collision
const sizeBoth = this.size.add(o.size);
const smallStepUp = (oldPos.y - o.pos.y)*2 > sizeBoth.y + gravity.y; // prefer to push up if small delta
const isBlockedX = abs(oldPos.y - o.pos.y)*2 < sizeBoth.y;
const isBlockedY = abs(oldPos.x - o.pos.x)*2 < sizeBoth.x;
const restitution = max(this.restitution, o.restitution);
if (smallStepUp || isBlockedY || !isBlockedX) // resolve y collision
{
// push outside object collision
this.pos.y = o.pos.y + (sizeBoth.y/2 + epsilon) * sign(oldPos.y - o.pos.y);
if ((o.groundObject && wasFalling) || !o.mass)
{
// set ground object if landed on something
if (wasFalling)
this.groundObject = o;
// bounce if other object is fixed or grounded
this.velocity.y *= -restitution;
}
else if (o.mass)
{
// inelastic collision
const inelastic = (this.mass * this.velocity.y + o.mass * o.velocity.y) / (this.mass + o.mass);
// elastic collision
const elastic0 = this.velocity.y * (this.mass - o.mass) / (this.mass + o.mass)
+ o.velocity.y * 2 * o.mass / (this.mass + o.mass);
const elastic1 = o.velocity.y * (o.mass - this.mass) / (this.mass + o.mass)
+ this.velocity.y * 2 * this.mass / (this.mass + o.mass);
// lerp between elastic or inelastic based on restitution
this.velocity.y = lerp(inelastic, elastic0, restitution);
o.velocity.y = lerp(inelastic, elastic1, restitution);
}
}
if (!smallStepUp && isBlockedX) // resolve x collision
{
// push outside collision
this.pos.x = o.pos.x + (sizeBoth.x/2 + epsilon) * sign(oldPos.x - o.pos.x);
if (o.mass)
{
// inelastic collision
const inelastic = (this.mass * this.velocity.x + o.mass * o.velocity.x) / (this.mass + o.mass);
// elastic collision
const elastic0 = this.velocity.x * (this.mass - o.mass) / (this.mass + o.mass)
+ o.velocity.x * 2 * o.mass / (this.mass + o.mass);
const elastic1 = o.velocity.x * (o.mass - this.mass) / (this.mass + o.mass)
+ this.velocity.x * 2 * this.mass / (this.mass + o.mass);
// lerp between elastic or inelastic based on restitution
this.velocity.x = lerp(inelastic, elastic0, restitution);
o.velocity.x = lerp(inelastic, elastic1, restitution);
}
else // bounce if other object is fixed
this.velocity.x *= -restitution;
}
debugPhysics && debugOverlap(this.pos, this.size, o.pos, o.size, '#f0f');
}
}
if (this.collideTiles)
{
// check collision against tiles
const hitLayer = tileCollisionTest(this.pos, this.size, this);
if (hitLayer)
{
// if already was stuck in collision, don't do anything
// this should not happen unless something starts in collision
if (!tileCollisionTest(oldPos, this.size, this))
{
// test which side we bounced off (or both if a corner)
const isBlockedX = tileCollisionTest(vec2(this.pos.x, oldPos.y), this.size, this);
const isBlockedY = tileCollisionTest(vec2(oldPos.x, this.pos.y), this.size, this);
const restitution = max(this.restitution, hitLayer.restitution);
if (isBlockedX)
{
// try to move up a tiny bit
const epsilon = 1e-3;
const maxMoveUp = .1;
const y = floor(oldPos.y-this.size.y/2+1) +
this.size.y/2 + epsilon;
const delta = y - this.pos.y;
if (delta < maxMoveUp)
if (!tileCollisionTest(vec2(this.pos.x, y), this.size, this))
{
this.pos.y = y;
debugPhysics && debugRect(this.pos, this.size, '#ff0');
return;
}
// move to previous X position and bounce
this.pos.x = oldPos.x;
this.velocity.x *= -restitution;
}
if (isBlockedY || !isBlockedX)
{
if (wasFalling)
{
// adjust position to slightly away from nearest tile
// this prevents gap between object and ground
const epsilon = .0001;
const offset = this.size.y/2 + epsilon;
this.pos.y = gravity.y < 0 ?
floor(oldPos.y-this.size.y/2) + offset :
ceil( oldPos.y+this.size.y/2) - offset;
// set ground object for tile collision
this.groundObject = hitLayer;
}
else
{
// move to previous Y position
this.pos.y = oldPos.y;
this.groundObject = undefined;
}
// bounce velocity
this.velocity.y *= -restitution;
}
debugPhysics && debugRect(this.pos, this.size, '#f00');
}
}
}
}
/** Update the object, called automatically by engine once each frame. Does nothing by default. */
update() {}
/** Render the object, draws a tile by default, automatically called each frame, sorted by renderOrder */
render()
{
// default object render
drawTile(this.pos, this.drawSize || this.size, this.tileInfo, this.color, this.angle, this.mirror, this.additiveColor);
}
/** Destroy this object, destroy its children, detach its parent, and mark it for removal
* @param {boolean} [immediate] - should attached effects be allowed to die off? */
destroy(immediate=false)
{
if (this.destroyed) return;
// disconnect from parent and destroy children
this.destroyed = true;
this.parent?.removeChild(this);
for (const child of this.children)
{
child.parent = undefined;
child.destroy(immediate);
}
}
/** Convert from local space to world space
* @param {Vector2} pos - local space point */
localToWorld(pos) { return this.pos.add(pos.rotate(this.angle)); }
/** Convert from world space to local space
* @param {Vector2} pos - world space point */
worldToLocal(pos) { return pos.subtract(this.pos).rotate(-this.angle); }
/** Convert from local space to world space for a vector (rotation only)
* @param {Vector2} vec - local space vector */
localToWorldVector(vec) { return vec.rotate(this.angle); }
/** Convert from world space to local space for a vector (rotation only)
* @param {Vector2} vec - world space vector */
worldToLocalVector(vec) { return vec.rotate(-this.angle); }
/** Called to check if a tile collision should be resolved. Return true for physics to resolve the collision or false to ignore and resolve it manually.
* @param {number} tileData - the value of the tile at the position
* @param {Vector2} pos - tile where the collision occurred
* @return {boolean} - true if the collision should be resolved by modifying it's position and velocity */
collideWithTile(tileData, pos) { return tileData > 0; }
/** Called by the engine to check if an object collision should be resolved. Return true for physics to resolve the collision or false to ignore and resolve it manually.
* @param {EngineObject} object - the object to test against
* @return {boolean} - true if the collision should be resolved by modifying it's position and velocity
*/
collideWithObject(object) { return true; }
/** Get this object's up vector
* @param {number} [scale] - length of the vector
* @return {Vector2} */
getUp(scale=1) { return vec2().setAngle(this.angle, scale); }
/** Get this object's right vector
* @param {number} [scale] - length of the vector
* @return {Vector2} */
getRight(scale=1) { return vec2().setAngle(this.angle+PI/2, scale); }
/** How long since the object was created
* @return {number} */
getAliveTime() { return time - this.spawnTime; }
/** Get the speed of this object
* @return {number} */
getSpeed() { return this.velocity.length(); }
/** Apply acceleration to this object (adjust velocity, not affected by mass)
* @param {Vector2} acceleration */
applyAcceleration(acceleration)
{ if (this.mass) this.velocity = this.velocity.add(acceleration); }
/** Apply angular acceleration to this object
* @param {number} acceleration */
applyAngularAcceleration(acceleration)
{ if (this.mass) this.angleVelocity += acceleration; }
/** Apply force to this object (adjust velocity, affected by mass)
* @param {Vector2} force */
applyForce(force)
{ if (this.mass) this.applyAcceleration(force.scale(1/this.mass)); }
/** Get the direction of the mirror
* @return {number} -1 if this.mirror is true, or 1 if not mirrored */
getMirrorSign() { return this.mirror ? -1 : 1; }
/** Attaches a child to this with a local transform, returns child for chaining
* @param {EngineObject} child
* @param {Vector2} [localPos=vec2()]
* @param {number} [localAngle]
* @return {EngineObject} The child object added */
addChild(child, localPos=vec2(), localAngle=0)
{
ASSERT(!child.parent && !this.children.includes(child));
ASSERT(child instanceof EngineObject, 'child must be an EngineObject');
ASSERT(child !== this, 'cannot add self as child');
this.children.push(child);
child.parent = this;
child.localPos = localPos.copy();
child.localAngle = localAngle;
return child;
}
/** Removes a child from this one
* @param {EngineObject} child */
removeChild(child)
{
ASSERT(child.parent === this && this.children.includes(child));
ASSERT(child instanceof EngineObject, 'child must be an EngineObject');
const index = this.children.indexOf(child);
ASSERT(index >= 0, 'child not found in children array');
index >= 0 && this.children.splice(index, 1);
child.parent = undefined;
}
/** Check if overlapping another engine object
* Collisions are resolved to prevent overlaps
* @param {EngineObject} object
* @return {boolean} */
isOverlappingObject(object)
{ return this.isOverlapping(object.pos, object.size); }
/** Check if overlapping a point or aligned bounding box
* @param {Vector2} pos - Center of box
* @param {Vector2} [size=vec2()] - Size of box, uses a point if undefined
* @return {boolean} */
isOverlapping(pos, size=vec2())
{ return isOverlapping(this.pos, this.size, pos, size); }
/** Set how this object collides
* @param {boolean} [collideSolidObjects] - Does it collide with solid objects?
* @param {boolean} [isSolid] - Does it collide with and block other objects? (expensive in large numbers)
* @param {boolean} [collideTiles] - Does it collide with the tile collision?
* @param {boolean} [collideRaycast] - Does it collide with raycasts? */
setCollision(collideSolidObjects=true, isSolid=true, collideTiles=true, collideRaycast=true)
{
ASSERT(collideSolidObjects || !isSolid, 'solid objects must be set to collide');
this.collideSolidObjects = collideSolidObjects;
this.isSolid = isSolid;
this.collideTiles = collideTiles;
this.collideRaycast = collideRaycast;
}
/** Returns string containing info about this object for debugging
* @return {string} */
toString()
{
if (!debug) return;
let text = 'type = ' + this.constructor.name;
if (this.pos.x || this.pos.y)
text += '\npos = ' + this.pos;
if (this.velocity.x || this.velocity.y)
text += '\nvelocity = ' + this.velocity;
if (this.size.x || this.size.y)
text += '\nsize = ' + this.size;
if (this.angle)
text += '\nangle = ' + this.angle.toFixed(3);
if (this.color)
text += '\ncolor = ' + this.color;
return text;
}
/** Render debug info for this object */
renderDebugInfo()
{
if (!debug) return;
// show object info for debugging
const size = vec2(max(this.size.x, .2), max(this.size.y, .2));
const color = rgb(this.collideTiles?1:0, this.collideSolidObjects?1:0, this.isSolid?1:0, .5);
drawRect(this.pos, size, color, this.angle);
if (this.parent)
drawRect(this.pos, size.scale(.8), rgb(1,1,1,.5), this.angle);
this.parent && drawLine(this.pos, this.parent.pos, .1, rgb(1,1,1,.5));
}
}</code></pre></article></section><footer class="footer" id="PeOAagUepe"><div class="wrapper"><a href="https://github.com/KilledByAPixel/LittleJS">LittleJS - MIT License - Copyright 2021 Frank Force</a></div></footer></div></div></div><div class="search-container" id="PkfLWpAbet" style="display:none"><div class="wrapper" id="iCxFxjkHbP"><button class="icon-button search-close-button" id="VjLlGakifb" aria-label="close search"><svg><use xlink:href="#close-icon"></use></svg></button><div class="search-box-c"><svg><use xlink:href="#search-icon"></use></svg> <input type="text" id="vpcKVYIppa" class="search-input" placeholder="Search..." autofocus></div><div class="search-result-c" id="fWwVHRuDuN"><span class="search-result-c-text">Type anything to view search result</span></div></div></div><div class="mobile-menu-icon-container"><button class="icon-button" id="mobile-menu" data-isopen="false" aria-label="menu"><svg><use xlink:href="#menu-icon"></use></svg></button></div><div id="mobile-sidebar" class="mobile-sidebar-container"><div class="mobile-sidebar-wrapper"><a href="/" class="sidebar-title sidebar-title-anchor">LittleJS - The Tiny JavaScript Game Engine That Can!</a><div class="mobile-nav-links"><div class="navbar-item"><a id="" href="https://github.com/KilledByAPixel/LittleJS" target="_blank">GitHub</a></div><div class="navbar-item"><a id="" href="https://killedbyapixel.github.io/LittleJS/examples/" target="_blank">Examples</a></div><div class="navbar-item"><a id="" href="https://github.com/KilledByAPixel/LittleJS/blob/main/FAQ.md" target="_blank">FAQ</a></div></div><div class="mobile-sidebar-items-c"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-classes"><div>Classes</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="Audio.Sound.html">Sound</a></div><div class="sidebar-section-children"><a href="Audio.SoundInstance.html">SoundInstance</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dDistanceJoint.html">Box2dDistanceJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dFrictionJoint.html">Box2dFrictionJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dGearJoint.html">Box2dGearJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dJoint.html">Box2dJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dKinematicObject.html">Box2dKinematicObject</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dMotorJoint.html">Box2dMotorJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dObject.html">Box2dObject</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dPinJoint.html">Box2dPinJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dPlugin.html">Box2dPlugin</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dPrismaticJoint.html">Box2dPrismaticJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dPulleyJoint.html">Box2dPulleyJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dRevoluteJoint.html">Box2dRevoluteJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dRopeJoint.html">Box2dRopeJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dStaticObject.html">Box2dStaticObject</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dTargetJoint.html">Box2dTargetJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dTileLayer.html">Box2dTileLayer</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dWeldJoint.html">Box2dWeldJoint</a></div><div class="sidebar-section-children"><a href="Box2D.Box2dWheelJoint.html">Box2dWheelJoint</a></div><div class="sidebar-section-children"><a href="Box2dRaycastResult.html">Box2dRaycastResult</a></div><div class="sidebar-section-children"><a href="Draw.FontImage.html">FontImage</a></div><div class="sidebar-section-children"><a href="Draw.TextureInfo.html">TextureInfo</a></div><div class="sidebar-section-children"><a href="Draw.TileInfo.html">TileInfo</a></div><div class="sidebar-section-children"><a href="Engine.Color.html">Color</a></div><div class="sidebar-section-children"><a href="Engine.EngineObject.html">EngineObject</a></div><div class="sidebar-section-children"><a href="Engine.RandomGenerator.html">RandomGenerator</a></div><div class="sidebar-section-children"><a href="Engine.Timer.html">Timer</a></div><div class="sidebar-section-children"><a href="Engine.Vector2.html">Vector2</a></div><div class="sidebar-section-children"><a href="Medals.Medal.html">Medal</a></div><div class="sidebar-section-children"><a href="Newgrounds.NewgroundsMedal.html">NewgroundsMedal</a></div><div class="sidebar-section-children"><a href="Newgrounds.NewgroundsPlugin.html">NewgroundsPlugin</a></div><div class="sidebar-section-children"><a href="Particles.Particle.html">Particle</a></div><div class="sidebar-section-children"><a href="Particles.ParticleEmitter.html">ParticleEmitter</a></div><div class="sidebar-section-children"><a href="PostProcess.PostProcessPlugin.html">PostProcessPlugin</a></div><div class="sidebar-section-children"><a href="TileLayers.CanvasLayer.html">CanvasLayer</a></div><div class="sidebar-section-children"><a href="TileLayers.TileCollisionLayer.html">TileCollisionLayer</a></div><div class="sidebar-section-children"><a href="TileLayers.TileLayer.html">TileLayer</a></div><div class="sidebar-section-children"><a href="TileLayers.TileLayerData.html">TileLayerData</a></div><div class="sidebar-section-children"><a href="UISystem.UIButton.html">UIButton</a></div><div class="sidebar-section-children"><a href="UISystem.UICheckbox.html">UICheckbox</a></div><div class="sidebar-section-children"><a href="UISystem.UIObject.html">UIObject</a></div><div class="sidebar-section-children"><a href="UISystem.UIScrollbar.html">UIScrollbar</a></div><div class="sidebar-section-children"><a href="UISystem.UISystemPlugin.html">UISystemPlugin</a></div><div class="sidebar-section-children"><a href="UISystem.UIText.html">UIText</a></div><div class="sidebar-section-children"><a href="UISystem.UITile.html">UITile</a></div><div class="sidebar-section-children"><a href="UISystem.UIVideo.html">UIVideo</a></div><div class="sidebar-section-children"><a href="ZzFXM.ZzFXMusic.html">ZzFXMusic</a></div></div><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-namespaces"><div>Namespaces</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="Audio.html">Audio</a></div><div class="sidebar-section-children"><a href="Box2D.html">Box2D</a></div><div class="sidebar-section-children"><a href="Debug.html">Debug</a></div><div class="sidebar-section-children"><a href="Draw.html">Draw</a></div><div class="sidebar-section-children"><a href="DrawUtilities.html">DrawUtilities</a></div><div class="sidebar-section-children"><a href="Engine.html">Engine</a></div><div class="sidebar-section-children"><a href="Input.html">Input</a></div><div class="sidebar-section-children"><a href="Math.html">Math</a></div><div class="sidebar-section-children"><a href="Medals.html">Medals</a></div><div class="sidebar-section-children"><a href="Newgrounds.html">Newgrounds</a></div><div class="sidebar-section-children"><a href="Particles.html">Particles</a></div><div class="sidebar-section-children"><a href="PostProcess.html">PostProcess</a></div><div class="sidebar-section-children"><a href="Random.html">Random</a></div><div class="sidebar-section-children"><a href="Settings.html">Settings</a></div><div class="sidebar-section-children"><a href="TileLayers.html">TileLayers</a></div><div class="sidebar-section-children"><a href="UISystem.html">UISystem</a></div><div class="sidebar-section-children"><a href="Utilities.html">Utilities</a></div><div class="sidebar-section-children"><a href="WebGL.html">WebGL</a></div><div class="sidebar-section-children"><a href="ZzFXM.html">ZzFXM</a></div></div></div><div class="mobile-navbar-actions"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#light-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div></div></div><script type="text/javascript" src="scripts/core.min.js"></script><script src="scripts/search.min.js" defer="defer"></script><script src="scripts/third-party/fuse.js" defer="defer"></script><script type="text/javascript">var tocbotInstance=tocbot.init({tocSelector:"#eed4d2a0bfd64539bb9df78095dec881",contentSelector:".main-content",headingSelector:"h1, h2, h3",hasInnerContainers:!0,scrollContainer:".main-content",headingsOffset:130,onClick:bringLinkToView})</script></body></html>