littlejsengine 1.18.4 → 1.18.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/COPYRIGHT.txt +38 -0
  2. package/FAQ.md +633 -0
  3. package/README.md +19 -1
  4. package/dist/littlejs.d.ts +354 -55
  5. package/dist/littlejs.esm.js +1531 -489
  6. package/dist/littlejs.esm.min.js +1 -1
  7. package/dist/littlejs.js +1499 -476
  8. package/dist/littlejs.min.js +1 -1
  9. package/dist/littlejs.release.js +1493 -470
  10. package/package.json +8 -1
  11. package/plugins/box2d.js +32 -7
  12. package/{src/engineMedals.js → plugins/medalSystem.js} +248 -196
  13. package/plugins/pathFinder.js +758 -0
  14. package/plugins/pluginExport.js +19 -0
  15. package/plugins/{tween.js → tweenSystem.js} +7 -7
  16. package/plugins/uiSystem.js +186 -25
  17. package/src/engine.js +2 -141
  18. package/src/engineAudio.js +3 -3
  19. package/src/engineBuild.mjs +4 -2
  20. package/src/engineDebug.js +7 -7
  21. package/src/engineDraw.js +26 -8
  22. package/src/engineExport.js +13 -13
  23. package/src/engineInput.js +8 -8
  24. package/src/engineLogo.js +146 -0
  25. package/src/engineMath.js +15 -6
  26. package/src/engineObject.js +11 -5
  27. package/src/engineParticles.js +6 -3
  28. package/src/engineRelease.js +1 -1
  29. package/src/engineSettings.js +0 -47
  30. package/src/engineUtilities.js +13 -8
  31. package/src/engineWebGL.js +34 -7
  32. package/src/jsconfig.json +3 -1
  33. package/.github/workflows/test.yml +0 -17
  34. package/AI.md +0 -173
  35. package/CLAUDE.md +0 -1
  36. package/examples/box2d/game.js +0 -192
  37. package/examples/box2d/gameObjects.js +0 -564
  38. package/examples/box2d/index.html +0 -9
  39. package/examples/box2d/scenes.js +0 -194
  40. package/examples/box2d/tiles.png +0 -0
  41. package/examples/breakout/game.js +0 -175
  42. package/examples/breakout/gameObjects.js +0 -147
  43. package/examples/breakout/index.html +0 -8
  44. package/examples/breakout/tiles.png +0 -0
  45. package/examples/breakoutTutorial/README.md +0 -521
  46. package/examples/breakoutTutorial/game.js +0 -191
  47. package/examples/breakoutTutorial/images/1.png +0 -0
  48. package/examples/breakoutTutorial/images/10.png +0 -0
  49. package/examples/breakoutTutorial/images/11.png +0 -0
  50. package/examples/breakoutTutorial/images/2.png +0 -0
  51. package/examples/breakoutTutorial/images/3.png +0 -0
  52. package/examples/breakoutTutorial/images/4.png +0 -0
  53. package/examples/breakoutTutorial/images/5.png +0 -0
  54. package/examples/breakoutTutorial/images/6.png +0 -0
  55. package/examples/breakoutTutorial/images/7.png +0 -0
  56. package/examples/breakoutTutorial/images/8.png +0 -0
  57. package/examples/breakoutTutorial/images/9.png +0 -0
  58. package/examples/breakoutTutorial/index.html +0 -8
  59. package/examples/electron/build.mjs +0 -127
  60. package/examples/electron/electron.js +0 -35
  61. package/examples/electron/game.js +0 -54
  62. package/examples/electron/index.html +0 -13
  63. package/examples/electron/package.json +0 -5
  64. package/examples/electron/tiles.png +0 -0
  65. package/examples/empty/game.js +0 -51
  66. package/examples/empty/index.html +0 -5
  67. package/examples/empty/tiles.png +0 -0
  68. package/examples/favicon.png +0 -0
  69. package/examples/games.jpg +0 -0
  70. package/examples/htmlMenu/game.js +0 -82
  71. package/examples/htmlMenu/index.html +0 -45
  72. package/examples/htmlMenu/tiles.png +0 -0
  73. package/examples/index.html +0 -62
  74. package/examples/logo.png +0 -0
  75. package/examples/logo2.png +0 -0
  76. package/examples/module/build.mjs +0 -124
  77. package/examples/module/game.js +0 -132
  78. package/examples/module/index.html +0 -10
  79. package/examples/module/tiles.png +0 -0
  80. package/examples/particles/index.html +0 -426
  81. package/examples/particles/tiles.png +0 -0
  82. package/examples/platformer/data/gameLevelData.tmx +0 -143
  83. package/examples/platformer/data/gameLevelData.tsx +0 -4
  84. package/examples/platformer/game.js +0 -147
  85. package/examples/platformer/gameCharacter.js +0 -309
  86. package/examples/platformer/gameEffects.js +0 -278
  87. package/examples/platformer/gameLevel.js +0 -205
  88. package/examples/platformer/gameLevelData.json +0 -171
  89. package/examples/platformer/gameObjects.js +0 -378
  90. package/examples/platformer/gamePlayer.js +0 -35
  91. package/examples/platformer/index.html +0 -9
  92. package/examples/platformer/tiles.png +0 -0
  93. package/examples/platformer/tilesLevel.png +0 -0
  94. package/examples/puzzle/game.js +0 -331
  95. package/examples/puzzle/index.html +0 -8
  96. package/examples/puzzle/tiles.png +0 -0
  97. package/examples/screenshot.jpg +0 -0
  98. package/examples/shorts/animation.js +0 -18
  99. package/examples/shorts/base.html +0 -54
  100. package/examples/shorts/blending.js +0 -14
  101. package/examples/shorts/box2d.js +0 -51
  102. package/examples/shorts/box2dCar.js +0 -59
  103. package/examples/shorts/box2dPool.js +0 -107
  104. package/examples/shorts/box2dTileLayer.js +0 -48
  105. package/examples/shorts/cameraDrag.js +0 -22
  106. package/examples/shorts/clock.js +0 -21
  107. package/examples/shorts/colors.js +0 -25
  108. package/examples/shorts/debugDraw.js +0 -37
  109. package/examples/shorts/empty.js +0 -30
  110. package/examples/shorts/flappyGame.js +0 -55
  111. package/examples/shorts/fontImage.js +0 -17
  112. package/examples/shorts/fps.js +0 -90
  113. package/examples/shorts/helloWorld.js +0 -11
  114. package/examples/shorts/hillGlideGame.js +0 -63
  115. package/examples/shorts/input.js +0 -64
  116. package/examples/shorts/landerGame.js +0 -57
  117. package/examples/shorts/maze.js +0 -48
  118. package/examples/shorts/medals.js +0 -51
  119. package/examples/shorts/music.js +0 -78
  120. package/examples/shorts/musicPlayer.js +0 -137
  121. package/examples/shorts/nineSlice.js +0 -40
  122. package/examples/shorts/parallax.js +0 -72
  123. package/examples/shorts/particles.js +0 -28
  124. package/examples/shorts/piano.js +0 -44
  125. package/examples/shorts/platformer.js +0 -45
  126. package/examples/shorts/pongGame.js +0 -41
  127. package/examples/shorts/postProcess.js +0 -62
  128. package/examples/shorts/sequencer.js +0 -124
  129. package/examples/shorts/shader.js +0 -29
  130. package/examples/shorts/shapes.js +0 -21
  131. package/examples/shorts/slidingPuzzle.js +0 -52
  132. package/examples/shorts/song.mp3 +0 -0
  133. package/examples/shorts/sound.js +0 -36
  134. package/examples/shorts/spaceGame.js +0 -58
  135. package/examples/shorts/spriteAtlas.js +0 -31
  136. package/examples/shorts/starfield.js +0 -15
  137. package/examples/shorts/texture.js +0 -16
  138. package/examples/shorts/textureWrapped.js +0 -12
  139. package/examples/shorts/tileLayer.js +0 -48
  140. package/examples/shorts/tileRaycast.js +0 -39
  141. package/examples/shorts/tiles.png +0 -0
  142. package/examples/shorts/tiltedView.js +0 -63
  143. package/examples/shorts/timers.js +0 -53
  144. package/examples/shorts/topDown.js +0 -38
  145. package/examples/shorts/tween.js +0 -24
  146. package/examples/shorts/uiSystem.js +0 -61
  147. package/examples/shorts/video.webm +0 -0
  148. package/examples/shorts/videoPlayer.js +0 -34
  149. package/examples/shorts.js +0 -743
  150. package/examples/starter/build.bat +0 -7
  151. package/examples/starter/build.mjs +0 -126
  152. package/examples/starter/game.js +0 -137
  153. package/examples/starter/index.html +0 -35
  154. package/examples/starter/tiles.png +0 -0
  155. package/examples/stress/index.html +0 -173
  156. package/examples/style.css +0 -150
  157. package/examples/tweenSystem/game.js +0 -171
  158. package/examples/tweenSystem/index.html +0 -10
  159. package/examples/tweenSystem/tiles.png +0 -0
  160. package/examples/typescript/build.mjs +0 -60
  161. package/examples/typescript/game.js +0 -100
  162. package/examples/typescript/game.ts +0 -132
  163. package/examples/typescript/index.html +0 -10
  164. package/examples/typescript/tiles.png +0 -0
  165. package/examples/typescript/tsconfig.json +0 -17
  166. package/examples/uiSystem/game.js +0 -139
  167. package/examples/uiSystem/index.html +0 -10
  168. package/examples/uiSystem/tiles.png +0 -0
  169. package/jsconfig.json +0 -12
  170. package/plugins/desktop.ini +0 -2
  171. package/reference.md +0 -448
  172. package/test/math.test.mjs +0 -774
  173. package/test/setup.mjs +0 -22
  174. package/test/smoke.test.mjs +0 -274
  175. package/test/tween.test.mjs +0 -576
  176. package/test/util.test.mjs +0 -80
@@ -1,564 +0,0 @@
1
- /*
2
- Little JS Box2d Demo Objects
3
- - Object functions that use Box2D features
4
- - Feel free to copy and paste these into your own project
5
- */
6
-
7
- 'use strict';
8
-
9
- // import LittleJS module
10
- import * as LJS from '../../dist/littlejs.esm.js';
11
- import * as Game from './game.js';
12
- const {vec2, hsl} = LJS;
13
-
14
- ///////////////////////////////////////////////////////////////////////////////
15
- // spawn object functions
16
-
17
- const density = 1;
18
- const friction = .5;
19
- const restitution = .2;
20
-
21
- export function spawnBox(pos, size=1, color=LJS.WHITE, type=LJS.box2d.bodyTypeDynamic, applyTexture=false, angle=0)
22
- {
23
- size = typeof size === 'number' ? vec2(size) : size; // square
24
- const o = new LJS.Box2dObject(pos, size, applyTexture && Game.spriteAtlas.squareOutline, angle, color, type);
25
- o.drawSize = size.scale(1.02); // slightly enlarge to cover gaps
26
- o.addBox(size, vec2(), 0, density, friction, restitution);
27
- return o;
28
- }
29
-
30
- export function spawnCircle(pos, diameter=1, color=LJS.WHITE, type=LJS.box2d.bodyTypeDynamic, applyTexture=false, angle=0)
31
- {
32
- const size = vec2(diameter);
33
- const o = new LJS.Box2dObject(pos, size, applyTexture && Game.spriteAtlas.circleOutline, angle, color, type);
34
- o.addCircle(diameter, vec2(), density, friction, restitution);
35
- return o;
36
- }
37
-
38
- export function spawnRandomPoly(pos, diameter=1, color=LJS.WHITE, type=LJS.box2d.bodyTypeDynamic, angle=0)
39
- {
40
- const o = new LJS.Box2dObject(pos, vec2(), 0, angle, color, type);
41
- o.addRandomPoly(diameter, density, friction, restitution);
42
- return o;
43
- }
44
-
45
- export function spawnRandomObject(pos, scale=1, type=LJS.box2d.bodyTypeDynamic, angle=0)
46
- {
47
- if (LJS.randInt(2))
48
- {
49
- const size = vec2(scale*LJS.rand(.5,1), scale*LJS.rand(.5,1));
50
- return spawnBox(pos, size, LJS.randColor(), type, true, angle);
51
- }
52
- else
53
- {
54
- const diameter = scale*LJS.rand(.5,1);
55
- return spawnCircle(pos, diameter, LJS.randColor(), type, true, angle);
56
- }
57
- }
58
-
59
- export function spawnPyramid(pos, count)
60
- {
61
- for (let i=count+1;i--;)
62
- for (let j=i;j--;)
63
- spawnBox(pos.add(vec2(j-i/2+.5,count-i+.5)), 1, LJS.randColor());
64
- }
65
-
66
- export function spawnDominoes(pos, count, size=vec2(.5,3))
67
- {
68
- for (let i=count; i--;)
69
- spawnBox(pos.add(vec2(i*size.y*.9,size.y/2)), size, LJS.randColor());
70
- }
71
-
72
- export function spawnRandomEdges()
73
- {
74
- // edge list along bottom
75
- const edgePoints = [];
76
- edgePoints.push(vec2(40,0));
77
- for (let i=40, y=0; i--;)
78
- edgePoints.push(vec2(i, y=LJS.clamp(y+LJS.rand(-2,2),0,5)));
79
- edgePoints.push(vec2());
80
- const o = new LJS.Box2dStaticObject;
81
- o.addEdgeList(edgePoints);
82
- }
83
-
84
- export function spawnRope(startPos, count, angle=PI, color=LJS.WHITE, size=vec2(.3,1))
85
- {
86
- let lastObject = Game.groundObject;
87
- for (let i=0; i<count; ++i)
88
- {
89
- const pos = startPos.add(size.multiply(vec2(0,i+.5)).rotate(-angle));
90
- const o = spawnBox(pos, size, color, LJS.box2d.bodyTypeDynamic, false, angle);
91
- o.setFilterData(2, 2);
92
- const anchorPos = pos.add(vec2(0,-size.y/2).rotate(-angle));
93
- new LJS.Box2dRevoluteJoint(lastObject, o, anchorPos);
94
- lastObject = o;
95
- }
96
- const endPos = lastObject.localToWorld(vec2(0,-size.y/2));
97
- new LJS.Box2dRopeJoint(Game.groundObject, lastObject, startPos, endPos);
98
- return lastObject;
99
- }
100
-
101
- ///////////////////////////////////////////////////////////////////////////////
102
-
103
- // simple car vehicle using wheel joints
104
- export class CarObject extends LJS.Box2dObject
105
- {
106
- constructor(pos)
107
- {
108
- super(pos, vec2(), 0, 0, LJS.randColor());
109
- const carPoints = [
110
- vec2(-1.5,-.5),
111
- vec2(1.5, -.5),
112
- vec2(1.5, 0),
113
- vec2(0, .9),
114
- vec2(-1.15,.9),
115
- vec2(-1.5, .2),
116
- ];
117
- this.addPoly(carPoints);
118
-
119
- // create wheels
120
- const diameter = 1;
121
- const density = 1;
122
- const friction = 1;
123
- const restitution = 0;
124
- const damping = .7;
125
- const frequency = 4;
126
- const maxTorque = 35;
127
- const sprite = Game.spriteAtlas.wheel;
128
- this.wheels = [];
129
- const makeWheel = (pos, isMotor)=>
130
- {
131
- const wheel = new LJS.Box2dObject(pos, vec2(diameter), sprite);
132
- const joint = new LJS.Box2dWheelJoint(this, wheel);
133
- joint.setSpringDampingRatio(damping);
134
- joint.setSpringFrequencyHz(frequency);
135
- if (isMotor)
136
- {
137
- joint.enableMotor();
138
- joint.setMaxMotorTorque(maxTorque);
139
- this.wheelMotorJoint = joint;
140
- }
141
- wheel.addCircle(diameter, vec2(), density, friction, restitution);
142
- this.wheels.push(wheel);
143
- }
144
-
145
- makeWheel(pos.add(vec2( 1, -.6)));
146
- makeWheel(pos.add(vec2(-1, -.65)), true);
147
- }
148
- update()
149
- {
150
- // car controls
151
- const maxSpeed = 40;
152
- const input = LJS.keyDirection().x;
153
- let s = this.wheelMotorJoint.getMotorSpeed();
154
- s = input ? LJS.clamp(s - input, -maxSpeed, maxSpeed) : 0;
155
- this.wheelMotorJoint.setMotorSpeed(s);
156
- }
157
- destroy()
158
- {
159
- this.wheels.forEach(o=>o.destroy());
160
- super.destroy();
161
- }
162
- }
163
-
164
- ///////////////////////////////////////////////////////////////////////////////
165
-
166
- // changes objects color when touched
167
- export class ContactTester extends LJS.Box2dStaticObject
168
- {
169
- constructor(pos, size, color, contactColor, isCircle=true, isSensor=true)
170
- {
171
- super(pos, size, 0, 0, color);
172
- isCircle ? this.addCircle(size.x) : this.addBox(size);
173
- this.setSensor(isSensor);
174
- this.contactColor = contactColor;
175
- }
176
- beginContact(other) { other.color = this.contactColor; }
177
- endContact(other) { other.color = LJS.WHITE; }
178
- }
179
-
180
- ///////////////////////////////////////////////////////////////////////////////
181
-
182
- // balanced recursive mobile object with revolve joints
183
- export class MobileObject extends LJS.Box2dObject
184
- {
185
- constructor(anchor, w, h, depth)
186
- {
187
- super(anchor, vec2(w, h), 0, 0, LJS.randColor());
188
- this.addBox(vec2(h/4, h), vec2(0, -h/2));
189
- this.childMobiles = [];
190
- if (--depth)
191
- {
192
- // long box on bottom
193
- this.addBox(vec2(w, h/4), vec2(0, -h));
194
- for (let i=2; i--;)
195
- {
196
- // spawn smaller mobiles attached to each side
197
- const a = anchor.add(vec2( w/(i?2:-2), -h));
198
- const o = new MobileObject(a, w/2, h, depth);
199
- new LJS.Box2dRevoluteJoint(this, o, a);
200
- this.childMobiles.push(o);
201
- }
202
- }
203
- }
204
- destroy()
205
- {
206
- this.childMobiles.forEach(o=>o && o.destroy());
207
- super.destroy();
208
- }
209
- }
210
-
211
- ///////////////////////////////////////////////////////////////////////////////
212
-
213
- // pulley object renders a rope to connected point
214
- export class PulleyJointObjects extends LJS.Box2dObject
215
- {
216
- constructor(pos, size, color, connectionPos)
217
- {
218
- super(pos, size, Game.spriteAtlas.squareOutline, 0, color);
219
- this.addBox(size);
220
- this.connectionPos = connectionPos;
221
- }
222
- render()
223
- {
224
- // draw rope
225
- const topPos = this.localToWorld(vec2(0,this.size.y/2));
226
- LJS.drawLine(topPos, this.connectionPos, .2, LJS.BLACK);
227
- super.render();
228
- }
229
- }
230
-
231
- ///////////////////////////////////////////////////////////////////////////////
232
-
233
- // motor object renders a rope to connected point
234
- export class MotorJointObject extends LJS.Box2dObject
235
- {
236
- constructor(pos, size, color, otherObject)
237
- {
238
- super(pos, size, Game.spriteAtlas.wheel, 0, color);
239
- this.addCircle(size.x);
240
- this.connectionPos = pos;
241
- const joint = new LJS.Box2dMotorJoint(otherObject, this);
242
- joint.setMaxForce(500);
243
- joint.setMaxTorque(500);
244
- }
245
- render()
246
- {
247
- // draw rope
248
- const width = 2/(1+this.pos.distance(this.connectionPos));
249
- LJS.drawLine(this.pos, this.connectionPos, width, LJS.BLACK);
250
- super.render();
251
- }
252
- }
253
-
254
- ///////////////////////////////////////////////////////////////////////////////
255
-
256
- // soft body sim using grid of weld joints
257
- export class SoftBodyObject extends LJS.Box2dObject
258
- {
259
- constructor(pos, scale, sizeCount, color)
260
- {
261
- super(pos, vec2());
262
- const nodeSize = sizeCount.subtract(vec2(1));
263
- const spacing = scale.divide(nodeSize);
264
- const objectDiameter = LJS.min(spacing.x, spacing.y);
265
- this.sizeCount = sizeCount.copy();
266
-
267
- // create nodes
268
- this.nodes = [];
269
- for (let y=sizeCount.y; y--;)
270
- for (let x=sizeCount.y; x--;)
271
- {
272
- const mass = .1;
273
- const center = vec2(x-nodeSize.x/2, y-nodeSize.y/2);
274
- const p = pos.add(center.multiply(spacing));
275
- const o = new LJS.Box2dObject(p, vec2(objectDiameter*1.1), Game.spriteAtlas.circle, 0, color);
276
- o.addCircle(objectDiameter);
277
- o.setMass(mass);
278
- o.setAngularDamping(10);
279
- o.joints = [];
280
- this.nodes.push(o);
281
- }
282
- // attach joints
283
- for (let y=sizeCount.y; y--;)
284
- for (let x=sizeCount.x; x--;)
285
- {
286
- const o = this.getNode(x, y);
287
- const tryAddJoint = (xo, yo)=>
288
- {
289
- const o2 = this.getNode(x+xo, y+yo);
290
- const joint = o2 ? new LJS.Box2dWeldJoint(o, o2) : 0;
291
- o.joints.push(joint);
292
- }
293
-
294
- // attach horizontal and vertical joints first
295
- tryAddJoint(1, 0);
296
- tryAddJoint(0, 1);
297
- }
298
- }
299
- render()
300
- {
301
- // fill inside background with a poly around the perimeter
302
- const poly = [];
303
- const sx = this.sizeCount.x;
304
- const sy = this.sizeCount.y;
305
- for (let x = 0; x < sx; ++x) poly.push(this.getNode(x, 0).pos);
306
- for (let y = 0; y < sy.y; ++y) poly.push(this.getNode(sx-1, y).pos);
307
- for (let x = sx; x--;) poly.push(this.getNode(x, sy-1).pos);
308
- for (let y = sy; y--;) poly.push(this.getNode(0, y).pos);
309
- LJS.drawPoly(poly, LJS.BLACK)
310
- }
311
- getNode(x, y)
312
- {
313
- if (vec2(x,y).arrayCheck(this.sizeCount))
314
- return this.nodes[y*this.sizeCount.x+x];
315
- }
316
- destroy()
317
- {
318
- this.nodes.forEach(o=>o && o.destroy());
319
- super.destroy();
320
- }
321
- }
322
-
323
- ///////////////////////////////////////////////////////////////////////////////
324
-
325
- // cloth sim using grid of rope joints
326
- export class ClothObject extends LJS.Box2dStaticObject
327
- {
328
- constructor(pos, scale, sizeCount, color, maxJointStress=10)
329
- {
330
- super(pos, vec2(), 0, 0, color);
331
- const nodeSize = sizeCount.subtract(vec2(1));
332
- const spacing = scale.divide(nodeSize);
333
- const objectDiameter = LJS.min(spacing.x, spacing.y);
334
- this.sizeCount = sizeCount.copy();
335
- this.maxJointStress = maxJointStress;
336
- this.lineWidth = .1;
337
-
338
- // create nodes
339
- this.nodes = [];
340
- for (let y=sizeCount.y; y--;)
341
- for (let x=sizeCount.y; x--;)
342
- {
343
- const mass = .5;
344
- const center = vec2(x-nodeSize.x/2, y-nodeSize.y/2);
345
- const p = pos.add(center.multiply(spacing));
346
- const o = new LJS.Box2dObject(p, vec2(.4), Game.spriteAtlas.circle, 0, color);
347
- o.addCircle(objectDiameter);
348
- o.setFilterData(2, 2);
349
- o.setLinearDamping(1);
350
- o.setMass(mass);
351
- o.joints = [];
352
- this.nodes.push(o);
353
- }
354
- // attach joints
355
- for (let pass=2; pass--;)
356
- for (let y=sizeCount.y; y--;)
357
- for (let x=sizeCount.x; x--;)
358
- {
359
- // alternate direction each row for stability
360
- const d = y%2 ? 1 : -1;
361
- const x2 = d>1 ? x : sizeCount.x-1-x;
362
- const o = this.getNode(x2, y);
363
- const tryAddJoint = (xo, yo)=>
364
- {
365
- const o2 = this.getNode(x2+xo, y+yo);
366
- const joint = o2 ? new LJS.Box2dRopeJoint(o, o2) : 0;
367
- o.joints.push(joint);
368
- }
369
-
370
- if (pass)
371
- {
372
- // attach horizontal and vertical joints first
373
- tryAddJoint(d, 0);
374
- tryAddJoint(0, 1);
375
- }
376
- else
377
- {
378
- // attach cross joints
379
- tryAddJoint(-d, 1);
380
- tryAddJoint( d, 1);
381
-
382
- // attach pin joint to top row
383
- y || new LJS.Box2dPinJoint(this.getNode(x, y), this);
384
- }
385
- }
386
- }
387
- getNode(x, y)
388
- {
389
- if (vec2(x,y).arrayCheck(this.sizeCount))
390
- return this.nodes[y*this.sizeCount.x+x];
391
- }
392
- update()
393
- {
394
- for (let y=this.sizeCount.y; y--;)
395
- for (let x=this.sizeCount.x; x--;)
396
- {
397
- const o = this.getNode(x, y)
398
- if (!o) continue;
399
-
400
- // check node joints
401
- const joints = o.joints;
402
- for (let i=joints.length; i--;)
403
- {
404
- const j = joints[i];
405
- if (!j) continue;
406
-
407
- const oA = j.getObjectA();
408
- const oB = j.getObjectB();
409
- const d2 = oA.pos.distanceSquared(oB.pos);
410
- const maxLength2 = j.getMaxLength()**2;
411
- const stress = j.getReactionForce(1).length();
412
- if (stress > this.maxJointStress || d2 > maxLength2*4)
413
- {
414
- // remove stressed joint
415
- j.destroy();
416
- joints[i] = 0;
417
- }
418
- }
419
- if (!o.hasJoints())
420
- {
421
- // destroy if not connected to anything
422
- o.destroy();
423
- this.nodes[y*this.sizeCount.x+x] = 0;
424
- }
425
- }
426
- }
427
- render()
428
- {
429
- // draw connections
430
- for (const o of this.nodes)
431
- {
432
- if (!o) continue;
433
- for (const joint of o.joints)
434
- {
435
- if (!joint) continue;
436
- const oA = joint.getObjectA();
437
- const oB = joint.getObjectB();
438
- LJS.drawLine(oA.pos, oB.pos, this.lineWidth, LJS.BLACK);
439
- }
440
- }
441
- }
442
- destroy()
443
- {
444
- this.nodes.forEach(o=>o && o.destroy());
445
- super.destroy();
446
- }
447
- }
448
-
449
- ///////////////////////////////////////////////////////////////////////////////
450
-
451
- // ragdoll with head, arms, and legs connected to torso by revolute joints
452
- export class RagdollObject extends LJS.Box2dObject
453
- {
454
- constructor(pos, scale=1, color=LJS.randColor())
455
- {
456
- const headSize = .8 * scale;
457
- const torsoWidth = 1.2 * scale;
458
- const torsoHeight = 2 * scale;
459
- const limbWidth = .4 * scale;
460
- const upperArmLen = 1 * scale;
461
- const lowerArmLen = 1 * scale;
462
- const upperLegLen = 1.1 * scale;
463
- const lowerLegLen = 1.1 * scale;
464
-
465
- // torso is the main body
466
- super(pos, vec2(torsoWidth, torsoHeight), 0, 0, color);
467
- this.addBox(vec2(torsoWidth, torsoHeight), vec2(), 0, density, friction, restitution);
468
- this.limbs = [];
469
-
470
- const addLimb = (offset, size, isCircle=false) =>
471
- {
472
- const o = new LJS.Box2dObject(pos.add(offset), size, 0, 0, color);
473
- if (isCircle)
474
- o.addCircle(size.x, vec2(), density, friction, restitution);
475
- else
476
- o.addBox(size, vec2(), 0, density, friction, restitution);
477
- this.limbs.push(o);
478
- return o;
479
- };
480
- const addJoint = (a, b, anchor, lower, upper) =>
481
- {
482
- const joint = new LJS.Box2dRevoluteJoint(a, b, anchor);
483
- joint.enableLimit();
484
- joint.setLimits(lower, upper);
485
- };
486
-
487
- // head
488
- const head = addLimb(vec2(0, torsoHeight/2 + headSize/2 + .1*scale), vec2(headSize), true);
489
- addJoint(this, head, pos.add(vec2(0, torsoHeight/2)), -.5, .5);
490
-
491
- // arms
492
- const shoulderY = torsoHeight/2 - .2*scale;
493
- for (const side of [-1, 1])
494
- {
495
- const shoulder = pos.add(vec2(side*torsoWidth/2, shoulderY));
496
- const upperArm = addLimb(vec2(side*(torsoWidth/2 + upperArmLen/2), shoulderY), vec2(upperArmLen, limbWidth));
497
- addJoint(this, upperArm, shoulder, -2, 2);
498
-
499
- const elbow = shoulder.add(vec2(side*upperArmLen, 0));
500
- const lowerArm = addLimb(vec2(side*(torsoWidth/2 + upperArmLen + lowerArmLen/2), shoulderY), vec2(lowerArmLen, limbWidth));
501
- addJoint(upperArm, lowerArm, elbow, -2.5, 2.5);
502
- }
503
-
504
- // legs
505
- for (const side of [-1, 1])
506
- {
507
- const hip = pos.add(vec2(side*torsoWidth/4, -torsoHeight/2));
508
- const upperLeg = addLimb(vec2(side*torsoWidth/4, -torsoHeight/2 - upperLegLen/2), vec2(limbWidth, upperLegLen));
509
- addJoint(this, upperLeg, hip, -.5, 2.5);
510
-
511
- const knee = hip.add(vec2(0, -upperLegLen));
512
- const lowerLeg = addLimb(vec2(side*torsoWidth/4, -torsoHeight/2 - upperLegLen - lowerLegLen/2), vec2(limbWidth, lowerLegLen));
513
- addJoint(upperLeg, lowerLeg, knee, -2.5, 2.5);
514
- }
515
- }
516
- destroy()
517
- {
518
- this.limbs.forEach(o => o.destroy());
519
- super.destroy();
520
- }
521
- }
522
-
523
- ///////////////////////////////////////////////////////////////////////////////
524
- // Effects
525
-
526
- const sound_explosion = new LJS.Sound([.5,.2,72,.01,.01,.2,4,,,,,,,1,,.5,.1,.5,.02]);
527
-
528
- export function explosion(pos, radius=3, strength=300)
529
- {
530
- sound_explosion.play(pos);
531
- const objects = LJS.box2d.circleCastAll(pos, (radius*2));
532
- const newColor = LJS.randColor();
533
- for (const o of objects)
534
- {
535
- const p = LJS.percent(o.pos.distance(pos), 2*radius, radius);
536
- const force = o.pos.subtract(pos).normalize(p*radius*strength);
537
- o.applyForce(force);
538
- o.color = newColor;
539
- }
540
-
541
- // smoke
542
- new LJS.ParticleEmitter(
543
- pos, 0, // pos, angle
544
- radius/2, .2, 50*radius, 3.14,// emitSize, emitTime, rate, cone
545
- Game.spriteAtlas.dot, // tileInfo
546
- hsl(0,0,0), hsl(0,0,0), // colorStartA, colorStartB
547
- hsl(0,0,0,0), hsl(0,0,0,0), // colorEndA, colorEndB
548
- 1, 1, 2, .1, .1, // time, sizeStart, sizeEnd, speed, angleSpeed
549
- .9, 1, -.5, 3.14, .1, // damp, angleDamp, gravity, particleCone, fade
550
- 1, 0, 0, 0, 1e8 // randomness, collide, additive, colorLinear, renderOrder
551
- );
552
-
553
- // fire
554
- new LJS.ParticleEmitter(
555
- pos, 0, // pos, angle
556
- radius, .1, 100*radius, 3.14, // emitSize, emitTime, rate, cone
557
- Game.spriteAtlas.dot, // tileInfo
558
- hsl(0,.8,.5), hsl(.15,.8,.5), // colorStartA, colorStartB
559
- hsl(0,1,.5,0), hsl(.1, 1,.5,0),// colorEndA, colorEndB
560
- .7, 1, .5, .1, .1, // time, sizeStart, sizeEnd, speed, angleSpeed
561
- .9, 1, 0, 3.14, .05, // damp, angleDamp, gravity, particleCone, fade
562
- 1, 0, 1, 0, 1e9 // randomness, collide, additive, colorLinear, renderOrder
563
- );
564
- }
@@ -1,9 +0,0 @@
1
- <!DOCTYPE html><head>
2
- <title>LittleJS Box2D Example</title>
3
- <meta charset=utf-8>
4
- <meta name=apple-mobile-web-app-capable content=yes>
5
- <meta name=mobile-web-app-capable content=yes>
6
- <link rel=icon type=image/png href=../favicon.png>
7
- </head><body>
8
- <script src=../../dist/box2d.wasm.js></script>
9
- <script src=game.js type=module></script>