littlejsengine 1.9.1 → 1.9.3
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/README.md +11 -9
- package/{build → dist}/littlejs.d.ts +48 -43
- package/{build → dist}/littlejs.esm.js +256 -147
- package/dist/littlejs.esm.min.js +1 -0
- package/{build → dist}/littlejs.js +256 -147
- package/dist/littlejs.min.js +1 -0
- package/{build → dist}/littlejs.release.js +249 -144
- package/examples/breakout/game.js +2 -2
- package/examples/breakout/gameObjects.js +3 -3
- package/examples/breakout/index.html +3 -3
- package/examples/breakoutTutorial/index.html +2 -2
- package/examples/electron/build.js +1 -1
- package/examples/electron/game.js +49 -38
- package/examples/electron/index.html +2 -2
- package/examples/electron/tiles.png +0 -0
- package/examples/empty/index.html +1 -1
- package/examples/js13k/build.js +1 -1
- package/examples/js13k/game.js +10 -9
- package/examples/js13k/index.html +13 -13
- package/examples/js13k/tiles.png +0 -0
- package/examples/logo.png +0 -0
- package/examples/module/game.js +45 -41
- package/examples/module/index.html +1 -1
- package/examples/module/tiles.png +0 -0
- package/examples/particles/index.html +1 -1
- package/examples/platformer/data/gameLevelData.tmx +143 -0
- package/examples/platformer/data/gameLevelData.tsx +4 -0
- package/examples/platformer/game.js +31 -11
- package/examples/platformer/gameCharacter.js +9 -7
- package/examples/platformer/gameEffects.js +105 -164
- package/examples/platformer/gameLevel.js +164 -181
- package/examples/platformer/gameLevelData.js +181 -0
- package/examples/platformer/gameObjects.js +71 -26
- package/examples/platformer/gamePlayer.js +3 -2
- package/examples/platformer/index.html +8 -7
- package/examples/platformer/tiles.png +0 -0
- package/examples/platformer/tilesLevel.png +0 -0
- package/examples/puzzle/game.js +12 -12
- package/examples/puzzle/index.html +2 -2
- package/examples/screenshot.jpg +0 -0
- package/examples/starter/build.js +1 -1
- package/examples/starter/game.js +6 -6
- package/examples/starter/index.html +13 -13
- package/examples/starter/tiles.png +0 -0
- package/examples/stress/index.html +2 -2
- package/examples/typescript/build.bat +4 -1
- package/examples/typescript/game.js +34 -31
- package/examples/typescript/game.ts +40 -36
- package/examples/typescript/index.html +1 -1
- package/examples/typescript/tiles.png +0 -0
- package/package.json +3 -3
- package/reference.md +409 -0
- package/src/engine.js +46 -41
- package/src/engineAudio.js +22 -19
- package/src/engineBuild.js +9 -2
- package/src/engineDebug.js +7 -3
- package/src/engineDraw.js +8 -7
- package/src/engineInput.js +5 -5
- package/src/engineMedals.js +3 -3
- package/src/engineObject.js +2 -2
- package/src/engineParticles.js +16 -15
- package/src/engineSettings.js +3 -3
- package/src/engineTileLayer.js +3 -3
- package/src/engineUtilities.js +139 -38
- package/src/engineWebGL.js +2 -8
- package/build/littlejs.esm.min.js +0 -1
- package/build/littlejs.min.js +0 -1
- package/index.d.ts +0 -2094
|
@@ -8,214 +8,197 @@
|
|
|
8
8
|
|
|
9
9
|
'use strict';
|
|
10
10
|
|
|
11
|
-
const tileType_ladder
|
|
12
|
-
const tileType_empty
|
|
13
|
-
const tileType_solid
|
|
11
|
+
const tileType_ladder = -1;
|
|
12
|
+
const tileType_empty = 0;
|
|
13
|
+
const tileType_solid = 1;
|
|
14
|
+
const tileType_breakable = 2;
|
|
14
15
|
|
|
15
|
-
let player, playerStartPos,
|
|
16
|
-
let levelSize, levelColor,
|
|
16
|
+
let player, playerStartPos, tileData, tileLayers, foregroundLayerIndex, sky;
|
|
17
|
+
let levelSize, levelColor, levelBackgroundColor, levelOutlineColor, warmup;
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
pos.arrayCheck(tileCollisionSize) ? tileBackground[(pos.y|0)*tileCollisionSize.x+pos.x|0] : 0;
|
|
19
|
+
const setTileData = (pos, layer, data)=>
|
|
20
|
+
pos.arrayCheck(tileCollisionSize) && (tileData[layer][(pos.y|0)*tileCollisionSize.x+pos.x|0] = data);
|
|
21
|
+
const getTileData = (pos, layer)=>
|
|
22
|
+
pos.arrayCheck(tileCollisionSize) ? tileData[layer][(pos.y|0)*tileCollisionSize.x+pos.x|0]: 0;
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
// level generation
|
|
26
|
-
|
|
27
|
-
function buildTerrain(size)
|
|
24
|
+
function buildLevel()
|
|
28
25
|
{
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
startGroundLevel = clamp(startGroundLevel + jumpDelta, 20, 80);
|
|
50
|
-
groundLevel += jumpDelta;
|
|
51
|
-
groundSlope = rand(-1,1);
|
|
52
|
-
}
|
|
26
|
+
// create the level
|
|
27
|
+
levelColor = randColor(hsl(0,0,.2), hsl(0,0,.8));
|
|
28
|
+
levelBackgroundColor = levelColor.mutate().scale(.4,1);
|
|
29
|
+
levelOutlineColor = levelColor.mutate().add(hsl(0,0,.4)).clamp();
|
|
30
|
+
loadLevel();
|
|
31
|
+
|
|
32
|
+
// create sky object with gradient and stars
|
|
33
|
+
sky = new Sky;
|
|
34
|
+
|
|
35
|
+
// create parallax layers
|
|
36
|
+
for (let i=3; i--;)
|
|
37
|
+
new ParallaxLayer(i);
|
|
38
|
+
|
|
39
|
+
// apply decoration to all level tiles
|
|
40
|
+
const pos = vec2();
|
|
41
|
+
const layerCount = tileLayers.length;
|
|
42
|
+
for (let layer=layerCount; layer--;)
|
|
43
|
+
for (pos.x=levelSize.x; pos.x--;)
|
|
44
|
+
for (pos.y=levelSize.y; pos.y--;)
|
|
45
|
+
decorateTile(pos, layer);
|
|
53
46
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
let backTile = tileType_empty;
|
|
73
|
-
if (y < groundLevel + backgroundDelta)
|
|
74
|
-
backTile = tileType_solid;
|
|
75
|
-
|
|
76
|
-
setTileCollisionData(pos, frontTile);
|
|
77
|
-
setTileBackgroundData(pos, backTile);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
47
|
+
// warm up level
|
|
48
|
+
warmup = 1;
|
|
49
|
+
for (let i = 500; i--;)
|
|
50
|
+
engineObjectsUpdate();
|
|
51
|
+
warmup = 0;
|
|
52
|
+
|
|
53
|
+
// spawn player
|
|
54
|
+
player = new Player(playerStartPos);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function loadLevel()
|
|
58
|
+
{
|
|
59
|
+
// load level data from an exported Tiled js file
|
|
60
|
+
const dataName = Object.keys(TileMaps)[0];
|
|
61
|
+
const tileMapData = TileMaps[dataName];
|
|
62
|
+
levelSize = vec2(tileMapData.width, tileMapData.height);
|
|
63
|
+
initTileCollision(levelSize);
|
|
64
|
+
engineObjectsDestroy();
|
|
80
65
|
|
|
81
|
-
//
|
|
82
|
-
|
|
66
|
+
// create table for tiles in the level tilemap
|
|
67
|
+
const tileLookup =
|
|
83
68
|
{
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
69
|
+
circle: 1,
|
|
70
|
+
ground: 2,
|
|
71
|
+
ladder: 4,
|
|
72
|
+
metal: 5,
|
|
73
|
+
player: 17,
|
|
74
|
+
crate: 18,
|
|
75
|
+
enemy: 19,
|
|
76
|
+
coin: 20,
|
|
90
77
|
}
|
|
91
78
|
|
|
92
|
-
//
|
|
93
|
-
|
|
79
|
+
// set all level data tiles
|
|
80
|
+
tileData = [];
|
|
81
|
+
tileLayers = [];
|
|
82
|
+
playerStartPos = vec2(1, levelSize.y);
|
|
83
|
+
const layerCount = tileMapData.layers.length;
|
|
84
|
+
foregroundLayerIndex = layerCount-1;
|
|
85
|
+
for (let layer=layerCount; layer--;)
|
|
94
86
|
{
|
|
95
|
-
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
87
|
+
const layerData = tileMapData.layers[layer].data;
|
|
88
|
+
const tileLayer = new TileLayer(vec2(), levelSize, tile(0,16,1));
|
|
89
|
+
tileLayer.renderOrder = -1e3+layer;
|
|
90
|
+
tileLayers[layer] = tileLayer;
|
|
91
|
+
tileData[layer] = [];
|
|
92
|
+
|
|
93
|
+
for (let x=levelSize.x; x--;)
|
|
94
|
+
for (let y=levelSize.y; y--;)
|
|
101
95
|
{
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
96
|
+
const pos = vec2(x,levelSize.y-1-y);
|
|
97
|
+
const tile = layerData[y*levelSize.x+x];
|
|
98
|
+
|
|
99
|
+
if (tile >= tileLookup.player)
|
|
106
100
|
{
|
|
107
|
-
|
|
108
|
-
|
|
101
|
+
// create object instead of tile
|
|
102
|
+
const objectPos = pos.add(vec2(.5));
|
|
103
|
+
if (tile == tileLookup.player)
|
|
104
|
+
playerStartPos = objectPos;
|
|
105
|
+
if (tile == tileLookup.crate)
|
|
106
|
+
new Crate(objectPos);
|
|
107
|
+
if (tile == tileLookup.enemy)
|
|
108
|
+
new Enemy(objectPos);
|
|
109
|
+
if (tile == tileLookup.coin)
|
|
110
|
+
new Coin(objectPos);
|
|
111
|
+
setTileData(pos, layer, 0);
|
|
112
|
+
continue;
|
|
109
113
|
}
|
|
110
|
-
|
|
114
|
+
|
|
115
|
+
// set the tile data
|
|
116
|
+
setTileData(pos, layer, tile);
|
|
117
|
+
|
|
118
|
+
// get tile type for special tiles
|
|
119
|
+
let tileType = tileType_empty;
|
|
120
|
+
if (tile > 0)
|
|
121
|
+
tileType = tileType_breakable;
|
|
122
|
+
if (tile == tileLookup.ladder)
|
|
123
|
+
tileType = tileType_ladder;
|
|
124
|
+
if (tile == tileLookup.metal)
|
|
125
|
+
tileType = tileType_solid;
|
|
126
|
+
if (tileType)
|
|
111
127
|
{
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
setTileCollisionData(pos,
|
|
115
|
-
|
|
128
|
+
// set collision for solid tiles
|
|
129
|
+
if (layer == foregroundLayerIndex)
|
|
130
|
+
setTileCollisionData(pos, tileType);
|
|
131
|
+
|
|
132
|
+
// randomize tile appearance
|
|
133
|
+
let direction, mirror, color;
|
|
134
|
+
if (tileType == tileType_breakable)
|
|
135
|
+
{
|
|
136
|
+
direction = randInt(4);
|
|
137
|
+
mirror = randInt(2);
|
|
138
|
+
color = layer ? levelColor : levelBackgroundColor;
|
|
139
|
+
color = color.mutate(.03);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// set tile layer data
|
|
143
|
+
const data = new TileLayerData(tile-1, direction, mirror, color);
|
|
144
|
+
tileLayer.setData(pos, data);
|
|
116
145
|
}
|
|
117
146
|
}
|
|
147
|
+
tileLayer.redraw();
|
|
118
148
|
}
|
|
119
|
-
|
|
120
|
-
// spawn crates
|
|
121
|
-
for (let crateCount=100; crateCount--;)
|
|
122
|
-
new Crate(vec2((randInt(levelSize.x))+.5, randInt(levelSize.y)));
|
|
123
|
-
|
|
124
|
-
// spawn enemies
|
|
125
|
-
for (let enemyCount=10; enemyCount--;)
|
|
126
|
-
new Enemy(vec2(rand(levelSize.x), rand(levelSize.y)));
|
|
127
149
|
}
|
|
128
150
|
|
|
129
|
-
function
|
|
151
|
+
function decorateTile(pos, layer=1)
|
|
130
152
|
{
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
// randomize ground level hills
|
|
135
|
-
buildTerrain(levelSize);
|
|
153
|
+
ASSERT((pos.x|0) == pos.x && (pos.y|0)== pos.y);
|
|
154
|
+
const tileLayer = tileLayers[layer];
|
|
136
155
|
|
|
137
|
-
|
|
138
|
-
playerStartPos = vec2(rand(levelSize.x), levelSize.y);
|
|
139
|
-
const raycastHit = tileCollisionRaycast(playerStartPos, vec2(playerStartPos.x, 0));
|
|
140
|
-
playerStartPos = raycastHit.add(vec2(0,1));
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function makeTileLayers()
|
|
144
|
-
{
|
|
145
|
-
// create tile layers
|
|
146
|
-
tileLayer = new TileLayer(vec2(), levelSize, tile(0,16,1));
|
|
147
|
-
tileLayer.renderOrder = -1e3;
|
|
148
|
-
tileBackgroundLayer = new TileLayer(vec2(), levelSize, tile(0,16,1));
|
|
149
|
-
tileBackgroundLayer.renderOrder = -2e3;
|
|
150
|
-
|
|
151
|
-
const pos = vec2();
|
|
152
|
-
for (pos.x = levelSize.x; pos.x--;)
|
|
153
|
-
for (pos.y = levelSize.y; pos.y--;)
|
|
156
|
+
if (layer == foregroundLayerIndex)
|
|
154
157
|
{
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (tileType)
|
|
158
|
+
const tileType = getTileCollisionData(pos);
|
|
159
|
+
if (tileType <= 0)
|
|
158
160
|
{
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
tileIndex = 1 + rand()**3*2|0;
|
|
163
|
-
color = levelColor.mutate(.03);
|
|
164
|
-
direction = randInt(4);
|
|
165
|
-
mirror = randInt(2);
|
|
166
|
-
}
|
|
167
|
-
else if (tileType == tileType_ladder)
|
|
168
|
-
tileIndex = 3;
|
|
169
|
-
|
|
170
|
-
const data = new TileLayerData(tileIndex, direction, mirror, color);
|
|
171
|
-
tileLayer.setData(pos, data);
|
|
161
|
+
// force it to clear if it is empty
|
|
162
|
+
tileType || tileLayer.setData(pos, new TileLayerData, 1);
|
|
163
|
+
return;
|
|
172
164
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
tileType = getTileBackgroundData(pos);
|
|
176
|
-
if (tileType)
|
|
165
|
+
if (tileType == tileType_breakable)
|
|
166
|
+
for (let i=4;i--;)
|
|
177
167
|
{
|
|
178
|
-
|
|
179
|
-
|
|
168
|
+
// outline towards neighbors of differing type
|
|
169
|
+
const neighborTileType = getTileCollisionData(pos.add(vec2().setDirection(i)));
|
|
170
|
+
if (neighborTileType == tileType)
|
|
171
|
+
continue;
|
|
172
|
+
|
|
173
|
+
// make pixel perfect outlines
|
|
174
|
+
const size = i&1 ? vec2(2, 16) : vec2(16, 2);
|
|
175
|
+
tileLayer.context.fillStyle = levelOutlineColor.mutate(.1);
|
|
176
|
+
const drawPos = pos.scale(16)
|
|
177
|
+
.add(vec2(i==1?14:0,(i==0?14:0)))
|
|
178
|
+
.subtract((i&1? vec2(0,8-size.y/2) : vec2(8-size.x/2,0)));
|
|
179
|
+
tileLayer.context.fillRect(
|
|
180
|
+
drawPos.x, tileLayer.canvas.height - drawPos.y, size.x, -size.y);
|
|
180
181
|
}
|
|
181
182
|
}
|
|
182
|
-
|
|
183
|
-
tileBackgroundLayer.redraw();
|
|
184
|
-
|
|
185
|
-
if (!glEnable)
|
|
183
|
+
else
|
|
186
184
|
{
|
|
187
|
-
//
|
|
188
|
-
|
|
189
|
-
|
|
185
|
+
// make round corners
|
|
186
|
+
for (let i=4;i--;)
|
|
187
|
+
{
|
|
188
|
+
// check corner neighbors
|
|
189
|
+
const neighborTileDataA = getTileData(pos.add(vec2().setDirection(i)), layer);
|
|
190
|
+
const neighborTileDataB = getTileData(pos.add(vec2().setAngle((i+1)%4*PI/2)), layer);
|
|
191
|
+
if (neighborTileDataA > 0 || neighborTileDataB > 0)
|
|
192
|
+
continue;
|
|
193
|
+
|
|
194
|
+
const directionVector = vec2().setAngle(i*PI/2+PI/4, 10).floor();
|
|
195
|
+
const drawPos = pos.add(vec2(.5)) // center
|
|
196
|
+
.scale(16).add(directionVector).floor(); // direction offset
|
|
197
|
+
|
|
198
|
+
// clear rect without any scaling to prevent blur from filtering
|
|
199
|
+
const s = 2;
|
|
200
|
+
tileLayer.context.clearRect(
|
|
201
|
+
drawPos.x - s/2, tileLayer.canvas.height - drawPos.y - s/2, s, s);
|
|
202
|
+
}
|
|
190
203
|
}
|
|
191
204
|
}
|
|
192
|
-
|
|
193
|
-
function buildLevel()
|
|
194
|
-
{
|
|
195
|
-
levelSize = vec2(128);
|
|
196
|
-
levelColor = randColor(new Color(.2,.2,.2), new Color(.8,.8,.8));
|
|
197
|
-
levelGroundColor = levelColor.mutate().add(new Color(.4,.4,.4)).clamp();
|
|
198
|
-
|
|
199
|
-
generateLevel();
|
|
200
|
-
initSky();
|
|
201
|
-
initParallaxLayers();
|
|
202
|
-
|
|
203
|
-
// apply decoration to level tiles
|
|
204
|
-
makeTileLayers();
|
|
205
|
-
const pos = vec2();
|
|
206
|
-
for (pos.x=levelSize.x; pos.x--;)
|
|
207
|
-
for (pos.y=levelSize.y; pos.y-->1;)
|
|
208
|
-
{
|
|
209
|
-
decorateBackgroundTile(pos);
|
|
210
|
-
decorateTile(pos);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// warm up level
|
|
214
|
-
warmup = 1;
|
|
215
|
-
for (let i = 500; i--;)
|
|
216
|
-
engineObjectsUpdate();
|
|
217
|
-
warmup = 0;
|
|
218
|
-
|
|
219
|
-
// spawn player
|
|
220
|
-
player = new Player(cameraPos = playerStartPos);
|
|
221
|
-
}
|