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.
- package/README.md +27 -55
- package/build/littlejs.d.ts +253 -76
- package/build/littlejs.esm.js +644 -523
- package/build/littlejs.esm.min.js +1 -1
- package/build/littlejs.js +640 -332
- package/build/littlejs.min.js +1 -1
- package/build/littlejs.release.js +640 -332
- package/examples/breakout/game.js +17 -14
- package/examples/breakout/gameObjects.js +29 -8
- package/examples/breakout/index.html +3 -3
- package/examples/breakoutTutorial/README.md +2 -2
- package/examples/breakoutTutorial/game.js +4 -4
- package/examples/breakoutTutorial/index.html +2 -2
- package/examples/electron/build.js +2 -0
- package/examples/electron/game.js +3 -2
- package/examples/electron/index.html +2 -2
- package/examples/empty/game.js +1 -1
- package/examples/favicon.png +0 -0
- package/examples/js13k/build.js +2 -0
- package/examples/js13k/game.js +20 -15
- package/examples/js13k/index.html +14 -14
- package/examples/module/game.js +4 -3
- package/examples/module/index.html +1 -1
- package/examples/particles/index.html +19 -22
- package/examples/platformer/game.js +3 -3
- package/examples/platformer/gameEffects.js +21 -19
- package/examples/platformer/gameLevel.js +6 -6
- package/examples/platformer/gameObjects.js +18 -18
- package/examples/platformer/gamePlayer.js +4 -3
- package/examples/platformer/index.html +6 -6
- package/examples/platformer/tiles.png +0 -0
- package/examples/platformer/tilesLevel.png +0 -0
- package/examples/puzzle/game.js +10 -8
- package/examples/puzzle/index.html +2 -2
- package/examples/screenshot.jpg +0 -0
- package/examples/starter/build.js +2 -0
- package/examples/starter/game.js +32 -21
- 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.js +2 -0
- package/examples/typescript/game.js +4 -3
- package/examples/typescript/game.ts +4 -3
- package/examples/typescript/index.html +1 -1
- package/package.json +1 -1
- package/src/engine.js +59 -49
- package/src/engineAudio.js +67 -41
- package/src/engineBuild.js +23 -7
- package/src/engineDraw.js +139 -40
- package/src/engineExport.js +4 -191
- package/src/engineInput.js +22 -10
- package/src/engineMedals.js +13 -45
- package/src/engineObject.js +12 -13
- package/src/engineParticles.js +17 -17
- package/src/engineSettings.js +195 -2
- package/src/engineTileLayer.js +23 -22
- package/src/engineUtilities.js +6 -6
- package/src/engineWebGL.js +73 -74
package/src/engineAudio.js
CHANGED
|
@@ -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.
|
|
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
|
-
* @
|
|
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.
|
|
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(
|
|
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
|
|
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}
|
|
105
|
-
* @param {Number} [randomness
|
|
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(
|
|
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 (!
|
|
148
|
+
if (!soundDecoderContext)
|
|
116
149
|
soundDecoderContext = new AudioContext;
|
|
117
150
|
|
|
118
|
-
fetch(
|
|
151
|
+
fetch(filename)
|
|
119
152
|
.then(response => response.arrayBuffer())
|
|
120
|
-
.then(arrayBuffer =>
|
|
121
|
-
.then(audioBuffer =>
|
|
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
|
-
|
|
202
|
+
super();
|
|
164
203
|
|
|
165
|
-
|
|
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
|
|
171
|
-
* @return {AudioBufferSourceNode} - The audio node
|
|
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
|
|
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,
|
|
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
|
package/src/engineBuild.js
CHANGED
|
@@ -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
|
-
[],
|
|
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
|
-
[],
|
|
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=[],
|
|
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 (
|
|
105
|
-
|
|
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
|
-
|
|
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
|
-
/**
|
|
51
|
-
* @type {
|
|
50
|
+
/** Array containing texture info for batch rendering system
|
|
51
|
+
* @type {Array}
|
|
52
52
|
* @memberof Draw */
|
|
53
|
-
|
|
53
|
+
let textureInfos = [];
|
|
54
54
|
|
|
55
55
|
// Engine internal variables not exposed to documentation
|
|
56
|
-
let
|
|
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 {
|
|
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),
|
|
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
|
-
|
|
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
|
|
118
|
-
const
|
|
119
|
-
const
|
|
120
|
-
const
|
|
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
|
-
|
|
124
|
-
|
|
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 (
|
|
234
|
+
if (textureInfo)
|
|
134
235
|
{
|
|
135
|
-
//
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
//
|
|
142
|
-
|
|
143
|
-
|
|
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,
|
|
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
|
-
//
|
|
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
|
|
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),
|
|
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 =
|
|
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
|
+
}
|