littlejsengine 1.19.3 → 1.21.0

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 (54) hide show
  1. package/FAQ.md +841 -820
  2. package/README.md +29 -25
  3. package/dist/littlejs.d.ts +2857 -955
  4. package/dist/littlejs.esm.js +33428 -20995
  5. package/dist/littlejs.esm.min.js +4 -3
  6. package/dist/littlejs.js +33386 -20996
  7. package/dist/littlejs.min.js +2 -2
  8. package/dist/littlejs.release.js +27841 -20422
  9. package/package.json +10 -5
  10. package/plugins/audioEffects.js +28 -24
  11. package/plugins/box2d.js +2516 -2073
  12. package/plugins/drawUtilities.js +206 -31
  13. package/plugins/gltf.js +786 -0
  14. package/plugins/jsconfig.json +19 -0
  15. package/plugins/lightSystem.js +719 -332
  16. package/plugins/math3d.js +148 -27
  17. package/plugins/medalSystem.js +326 -280
  18. package/plugins/newgrounds.js +400 -199
  19. package/plugins/pathFinder.js +208 -175
  20. package/plugins/pluginExport.js +25 -0
  21. package/plugins/postProcess.js +96 -24
  22. package/plugins/render3d.js +2067 -1632
  23. package/plugins/render3dDebug.js +110 -0
  24. package/plugins/render3dEditor.js +1812 -0
  25. package/plugins/render3dExtras.js +1948 -0
  26. package/plugins/render3dLevel.js +189 -0
  27. package/plugins/render3dVoxels.js +514 -0
  28. package/plugins/sceneSystem.js +58 -0
  29. package/plugins/textureSheet.js +496 -458
  30. package/plugins/threejs.js +183 -163
  31. package/plugins/tweakables.js +411 -0
  32. package/plugins/tweenSystem.js +265 -145
  33. package/plugins/uiSystem.js +2024 -1687
  34. package/plugins/zzfxm.js +159 -159
  35. package/src/engine.js +378 -97
  36. package/src/engineAudio.js +231 -127
  37. package/src/engineBuild.mjs +292 -256
  38. package/src/engineDebug.js +967 -743
  39. package/src/engineDraw.js +391 -198
  40. package/src/engineEditor.js +2452 -0
  41. package/src/engineExport.js +18 -0
  42. package/src/engineInput.js +1466 -1293
  43. package/src/engineLogo.js +19 -0
  44. package/src/engineMath.js +1274 -1252
  45. package/src/engineObject.js +197 -82
  46. package/src/engineParticles.js +583 -532
  47. package/src/engineRelease.js +79 -45
  48. package/src/engineSettings.js +115 -29
  49. package/src/engineTileLayer.js +995 -741
  50. package/src/engineUtilities.js +19 -13
  51. package/src/engineWebGL.js +239 -82
  52. package/src/jsconfig.json +17 -13
  53. package/plugins/box2d.wasm.js +0 -630
  54. package/plugins/box2d.wasm.wasm +0 -0
@@ -0,0 +1,189 @@
1
+ /**
2
+ * LittleJS 3D Level Plugin
3
+ * - A 3D level is a list of objects, each a type name, a position, and a rotation, scale and properties where
4
+ * they are not the default, kept as plain JSON that can be written by hand
5
+ * - level3DAddType names the types a game makes them from, as objectLayersAddType does in 2D
6
+ * - level3DLoad makes every object of a level
7
+ * - Box, Sphere, Cylinder and Light are built in, to block out and light a level with no code
8
+ * - The 3D level editor, in debug builds, edits the level a game loaded
9
+ * @namespace Level3D
10
+ */
11
+
12
+ 'use strict';
13
+
14
+ ///////////////////////////////////////////////////////////////////////////////
15
+
16
+ const LEVEL3D_VERSION = 1; // the format a level's littlejs3D names
17
+
18
+ // the types a level's objects are made from, by name
19
+ const level3DTypes = new Map;
20
+
21
+ // the scale each object had when it was made, the level's scale multiplies it
22
+ const level3DBaseScale = new WeakMap;
23
+
24
+ /** Add a type of object, so level3DLoad makes one wherever a level has an object of that type
25
+ * - The name is a string because minified builds rename classes
26
+ * - A class, or any function with a prototype, is made with new make(pos3D, properties); an arrow function is
27
+ * called as make(pos3D, properties), for what is not an object, like a player start
28
+ * - properties is the defaults with the object's own values over them, and each of the type's own is also set on
29
+ * what was made; a property the type has no default for is in properties and is not set
30
+ * - Give a class a constructor of its own that takes the position: one that hands every argument on to
31
+ * EngineObject3D would hand it the properties as its mesh
32
+ * - An EngineObject3D then gets the object's rotation, and its scale times the scale it was made with
33
+ * - Adding a name again replaces it, Box, Sphere, Cylinder and Light too
34
+ * @param {string} name - The type the objects have in the level
35
+ * @param {Function} make - A class made at each object's position, or a function called with it
36
+ * @param {Object} [defaults] - Properties of each one made, the level editor shows inputs for them
37
+ * @param {TileInfo} [tileInfo] - An icon for the level editor
38
+ * @memberof Level3D
39
+ * @example
40
+ * level3DAddType('Crate', Crate, {health: 3});
41
+ * level3DAddType('PlayerStart', (pos)=> playerStart = pos); */
42
+ function level3DAddType(name, make, defaults={}, tileInfo)
43
+ {
44
+ ASSERT(isStringLike(name), 'object type name must be a string');
45
+ ASSERT(typeof make === 'function', 'make must be a class or function');
46
+ ASSERT(!!defaults && typeof defaults === 'object', 'defaults must be an object');
47
+ level3DTypes.set(String(name), {make, defaults, tileInfo});
48
+ }
49
+
50
+ /** Add a type that is a mesh and nothing more, a static prop with no class to write, for a built mesh or a model
51
+ * - Each object has a color and a solid property, solid collides as the box around the mesh
52
+ * @param {string} name - The type the objects have in the level
53
+ * @param {Mesh} mesh - Shared by every object of the type
54
+ * @param {TileInfo} [tileInfo] - Its texture
55
+ * @param {Color} [color] - Its color, an object's own color property goes over it
56
+ * @memberof Level3D
57
+ * @example
58
+ * level3DAddMesh('Tree', treeMesh, tile(4)); */
59
+ function level3DAddMesh(name, mesh, tileInfo, color=WHITE)
60
+ {
61
+ ASSERT(mesh instanceof Mesh, 'mesh must be a Mesh');
62
+ ASSERT(isColor(color), 'color must be a color');
63
+ level3DAddType(name, function(pos, properties) { return level3DMakeShape(pos, properties, mesh, tileInfo); },
64
+ {color, solid: false}, tileInfo);
65
+ }
66
+
67
+ /** Make the objects of a level, each from the type added for its name
68
+ * - The level is an object: {littlejs3D: 1, objects: [{id, type, pos: [x, y, z]}, ...]}, and {} is a new one
69
+ * - rotation is pitch, yaw and roll in degrees, scale is a number for each axis, both left out when they are
70
+ * the default, and properties holds what differs from the type's defaults
71
+ * - A Color property is a #rrggbb or #rrggbbaa string, a Vector2 or Vector3 an array, as the default says
72
+ * - An object whose type was not added is skipped, with a warning in debug builds
73
+ * - What a file written by hand gets wrong uses the default: a value that is not of its default's type
74
+ * - An object its type can not make is skipped with an error in debug builds, where asserts throw, and the rest
75
+ * of the level is made
76
+ * @param {Object} level - The level, the level editor edits this same object
77
+ * @return {Array<any>} - What each object's type made, a function that made nothing is left out
78
+ * @memberof Level3D */
79
+ function level3DLoad(level)
80
+ {
81
+ ASSERT(!!level && typeof level === 'object', 'a level is an object, {} for a new one');
82
+ ASSERT(!(level.littlejs3D > LEVEL3D_VERSION), 'the level was made by a newer LittleJS');
83
+ editor3DLevelLoaded(level); // debug builds: the 3D editor takes the level, its autosaved edits go in first
84
+ const made = [];
85
+ for (const object of isArray(level.objects) ? level.objects : [])
86
+ {
87
+ if (!object || typeof object !== 'object') continue;
88
+ const result = level3DMake(object);
89
+ editor3DObjectMade(object, result); // debug builds link it for the 3D editor
90
+ result && made.push(result);
91
+ }
92
+ return made;
93
+ }
94
+
95
+ // a vec3 of an array of three numbers, as the file has them, or the fallback
96
+ function level3DVector(value, fallback)
97
+ {
98
+ return isArray(value) && value.length === 3 && value.every((v)=> isNumber(v)) ?
99
+ vec3(value[0], value[1], value[2]) : fallback;
100
+ }
101
+
102
+ // the defaults of an object's type, a Color or vector copied for each object, then its own properties over them,
103
+ // each read as its default is; one the file got wrong, a value not of its default's type, keeps the default, and
104
+ // one the type has no default for is kept as it is
105
+ function level3DProperties(type, object)
106
+ {
107
+ const properties = {}, own = object.properties;
108
+ for (const [key, value] of Object.entries(type.defaults))
109
+ properties[key] = value?.copy ? value.copy() : value;
110
+ for (const [key, value] of Object.entries(own && typeof own === 'object' ? own : {}))
111
+ {
112
+ const d = type.defaults[key];
113
+ if (isColor(d))
114
+ /^#([0-9a-f]{6}|[0-9a-f]{8})$/i.test(value) && (properties[key] = new Color().setHex(value));
115
+ else if (isVector3(d))
116
+ properties[key] = level3DVector(value, properties[key]);
117
+ else if (isVector2(d))
118
+ isArray(value) && value.length === 2 && value.every((v)=> isNumber(v)) &&
119
+ (properties[key] = vec2(value[0], value[1]));
120
+ else if (d === undefined || typeof value === typeof d)
121
+ properties[key] = value;
122
+ }
123
+ return properties;
124
+ }
125
+
126
+ // make one object of a level from the type added for its name, undefined when there is no such type or it made
127
+ // nothing
128
+ function level3DMake(object)
129
+ {
130
+ const type = level3DTypes.get(object.type);
131
+ if (!type)
132
+ {
133
+ debug && console.warn(`level3DLoad: no type added for ${object.type}, skipped`);
134
+ return;
135
+ }
136
+ const pos = level3DVector(object.pos, vec3()), properties = level3DProperties(type, object);
137
+ const {make} = type, count = engineObjects.length;
138
+ let result;
139
+ try { result = make.prototype ? new make(pos, properties) : make(pos, properties); }
140
+ catch (error)
141
+ {
142
+ // a value the type can not be made with: in debug builds, where asserts throw, the object is skipped with
143
+ // what it made so far, so the rest of the level loads and the level editor can put the value right
144
+ if (!debug) throw error;
145
+ console.error(`level3DLoad: ${object.type} ${object.id} could not be made, skipped:`, error);
146
+ for (const o of engineObjects.slice(count))
147
+ o.destroy();
148
+ return;
149
+ }
150
+ if (!result || typeof result !== 'object') return;
151
+ if (result instanceof EngineObject3D)
152
+ {
153
+ level3DBaseScale.set(result, result.scale3D.copy());
154
+ result.rotation3D = level3DVector(object.rotation, vec3()).scale(PI / 180);
155
+ result.scale3D = result.scale3D.multiply(level3DVector(object.scale, vec3(1)));
156
+ }
157
+
158
+ // the type's own properties are set on it, one the type has no default for could be a field of the engine's
159
+ for (const key in type.defaults)
160
+ result[key] = properties[key];
161
+ return result;
162
+ }
163
+
164
+ ///////////////////////////////////////////////////////////////////////////////
165
+ // the built-in types
166
+
167
+ // a static object of a mesh, with the color, tile and solid properties the built-in types have
168
+ function level3DMakeShape(pos, properties, mesh, tileInfo, asSphere=false)
169
+ {
170
+ const o = new EngineObject3D(pos, mesh, properties.tile >= 0 ? tile(properties.tile) : tileInfo, properties.color);
171
+ o.collideAsSphere3D = asSphere;
172
+ properties.solid && o.setCollision();
173
+ return o;
174
+ }
175
+
176
+ // the cylinder all Cylinder objects share, built the first time one is made
177
+ let level3DCylinderMesh;
178
+
179
+ level3DAddType('Box', function(pos, properties) { return level3DMakeShape(pos, properties, render3D.boxMesh); },
180
+ {color: WHITE, tile: -1, solid: true});
181
+ level3DAddType('Sphere', function(pos, properties)
182
+ { return level3DMakeShape(pos, properties, render3D.sphereMesh, undefined, true); },
183
+ {color: WHITE, tile: -1, solid: true});
184
+ level3DAddType('Cylinder', function(pos, properties)
185
+ { return level3DMakeShape(pos, properties, level3DCylinderMesh ||= buildCylinder()); },
186
+ {color: WHITE, tile: -1, solid: true});
187
+ level3DAddType('Light', function(pos, properties)
188
+ { return new Light3D(pos, properties.radius, properties.color, properties.intensity); },
189
+ {color: WHITE, radius: 5, intensity: 1});