littlejsengine 1.18.4 → 1.18.7
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.
- package/COPYRIGHT.txt +38 -0
- package/FAQ.md +633 -0
- package/README.md +19 -1
- package/dist/littlejs.d.ts +349 -54
- package/dist/littlejs.esm.js +1469 -448
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +1438 -436
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +1438 -436
- package/package.json +8 -1
- package/plugins/box2d.js +32 -7
- package/{src/engineMedals.js → plugins/medalSystem.js} +248 -196
- package/plugins/pathFinder.js +758 -0
- package/plugins/pluginExport.js +19 -0
- package/plugins/tween.js +1 -1
- package/plugins/tweenSystem.js +509 -0
- package/plugins/uiSystem.js +150 -11
- package/src/engine.js +2 -141
- package/src/engineAudio.js +8 -5
- package/src/engineBuild.mjs +4 -2
- package/src/engineDebug.js +1 -1
- package/src/engineDraw.js +21 -3
- package/src/engineExport.js +12 -12
- package/src/engineInput.js +1 -1
- package/src/engineLogo.js +146 -0
- package/src/engineMath.js +10 -3
- package/src/engineObject.js +11 -5
- package/src/engineParticles.js +6 -3
- package/src/engineRelease.js +1 -1
- package/src/engineSettings.js +0 -47
- package/src/engineUtilities.js +7 -2
- package/src/engineWebGL.js +34 -7
- package/src/jsconfig.json +3 -1
- package/.github/workflows/test.yml +0 -17
- package/AI.md +0 -173
- package/CLAUDE.md +0 -1
- package/examples/box2d/game.js +0 -192
- package/examples/box2d/gameObjects.js +0 -564
- package/examples/box2d/index.html +0 -9
- package/examples/box2d/scenes.js +0 -194
- package/examples/box2d/tiles.png +0 -0
- package/examples/breakout/game.js +0 -175
- package/examples/breakout/gameObjects.js +0 -147
- package/examples/breakout/index.html +0 -8
- package/examples/breakout/tiles.png +0 -0
- package/examples/breakoutTutorial/README.md +0 -521
- package/examples/breakoutTutorial/game.js +0 -191
- package/examples/breakoutTutorial/images/1.png +0 -0
- package/examples/breakoutTutorial/images/10.png +0 -0
- package/examples/breakoutTutorial/images/11.png +0 -0
- package/examples/breakoutTutorial/images/2.png +0 -0
- package/examples/breakoutTutorial/images/3.png +0 -0
- package/examples/breakoutTutorial/images/4.png +0 -0
- package/examples/breakoutTutorial/images/5.png +0 -0
- package/examples/breakoutTutorial/images/6.png +0 -0
- package/examples/breakoutTutorial/images/7.png +0 -0
- package/examples/breakoutTutorial/images/8.png +0 -0
- package/examples/breakoutTutorial/images/9.png +0 -0
- package/examples/breakoutTutorial/index.html +0 -8
- package/examples/electron/build.mjs +0 -127
- package/examples/electron/electron.js +0 -35
- package/examples/electron/game.js +0 -54
- package/examples/electron/index.html +0 -13
- package/examples/electron/package.json +0 -5
- package/examples/electron/tiles.png +0 -0
- package/examples/empty/game.js +0 -51
- package/examples/empty/index.html +0 -5
- package/examples/empty/tiles.png +0 -0
- package/examples/favicon.png +0 -0
- package/examples/games.jpg +0 -0
- package/examples/htmlMenu/game.js +0 -82
- package/examples/htmlMenu/index.html +0 -45
- package/examples/htmlMenu/tiles.png +0 -0
- package/examples/index.html +0 -62
- package/examples/logo.png +0 -0
- package/examples/logo2.png +0 -0
- package/examples/module/build.mjs +0 -124
- package/examples/module/game.js +0 -132
- package/examples/module/index.html +0 -10
- package/examples/module/tiles.png +0 -0
- package/examples/particles/index.html +0 -426
- package/examples/particles/tiles.png +0 -0
- package/examples/platformer/data/gameLevelData.tmx +0 -143
- package/examples/platformer/data/gameLevelData.tsx +0 -4
- package/examples/platformer/game.js +0 -147
- package/examples/platformer/gameCharacter.js +0 -309
- package/examples/platformer/gameEffects.js +0 -278
- package/examples/platformer/gameLevel.js +0 -205
- package/examples/platformer/gameLevelData.json +0 -171
- package/examples/platformer/gameObjects.js +0 -378
- package/examples/platformer/gamePlayer.js +0 -35
- package/examples/platformer/index.html +0 -9
- package/examples/platformer/tiles.png +0 -0
- package/examples/platformer/tilesLevel.png +0 -0
- package/examples/puzzle/game.js +0 -331
- package/examples/puzzle/index.html +0 -8
- package/examples/puzzle/tiles.png +0 -0
- package/examples/screenshot.jpg +0 -0
- package/examples/shorts/animation.js +0 -18
- package/examples/shorts/base.html +0 -54
- package/examples/shorts/blending.js +0 -14
- package/examples/shorts/box2d.js +0 -51
- package/examples/shorts/box2dCar.js +0 -59
- package/examples/shorts/box2dPool.js +0 -107
- package/examples/shorts/box2dTileLayer.js +0 -48
- package/examples/shorts/cameraDrag.js +0 -22
- package/examples/shorts/clock.js +0 -21
- package/examples/shorts/colors.js +0 -25
- package/examples/shorts/debugDraw.js +0 -37
- package/examples/shorts/empty.js +0 -30
- package/examples/shorts/flappyGame.js +0 -55
- package/examples/shorts/fontImage.js +0 -17
- package/examples/shorts/fps.js +0 -90
- package/examples/shorts/helloWorld.js +0 -11
- package/examples/shorts/hillGlideGame.js +0 -63
- package/examples/shorts/input.js +0 -64
- package/examples/shorts/landerGame.js +0 -57
- package/examples/shorts/maze.js +0 -48
- package/examples/shorts/medals.js +0 -51
- package/examples/shorts/music.js +0 -78
- package/examples/shorts/musicPlayer.js +0 -137
- package/examples/shorts/nineSlice.js +0 -40
- package/examples/shorts/parallax.js +0 -72
- package/examples/shorts/particles.js +0 -28
- package/examples/shorts/piano.js +0 -44
- package/examples/shorts/platformer.js +0 -45
- package/examples/shorts/pongGame.js +0 -41
- package/examples/shorts/postProcess.js +0 -62
- package/examples/shorts/sequencer.js +0 -124
- package/examples/shorts/shader.js +0 -29
- package/examples/shorts/shapes.js +0 -21
- package/examples/shorts/slidingPuzzle.js +0 -52
- package/examples/shorts/song.mp3 +0 -0
- package/examples/shorts/sound.js +0 -36
- package/examples/shorts/spaceGame.js +0 -58
- package/examples/shorts/spriteAtlas.js +0 -31
- package/examples/shorts/starfield.js +0 -15
- package/examples/shorts/texture.js +0 -16
- package/examples/shorts/textureWrapped.js +0 -12
- package/examples/shorts/tileLayer.js +0 -48
- package/examples/shorts/tileRaycast.js +0 -39
- package/examples/shorts/tiles.png +0 -0
- package/examples/shorts/tiltedView.js +0 -63
- package/examples/shorts/timers.js +0 -53
- package/examples/shorts/topDown.js +0 -38
- package/examples/shorts/tween.js +0 -24
- package/examples/shorts/uiSystem.js +0 -61
- package/examples/shorts/video.webm +0 -0
- package/examples/shorts/videoPlayer.js +0 -34
- package/examples/shorts.js +0 -743
- package/examples/starter/build.bat +0 -7
- package/examples/starter/build.mjs +0 -126
- package/examples/starter/game.js +0 -137
- package/examples/starter/index.html +0 -35
- package/examples/starter/tiles.png +0 -0
- package/examples/stress/index.html +0 -173
- package/examples/style.css +0 -150
- package/examples/tweenSystem/game.js +0 -171
- package/examples/tweenSystem/index.html +0 -10
- package/examples/tweenSystem/tiles.png +0 -0
- package/examples/typescript/build.mjs +0 -60
- package/examples/typescript/game.js +0 -100
- package/examples/typescript/game.ts +0 -132
- package/examples/typescript/index.html +0 -10
- package/examples/typescript/tiles.png +0 -0
- package/examples/typescript/tsconfig.json +0 -17
- package/examples/uiSystem/game.js +0 -139
- package/examples/uiSystem/index.html +0 -10
- package/examples/uiSystem/tiles.png +0 -0
- package/jsconfig.json +0 -12
- package/plugins/desktop.ini +0 -2
- package/reference.md +0 -448
- package/test/math.test.mjs +0 -774
- package/test/setup.mjs +0 -22
- package/test/smoke.test.mjs +0 -274
- package/test/tween.test.mjs +0 -576
- 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>
|