littlejsengine 1.22.0 → 1.23.1
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 +65 -38
- package/EDITOR.md +359 -0
- package/README.md +12 -7
- package/REFERENCE.md +2314 -0
- package/dist/littlejs.d.ts +640 -100
- package/dist/littlejs.esm.js +3596 -1444
- package/dist/littlejs.esm.min.js +3 -3
- package/dist/littlejs.js +3583 -1444
- package/dist/littlejs.min.js +2 -2
- package/dist/littlejs.release.js +2106 -1355
- package/package.json +4 -3
- package/plugins/gltf.js +29 -13
- package/plugins/lightSystem.js +8 -6
- package/plugins/parallax.js +174 -0
- package/plugins/particleEffects.js +37 -22
- package/plugins/pluginExport.js +8 -0
- package/plugins/postProcess.js +5 -2
- package/plugins/render3d.js +59 -21
- package/plugins/render3dEditor.js +1058 -118
- package/plugins/render3dExtras.js +82 -21
- package/plugins/render3dLevel.js +328 -8
- package/plugins/textureSheet.js +1 -0
- package/plugins/tweenSystem.js +39 -34
- package/plugins/uiSystem.js +7 -3
- package/plugins/zzfxm.js +161 -159
- package/src/engine.js +1 -1
- package/src/engineAudio.js +17 -3
- package/src/engineBuild.mjs +18 -2
- package/src/engineDraw.js +26 -10
- package/src/engineEditor.js +515 -52
- package/src/engineExport.js +5 -0
- package/src/engineInput.js +48 -6
- package/src/engineObject.js +675 -675
- package/src/engineRelease.js +17 -2
- package/src/engineSettings.js +14 -0
- package/src/engineTileLayer.js +2 -1
- package/src/engineUtilities.js +291 -291
- package/src/engineWebGL.js +12 -3
package/COPYRIGHT.txt
CHANGED
|
@@ -1,38 +1,65 @@
|
|
|
1
|
-
LittleJS Notices and Third-Party Licenses
|
|
2
|
-
=========================================
|
|
3
|
-
|
|
4
|
-
This repository is licensed under the MIT License. See the file LICENSE.
|
|
5
|
-
|
|
6
|
-
This file collects copyright notices and third-party license texts for
|
|
7
|
-
software included with or used by this repository. If you redistribute
|
|
8
|
-
LittleJS with third-party components, keep the relevant notices below.
|
|
9
|
-
|
|
10
|
-
-------------------------------------------------------------------------------
|
|
11
|
-
|
|
12
|
-
LittleJS Engine License
|
|
13
|
-
|
|
14
|
-
Copyright (c) 2021 Frank Force
|
|
15
|
-
http://www.frankforce.com
|
|
16
|
-
Licensed under the MIT License. See LICENSE.
|
|
17
|
-
|
|
18
|
-
-------------------------------------------------------------------------------
|
|
19
|
-
|
|
20
|
-
Box2D License
|
|
21
|
-
|
|
22
|
-
Copyright (c) 2006-2013 Erin Catto http://www.gphysics.com
|
|
23
|
-
|
|
24
|
-
This software is provided 'as-is', without any express or implied
|
|
25
|
-
warranty. In no event will the authors be held liable for any damages
|
|
26
|
-
arising from the use of this software.
|
|
27
|
-
|
|
28
|
-
Permission is granted to anyone to use this software for any purpose,
|
|
29
|
-
including commercial applications, and to alter it and redistribute it
|
|
30
|
-
freely, subject to the following restrictions:
|
|
31
|
-
|
|
32
|
-
1. The origin of this software must not be misrepresented; you must not
|
|
33
|
-
claim that you wrote the original software. If you use this software
|
|
34
|
-
in a product, an acknowledgment in the product documentation would be
|
|
35
|
-
appreciated but is not required.
|
|
36
|
-
2. Altered source versions must be plainly marked as such, and must not be
|
|
37
|
-
misrepresented as being the original software.
|
|
38
|
-
3. This notice may not be removed or altered from any source distribution.
|
|
1
|
+
LittleJS Notices and Third-Party Licenses
|
|
2
|
+
=========================================
|
|
3
|
+
|
|
4
|
+
This repository is licensed under the MIT License. See the file LICENSE.
|
|
5
|
+
|
|
6
|
+
This file collects copyright notices and third-party license texts for
|
|
7
|
+
software included with or used by this repository. If you redistribute
|
|
8
|
+
LittleJS with third-party components, keep the relevant notices below.
|
|
9
|
+
|
|
10
|
+
-------------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
LittleJS Engine License
|
|
13
|
+
|
|
14
|
+
Copyright (c) 2021 Frank Force
|
|
15
|
+
http://www.frankforce.com
|
|
16
|
+
Licensed under the MIT License. See LICENSE.
|
|
17
|
+
|
|
18
|
+
-------------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
Box2D License
|
|
21
|
+
|
|
22
|
+
Copyright (c) 2006-2013 Erin Catto http://www.gphysics.com
|
|
23
|
+
|
|
24
|
+
This software is provided 'as-is', without any express or implied
|
|
25
|
+
warranty. In no event will the authors be held liable for any damages
|
|
26
|
+
arising from the use of this software.
|
|
27
|
+
|
|
28
|
+
Permission is granted to anyone to use this software for any purpose,
|
|
29
|
+
including commercial applications, and to alter it and redistribute it
|
|
30
|
+
freely, subject to the following restrictions:
|
|
31
|
+
|
|
32
|
+
1. The origin of this software must not be misrepresented; you must not
|
|
33
|
+
claim that you wrote the original software. If you use this software
|
|
34
|
+
in a product, an acknowledgment in the product documentation would be
|
|
35
|
+
appreciated but is not required.
|
|
36
|
+
2. Altered source versions must be plainly marked as such, and must not be
|
|
37
|
+
misrepresented as being the original software.
|
|
38
|
+
3. This notice may not be removed or altered from any source distribution.
|
|
39
|
+
|
|
40
|
+
-------------------------------------------------------------------------------
|
|
41
|
+
|
|
42
|
+
ZzFXM License
|
|
43
|
+
|
|
44
|
+
The ZzFXM plugin (plugins/zzfxm.js) is a port of ZzFXM, the Zuper Zmall Zound Zynth music player.
|
|
45
|
+
https://github.com/keithclark/ZzFXM
|
|
46
|
+
|
|
47
|
+
Copyright (c) 2020 Keith Clark, Frank Force
|
|
48
|
+
|
|
49
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
50
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
51
|
+
in the Software without restriction, including without limitation the rights
|
|
52
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
53
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
54
|
+
furnished to do so, subject to the following conditions:
|
|
55
|
+
|
|
56
|
+
The above copyright notice and this permission notice shall be included in all
|
|
57
|
+
copies or substantial portions of the Software.
|
|
58
|
+
|
|
59
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
60
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
61
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
62
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
63
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
64
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
65
|
+
SOFTWARE.
|
package/EDITOR.md
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# Making your own level editor with LittleJS
|
|
2
|
+
|
|
3
|
+
LittleJS has two level editors built in, one for 2D tile maps and one for 3D levels. They are meant to be a
|
|
4
|
+
starting point: a game adds its own object types, properties, keys, buttons and tools, and ends up with an
|
|
5
|
+
editor made for that one game. Everything goes through one object, `levelEditor`, and the same calls work in
|
|
6
|
+
both editors.
|
|
7
|
+
|
|
8
|
+
This page is written to be followed by a person or by an AI coding assistant. Every code block marked "tested"
|
|
9
|
+
is run by `test/editorCustom.test.mjs` straight from this file, so it works as written.
|
|
10
|
+
|
|
11
|
+
## The rules
|
|
12
|
+
|
|
13
|
+
1. **Everything is on `levelEditor`**, or on a class of your own that extends `LevelEditor`. It is exported
|
|
14
|
+
from every build, script tag and ES module alike.
|
|
15
|
+
2. **No guards are needed.** In release builds `LevelEditor` is a stub: it takes what you add and never calls
|
|
16
|
+
it. The editor's code is only in the debug builds (`dist/littlejs.js`, `dist/littlejs.esm.js`).
|
|
17
|
+
3. **The level data is the source of truth.** The editor changes the level object (3D) or the Tiled map (2D) the
|
|
18
|
+
game loaded, and brings the game's objects in line. Change the level through `edit3D` or `edit2D`, never the
|
|
19
|
+
game's objects.
|
|
20
|
+
4. **An edit is a stroke.** Make changes with `edit3D.change(...)`, `edit3D.place(...)`, `edit2D.paint(...)` or
|
|
21
|
+
`edit2D.changeObjects(...)`, then call `strokeEnd()`: that is one undo step, autosaved. A tool's press, drag
|
|
22
|
+
and release are ended for you.
|
|
23
|
+
5. **A type is named by a string**, never by its class, because minified builds rename classes.
|
|
24
|
+
6. **Use `levelEditor.edit3D` and `levelEditor.edit2D` only inside what the editor calls**: a key's action, a
|
|
25
|
+
button's click, a tool's callbacks, `onUpdate`, `onDraw`. In a release build they are undefined, and none of
|
|
26
|
+
those are ever called.
|
|
27
|
+
7. **`levelEditor.is3D`** says which editor is in use, for a game that has both kinds of level.
|
|
28
|
+
|
|
29
|
+
## The hooks
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
levelEditor.open(); // start in the editor; close() plays on with the changes
|
|
33
|
+
levelEditor.isOpen; // true while editing
|
|
34
|
+
levelEditor.onRestart = ()=> buildLevel(); // adds a Restart button: load the level again
|
|
35
|
+
levelEditor.onPlayFrom = (pos)=> player.pos = pos; // adds "Play from mouse": put the player at the mouse
|
|
36
|
+
levelEditor.onOpen = ()=> {}; // the editor opened
|
|
37
|
+
levelEditor.onClose = ()=> {}; // it closed, the game plays on
|
|
38
|
+
levelEditor.onUpdate = ()=> {}; // each frame while it is open
|
|
39
|
+
levelEditor.onDraw = ()=> {}; // while it draws the level, for overlays of your own
|
|
40
|
+
levelEditor.onPanel = (box)=> {}; // once, when the panel is made: a box in it for your own controls
|
|
41
|
+
levelEditor.onSave = (text, name)=> false; // Save: return true when you kept the file yourself
|
|
42
|
+
levelEditor.use3D = true; // force the 3D editor (false, the 2D one); undefined picks by the level
|
|
43
|
+
levelEditor.onTile = (layer, pos, tile)=> {}; // 2D: a tile was painted, tile undefined when erased
|
|
44
|
+
levelEditor.paletteTiles = [0, 1, 10]; // 2D: the tiles the palette shows, undefined for the whole sheet
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Without code, `0` on the debug overlay (`Esc`) opens the editor, and `Esc` then switches between editing and
|
|
48
|
+
playing.
|
|
49
|
+
|
|
50
|
+
## Your own object types, and their properties as panel inputs
|
|
51
|
+
|
|
52
|
+
A type is a name, something to make, and default properties. The editor lists the type to place, and shows an
|
|
53
|
+
input for each default whose value is a number, a true or false, a string, a `Color` or a vector. What the
|
|
54
|
+
level designer sets is saved in the level and set on the object when the level loads.
|
|
55
|
+
|
|
56
|
+
3D, tested:
|
|
57
|
+
|
|
58
|
+
<!-- test:type3d -->
|
|
59
|
+
```javascript
|
|
60
|
+
class Spawner extends EngineObject3D
|
|
61
|
+
{
|
|
62
|
+
// a level type's class is made with (pos3D, properties)
|
|
63
|
+
constructor(pos, properties)
|
|
64
|
+
{
|
|
65
|
+
super(pos, render3D.boxMesh, undefined, properties.color);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
level3DAddType('Spawner', Spawner, {rate: 2, enemy: 'bat', color: hsl(0, 1, .5), active: true});
|
|
69
|
+
level3DAddType('PlayerStart', (pos)=> playerStart = pos); // a function, for what is not an object
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
2D, tested:
|
|
73
|
+
|
|
74
|
+
<!-- test:type2d -->
|
|
75
|
+
```javascript
|
|
76
|
+
class Coin extends EngineObject
|
|
77
|
+
{
|
|
78
|
+
constructor(pos) { super(pos, vec2(1)); }
|
|
79
|
+
}
|
|
80
|
+
objectLayersAddType('Coin', Coin, {value: 1});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
- In 3D a class needs its own constructor that takes the position: one that passes every argument on to
|
|
84
|
+
`EngineObject3D` would pass the properties as its mesh.
|
|
85
|
+
- `level3DAddMesh('Tree', mesh, tileInfo)` is a 3D type with no class: a static prop with `color` and `solid`.
|
|
86
|
+
- Changing a 3D object's property in the editor makes the object again, since its constructor takes them.
|
|
87
|
+
- 3D prefabs, small levels placed many times, are types too: see "Prefabs" in [REFERENCE.md](REFERENCE.md). The
|
|
88
|
+
panel's Load prefab button adds one from a file to the level being edited.
|
|
89
|
+
|
|
90
|
+
## A key of your own
|
|
91
|
+
|
|
92
|
+
`addKey(key, action, helpLine)`. The key is a letter or digit (`'k'`), a key's name in any case (`'Delete'`,
|
|
93
|
+
`'F2'`, `'Enter'`, `'Space'`), or either with `'ctrl+'` in front. The action is called with whether Shift is
|
|
94
|
+
held. Return `false` when it did nothing.
|
|
95
|
+
|
|
96
|
+
- A key the editor already uses is replaced by yours, with a warning in the console when the editor opens. The
|
|
97
|
+
two editors use different keys, so check the `?` help of the one your game uses.
|
|
98
|
+
- `Escape` and `0` are the editor's own, to play and to exit, and are not taken.
|
|
99
|
+
- Ctrl is the one modifier. For Shift, read the argument the action is given.
|
|
100
|
+
|
|
101
|
+
3D, tested:
|
|
102
|
+
|
|
103
|
+
<!-- test:key3d -->
|
|
104
|
+
```javascript
|
|
105
|
+
// K lifts every selected object one unit, as one undo
|
|
106
|
+
levelEditor.addKey('k', ()=>
|
|
107
|
+
{
|
|
108
|
+
const edit = levelEditor.edit3D;
|
|
109
|
+
const changed = edit.change((list)=>
|
|
110
|
+
{
|
|
111
|
+
for (const object of list)
|
|
112
|
+
if (edit.selection.has(object.id))
|
|
113
|
+
edit.setTransform(object, edit.pos(object).add(vec3(0, 1, 0)));
|
|
114
|
+
});
|
|
115
|
+
edit.strokeEnd();
|
|
116
|
+
return changed; // false when nothing was selected
|
|
117
|
+
}, 'K: lift the selection one unit');
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
2D, tested:
|
|
121
|
+
|
|
122
|
+
<!-- test:key2d -->
|
|
123
|
+
```javascript
|
|
124
|
+
// T paints tile 5 under the mouse on the selected tile layer, as one undo
|
|
125
|
+
levelEditor.addKey('t', ()=>
|
|
126
|
+
{
|
|
127
|
+
const edit = levelEditor.edit2D;
|
|
128
|
+
if (!edit.hover) return false; // the mouse is over no cell
|
|
129
|
+
edit.paint(edit.hover, 5);
|
|
130
|
+
edit.strokeEnd();
|
|
131
|
+
}, 'T: paint tile 5 under the mouse');
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## A panel button of your own
|
|
135
|
+
|
|
136
|
+
`addButton(label, onClick, title)`. Tested:
|
|
137
|
+
|
|
138
|
+
<!-- test:button3d -->
|
|
139
|
+
```javascript
|
|
140
|
+
levelEditor.addButton('Scatter 5 spawners', ()=>
|
|
141
|
+
{
|
|
142
|
+
const edit = levelEditor.edit3D;
|
|
143
|
+
for (let i = 0; i < 5; ++i)
|
|
144
|
+
edit.place('Spawner', vec3(rand(-8, 8), .5, rand(-8, 8)));
|
|
145
|
+
edit.strokeEnd(); // the five are one undo
|
|
146
|
+
}, 'Put five spawners at random places');
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
For anything more than a button, `onPanel` gives you a box in the panel to fill with your own HTML.
|
|
150
|
+
|
|
151
|
+
## A tool of your own
|
|
152
|
+
|
|
153
|
+
`addTool(name, tool)` adds a tool beside the editor's own: a button in the panel by its name, and a key if you
|
|
154
|
+
give one. While it is on, the left button in the level is your tool's. Each callback is given
|
|
155
|
+
`{pos, cell, ray, shift, ctrl}`:
|
|
156
|
+
|
|
157
|
+
- `pos`: where the mouse is in the level. In 3D a `Vector3` on the level or the ground, in 2D a `Vector2`.
|
|
158
|
+
- `cell`: 2D, the tile cell under the mouse on the selected tile layer, or undefined.
|
|
159
|
+
- `ray`: 3D, the mouse's ray.
|
|
160
|
+
|
|
161
|
+
What the callbacks change is one undo: the editor ends the stroke at the release, and takes it back when the
|
|
162
|
+
right button or Escape ends the press. Do not call `strokeEnd` in a tool.
|
|
163
|
+
|
|
164
|
+
3D, a tool that lays a row of posts along a drag, tested:
|
|
165
|
+
|
|
166
|
+
<!-- test:tool3d -->
|
|
167
|
+
```javascript
|
|
168
|
+
let lastPost;
|
|
169
|
+
levelEditor.addTool('Posts',
|
|
170
|
+
{
|
|
171
|
+
key: 'o',
|
|
172
|
+
hint: 'Posts: drag along the ground to lay a row',
|
|
173
|
+
onPress(at)
|
|
174
|
+
{
|
|
175
|
+
if (!at.pos) return false; // not on the level
|
|
176
|
+
levelEditor.edit3D.place('Cylinder', lastPost = at.pos.add(vec3(0, .5, 0)));
|
|
177
|
+
},
|
|
178
|
+
onDrag(at)
|
|
179
|
+
{
|
|
180
|
+
// another post each 2 units along the drag
|
|
181
|
+
if (at.pos && at.pos.distance(lastPost) >= 2)
|
|
182
|
+
levelEditor.edit3D.place('Cylinder', lastPost = at.pos.add(vec3(0, .5, 0)));
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
2D, a tool that paints a tile wherever it is dragged, Shift erasing, tested:
|
|
188
|
+
|
|
189
|
+
<!-- test:tool2d -->
|
|
190
|
+
```javascript
|
|
191
|
+
levelEditor.addTool('Water',
|
|
192
|
+
{
|
|
193
|
+
key: 'w',
|
|
194
|
+
hint: 'Water: drag to fill cells · Shift erases',
|
|
195
|
+
onPress(at) { at.cell && levelEditor.edit2D.paint(at.cell, at.shift ? -1 : 7); },
|
|
196
|
+
onDrag(at) { at.cell && levelEditor.edit2D.paint(at.cell, at.shift ? -1 : 7); },
|
|
197
|
+
onDraw(at)
|
|
198
|
+
{
|
|
199
|
+
// a cell is counted from its layer's corner, which is at the layer's pos in the world
|
|
200
|
+
const corner = levelEditor.edit2D.layer.pos;
|
|
201
|
+
at.cell && drawRect(corner.add(at.cell).add(vec2(.5)), vec2(1), hsl(.55, 1, .5, .4));
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
A tool is put down by its key or button again, or by picking one of the editor's own tools, layers or types.
|
|
207
|
+
`levelEditor.tool` is the name of the one that is on.
|
|
208
|
+
|
|
209
|
+
`onDraw`, a tool's and the editor's, draws in the level as the editor does: in the 2D editor with the 2D draws
|
|
210
|
+
(`drawRect`, `drawLine`), and in the 3D editor inside the 3D pass, with `render3D.drawBox`, `render3D.drawLine`
|
|
211
|
+
and the rest.
|
|
212
|
+
|
|
213
|
+
## An editor class of your own
|
|
214
|
+
|
|
215
|
+
Everything above can be a class instead, with the hooks as methods. Tested:
|
|
216
|
+
|
|
217
|
+
<!-- test:class -->
|
|
218
|
+
```javascript
|
|
219
|
+
class MyEditor extends LevelEditor
|
|
220
|
+
{
|
|
221
|
+
constructor()
|
|
222
|
+
{
|
|
223
|
+
super();
|
|
224
|
+
this.showZones = true;
|
|
225
|
+
this.addKey('z', ()=> { this.showZones = !this.showZones; }, 'Z: show the spawn zones');
|
|
226
|
+
this.addButton('Clear spawners', ()=> this.clearSpawners());
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// the hooks are methods
|
|
230
|
+
onRestart() { restarts++; }
|
|
231
|
+
onDraw() { this.showZones && drawnZones++; }
|
|
232
|
+
|
|
233
|
+
clearSpawners()
|
|
234
|
+
{
|
|
235
|
+
const edit = this.edit3D;
|
|
236
|
+
edit.change((list)=>
|
|
237
|
+
{
|
|
238
|
+
for (let i = list.length; i--;)
|
|
239
|
+
list[i].type === 'Spawner' && list.splice(i, 1);
|
|
240
|
+
});
|
|
241
|
+
edit.strokeEnd();
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
setLevelEditor(new MyEditor);
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
- Call `setLevelEditor` before the editor opens, and use `levelEditor` itself afterwards, not a copy of it
|
|
248
|
+
taken earlier.
|
|
249
|
+
- `keys`, `buttons`, `tools` and `tool` are fields the class keeps what you added in: do not name your own
|
|
250
|
+
fields those.
|
|
251
|
+
- A method of your class is a hook the same as one you set: defining `onRestart` shows the Restart button.
|
|
252
|
+
|
|
253
|
+
## The edit functions
|
|
254
|
+
|
|
255
|
+
### `levelEditor.edit3D`
|
|
256
|
+
|
|
257
|
+
| Member | What it is |
|
|
258
|
+
| --- | --- |
|
|
259
|
+
| `level` | The level object being edited |
|
|
260
|
+
| `objects` | Its objects, the list in the level: read it, edit through `change` |
|
|
261
|
+
| `selection` | A `Set` of the selected objects' ids, yours to add to and delete from |
|
|
262
|
+
| `selected()` | The selected objects |
|
|
263
|
+
| `made(id)` | What the game made for an object |
|
|
264
|
+
| `change((list)=> {...})` | Edit a copy of the object list; false when nothing changed |
|
|
265
|
+
| `changePart(name, (part)=> newPart)` | Edit the level's `scene`, `voxels`, `terrain` or `prefabs` block |
|
|
266
|
+
| `strokeEnd()` | End the edit: one undo step, and the autosave |
|
|
267
|
+
| `strokeCancel()` | Take the edit being made back |
|
|
268
|
+
| `place(type, pos3D)` | Add an object of a type, selected; its id, or undefined when there is no such type or the level can not be edited |
|
|
269
|
+
| `setTransform(object, pos3D, rotation, scale3D)` | Inside `change`, on an object of its list: write a place, a rotation in degrees and a scale; leave one out to keep it |
|
|
270
|
+
| `setProperty(object, name, value)` | Inside `change`, on an object of its list: write a property, left out of the file when it is the type's default |
|
|
271
|
+
| `pos(object)`, `rotation(object)`, `scale(object)` | Read them as vectors, the rotation in degrees |
|
|
272
|
+
| `mousePoint()` | Where the mouse is on the level or the ground, undefined while it is over the panel |
|
|
273
|
+
| `undo(redo)` | Undo, or redo with true |
|
|
274
|
+
| `toJSON()` | The level as the text Save writes |
|
|
275
|
+
|
|
276
|
+
### `levelEditor.edit2D`
|
|
277
|
+
|
|
278
|
+
| Member | What it is |
|
|
279
|
+
| --- | --- |
|
|
280
|
+
| `map` | The Tiled map of the selected layer |
|
|
281
|
+
| `layer` | The selected tile layer, a `TileLayer`, undefined on an object layer |
|
|
282
|
+
| `objects` | A copy of the selected object layer's objects, as Tiled has them |
|
|
283
|
+
| `hover` | The cell under the mouse on the selected tile layer |
|
|
284
|
+
| `selection` | A `Set` of the selected objects' ids |
|
|
285
|
+
| `paint(cell, tile, direction, mirror)` | Set a cell of the selected tile layer to a tile index, -1 erases; false off the layer |
|
|
286
|
+
| `changeObjects((list)=> {...})` | Edit a copy of the selected object layer's objects |
|
|
287
|
+
| `strokeEnd()` | End the edit: one undo step, and the autosave |
|
|
288
|
+
| `strokeCancel()` | Take the edit being made back |
|
|
289
|
+
| `bulk(()=> {...})` | Many `paint` calls with one redraw a layer |
|
|
290
|
+
| `undo(redo)` | Undo, or redo with true |
|
|
291
|
+
| `toJSON()` | The map as the text Save writes |
|
|
292
|
+
|
|
293
|
+
## The files
|
|
294
|
+
|
|
295
|
+
- 3D: plain JSON, `{littlejs3D: 1, scene, voxels, terrain, prefabs, objects: [{id, type, pos, rotation, scale,
|
|
296
|
+
properties}]}`. Load with `level3DLoad(await fetchJSON('level.json'))`.
|
|
297
|
+
- 2D: Tiled JSON. Load with `tileLayersLoad(map)` and `objectLayersLoad(map)`. Tiled itself can open the file.
|
|
298
|
+
- A game that loads the same level object again, as a restart does, gets the edits.
|
|
299
|
+
- A 3D level's block map shows the tiles of the sheet given to `level3DVoxelSetup`, or of the game's first image;
|
|
300
|
+
a game that has loaded no image gets plain colored blocks.
|
|
301
|
+
- To keep levels somewhere of your own, a server or your own format, use `onSave`:
|
|
302
|
+
|
|
303
|
+
```javascript
|
|
304
|
+
levelEditor.onSave = (text, fileName)=>
|
|
305
|
+
{
|
|
306
|
+
fetch('/levels/' + fileName, {method: 'PUT', body: text});
|
|
307
|
+
return true; // kept, the editor writes no file
|
|
308
|
+
};
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
`onSave` may be an async function. In the 3D editor it is asked for a prefab too, when Save is pressed inside one.
|
|
312
|
+
|
|
313
|
+
### A game opened from disk
|
|
314
|
+
|
|
315
|
+
A page opened straight from a folder, with no server, can not `fetch` a JSON file. Keep the level as a script
|
|
316
|
+
instead: a file that sets a variable, loaded with a script tag before the game. `onSave` writes it. Tested:
|
|
317
|
+
|
|
318
|
+
<!-- test:disklevel -->
|
|
319
|
+
```javascript
|
|
320
|
+
// index.html has <script src="level.js"></script> before the game's own script, and level.js is one line:
|
|
321
|
+
// var level = {"littlejs3D": 1, "objects": [...]};
|
|
322
|
+
levelEditor.onSave = (text, fileName)=>
|
|
323
|
+
{
|
|
324
|
+
saveText('var level = ' + text.trim() + ';\n', 'level.js', 'text/javascript');
|
|
325
|
+
return true; // kept, the editor writes no JSON file
|
|
326
|
+
};
|
|
327
|
+
level3DLoad(level); // the same object the script made, so the editor's changes are the game's
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
Save then downloads `level.js`, to put in place of the old one. The autosave still brings unsaved edits back
|
|
331
|
+
after a reload.
|
|
332
|
+
|
|
333
|
+
## A checklist for a custom editor
|
|
334
|
+
|
|
335
|
+
1. Register the game's types with their defaults, before the level loads.
|
|
336
|
+
2. Set `onRestart` and `onPlayFrom`, so Restart and Play from mouse work.
|
|
337
|
+
3. Add keys and buttons for what the game's designers do most, each ending its stroke.
|
|
338
|
+
4. Add a tool for what is done with the mouse in the level: paths, zones, links between objects.
|
|
339
|
+
5. Draw what the level does not show by itself in `onDraw`: zones, ranges, links.
|
|
340
|
+
6. Ship the release build: the editor and everything you added to it are gone.
|
|
341
|
+
|
|
342
|
+
## Where the working examples are
|
|
343
|
+
|
|
344
|
+
- `examples/shorts/render3dLevelEditor.js`: a 3D level with its own Coin and PlayerStart types and both hooks.
|
|
345
|
+
- `examples/shorts/render3dPrefab.js`: the 3D editor used as a prefab maker.
|
|
346
|
+
- `examples/shorts/levelEditor.js` and `examples/platformer/`: the 2D editor with a game's own types, palette
|
|
347
|
+
and hooks.
|
|
348
|
+
|
|
349
|
+
## What it does not do
|
|
350
|
+
|
|
351
|
+
- **It does not replace the editor's own tools.** Your keys, buttons and tools are added beside them; how the
|
|
352
|
+
built-in Move tool snaps, or how painting works, is not something a game changes. That takes an engine build
|
|
353
|
+
of your own: get the LittleJS source at the version you use, edit `src/engineEditor.js` or
|
|
354
|
+
`plugins/render3dEditor.js`, run `npm run build`, and use the `dist/littlejs.js` it makes. A changed copy
|
|
355
|
+
of the file can not be loaded beside the engine, the debug build has the editor in it already, and a build of
|
|
356
|
+
your own has to be made again for each engine update.
|
|
357
|
+
- **A tool has no handles of its own.** It has the press, the drag and the release, and it can draw.
|
|
358
|
+
- **The editors' inner functions**, the ones named `editor...` and `editor3D...`, are not part of this. They can
|
|
359
|
+
be reached in a script-tag debug build, but they change between versions.
|
package/README.md
CHANGED
|
@@ -40,7 +40,8 @@ The code is very clean and well documented with many examples to get you started
|
|
|
40
40
|
- Blazing fast WebGL2 + Canvas2D hybrid rendering system
|
|
41
41
|
- Apply [Shadertoy](https://www.shadertoy.com) style shaders for post-processing effects, or on any object or draw
|
|
42
42
|
- 2D lights with soft shadows, tinted glass and emissive objects
|
|
43
|
-
- Robust particle effect system and [effect design tool](https://killedbyapixel.github.io/LittleJS/examples/particles/)
|
|
43
|
+
- Robust particle effect system with a library of ready made effects and an [effect design tool](https://killedbyapixel.github.io/LittleJS/examples/particles/)
|
|
44
|
+
- Parallax background layers that repeat across a level of any size
|
|
44
45
|
- Load sprites and animations into texture sheets at runtime, or import [TexturePacker](https://www.codeandweb.com/texturepacker) and [Aseprite](https://www.aseprite.org) atlases
|
|
45
46
|
|
|
46
47
|
### 🧊 LittleJS 3D
|
|
@@ -48,8 +49,9 @@ The code is very clean and well documented with many examples to get you started
|
|
|
48
49
|
- Built-in 3D renderer that shares the canvas with your 2D game
|
|
49
50
|
- 3D objects with the same physics, children and timers as 2D
|
|
50
51
|
- Shape builders, extruded sprites and text, and OBJ and glTF model loading
|
|
51
|
-
- Height map terrain with collision and raycasts
|
|
52
|
-
-
|
|
52
|
+
- Height map terrain and voxel maps with collision and raycasts
|
|
53
|
+
- 3D levels and prefabs, built in the 3D level editor and loaded with one call
|
|
54
|
+
- Shadow maps, colored lights, spotlights, lens flares, specular, emissive glow and fog
|
|
53
55
|
- Particles, trails, billboards and instanced drawing
|
|
54
56
|
- Orbit, chase and first person cameras with mouse picking
|
|
55
57
|
- Custom shaders on any object
|
|
@@ -66,6 +68,7 @@ The code is very clean and well documented with many examples to get you started
|
|
|
66
68
|
|
|
67
69
|
- Comprehensive input handling for mouse, keyboard, gamepad, and touch
|
|
68
70
|
- Customizable on screen gamepad designed for mobile devices
|
|
71
|
+
- Pinch to zoom on touch screens, read the same way as the mouse wheel
|
|
69
72
|
|
|
70
73
|
### 💥 Physics
|
|
71
74
|
|
|
@@ -85,9 +88,11 @@ The code is very clean and well documented with many examples to get you started
|
|
|
85
88
|
### 🛠️ Developer Tools
|
|
86
89
|
|
|
87
90
|
- Live example browser with code editor
|
|
88
|
-
-
|
|
91
|
+
- Built-in 2D and 3D level editors that edit your game while it runs, with undo, autosave and prefabs
|
|
92
|
+
- Make the editors your own with your game's own object types, keys, buttons and tools, see the [editor guide](https://github.com/KilledByAPixel/LittleJS/blob/main/EDITOR.md)
|
|
93
|
+
- 2D levels load and save as [Tiled](https://github.com/mapeditor/tiled) JSON, so Tiled can edit them too
|
|
89
94
|
- UI system with buttons, sliders, text input and nine-slice skins
|
|
90
|
-
- Tween system with easing curves
|
|
95
|
+
- Tween system with easing curves, and a scene system for titles, menus and game states
|
|
91
96
|
- Debug overlay and primitive rendering system
|
|
92
97
|
- Medal tracking system with [Newgrounds](https://www.newgrounds.com/) support
|
|
93
98
|
- Node.js build system
|
|
@@ -136,6 +141,7 @@ engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost);
|
|
|
136
141
|
- [Tutorial: Breakout](https://github.com/KilledByAPixel/LittleJS/tree/main/examples/breakoutTutorial) - Learn how to make a simple game from scratch
|
|
137
142
|
- [Tutorial: Make a ski game](https://eoinmcgrath.com/little-ski/tutorial.html) - A tutorial by eoinmcg that shows how to make a pixel art style game
|
|
138
143
|
- [LittleJS Quick Reference Sheet](https://github.com/KilledByAPixel/LittleJS/blob/main/REFERENCE.md) - A reference sheet to help you get started
|
|
144
|
+
- [Making Your Own Level Editor](https://github.com/KilledByAPixel/LittleJS/blob/main/EDITOR.md) - How to turn the built in 2D and 3D level editors into an editor for your own game
|
|
139
145
|
- [LittleJS FAQ](https://github.com/KilledByAPixel/LittleJS/blob/main/FAQ.md) - Answers to common questions about LittleJS
|
|
140
146
|
- [JS13k Branch](https://github.com/KilledByAPixel/LittleJS/tree/js13k) - A special branch for size coding events that builds to a 7KB zip
|
|
141
147
|
|
|
@@ -145,7 +151,7 @@ LittleJS comes with several demos both for learning and using as starter project
|
|
|
145
151
|
|
|
146
152
|
- [Example Browser](https://killedbyapixel.github.io/LittleJS/examples/) - Live example browser with all examples and editable source
|
|
147
153
|
- [LittleJS Arcade](https://killedbyapixel.github.io/LittleJSArcade/) - Over 50 example games you can use as starter projects
|
|
148
|
-
- [Short Examples](https://github.com/KilledByAPixel/LittleJS/tree/main/examples/shorts) -
|
|
154
|
+
- [Short Examples](https://github.com/KilledByAPixel/LittleJS/tree/main/examples/shorts) - 100+ single-file demos showing off individual engine features
|
|
149
155
|
- [Breakout](https://killedbyapixel.github.io/LittleJS/examples/breakout/) - Block breaking game with post-processing effects
|
|
150
156
|
- [Puzzle Game](https://killedbyapixel.github.io/LittleJS/examples/puzzle/) - Match 3 puzzle game with HD rendering and high score tracking
|
|
151
157
|
- [Platformer](https://killedbyapixel.github.io/LittleJS/examples/platformer/) - Platformer/shooter demo that loads level data
|
|
@@ -153,7 +159,6 @@ LittleJS comes with several demos both for learning and using as starter project
|
|
|
153
159
|
- [3D Example](https://killedbyapixel.github.io/LittleJS/examples/3d/) - The 3D plugin in one scene: terrain, shadows, lights, sprites, particles and bloom
|
|
154
160
|
- [3D Racing Game](https://killedbyapixel.github.io/LittleJS/examples/?example=3D%20Racing%20Game) - Built-in 3D plugin: terrain, shadows and a chase camera in one short file
|
|
155
161
|
- [Three.js Platformer](https://killedbyapixel.github.io/LittleJS/examples/threejs/) - 3D platformer with LittleJS gameplay and Three.js rendering
|
|
156
|
-
- [Stress Test](https://killedbyapixel.github.io/LittleJS/examples/stress/) - Sprite rendering benchmark and music system demo
|
|
157
162
|
- [Particle System Designer](https://killedbyapixel.github.io/LittleJS/examples/particles/) - Particle system editor and visualizer
|
|
158
163
|
|
|
159
164
|
## Builds
|