littlejsengine 1.12.6 → 1.13.4

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 (102) hide show
  1. package/README.md +15 -12
  2. package/dist/littlejs.d.ts +466 -236
  3. package/dist/littlejs.esm.js +6126 -5370
  4. package/dist/littlejs.esm.min.js +4 -1
  5. package/dist/littlejs.js +6093 -5359
  6. package/dist/littlejs.min.js +4 -1
  7. package/dist/littlejs.release.js +5614 -4907
  8. package/examples/box2d/game.js +2 -2
  9. package/examples/box2d/gameObjects.js +8 -7
  10. package/examples/box2d/index.html +1 -1
  11. package/examples/box2d/scenes.js +8 -8
  12. package/examples/breakout/game.js +1 -1
  13. package/examples/breakout/gameObjects.js +2 -2
  14. package/examples/breakout/index.html +1 -1
  15. package/examples/breakoutTutorial/README.md +46 -43
  16. package/examples/breakoutTutorial/game.js +3 -3
  17. package/examples/breakoutTutorial/index.html +1 -1
  18. package/examples/electron/build.bat +7 -0
  19. package/examples/electron/build.js +124 -0
  20. package/examples/electron/electron.js +35 -0
  21. package/examples/electron/game.js +140 -0
  22. package/examples/electron/index.html +13 -0
  23. package/examples/electron/package.json +12 -0
  24. package/examples/electron/tiles.png +0 -0
  25. package/examples/empty/game.js +1 -0
  26. package/examples/empty/index.html +1 -1
  27. package/examples/htmlMenu/game.js +1 -1
  28. package/examples/htmlMenu/index.html +1 -1
  29. package/examples/index.html +486 -182
  30. package/examples/module/game.js +6 -3
  31. package/examples/module/index.html +1 -1
  32. package/examples/particles/index.html +12 -3
  33. package/examples/platformer/game.js +4 -4
  34. package/examples/platformer/gameCharacter.js +6 -6
  35. package/examples/platformer/gameEffects.js +74 -57
  36. package/examples/platformer/gameLevel.js +61 -70
  37. package/examples/platformer/gameObjects.js +4 -4
  38. package/examples/platformer/index.html +1 -1
  39. package/examples/puzzle/index.html +1 -1
  40. package/examples/shorts/base.html +23 -3
  41. package/examples/shorts/blending.js +9 -5
  42. package/examples/shorts/box2d.js +1 -1
  43. package/examples/shorts/box2dCar.js +9 -13
  44. package/examples/shorts/clock.js +1 -1
  45. package/examples/shorts/colors.js +2 -2
  46. package/examples/shorts/flappyGame.js +52 -0
  47. package/examples/shorts/helloWorld.js +6 -3
  48. package/examples/shorts/hillGlideGame.js +56 -0
  49. package/examples/shorts/landerGame.js +32 -0
  50. package/examples/shorts/maze.js +47 -0
  51. package/examples/shorts/medals.js +42 -0
  52. package/examples/shorts/nineSlice.js +21 -0
  53. package/examples/shorts/piano.js +52 -0
  54. package/examples/shorts/platformer.js +24 -20
  55. package/examples/shorts/{pong.js → pongGame.js} +1 -1
  56. package/examples/shorts/raycasting.js +71 -0
  57. package/examples/shorts/shapes.js +9 -9
  58. package/examples/shorts/slidingPuzzle.js +42 -0
  59. package/examples/shorts/spaceGame.js +56 -0
  60. package/examples/shorts/starfield.js +15 -0
  61. package/examples/shorts/systemFont.js +1 -1
  62. package/examples/shorts/tileLayer.js +3 -5
  63. package/examples/shorts/tiles.png +0 -0
  64. package/examples/shorts/tiltedView.js +8 -7
  65. package/examples/shorts/topDown.js +18 -26
  66. package/examples/shorts/uiSystem.js +5 -7
  67. package/examples/starter/build.bat +6 -1
  68. package/examples/starter/build.js +9 -8
  69. package/examples/starter/game.js +7 -4
  70. package/examples/starter/index.html +23 -13
  71. package/examples/stress/index.html +7 -8
  72. package/examples/style.css +139 -0
  73. package/examples/typescript/build.js +2 -3
  74. package/examples/typescript/game.js +4 -4
  75. package/examples/typescript/game.ts +6 -3
  76. package/examples/typescript/index.html +1 -1
  77. package/examples/uiSystem/game.js +10 -25
  78. package/examples/uiSystem/index.html +1 -1
  79. package/package.json +2 -2
  80. package/plugins/box2d.js +22 -97
  81. package/plugins/drawUtilities.js +132 -0
  82. package/plugins/newgrounds.js +1 -1
  83. package/plugins/pluginExport.js +7 -1
  84. package/plugins/postProcess.js +9 -2
  85. package/plugins/uiSystem.js +155 -67
  86. package/plugins/zzfxm.js +1 -1
  87. package/reference.md +10 -10
  88. package/src/engine.js +56 -30
  89. package/src/engineAudio.js +15 -6
  90. package/src/engineBuild.bat +6 -1
  91. package/src/engineBuild.js +20 -5
  92. package/src/engineDebug.js +55 -28
  93. package/src/engineDraw.js +321 -177
  94. package/src/engineExport.js +27 -9
  95. package/src/engineInput.js +110 -38
  96. package/src/engineMedals.js +4 -4
  97. package/src/engineObject.js +71 -70
  98. package/src/engineParticles.js +33 -9
  99. package/src/engineSettings.js +69 -23
  100. package/src/engineTileLayer.js +312 -153
  101. package/src/engineUtilities.js +187 -135
  102. package/src/engineWebGL.js +70 -39
@@ -77,7 +77,7 @@ function gameInit()
77
77
  .99, 1, 1, Math.PI, // damping, angleDamping, gravityScale, cone
78
78
  .05, .5, true, true // fadeRate, randomness, collide, additive
79
79
  );
80
- particleEmitter.elasticity = .3; // bounce when it collides
80
+ particleEmitter.restitution = .3; // bounce when it collides
81
81
  particleEmitter.trailScale = 2; // stretch in direction of motion
82
82
  }
83
83
 
@@ -101,7 +101,10 @@ function gameUpdate()
101
101
 
102
102
  // move particles to mouse location if on screen
103
103
  if (LJS.mousePosScreen.x)
104
+ {
104
105
  particleEmitter.pos = LJS.mousePos;
106
+ particleEmitter.velocity = LJS.mouseDelta.scale(.3*LJS.timeDelta);
107
+ }
105
108
  }
106
109
 
107
110
  ///////////////////////////////////////////////////////////////////////////////
@@ -113,8 +116,8 @@ function gameUpdatePost()
113
116
  ///////////////////////////////////////////////////////////////////////////////
114
117
  function gameRender()
115
118
  {
116
- // draw a grey square in the background without using webgl
117
- LJS.drawRect(vec2(16,8), vec2(20,14), hsl(0,0,.6), 0, false);
119
+ // draw a grey square in the background
120
+ LJS.drawRect(vec2(16,8), vec2(20,14), hsl(0,0,.6));
118
121
 
119
122
  // draw the logo as a tile
120
123
  LJS.drawTile(vec2(21,5), vec2(4.5), tile(3,128));
@@ -7,4 +7,4 @@
7
7
  </head><body>
8
8
 
9
9
  <!-- Add your game scripts here -->
10
- <script src=game.js type=module></script>
10
+ <script src=game.js type=module></script>
@@ -94,7 +94,7 @@ function gameInit()
94
94
  if (type == 'color')
95
95
  {
96
96
  const color = particleSystem[name];
97
- defaultValue = color.toString(0);
97
+ defaultValue = color.toString(false);
98
98
  }
99
99
  else if (type == 'alpha')
100
100
  {
@@ -266,7 +266,7 @@ function updateSetting(setting, save=1)
266
266
  if (type == 'color')
267
267
  {
268
268
  const color = particleSystem[name];
269
- input.value = color.toString(0);
269
+ input.value = color.toString(false);
270
270
  }
271
271
  else if (type == 'alpha')
272
272
  {
@@ -369,7 +369,16 @@ function gameUpdate()
369
369
 
370
370
  if (document.activeElement == document.body)
371
371
  {
372
- particleSystem.pos = LJS.mouseIsDown(0) ? LJS.mousePos : vec2();
372
+ if (LJS.mouseIsDown(0))
373
+ {
374
+ particleSystem.pos = LJS.mousePos;
375
+ particleSystem.velocity = LJS.mouseDelta.scale(.3*LJS.timeDelta);
376
+ }
377
+ else
378
+ {
379
+ particleSystem.pos = vec2();
380
+ particleSystem.velocity = vec2();
381
+ }
373
382
  if (LJS.mouseWheel)
374
383
  {
375
384
  // zoom camera
@@ -16,11 +16,8 @@ import * as GamePlayer from './gamePlayer.js';
16
16
  import * as GameLevel from './gameLevel.js';
17
17
  const {vec2} = LJS;
18
18
 
19
- // load the game level data
20
- export const gameLevelData = await LJS.fetchJSON('gameLevelData.json');
21
-
22
19
  // globals
23
- export let spriteAtlas, player, score, deaths;
20
+ export let gameLevelData, spriteAtlas, player, score, deaths;
24
21
  export function addToScore(delta=1) { score += delta; }
25
22
  export function addToDeaths() { ++deaths; }
26
23
 
@@ -44,6 +41,9 @@ function loadLevel()
44
41
  ///////////////////////////////////////////////////////////////////////////////
45
42
  async function gameInit()
46
43
  {
44
+ // load the game level data
45
+ gameLevelData = await LJS.fetchJSON('gameLevelData.json');
46
+
47
47
  // engine settings
48
48
  LJS.setGravity(vec2(0,-.01));
49
49
  LJS.setObjectDefaultDamping(.99);
@@ -108,7 +108,7 @@ export class Character extends GameObjects.GameObject
108
108
  for (let y=2;y--;)
109
109
  {
110
110
  const testPos = this.pos.add(vec2(0, y + .1*moveInput.y - this.size.y/2));
111
- const collisionData = LJS.getTileCollisionData(testPos);
111
+ const collisionData = LJS.tileCollisionGetData(testPos);
112
112
  touchingLadder ||= collisionData == GameLevel.tileType_ladder;
113
113
  }
114
114
  if (!touchingLadder)
@@ -133,7 +133,7 @@ export class Character extends GameObjects.GameObject
133
133
  moveInput.x *= .2;
134
134
 
135
135
  // exit ladder if ground is below
136
- this.climbingLadder = moveInput.y >= 0 || LJS.getTileCollisionData(this.pos.subtract(vec2(0,1))) <= 0;
136
+ this.climbingLadder = moveInput.y >= 0 || LJS.tileCollisionGetData(this.pos.subtract(vec2(0,1))) <= 0;
137
137
  }
138
138
  else
139
139
  {
@@ -234,7 +234,7 @@ export class Character extends GameObjects.GameObject
234
234
  if (!this.isDead())
235
235
  {
236
236
  // bounce pos with walk cycle
237
- bodyPos = bodyPos.add(vec2(0,.01+.05*Math.sin(this.walkCyclePercent*LJS.PI)));
237
+ bodyPos = bodyPos.add(vec2(0,.05*Math.sin(this.walkCyclePercent*LJS.PI)));
238
238
 
239
239
  // make bottom flush
240
240
  bodyPos = bodyPos.add(vec2(0,(this.drawSize.y-this.size.y)/2));
@@ -281,9 +281,9 @@ export class Character extends GameObjects.GameObject
281
281
  if (pos.y + 1 > this.lastPos.y - this.size.y/2)
282
282
  return false;
283
283
 
284
- if (LJS.getTileCollisionData(pos.add(vec2(0,1))) // above
285
- && !LJS.getTileCollisionData(pos.add(vec2(1,0))) // left
286
- && !LJS.getTileCollisionData(pos.add(vec2(1,0)))) // right
284
+ if (LJS.tileCollisionGetData(pos.add(vec2(0,1))) // above
285
+ && !LJS.tileCollisionGetData(pos.add(vec2(1,0))) // left
286
+ && !LJS.tileCollisionGetData(pos.add(vec2(1,0)))) // right
287
287
  return false; // don't collide if something above it and nothing to left or right
288
288
 
289
289
  // allow standing on top of ladders
@@ -40,7 +40,7 @@ export const persistentParticleDestroyCallback = (particle)=>
40
40
  }
41
41
 
42
42
  export function makeBlood(pos, amount) { makeDebris(pos, hsl(0,1,.5), amount, .1, 0); }
43
- export function makeDebris(pos, color = hsl(), amount = 50, size=.2, elasticity = .3)
43
+ export function makeDebris(pos, color = hsl(), amount = 50, size=.2, restitution = .3)
44
44
  {
45
45
  const color2 = color.lerp(hsl(), .5);
46
46
  const emitter = new LJS.ParticleEmitter(
@@ -52,7 +52,7 @@ export function makeDebris(pos, color = hsl(), amount = 50, size=.2, elasticity
52
52
  1, .95, .4, 3.14, 0, // damp, angleDamp, gravity, particleCone, fade
53
53
  .5, 1 // randomness, collide, additive, colorLinear, renderOrder
54
54
  );
55
- emitter.elasticity = elasticity;
55
+ emitter.restitution = restitution;
56
56
  emitter.particleDestroyCallback = persistentParticleDestroyCallback;
57
57
  return emitter;
58
58
  }
@@ -82,6 +82,9 @@ export function explosion(pos, radius=3)
82
82
  GameLevel.decorateTile(pos.add(vec2(x,y)).floor());
83
83
  }
84
84
 
85
+ // update webgl texture
86
+ GameLevel.updateWebGL(GameLevel.foregroundTileLayer);
87
+
85
88
  // kill/push objects
86
89
  LJS.engineObjectsCallback(pos, radius*3, (o)=>
87
90
  {
@@ -126,7 +129,7 @@ export function explosion(pos, radius=3)
126
129
 
127
130
  ///////////////////////////////////////////////////////////////////////////////
128
131
 
129
- export function destroyTile(pos, makeSound = 1, cleanNeighbors = 1)
132
+ export function destroyTile(pos, makeSound = 1, cleanup = 1)
130
133
  {
131
134
  // pos must be an int
132
135
  pos = pos.floor();
@@ -146,16 +149,17 @@ export function destroyTile(pos, makeSound = 1, cleanNeighbors = 1)
146
149
  makeDebris(centerPos, layerData.color.mutate());
147
150
  makeSound && sound_destroyObject.play(centerPos);
148
151
 
149
- // set and clear tile
150
- layer.setData(pos, new LJS.TileLayerData, 1);
152
+ // set and clear tile
153
+ layer.setData(pos, new LJS.TileLayerData, true);
151
154
  layer.setCollisionData(pos, GameLevel.tileType_empty);
152
155
 
153
- // cleanup neighbors
154
- if (cleanNeighbors)
156
+ // cleanup neighbors and rebuild webgl
157
+ if (cleanup)
155
158
  {
156
159
  for (let i=-1;i<=1;++i)
157
160
  for (let j=-1;j<=1;++j)
158
161
  GameLevel.decorateTile(pos.add(vec2(i,j)));
162
+ GameLevel.updateWebGL(layer);
159
163
  }
160
164
 
161
165
  return true;
@@ -180,16 +184,16 @@ export class Sky extends LJS.EngineObject
180
184
  {
181
185
  // fill background with a gradient
182
186
  const canvas = LJS.mainCanvas;
183
- const context = LJS.mainContext;
184
- const gradient = context.createLinearGradient(0, 0, 0, canvas.height);
185
- gradient.addColorStop(0, this.skyColor);
186
- gradient.addColorStop(1, this.horizonColor);
187
- context.save();
188
- context.fillStyle = gradient;
189
- context.fillRect(0, 0, canvas.width, canvas.height);
190
- context.globalCompositeOperation = 'lighter';
187
+ const gradientDelta = 5;
188
+ for (let y=0; y<canvas.height; y+=gradientDelta)
189
+ {
190
+ // draw horizontal lines to create a gradient
191
+ const color = this.skyColor.lerp(this.horizonColor, y/canvas.height);
192
+ LJS.drawRect(vec2(0,y), vec2(canvas.width*2, gradientDelta*2), color, 0, undefined, true)
193
+ }
191
194
 
192
195
  // draw stars
196
+ LJS.setBlendMode(true);
193
197
  const random = new LJS.RandomGenerator(this.seed);
194
198
  for (let i=1e3; i--;)
195
199
  {
@@ -201,61 +205,74 @@ export class Sky extends LJS.EngineObject
201
205
  const screenPos = vec2(
202
206
  (random.float(w)+LJS.time*speed)%w-extraSpace,
203
207
  (random.float(h)+LJS.time*speed*random.float())%h-extraSpace);
204
- context.fillStyle = color;
205
- context.fillRect(screenPos.x, screenPos.y, size, size);
208
+ LJS.drawRect(screenPos, vec2(size), color, 0, undefined, true)
206
209
  }
207
- context.restore();
210
+ LJS.setBlendMode(false);
208
211
  }
209
212
  }
210
213
 
211
214
  ///////////////////////////////////////////////////////////////////////////////
212
215
  // parallax background mountain ranges
213
216
 
214
- export class ParallaxLayer extends LJS.EngineObject
217
+ export class ParallaxLayer extends LJS.CanvasLayer
215
218
  {
216
- constructor(index)
219
+ constructor(depth)
217
220
  {
218
- super();
221
+ const renderOrder = depth - 3e3;
222
+ const canvasSize = vec2(512, 256);
223
+ super(vec2(), vec2(), 0, renderOrder, canvasSize);
224
+ this.canvasSize = canvasSize;
225
+ this.depth = depth;
226
+
227
+ // create a gradient for the mountains
228
+ const topColor = GameLevel.levelColor.mutate(.2).lerp(GameLevel.sky.skyColor, .8 - depth*.15);
229
+ const bottomColor = GameLevel.levelColor.subtract(LJS.CLEAR_WHITE).mutate(.2);
230
+ for (let i = canvasSize.y; i--;)
231
+ {
232
+ // draw a 1 pixel gradient line on the left side of the canvas
233
+ const p = i/canvasSize.y;
234
+ this.context.fillStyle = topColor.lerp(bottomColor, p);
235
+ this.context.fillRect(0, i, 1, 1);
236
+ }
219
237
 
220
- const size = vec2(1024,512);
221
- this.size = size;
222
- this.index = index;
223
- this.renderOrder = -3e3 + index;
224
- this.canvas = document.createElement('canvas');
225
- this.context = this.canvas.getContext('2d');
226
- this.canvas.width = size.x;
227
- this.canvas.height = size.y;
228
-
229
- // create a gradient
230
- const o1 = 40-20*index;
231
- const o2 = 100-30*index;
232
- const gradient = this.context.createLinearGradient(0,size.y/2-o1,0,size.y/2+o2);
233
- const layerColor = GameLevel.levelColor.mutate(.1).lerp(GameLevel.sky.skyColor,1-index*.15);
234
- gradient.addColorStop(0,layerColor);
235
- gradient.addColorStop(1,layerColor.mutate(.5).scale(.1,1));
236
- this.context.fillStyle = gradient;
237
-
238
- // draw procedural mountains ranges
239
- let groundLevel = size.y/2, groundSlope = LJS.rand(-1,1);
240
- for (let i=size.x; i--;)
241
- this.context.fillRect(i, groundLevel += groundSlope = LJS.rand() < .3 ? LJS.rand(1,-1) :
242
- groundSlope + (size.y/2 - groundLevel)/300, 1, size.y);
238
+ // draw random mountains
239
+ const pointiness = .2; // how pointy the mountains are
240
+ const levelness = .005; // how much the mountains level out
241
+ const slopeRange = 1; // max slope of the mountains
242
+ const startGroundLevel = canvasSize.y/2;
243
+ let y = startGroundLevel, groundSlope = LJS.rand(-slopeRange, slopeRange);
244
+ for (let x=canvasSize.x; x--;)
245
+ {
246
+ // pull slope towards start ground level
247
+ y += groundSlope -= (y-startGroundLevel)*levelness;
248
+
249
+ // random change slope
250
+ if (LJS.rand() < pointiness)
251
+ groundSlope = LJS.rand(-slopeRange, slopeRange);
252
+
253
+ // draw 1 pixel wide vertical slice of mountain
254
+ this.context.drawImage(this.canvas, 0, 0, 1, canvasSize.y, x, y, 1, canvasSize.y - y);
255
+ }
256
+
257
+ // remove gradient sliver from left side
258
+ this.context.clearRect(0,0,1,canvasSize.y);
259
+
260
+ // make webgl texture
261
+ this.useWebGL(LJS.glEnable);
243
262
  }
244
263
 
245
264
  render()
246
265
  {
247
- // position layer based on camera distance from center of level
248
- const parallax = vec2(1e3,-100).scale(this.index**2);
249
- const cameraDeltaFromCenter = LJS.cameraPos
250
- .subtract(GameLevel.levelSize.scale(.5))
251
- .divide(GameLevel.levelSize.divide(parallax));
252
- const scale = this.size.scale(2+2*this.index);
253
- const pos = LJS.mainCanvasSize.scale(.5) // center screen
254
- .add(vec2(-scale.x/2,-scale.y/2)) // center layer
255
- .add(cameraDeltaFromCenter.scale(-.5)) // apply parallax
256
- .add(vec2(0,(this.index*.1)*this.size.y)); // separate layers
257
-
258
- // draw the parallax layer onto the main canvas
259
- LJS.mainContext.drawImage(this.canvas, pos.x, pos.y, scale.x, scale.y);
266
+ const depth = this.depth
267
+ const distance = 4 + depth;
268
+ const parallax = vec2(150, 30).scale(depth**2+1);
269
+ const levelCenter = GameLevel.levelSize.scale(.5);
270
+ const cameraDeltaFromCenter = LJS.cameraPos.subtract(levelCenter).divide(levelCenter.scale(-1).divide(parallax));
271
+ const scale = distance/LJS.cameraScale;
272
+ const positonOffset = vec2(0, 2-depth);
273
+ const cameraOffset = cameraDeltaFromCenter.scale(1/LJS.cameraScale);
274
+ this.pos = LJS.cameraPos.add(positonOffset).add(cameraOffset);
275
+ this.size = this.canvasSize.scale(scale);
276
+ super.render();
260
277
  }
261
278
  }
@@ -14,6 +14,7 @@ import * as GameEffects from './gameEffects.js';
14
14
  import * as Game from './game.js';
15
15
  const {vec2, hsl, tile} = LJS;
16
16
 
17
+ export const useWebGLTileLayers = true;
17
18
  export const tileType_ladder = -1;
18
19
  export const tileType_empty = 0;
19
20
  export const tileType_solid = 1;
@@ -31,9 +32,9 @@ export function buildLevel()
31
32
  levelColor = LJS.randColor(hsl(0,0,.2), hsl(0,0,.8));
32
33
  levelBackgroundColor = levelColor.mutate().scale(.4,1);
33
34
  levelOutlineColor = levelColor.mutate().add(hsl(0,0,.4)).clamp();
34
- buildLevelData();
35
+ loadLevelData();
35
36
 
36
- // create sky object with gradient and stars
37
+ // create sky object with gradient background and stars
37
38
  sky = new GameEffects.Sky;
38
39
 
39
40
  // create parallax layers
@@ -41,114 +42,99 @@ export function buildLevel()
41
42
  new GameEffects.ParallaxLayer(i);
42
43
  }
43
44
 
44
- function buildLevelData()
45
+ function loadLevelData()
45
46
  {
46
- // load level data from an exported Tiled js file
47
- let tileMapData = Game.gameLevelData;
48
- if (!tileMapData)
49
- {
50
- // default level data if loading failed
51
- tileMapData = {};
52
- tileMapData.width = 100;
53
- tileMapData.height = 20;
54
- tileMapData.layers = [{data:[]}];
55
- for(let i=100*20;i--;)
56
- tileMapData.layers[0].data[i] = i>100 ? 2 : 0;
57
- }
58
-
59
- levelSize = vec2(tileMapData.width, tileMapData.height);
47
+ // load the level data
48
+ const tileMapData = Game.gameLevelData;
49
+ tileLayers = LJS.tileCollisionLoad(tileMapData, tile(0,16,1));
50
+ levelSize = tileLayers[0].size;
51
+ playerStartPos = vec2(0, levelSize.y); // default player start
52
+ foregroundTileLayer = tileLayers[0];
60
53
 
61
54
  // create table for tiles in the level tilemap
62
55
  const tileLookup =
63
56
  {
64
- circle: 1,
65
- ground: 2,
66
- ladder: 4,
67
- metal: 5,
68
- player: 17,
69
- crate: 18,
70
- enemy: 19,
71
- coin: 20,
57
+ circle: 0,
58
+ ground: 1,
59
+ ladder: 3,
60
+ metal: 4,
61
+ player: 16,
62
+ crate: 17,
63
+ enemy: 18,
64
+ coin: 19,
72
65
  }
73
66
 
74
- // set all level data tiles
75
- tileLayers = [];
76
- playerStartPos = vec2(1, levelSize.y);
77
- const layerCount = tileMapData.layers.length;
78
- for (let layer=layerCount; layer--;)
67
+ for (let i=tileLayers.length; i--;)
79
68
  {
80
- const layerData = tileMapData.layers[layer].data;
81
- let tileLayer;
82
- if (layer < layerCount-1)
83
- tileLayer = new LJS.TileLayer(vec2(), levelSize, tile(0,16,1));
84
- else
85
- {
86
- // only foreground layer has collision
87
- tileLayer = new LJS.TileCollisionLayer(vec2(), levelSize, tile(0,16,1));
69
+ const tileLayer = tileLayers[i];
70
+ const isForeground = i == tileLayers.length - 1;
71
+ if (isForeground)
88
72
  foregroundTileLayer = tileLayer;
89
- }
90
- tileLayer.renderOrder = -1e3+layer;
91
- tileLayers[layer] = tileLayer;
73
+ else
74
+ tileLayer.isSolid = false;
92
75
 
93
76
  for (let x=levelSize.x; x--;)
94
77
  for (let y=levelSize.y; y--;)
95
78
  {
96
79
  const pos = vec2(x,levelSize.y-1-y);
97
- const tile = layerData[y*levelSize.x+x];
98
-
99
- if (tile >= tileLookup.player)
80
+ const tileData = tileLayer.getData(pos).tile;
81
+ if (tileData >= tileLookup.player)
100
82
  {
101
83
  // create object instead of tile
102
84
  const objectPos = pos.add(vec2(.5));
103
- if (tile == tileLookup.player)
85
+ if (tileData == tileLookup.player)
104
86
  playerStartPos = objectPos;
105
- if (tile == tileLookup.crate)
87
+ if (tileData == tileLookup.crate)
106
88
  new GameObjects.Crate(objectPos);
107
- if (tile == tileLookup.enemy)
89
+ if (tileData == tileLookup.enemy)
108
90
  new GameObjects.Enemy(objectPos);
109
- if (tile == tileLookup.coin)
91
+ if (tileData == tileLookup.coin)
110
92
  new GameObjects.Coin(objectPos);
93
+
94
+ // replace with empty tile and empty collision
95
+ tileLayer.setData(pos, new LJS.TileLayerData);
96
+ tileLayer.setCollisionData(pos, 0);
111
97
  continue;
112
98
  }
113
-
114
- // get tile type for special tiles
115
- let tileType = tileType_empty;
116
- if (tile > 0)
117
- tileType = tileType_breakable;
118
- if (tile == tileLookup.ladder)
99
+
100
+ // get tile type
101
+ let tileType = tileData? tileType_breakable : tileType_empty;
102
+ if (tileData == tileLookup.ladder)
119
103
  tileType = tileType_ladder;
120
- if (tile == tileLookup.metal)
104
+ if (tileData == tileLookup.metal)
121
105
  tileType = tileType_solid;
122
106
  if (tileType)
123
107
  {
124
108
  // set collision for solid tiles
125
- if (tileLayer == foregroundTileLayer)
109
+ if (tileLayer.isSolid)
126
110
  tileLayer.setCollisionData(pos, tileType);
127
-
128
- // randomize tile appearance
129
- let direction, mirror, color;
130
111
  if (tileType == tileType_breakable)
131
112
  {
132
- direction = LJS.randInt(4);
133
- mirror = LJS.randInt(2);
134
- color = layer ? levelColor : levelBackgroundColor;
113
+ // randomize tile appearance
114
+ let direction = LJS.randInt(4);
115
+ let mirror = LJS.randInt(2);
116
+ let color = i ? levelColor : levelBackgroundColor;
135
117
  color = color.mutate(.03);
136
- }
137
118
 
138
- // set tile layer data
139
- const data = new LJS.TileLayerData(tile-1, direction, mirror, color);
140
- tileLayer.setData(pos, data);
119
+ // set tile layer data
120
+ const data = new LJS.TileLayerData(tileData, direction, mirror, color);
121
+ tileLayer.setData(pos, data);
122
+ }
141
123
  }
142
124
  }
143
125
  tileLayer.redraw();
144
126
  }
145
-
127
+
146
128
  // apply decoration to all level tiles
147
129
  const pos = vec2();
130
+ const layerCount = tileMapData.layers.length;
148
131
  for (let layer=layerCount; layer--;)
149
- for (pos.x=levelSize.x; pos.x--;)
150
- for (pos.y=levelSize.y; pos.y--;)
151
- decorateTile(pos, layer);
132
+ {
133
+ for (pos.x=levelSize.x; pos.x--;)
134
+ for (pos.y=levelSize.y; pos.y--;)
135
+ decorateTile(pos, layer);
136
+ updateWebGL(tileLayers[layer]);
137
+ }
152
138
  }
153
139
 
154
140
  export function decorateTile(pos, layer=1)
@@ -213,4 +199,9 @@ export function getCameraTarget()
213
199
  // camera is above player
214
200
  const offset = 100/LJS.cameraScale*LJS.percent(LJS.mainCanvasSize.y, 300, 600);
215
201
  return Game.player.pos.add(vec2(0, offset));
202
+ }
203
+
204
+ export function updateWebGL(layer)
205
+ {
206
+ layer.useWebGL(useWebGLTileLayers);
216
207
  }
@@ -188,7 +188,7 @@ export class Grenade extends GameObject
188
188
  super(pos, vec2(.2), Game.spriteAtlas.grenade);
189
189
 
190
190
  this.beepTimer = new Timer(1);
191
- this.elasticity = .3;
191
+ this.restitution = .3;
192
192
  this.friction = .9;
193
193
  this.angleDamping = .96;
194
194
  this.renderOrder = 1e8;
@@ -253,7 +253,7 @@ export class Weapon extends LJS.EngineObject
253
253
  1, .95, 1, 0, 0, // damp, angleDamp, gravity, particleCone, fade
254
254
  .1, 1 // randomness, collide, additive, colorLinear, renderOrder
255
255
  ), vec2(.1,0), -.8);
256
- this.shellEmitter.elasticity = .5;
256
+ this.shellEmitter.restitution = .5;
257
257
  this.shellEmitter.particleDestroyCallback = GameEffects.persistentParticleDestroyCallback;
258
258
  }
259
259
 
@@ -263,7 +263,7 @@ export class Weapon extends LJS.EngineObject
263
263
 
264
264
  // update recoil
265
265
  if (this.recoilTimer.active())
266
- this.localAngle = LJS.lerp(this.recoilTimer.getPercent(), this.localAngle, 0);
266
+ this.localAngle = LJS.lerp(this.localAngle, 0, this.recoilTimer.getPercent());
267
267
 
268
268
  this.mirror = this.parent.mirror;
269
269
  this.fireTimeBuffer += LJS.timeDelta;
@@ -375,7 +375,7 @@ export class Bullet extends LJS.EngineObject
375
375
  .5, 1, 1 // randomness, collide, additive, colorLinear, renderOrder
376
376
  );
377
377
  emitter.trailScale = 1;
378
- emitter.elasticity = .3;
378
+ emitter.restitution = .3;
379
379
  emitter.angle = this.velocity.angle() + LJS.PI;
380
380
  }
381
381
  }
@@ -6,4 +6,4 @@
6
6
  <meta name=mobile-web-app-capable content=yes>
7
7
  <link rel=icon type=image/png href=../favicon.png>
8
8
  </head><body>
9
- <script src=game.js type=module></script>
9
+ <script src=game.js type=module></script>
@@ -5,4 +5,4 @@
5
5
  <meta name=mobile-web-app-capable content=yes>
6
6
  <link rel=icon type=image/png href=../favicon.png>
7
7
  </head><body>
8
- <script src=game.js type=module></script>
8
+ <script src=game.js type=module></script>
@@ -1,8 +1,28 @@
1
1
  <!DOCTYPE html><meta charset=utf-8><body>
2
+ <script src=../../dist/littlejs.js?1133></script>
2
3
  <script src=../../dist/box2d.wasm.js></script>
3
- <script src=../../dist/littlejs.js?1120></script>
4
- <script>
5
4
 
5
+ <!-- LittleJS Engine Source
6
+ <script src=../../src/engineDebug.js></script>
7
+ <script src=../../src/engineUtilities.js></script>
8
+ <script src=../../src/engineSettings.js></script>
9
+ <script src=../../src/engineObject.js></script>
10
+ <script src=../../src/engineDraw.js></script>
11
+ <script src=../../src/engineInput.js></script>
12
+ <script src=../../src/engineAudio.js></script>
13
+ <script src=../../src/engineTileLayer.js></script>
14
+ <script src=../../src/engineParticles.js></script>
15
+ <script src=../../src/engineMedals.js></script>
16
+ <script src=../../src/engineWebGL.js></script>
17
+ <script src=../../src/engine.js></script>
18
+ <script src=../../plugins/box2d.js></script>
19
+ <script src=../../plugins/box2d.wasm.js></script>
20
+ <script src=../../plugins/drawUtilities.js></script>
21
+ <script src=../../plugins/postProcess.js></script>
22
+ <script src=../../plugins/uiSystem.js></script>
23
+ <script src=../../plugins/zzfxm.js></script>
24
+ -->
25
+ <script>
6
26
  'use strict';
7
27
 
8
28
  // use fixed size canvas for examples
@@ -24,4 +44,4 @@ function gameUpdatePost() {}
24
44
  function gameRender() {}
25
45
  function gameRenderPost() {}
26
46
 
27
- </script>
47
+ </script>
@@ -1,16 +1,20 @@
1
+ // use smoother textures
2
+ setCanvasPixelated(false);
3
+ setTilesPixelated(false);
4
+
1
5
  function gameRender()
2
6
  {
3
7
  const circleTile = tile(2, 128); // get the circle tile
4
8
 
5
9
  // additive blend
6
10
  setBlendMode(1);
7
- drawTile(vec2(-4,-2), vec2(7), circleTile, rgb(1,0,0));
11
+ drawTile(vec2(-8,-2), vec2(7), circleTile, rgb(0,0,.5), 0, false, rgb(0,0,.5));
8
12
  drawTile(vec2(-6, 2), vec2(7), circleTile, rgb(0,1,0));
9
- drawTile(vec2(-8,-2), vec2(7), circleTile, rgb(0,0,1));
13
+ drawTile(vec2(-4,-2), vec2(7), circleTile, rgb(1,0,0));
10
14
 
11
15
  // alpha blend
12
16
  setBlendMode(0);
13
- drawTile(vec2(4,-2), vec2(7), circleTile, rgb(1,0,0,.5));
14
- drawTile(vec2(6, 2), vec2(7), circleTile, rgb(0,1,0,.5));
15
- drawTile(vec2(8,-2), vec2(7), circleTile, rgb(0,0,1,.5));
17
+ drawTile(vec2(4,-2), vec2(7), circleTile, hsl(time/9 ,1,.5), 0, false, hsl(1,1,.5));
18
+ drawTile(vec2(8,-2), vec2(7), circleTile, hsl(time/9+1/3,1,.5,.5));
19
+ drawTile(vec2(6, 2), vec2(7), circleTile, hsl(time/9+2/3,1,.5,.5));
16
20
  }