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
|
@@ -21,7 +21,7 @@ const sound_dodge = new Sound([.4,.2,150,.05,,.05,,,-1,,,,,4,,,,,.02]);
|
|
|
21
21
|
const sound_walk = new Sound([.3,.1,50,.005,,.01,4,,,,,,,,10,,,.5]);
|
|
22
22
|
const sound_explosion = new Sound([2,.2,72,.01,.01,.2,4,,,,,,,1,,.5,.1,.5,.02]);
|
|
23
23
|
const sound_grenade = new Sound([.5,.01,300,,,.02,3,.22,,,-9,.2,,,,,,.5]);
|
|
24
|
-
const
|
|
24
|
+
const sound_score = new Sound([,,783,,.03,.02,1,2,,,940,.03,,,,,.2,.6,,.06]);
|
|
25
25
|
|
|
26
26
|
///////////////////////////////////////////////////////////////////////////////
|
|
27
27
|
// special effects
|
|
@@ -31,15 +31,15 @@ const persistentParticleDestroyCallback = (particle)=>
|
|
|
31
31
|
// copy particle to tile layer on death
|
|
32
32
|
ASSERT(!particle.tileInfo, 'quick draw to tile layer uses canvas 2d so must be untextured');
|
|
33
33
|
if (particle.groundObject)
|
|
34
|
-
|
|
34
|
+
tileLayers[foregroundLayerIndex].drawTile(particle.pos, particle.size, particle.tileInfo, particle.color, particle.angle, particle.mirror);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
function makeBlood(pos, amount) { makeDebris(pos,
|
|
38
|
-
function makeDebris(pos, color =
|
|
37
|
+
function makeBlood(pos, amount) { makeDebris(pos, hsl(0,1,.5), amount, .1, 0); }
|
|
38
|
+
function makeDebris(pos, color = hsl(), amount = 50, size=.2, elasticity = .3)
|
|
39
39
|
{
|
|
40
|
-
const color2 = color.lerp(
|
|
40
|
+
const color2 = color.lerp(hsl(), .5);
|
|
41
41
|
const emitter = new ParticleEmitter(
|
|
42
|
-
pos, 0, 1, .1,
|
|
42
|
+
pos, 0, 1, .1, amount/.1, PI, // pos, angle, emitSize, emitTime, emitRate, emiteCone
|
|
43
43
|
0, // tileInfo
|
|
44
44
|
color, color2, // colorStartA, colorStartB
|
|
45
45
|
color, color2, // colorEndA, colorEndB
|
|
@@ -58,8 +58,6 @@ function explosion(pos, radius=3)
|
|
|
58
58
|
{
|
|
59
59
|
ASSERT(radius > 0);
|
|
60
60
|
|
|
61
|
-
const damage = radius*2;
|
|
62
|
-
|
|
63
61
|
// destroy level
|
|
64
62
|
for (let x = -radius; x < radius; ++x)
|
|
65
63
|
{
|
|
@@ -80,6 +78,7 @@ function explosion(pos, radius=3)
|
|
|
80
78
|
// kill/push objects
|
|
81
79
|
engineObjectsCallback(pos, radius*3, (o)=>
|
|
82
80
|
{
|
|
81
|
+
const damage = radius*2;
|
|
83
82
|
const d = o.pos.distance(pos);
|
|
84
83
|
if (o.isGameObject)
|
|
85
84
|
{
|
|
@@ -99,11 +98,11 @@ function explosion(pos, radius=3)
|
|
|
99
98
|
|
|
100
99
|
// smoke
|
|
101
100
|
new ParticleEmitter(
|
|
102
|
-
pos, 0,
|
|
103
|
-
radius/2, .2, 50*radius, PI
|
|
104
|
-
0,
|
|
105
|
-
|
|
106
|
-
|
|
101
|
+
pos, 0, // pos, angle
|
|
102
|
+
radius/2, .2, 50*radius, PI,// emitSize, emitTime, emitRate, emiteCone
|
|
103
|
+
0, // tileInfo
|
|
104
|
+
hsl(0,0,0), hsl(0,0,0), // colorStartA, colorStartB
|
|
105
|
+
hsl(0,0,0,0), hsl(0,0,0,0), // colorEndA, colorEndB
|
|
107
106
|
1, .5, 2, .2, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
|
|
108
107
|
.9, 1, -.3, PI, .1, // damp, angleDamp, gravity, particleCone, fade
|
|
109
108
|
.5, 0, 0, 0, 1e8 // randomness, collide, additive, colorLinear, renderOrder
|
|
@@ -111,11 +110,11 @@ function explosion(pos, radius=3)
|
|
|
111
110
|
|
|
112
111
|
// fire
|
|
113
112
|
new ParticleEmitter(
|
|
114
|
-
pos, 0,
|
|
115
|
-
radius/2, .1, 100*radius, PI,
|
|
116
|
-
0,
|
|
117
|
-
|
|
118
|
-
|
|
113
|
+
pos, 0, // pos, angle
|
|
114
|
+
radius/2, .1, 100*radius, PI, // emitSize, emitTime, emitRate, emiteCone
|
|
115
|
+
0, // tileInfo
|
|
116
|
+
rgb(1,.5,.1), rgb(1,.1,.1), // colorStartA, colorStartB
|
|
117
|
+
rgb(1,.5,.1,0), rgb(1,.1,.1,0), // colorEndA, colorEndB
|
|
119
118
|
.7, .8, .2, .2, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
|
|
120
119
|
.9, 1, -.2, PI, .05, // damp, angleDamp, gravity, particleCone, fade
|
|
121
120
|
.5, 0, 1, 0, 1e9 // randomness, collide, additive, colorLinear, renderOrder
|
|
@@ -132,186 +131,128 @@ function destroyTile(pos, makeSound = 1, cleanNeighbors = 1)
|
|
|
132
131
|
// destroy tile
|
|
133
132
|
const tileType = getTileCollisionData(pos);
|
|
134
133
|
|
|
135
|
-
if (!tileType
|
|
134
|
+
if (!tileType || tileType == tileType_solid)
|
|
135
|
+
return 1;
|
|
136
136
|
|
|
137
|
+
const tileLayer = tileLayers[foregroundLayerIndex];
|
|
137
138
|
const centerPos = pos.add(vec2(.5));
|
|
138
139
|
const layerData = tileLayer.getData(pos);
|
|
139
|
-
if (layerData)
|
|
140
|
-
{
|
|
141
|
-
makeDebris(centerPos, layerData.color.mutate());
|
|
142
|
-
makeSound && sound_destroyObject.play(centerPos);
|
|
143
|
-
|
|
144
|
-
setTileCollisionData(pos, tileType_empty);
|
|
145
|
-
tileLayer.setData(pos, new TileLayerData, 1); // set and clear tile
|
|
146
|
-
|
|
147
|
-
// cleanup neighbors
|
|
148
|
-
if (cleanNeighbors)
|
|
149
|
-
{
|
|
150
|
-
for (let i=-1;i<=1;++i)
|
|
151
|
-
for (let j=-1;j<=1;++j)
|
|
152
|
-
decorateTile(pos.add(vec2(i,j)));
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return 1;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function decorateBackgroundTile(pos)
|
|
160
|
-
{
|
|
161
|
-
if (!tileBackgroundLayer)
|
|
140
|
+
if (!layerData)
|
|
162
141
|
return;
|
|
163
142
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
143
|
+
// create effects
|
|
144
|
+
makeDebris(centerPos, layerData.color.mutate());
|
|
145
|
+
makeSound && sound_destroyObject.play(centerPos);
|
|
167
146
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const neighborTileDataA = getTileBackgroundData(pos.add(vec2().setAngle(i*PI/2)));
|
|
173
|
-
const neighborTileDataB = getTileBackgroundData(pos.add(vec2().setAngle((i+1)%4*PI/2)));
|
|
174
|
-
if (neighborTileDataA > 0 || neighborTileDataB > 0)
|
|
175
|
-
continue;
|
|
176
|
-
|
|
177
|
-
const directionVector = vec2().setAngle(i*PI/2+PI/4, 10).floor();
|
|
178
|
-
const drawPos = pos.add(vec2(.5)) // center
|
|
179
|
-
.scale(16).add(directionVector).floor(); // direction offset
|
|
180
|
-
|
|
181
|
-
// clear rect without any scaling to prevent blur from filtering
|
|
182
|
-
const s = 2;
|
|
183
|
-
tileBackgroundLayer.context.clearRect(
|
|
184
|
-
drawPos.x - s/2, tileBackgroundLayer.canvas.height - drawPos.y - s/2, s, s);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
147
|
+
// set and clear tile
|
|
148
|
+
tileLayer.setData(pos, new TileLayerData, 1);
|
|
149
|
+
setTileCollisionData(pos, tileType_empty);
|
|
150
|
+
setTileData(pos, foregroundLayerIndex, 0);
|
|
187
151
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
ASSERT((pos.x|0) == pos.x && (pos.y|0)== pos.y);
|
|
191
|
-
const tileData = getTileCollisionData(pos);
|
|
192
|
-
if (tileData <= 0)
|
|
152
|
+
// cleanup neighbors
|
|
153
|
+
if (cleanNeighbors)
|
|
193
154
|
{
|
|
194
|
-
|
|
195
|
-
|
|
155
|
+
for (let i=-1;i<=1;++i)
|
|
156
|
+
for (let j=-1;j<=1;++j)
|
|
157
|
+
decorateTile(pos.add(vec2(i,j)));
|
|
196
158
|
}
|
|
197
159
|
|
|
198
|
-
|
|
199
|
-
{
|
|
200
|
-
// outline towards neighbors of differing type
|
|
201
|
-
const neighborTileData = getTileCollisionData(pos.add(vec2().setAngle(i*PI/2)));
|
|
202
|
-
if (neighborTileData == tileData)
|
|
203
|
-
continue;
|
|
204
|
-
|
|
205
|
-
// make pixel perfect outlines
|
|
206
|
-
const size = i&1 ? vec2(2, 16) : vec2(16, 2);
|
|
207
|
-
tileLayer.context.fillStyle = levelGroundColor.mutate(.1);
|
|
208
|
-
const drawPos = pos.scale(16)
|
|
209
|
-
.add(vec2(i==1?14:0,(i==0?14:0)))
|
|
210
|
-
.subtract((i&1? vec2(0,8-size.y/2) : vec2(8-size.x/2,0)));
|
|
211
|
-
tileLayer.context.fillRect(
|
|
212
|
-
drawPos.x, tileLayer.canvas.height - drawPos.y, size.x, -size.y);
|
|
213
|
-
}
|
|
160
|
+
return 1;
|
|
214
161
|
}
|
|
215
162
|
|
|
216
163
|
///////////////////////////////////////////////////////////////////////////////
|
|
217
164
|
// sky with background gradient, stars, and planets
|
|
218
165
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
function initSky()
|
|
166
|
+
class Sky extends EngineObject
|
|
222
167
|
{
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
}
|
|
168
|
+
constructor()
|
|
169
|
+
{
|
|
170
|
+
super();
|
|
227
171
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
gradient.addColorStop(1, horizonColor);
|
|
234
|
-
mainContext.fillRect(0, 0, mainCanvas.width, mainCanvas.height);
|
|
235
|
-
}
|
|
172
|
+
this.renderOrder = -1e4;
|
|
173
|
+
this.seed = randInt(1e9);
|
|
174
|
+
this.skyColor = randColor(hsl(0,0,.5), hsl(0,0,.9));
|
|
175
|
+
this.horizonColor = this.skyColor.subtract(hsl(0,0,.05,0)).mutate(.3);
|
|
176
|
+
}
|
|
236
177
|
|
|
237
|
-
|
|
238
|
-
{
|
|
239
|
-
// draw stars and planets
|
|
240
|
-
const random = new RandomGenerator(skySeed);
|
|
241
|
-
const largeStarCount = 9;
|
|
242
|
-
for (let i = 1e3; i--;)
|
|
178
|
+
render()
|
|
243
179
|
{
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
color = (new Color).setHSLA(random.float(), random.float(), random.float(1,.5)).add(skyColor.scale(.5)).clamp();
|
|
253
|
-
}
|
|
180
|
+
// fill background with a gradient
|
|
181
|
+
const gradient = mainContext.createLinearGradient(0, 0, 0, mainCanvas.height);
|
|
182
|
+
gradient.addColorStop(0, this.skyColor);
|
|
183
|
+
gradient.addColorStop(1, this.horizonColor);
|
|
184
|
+
mainContext.save();
|
|
185
|
+
mainContext.fillStyle = gradient;
|
|
186
|
+
mainContext.fillRect(0, 0, mainCanvas.width, mainCanvas.height);
|
|
187
|
+
mainContext.globalCompositeOperation = 'lighter';
|
|
254
188
|
|
|
255
|
-
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
(random.float(w)+time*speed)%w-extraSpace,
|
|
259
|
-
(random.float(h)+time*speed*random.float())%h-extraSpace);
|
|
260
|
-
|
|
261
|
-
mainContext.fillStyle = color;
|
|
262
|
-
if (size < 9)
|
|
263
|
-
mainContext.fillRect(screenPos.x, screenPos.y, size, size);
|
|
264
|
-
else
|
|
189
|
+
// draw stars
|
|
190
|
+
const random = new RandomGenerator(this.seed);
|
|
191
|
+
for (let i=1e3; i--;)
|
|
265
192
|
{
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
193
|
+
const size = random.float(.5,2)**2;
|
|
194
|
+
const speed = random.float() < .9 ? random.float(5) : random.float(9,99);
|
|
195
|
+
const color = hsl(random.float(-.3,.2), random.float(), random.float());
|
|
196
|
+
const extraSpace = 50;
|
|
197
|
+
const w = mainCanvas.width+2*extraSpace, h = mainCanvas.height+2*extraSpace;
|
|
198
|
+
const screenPos = vec2(
|
|
199
|
+
(random.float(w)+time*speed)%w-extraSpace,
|
|
200
|
+
(random.float(h)+time*speed*random.float())%h-extraSpace);
|
|
201
|
+
mainContext.fillStyle = color;
|
|
202
|
+
mainContext.fillRect(screenPos.x, screenPos.y, size, size);
|
|
269
203
|
}
|
|
204
|
+
mainContext.restore();
|
|
270
205
|
}
|
|
271
206
|
}
|
|
272
207
|
|
|
273
208
|
///////////////////////////////////////////////////////////////////////////////
|
|
274
209
|
// parallax background mountain ranges
|
|
275
210
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
function initParallaxLayers()
|
|
211
|
+
class ParallaxLayer extends EngineObject
|
|
279
212
|
{
|
|
280
|
-
|
|
281
|
-
for (let i=3; i--;)
|
|
213
|
+
constructor(index)
|
|
282
214
|
{
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
215
|
+
super();
|
|
216
|
+
|
|
217
|
+
const size = vec2(1024,512);
|
|
218
|
+
this.size = size;
|
|
219
|
+
this.index = index;
|
|
220
|
+
this.renderOrder = -3e3 + index;
|
|
221
|
+
this.canvas = document.createElement('canvas');
|
|
222
|
+
this.context = this.canvas.getContext('2d');
|
|
223
|
+
this.canvas.width = size.x;
|
|
224
|
+
this.canvas.height = size.y;
|
|
288
225
|
|
|
289
226
|
// create a gradient
|
|
290
|
-
const
|
|
291
|
-
const
|
|
292
|
-
|
|
227
|
+
const o1 = 40-20*index;
|
|
228
|
+
const o2 = 100-30*index;
|
|
229
|
+
const gradient = this.context.createLinearGradient(0,size.y/2-o1,0,size.y/2+o2);
|
|
230
|
+
const layerColor = levelColor.mutate(.1).lerp(sky.skyColor,1-index*.15);
|
|
293
231
|
gradient.addColorStop(0,layerColor);
|
|
294
|
-
gradient.addColorStop(1,layerColor.
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
232
|
+
gradient.addColorStop(1,layerColor.mutate(.5).scale(.1,1));
|
|
233
|
+
this.context.fillStyle = gradient;
|
|
234
|
+
|
|
235
|
+
// draw procedural mountains ranges
|
|
236
|
+
let groundLevel = size.y/2, groundSlope = rand(-1,1);
|
|
237
|
+
for (let i=size.x; i--;)
|
|
238
|
+
this.context.fillRect(i, groundLevel += groundSlope = rand() < .3 ? rand(1,-1) :
|
|
239
|
+
groundSlope + (size.y/2 - groundLevel)/300, 1, size.y);
|
|
301
240
|
}
|
|
302
|
-
}
|
|
303
241
|
|
|
304
|
-
|
|
305
|
-
{
|
|
306
|
-
tileParallaxLayers.forEach((tileParallaxLayer, i)=>
|
|
242
|
+
render()
|
|
307
243
|
{
|
|
308
|
-
|
|
309
|
-
const parallax = vec2(
|
|
310
|
-
const cameraDeltaFromCenter = cameraPos
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
244
|
+
// position layer based on camera distance from center of level
|
|
245
|
+
const parallax = vec2(1e3,-100).scale(this.index**2);
|
|
246
|
+
const cameraDeltaFromCenter = cameraPos
|
|
247
|
+
.subtract(levelSize.scale(.5))
|
|
248
|
+
.divide(levelSize.divide(parallax));
|
|
249
|
+
const scale = this.size.scale(2+2*this.index);
|
|
250
|
+
const pos = mainCanvasSize.scale(.5) // center screen
|
|
251
|
+
.add(vec2(-scale.x/2,-scale.y/2)) // center layer
|
|
252
|
+
.add(cameraDeltaFromCenter.scale(-.5)) // apply parallax
|
|
253
|
+
.add(vec2(0,(this.index*.1)*this.size.y)); // separate layers
|
|
254
|
+
|
|
255
|
+
// draw the parallax layer onto the main canvas
|
|
256
|
+
mainContext.drawImage(this.canvas, pos.x, pos.y, scale.x, scale.y);
|
|
257
|
+
}
|
|
317
258
|
}
|