littlejsengine 1.7.13 → 1.8.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.
Files changed (58) hide show
  1. package/README.md +27 -55
  2. package/build/littlejs.d.ts +253 -76
  3. package/build/littlejs.esm.js +644 -523
  4. package/build/littlejs.esm.min.js +1 -1
  5. package/build/littlejs.js +640 -332
  6. package/build/littlejs.min.js +1 -1
  7. package/build/littlejs.release.js +640 -332
  8. package/examples/breakout/game.js +17 -14
  9. package/examples/breakout/gameObjects.js +29 -8
  10. package/examples/breakout/index.html +3 -3
  11. package/examples/breakoutTutorial/README.md +2 -2
  12. package/examples/breakoutTutorial/game.js +4 -4
  13. package/examples/breakoutTutorial/index.html +2 -2
  14. package/examples/electron/build.js +2 -0
  15. package/examples/electron/game.js +3 -2
  16. package/examples/electron/index.html +2 -2
  17. package/examples/empty/game.js +1 -1
  18. package/examples/favicon.png +0 -0
  19. package/examples/js13k/build.js +2 -0
  20. package/examples/js13k/game.js +20 -15
  21. package/examples/js13k/index.html +14 -14
  22. package/examples/module/game.js +4 -3
  23. package/examples/module/index.html +1 -1
  24. package/examples/particles/index.html +19 -22
  25. package/examples/platformer/game.js +3 -3
  26. package/examples/platformer/gameEffects.js +21 -19
  27. package/examples/platformer/gameLevel.js +6 -6
  28. package/examples/platformer/gameObjects.js +18 -18
  29. package/examples/platformer/gamePlayer.js +4 -3
  30. package/examples/platformer/index.html +6 -6
  31. package/examples/platformer/tiles.png +0 -0
  32. package/examples/platformer/tilesLevel.png +0 -0
  33. package/examples/puzzle/game.js +10 -8
  34. package/examples/puzzle/index.html +2 -2
  35. package/examples/screenshot.jpg +0 -0
  36. package/examples/starter/build.js +2 -0
  37. package/examples/starter/game.js +32 -21
  38. package/examples/starter/index.html +13 -13
  39. package/examples/starter/tiles.png +0 -0
  40. package/examples/stress/index.html +2 -2
  41. package/examples/typescript/build.js +2 -0
  42. package/examples/typescript/game.js +4 -3
  43. package/examples/typescript/game.ts +4 -3
  44. package/examples/typescript/index.html +1 -1
  45. package/package.json +1 -1
  46. package/src/engine.js +59 -49
  47. package/src/engineAudio.js +67 -41
  48. package/src/engineBuild.js +23 -7
  49. package/src/engineDraw.js +139 -40
  50. package/src/engineExport.js +4 -191
  51. package/src/engineInput.js +22 -10
  52. package/src/engineMedals.js +13 -45
  53. package/src/engineObject.js +12 -13
  54. package/src/engineParticles.js +17 -17
  55. package/src/engineSettings.js +195 -2
  56. package/src/engineTileLayer.js +23 -22
  57. package/src/engineUtilities.js +6 -6
  58. package/src/engineWebGL.js +73 -74
@@ -45,8 +45,9 @@ class Sound
45
45
  if (zzfxSound)
46
46
  {
47
47
  // generate zzfx sound now for fast playback
48
- this.randomness = zzfxSound[1] || (zzfxSound[1] = 0);
49
- this.cachedSamples = zzfxSound && zzfxG(...zzfxSound);
48
+ this.randomness = zzfxSound[1] || (zzfxSound[1] = 0);
49
+ this.sampleChannels = [zzfxG(...zzfxSound)];
50
+ this.sampleRate = zzfxR;
50
51
  }
51
52
  }
52
53
 
@@ -55,11 +56,12 @@ class Sound
55
56
  * @param {Number} [volume=1] - How much to scale volume by (in addition to range fade)
56
57
  * @param {Number} [pitch=1] - How much to scale pitch by (also adjusted by this.randomness)
57
58
  * @param {Number} [randomnessScale=1] - How much to scale randomness
58
- * @return {AudioBufferSourceNode} - The audio, can be used to stop sound later
59
+ * @param {Boolean} [loop=0] - Should the sound loop
60
+ * @return {AudioBufferSourceNode} - The audio source node
59
61
  */
60
- play(pos, volume=1, pitch=1, randomnessScale=1)
62
+ play(pos, volume=1, pitch=1, randomnessScale=1, loop=0)
61
63
  {
62
- if (!soundEnable || !this.cachedSamples) return;
64
+ if (!soundEnable || !this.sampleChannels) return;
63
65
 
64
66
  let pan;
65
67
  if (pos)
@@ -82,43 +84,80 @@ class Sound
82
84
 
83
85
  // play the sound
84
86
  const playbackRate = pitch + pitch * this.randomness*randomnessScale*rand(-1,1);
85
- return playSamples([this.cachedSamples], volume, playbackRate, pan);
87
+ return this.source = playSamples(this.sampleChannels, volume, playbackRate, pan, loop, this.sampleRate);
88
+ }
89
+
90
+ /** Stop the last instance of this sound that was played */
91
+ stop()
92
+ {
93
+ if (this.source)
94
+ this.source.stop();
95
+ this.source = 0;
86
96
  }
87
97
 
88
98
  /** Play the sound as a note with a semitone offset
89
99
  * @param {Number} semitoneOffset - How many semitones to offset pitch
90
100
  * @param {Vector2} [pos] - World space position to play the sound, sound is not attenuated if null
91
101
  * @param {Number} [volume=1] - How much to scale volume by (in addition to range fade)
92
- * @return {AudioBufferSourceNode} - The audio, can be used to stop sound later
102
+ * @return {AudioBufferSourceNode} - The audio source node
93
103
  */
94
104
  playNote(semitoneOffset, pos, volume)
95
105
  { return this.play(pos, volume, 2**(semitoneOffset/12), 0); }
106
+
107
+ /** Get how long this sound is in seconds
108
+ * @return {Number} - How long the sound is in seconds (undefined if loading)
109
+ */
110
+ getDuration()
111
+ { return this.sampleChannels && this.sampleChannels[0].length / this.sampleRate; }
112
+
113
+ /** Check if the last instance of this sound is playing
114
+ * @return {Boolean} - True if the sound is playing
115
+ */
116
+ isPlaying() { return this.source && !this.source.ended; }
117
+
118
+ /** Check if sound is loading, for sounds fetched from a url
119
+ * @return {Boolean} - True if sound is loading and not ready to play
120
+ */
121
+ isLoading() { return !this.sampleChannels; }
96
122
  }
97
123
 
98
124
  /**
99
125
  * Sound Wave Object - Stores a wave sound for later use and can be played positionally
126
+ * - this can be used to play wave, mp3, and ogg files
127
+ * @example
128
+ * // create a sound
129
+ * const sound_example = new SoundWave('sound.mp3');
130
+ *
131
+ * // play the sound
132
+ * sound_example.play();
100
133
  */
101
134
  class SoundWave extends Sound
102
135
  {
103
136
  /** Create a sound object and cache the wave file for later use
104
- * @param {String} waveFilename - Filename of wave file to load
105
- * @param {Number} [randomness=.05] - How much to randomize frequency each time sound plays
137
+ * @param {String} filename - Filename of audio file to load
138
+ * @param {Number} [randomness=0] - How much to randomize frequency each time sound plays
106
139
  * @param {Number} [range=soundDefaultRange] - World space max range of sound, will not play if camera is farther away
107
140
  * @param {Number} [taper=soundDefaultTaper] - At what percentage of range should it start tapering off
108
141
  */
109
- constructor(waveFilename, randomness=.05, range, taper)
142
+ constructor(filename, randomness=0, range, taper)
110
143
  {
111
144
  super(0, range, taper);
112
145
  this.randomness = randomness;
113
146
 
114
147
  if (!soundEnable) return;
115
- if (!soundWaveDecoderContext)
148
+ if (!soundDecoderContext)
116
149
  soundDecoderContext = new AudioContext;
117
150
 
118
- fetch(waveFilename)
151
+ fetch(filename)
119
152
  .then(response => response.arrayBuffer())
120
- .then(arrayBuffer => soundWaveDecoderContext.decodeAudioData(arrayBuffer))
121
- .then(audioBuffer => this.cachedSamples = audioBuffer.getChannelData(0));
153
+ .then(arrayBuffer => soundDecoderContext.decodeAudioData(arrayBuffer))
154
+ .then(audioBuffer =>
155
+ {
156
+ this.sampleChannels = [];
157
+ for (let i = audioBuffer.numberOfChannels; i--;)
158
+ this.sampleChannels[i] = audioBuffer.getChannelData(i);
159
+ this.sampleRate = audioBuffer.sampleRate;
160
+ });
122
161
  }
123
162
  }
124
163
  let soundDecoderContext; // audio context used only to decode audio files
@@ -153,48 +192,34 @@ let soundDecoderContext; // audio context used only to decode audio files
153
192
  * // play the music
154
193
  * music_example.play();
155
194
  */
156
- class Music
195
+ class Music extends Sound
157
196
  {
158
197
  /** Create a music object and cache the zzfx music samples for later use
159
198
  * @param {Array} zzfxMusic - Array of zzfx music parameters
160
199
  */
161
200
  constructor(zzfxMusic)
162
201
  {
163
- if (!soundEnable) return;
202
+ super();
164
203
 
165
- this.cachedSamples = zzfxM(...zzfxMusic);
204
+ if (!soundEnable) return;
205
+ this.randomness = 0;
206
+ this.sampleChannels = zzfxM(...zzfxMusic);
207
+ this.sampleRate = zzfxR;
166
208
  }
167
209
 
168
210
  /** Play the music
169
211
  * @param {Number} [volume=1] - How much to scale volume by
170
- * @param {Boolean} [loop=1] - True if the music should loop when it reaches the end
171
- * @return {AudioBufferSourceNode} - The audio node, can be used to stop sound later
212
+ * @param {Boolean} [loop=1] - True if the music should loop
213
+ * @return {AudioBufferSourceNode} - The audio source node
172
214
  */
173
215
  play(volume, loop = 1)
174
- {
175
- if (!soundEnable) return;
176
-
177
- return this.source = playSamples(this.cachedSamples, volume, 1, 0, loop);
178
- }
179
-
180
- /** Stop the music */
181
- stop()
182
- {
183
- if (this.source)
184
- this.source.stop();
185
- this.source = 0;
186
- }
187
-
188
- /** Check if music is playing
189
- * @return {Boolean}
190
- */
191
- isPlaying() { return this.source; }
216
+ { return super.play(0, volume, 1, 1, loop); }
192
217
  }
193
218
 
194
- /** Play an mp3 or wav audio from a local file or url
219
+ /** Play an mp3, ogg, or wav audio from a local file or url
195
220
  * @param {String} url - Location of sound file to play
196
221
  * @param {Number} [volume=1] - How much to scale volume by
197
- * @param {Boolean} [loop=1] - True if the music should loop when it reaches the end
222
+ * @param {Boolean} [loop=1] - True if the music should loop
198
223
  * @return {HTMLAudioElement} - The audio element for this sound
199
224
  * @memberof Audio */
200
225
  function playAudioFile(url, volume=1, loop=1)
@@ -258,9 +283,10 @@ let audioContext;
258
283
  * @param {Number} [rate=1] - The playback rate to use
259
284
  * @param {Number} [pan=0] - How much to apply stereo panning
260
285
  * @param {Boolean} [loop=0] - True if the sound should loop when it reaches the end
286
+ * @param {Number} [sampleRate=44100] - Sample rate for the sound
261
287
  * @return {AudioBufferSourceNode} - The audio node of the sound played
262
288
  * @memberof Audio */
263
- function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=0)
289
+ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=0, sampleRate=zzfxR)
264
290
  {
265
291
  if (!soundEnable) return;
266
292
 
@@ -277,7 +303,7 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=0)
277
303
  }
278
304
 
279
305
  // create buffer and source
280
- const buffer = audioContext.createBuffer(sampleChannels.length, sampleChannels[0].length, zzfxR),
306
+ const buffer = audioContext.createBuffer(sampleChannels.length, sampleChannels[0].length, sampleRate),
281
307
  source = audioContext.createBufferSource();
282
308
 
283
309
  // copy samples to buffer and setup source
@@ -6,9 +6,10 @@
6
6
  * - Run custom build steps
7
7
  * - Check for errors
8
8
  * - Output to build folder
9
- * @namespace Build
10
9
  */
11
10
 
11
+ 'use strict';
12
+
12
13
  const ENGINE_NAME = 'littlejs';
13
14
  const BUILD_FOLDER = 'build';
14
15
  const SOURCE_FOLDER = 'src';
@@ -54,7 +55,7 @@ Build
54
55
  'Build Engine -- all',
55
56
  `${BUILD_FOLDER}/${ENGINE_NAME}.js`,
56
57
  [`${SOURCE_FOLDER}/engineDebug.js`, ...engineSourceFiles],
57
- [], license
58
+ [], true
58
59
  );
59
60
 
60
61
  Build
@@ -62,7 +63,7 @@ Build
62
63
  'Build Engine -- release',
63
64
  `${BUILD_FOLDER}/${ENGINE_NAME}.release.js`,
64
65
  [`${SOURCE_FOLDER}/engineRelease.js`, ...engineSourceFiles],
65
- [], license
66
+ [], true
66
67
  );
67
68
 
68
69
  Build
@@ -95,16 +96,31 @@ console.log(`Engine built in ${((Date.now() - startTime)/1e3).toFixed(2)} second
95
96
 
96
97
  // A single build with its own source files, build steps, and output file
97
98
  // - each build step is a callback that accepts a single filename
98
- function Build(message, outputFile, files=[], buildSteps=[], topOfFileText)
99
+ function Build(message, outputFile, files=[], buildSteps=[], isPrimaryBuild)
99
100
  {
100
101
  console.log(message);
101
102
 
102
103
  // copy files into a buffer
103
104
  let buffer = '';
104
- if (topOfFileText)
105
- buffer += topOfFileText + '\n';
105
+ if (isPrimaryBuild)
106
+ {
107
+ // add license and strict mode to top
108
+ buffer += license + '\n';
109
+ buffer += "'use strict';\n\n";
110
+ }
111
+
106
112
  for (const file of files)
107
- buffer += fs.readFileSync(file) + '\n';
113
+ {
114
+ // get file content
115
+ let fileContent = fs.readFileSync(file) + '\n';
116
+
117
+ // remove first 'use strict' from each file
118
+ if (isPrimaryBuild)
119
+ fileContent = fileContent.replace("'use strict';", '');
120
+
121
+ // add it to the buffer
122
+ buffer += fileContent;
123
+ }
108
124
 
109
125
  // output file
110
126
  fs.writeFileSync(outputFile, buffer, {flag: 'w+'});
package/src/engineDraw.js CHANGED
@@ -47,13 +47,109 @@ let overlayContext;
47
47
  * @memberof Draw */
48
48
  let mainCanvasSize = vec2();
49
49
 
50
- /** Tile sheet for batch rendering system
51
- * @type {CanvasImageSource}
50
+ /** Array containing texture info for batch rendering system
51
+ * @type {Array}
52
52
  * @memberof Draw */
53
- const tileImage = new Image;
53
+ let textureInfos = [];
54
54
 
55
55
  // Engine internal variables not exposed to documentation
56
- let tileImageSize, tileImageFixBleed, drawCount;
56
+ let drawCount;
57
+
58
+ ///////////////////////////////////////////////////////////////////////////////
59
+
60
+ /**
61
+ * Create a tile info object
62
+ * - This can take vecs or floats for easier use and conversion
63
+ * - If an index is passed in, the tile size and index will determine the position
64
+ * @param {(Number|Vector2)} [pos=Vector2()] - Top left corner of tile in pixels or index
65
+ * @param {(Number|Vector2)} [size=tileSizeDefault] - Size of tile in pixels
66
+ * @param {Number} [textureIndex=0] - Texture index to use
67
+ * @return {TileInfo}
68
+ * @example
69
+ * tile(2) // a tile at index 2 using the default tile size of 16
70
+ * tile(5, 8) // a tile at index 5 using a tile size of 8
71
+ * tile(1, 16, 3) // a tile at index 1 of size 16 on texture 3
72
+ * tile(vec2(4,8), vec2(30,10)) // a tile at pixel location (4,8) with a size of (30,10)
73
+ * @memberof Draw
74
+ */
75
+ function tile(pos=vec2(), size=tileSizeDefault, textureIndex=0)
76
+ {
77
+ // if size is a number, make it a vector
78
+ if (size.x == undefined)
79
+ {
80
+ ASSERT(size > 0);
81
+ size = vec2(size);
82
+ }
83
+
84
+ // if pos is a number, use it as a tile index
85
+ if (pos.x == undefined)
86
+ {
87
+ const textureInfo = textureInfos[textureIndex];
88
+ if (textureInfo)
89
+ {
90
+ const cols = textureInfo.size.x / size.x |0;
91
+ pos = vec2((pos%cols)*size.x, (pos/cols|0)*size.y);
92
+ }
93
+ else
94
+ pos = vec2();
95
+ }
96
+
97
+ // return a tile info object
98
+ return new TileInfo(pos, size, textureIndex);
99
+ }
100
+
101
+ /**
102
+ * Tile Info - Stores info about how to draw a tile
103
+ */
104
+ class TileInfo
105
+ {
106
+ /** Create a tile info object
107
+ * @param {Vector2} [pos=Vector2()] - Top left corner of tile in pixels
108
+ * @param {Vector2} [size=tileSizeDefault] - Size of tile in pixels
109
+ * @param {Number} [textureIndex=0] - Texture index to use
110
+ */
111
+ constructor(pos=vec2(), size=tileSizeDefault, textureIndex=0)
112
+ {
113
+ /** @property {Vector2} - Top left corner of tile in pixels */
114
+ this.pos = pos;
115
+ /** @property {Vector2} - Size of tile in pixels */
116
+ this.size = size;
117
+ /** @property {Number} - Texture index to use */
118
+ this.textureIndex = textureIndex;
119
+ }
120
+
121
+ /** Returns an offset copy of this tile, useful for animation
122
+ * @param {Vector2} offset - Offset to apply in pixels
123
+ * @return {TileInfo}
124
+ */
125
+ offset(offset)
126
+ { return new TileInfo(this.pos.add(offset), this.size, this.textureIndex); }
127
+
128
+ /** Returns the texture info for this tile
129
+ * @return {TextureInfo}
130
+ */
131
+ getTextureInfo()
132
+ { return textureInfos[this.textureIndex]; }
133
+ }
134
+
135
+ /** Texture Info - Stores info about each texture */
136
+ class TextureInfo
137
+ {
138
+ // create a TextureInfo, called automatically by the engine
139
+ constructor(image)
140
+ {
141
+ /** @property {CanvasImageSource} - image source */
142
+ this.image = image;
143
+ /** @property {Vector2} - size of the image */
144
+ this.size = vec2(image.width, image.height);
145
+ /** @property {WebGLTexture} - webgl texture */
146
+ this.glTexture = glEnable && glCreateTexture(image);
147
+ /** @property {Vector2} - size to adjust tile to fix bleeding */
148
+ this.fixBleedSize = vec2(tileFixBleedScale).divide(this.size);
149
+ }
150
+ }
151
+
152
+ ///////////////////////////////////////////////////////////////////////////////
57
153
 
58
154
  /** Convert from screen to world space coordinates
59
155
  * @param {Vector2} screenPos
@@ -84,7 +180,7 @@ function worldToScreen(worldPos)
84
180
  /** Draw textured tile centered in world space, with color applied if using WebGL
85
181
  * @param {Vector2} pos - Center of the tile in world space
86
182
  * @param {Vector2} [size=Vector2(1,1)] - Size of the tile in world space
87
- * @param {Number} [tileIndex=-1] - Tile index to use, negative is untextured
183
+ * @param {TileInfo}[tileInfo] - Tile info to use, untextured if undefined
88
184
  * @param {Vector2} [tileSize=tileSizeDefault] - Tile size in source pixels
89
185
  * @param {Color} [color=Color()] - Color to modulate with
90
186
  * @param {Number} [angle=0] - Angle to rotate by
@@ -93,11 +189,14 @@ function worldToScreen(worldPos)
93
189
  * @param {Boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering
94
190
  * @param {Boolean} [screenSpace=0] - If true the pos and size are in screen space
95
191
  * @memberof Draw */
96
- function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, color=new Color,
192
+ function drawTile(pos, size=vec2(1), tileInfo, color=new Color,
97
193
  angle=0, mirror, additiveColor=new Color(0,0,0,0), useWebGL=glEnable, screenSpace)
98
194
  {
195
+ ASSERT(typeof tileInfo !== 'number' || !tileInfo); // prevent old style calls
196
+ // to fix old calls, replace with tile(tileIndex, tileSize)
197
+
99
198
  showWatermark && ++drawCount;
100
-
199
+ const textureInfo = tileInfo && tileInfo.getTextureInfo();
101
200
  if (glEnable && useWebGL)
102
201
  {
103
202
  if (screenSpace)
@@ -106,46 +205,48 @@ function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, col
106
205
  pos = screenToWorld(pos);
107
206
  size = size.scale(1/cameraScale);
108
207
  }
109
- if (tileIndex < 0 || !tileImage.width)
110
- {
111
- // if negative tile index or image not found, force untextured
112
- glDraw(pos.x, pos.y, size.x, size.y, angle, 0, 0, 0, 0, 0, color.rgbaInt());
113
- }
114
- else
208
+
209
+ if (textureInfo)
115
210
  {
116
211
  // calculate uvs and render
117
- const cols = tileImageSize.x / tileSize.x |0;
118
- const uvSizeX = tileSize.x / tileImageSize.x;
119
- const uvSizeY = tileSize.y / tileImageSize.y;
120
- const uvX = (tileIndex%cols)*uvSizeX, uvY = (tileIndex/cols|0)*uvSizeY;
121
-
212
+ const x = tileInfo.pos.x / textureInfo.size.x;
213
+ const y = tileInfo.pos.y / textureInfo.size.y;
214
+ const w = tileInfo.size.x / textureInfo.size.x;
215
+ const h = tileInfo.size.y / textureInfo.size.y;
216
+ const tileImageFixBleed = textureInfo.fixBleedSize;
217
+ glSetTexture(textureInfo.glTexture);
122
218
  glDraw(pos.x, pos.y, mirror ? -size.x : size.x, size.y, angle,
123
- uvX + tileImageFixBleed.x, uvY + tileImageFixBleed.y,
124
- uvX - tileImageFixBleed.x + uvSizeX, uvY - tileImageFixBleed.y + uvSizeY,
219
+ x + tileImageFixBleed.x, y + tileImageFixBleed.y,
220
+ x - tileImageFixBleed.x + w, y - tileImageFixBleed.y + h,
125
221
  color.rgbaInt(), additiveColor.rgbaInt());
126
222
  }
223
+ else
224
+ {
225
+ // if no tile info, force untextured
226
+ glDraw(pos.x, pos.y, size.x, size.y, angle, 0, 0, 0, 0, 0, color.rgbaInt());
227
+ }
127
228
  }
128
229
  else
129
230
  {
130
231
  // normal canvas 2D rendering method (slower)
131
232
  drawCanvas2D(pos, size, angle, mirror, (context)=>
132
233
  {
133
- if (tileIndex < 0)
234
+ if (textureInfo)
134
235
  {
135
- // if negative tile index, force untextured
136
- context.fillStyle = color;
137
- context.fillRect(-.5, -.5, 1, 1);
236
+ // calculate uvs and render
237
+ const x = tileInfo.pos.x + tileFixBleedScale;
238
+ const y = tileInfo.pos.y + tileFixBleedScale;
239
+ const w = tileInfo.size.x - 2*tileFixBleedScale;
240
+ const h = tileInfo.size.y - 2*tileFixBleedScale;
241
+ context.globalAlpha = color.a; // only alpha is supported
242
+ context.drawImage(textureInfo.image, x, y, w, h, -.5, -.5, 1, 1);
243
+ context.globalAlpha = 1; // set back to full alpha
138
244
  }
139
245
  else
140
246
  {
141
- // calculate uvs and render
142
- const cols = tileImageSize.x / tileSize.x |0;
143
- const sX = (tileIndex%cols)*tileSize.x + tileFixBleedScale;
144
- const sY = (tileIndex/cols|0)*tileSize.y + tileFixBleedScale;
145
- const sWidth = tileSize.x - 2*tileFixBleedScale;
146
- const sHeight = tileSize.y - 2*tileFixBleedScale;
147
- context.globalAlpha = color.a; // only alpha is supported
148
- context.drawImage(tileImage, sX, sY, sWidth, sHeight, -.5, -.5, 1, 1);
247
+ // if no tile info, force untextured
248
+ context.fillStyle = color;
249
+ context.fillRect(-.5, -.5, 1, 1);
149
250
  }
150
251
  }, undefined, screenSpace);
151
252
  }
@@ -160,7 +261,7 @@ function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, col
160
261
  * @param {Boolean} [screenSpace=0]
161
262
  * @memberof Draw */
162
263
  function drawRect(pos, size, color, angle, useWebGL, screenSpace)
163
- { drawTile(pos, size, -1, tileSizeDefault, color, angle, 0, undefined, useWebGL, screenSpace); }
264
+ { drawTile(pos, size, undefined, color, angle, 0, undefined, useWebGL, screenSpace); }
164
265
 
165
266
  /** Draw colored polygon using passed in points
166
267
  * @param {Array} points - Array of Vector2 points
@@ -211,12 +312,12 @@ function drawCanvas2D(pos, size, angle, mirror, drawFunction, context = mainCont
211
312
  {
212
313
  if (!screenSpace)
213
314
  {
214
- // create canvas transform from world space to screen space
315
+ // transform from world space to screen space
215
316
  pos = worldToScreen(pos);
216
317
  size = size.scale(cameraScale);
217
318
  }
218
319
  context.save();
219
- context.translate(pos.x+.5|0, pos.y+.5|0);
320
+ context.translate(pos.x+.5, pos.y+.5);
220
321
  context.rotate(angle);
221
322
  context.scale(mirror ? -size.x : size.x, size.y);
222
323
  drawFunction(context);
@@ -305,10 +406,9 @@ class FontImage
305
406
  * @param {HTMLImageElement} [image] - Image for the font, if undefined default font is used
306
407
  * @param {Vector2} [tileSize=vec2(8)] - Size of the font source tiles
307
408
  * @param {Vector2} [paddingSize=vec2(0,1)] - How much extra space to add between characters
308
- * @param {Number} [startTileIndex=0] - Tile index in image where font starts
309
409
  * @param {CanvasRenderingContext2D} [context=overlayContext] - context to draw to
310
410
  */
311
- constructor(image, tileSize=vec2(8), paddingSize=vec2(0,1), startTileIndex=0, context=overlayContext)
411
+ constructor(image, tileSize=vec2(8), paddingSize=vec2(0,1), context=overlayContext)
312
412
  {
313
413
  // load default font image
314
414
  if (!engineFontImage)
@@ -317,7 +417,6 @@ class FontImage
317
417
  this.image = image || engineFontImage;
318
418
  this.tileSize = tileSize;
319
419
  this.paddingSize = paddingSize;
320
- this.startTileIndex = startTileIndex;
321
420
  this.context = context;
322
421
  }
323
422
 
@@ -358,7 +457,7 @@ class FontImage
358
457
  charCode = 127; // unknown character
359
458
 
360
459
  // get the character source location and draw it
361
- const tile = this.startTileIndex + charCode - 32;
460
+ const tile = charCode - 32;
362
461
  const x = tile % cols;
363
462
  const y = tile / cols |0;
364
463
  const drawPos = pos.add(vec2(j,i).multiply(drawSize));
@@ -390,4 +489,4 @@ function toggleFullscreen()
390
489
  }
391
490
  else if (document.body.requestFullscreen)
392
491
  document.body.requestFullscreen();
393
- }
492
+ }