littlejsengine 1.14.16 → 1.14.23
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/dist/littlejs.d.ts +173 -50
- package/dist/littlejs.esm.js +892 -419
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +879 -419
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +854 -420
- package/examples/box2d/game.js +3 -2
- package/examples/box2d/tiles.png +0 -0
- package/examples/breakout/game.js +5 -5
- package/examples/electron/game.js +1 -41
- package/examples/electron/index.html +2 -2
- package/examples/htmlMenu/game.js +1 -1
- package/examples/index.html +69 -55
- package/examples/module/game.js +6 -8
- package/examples/particles/index.html +6 -9
- package/examples/platformer/gameCharacter.js +1 -1
- package/examples/platformer/gameEffects.js +8 -3
- package/examples/platformer/gameObjects.js +3 -3
- package/examples/shorts/animation.js +2 -2
- package/examples/shorts/base.html +4 -1
- package/examples/shorts/cameraDrag.js +22 -0
- package/examples/shorts/debugDraw.js +38 -0
- package/examples/shorts/fps.js +90 -0
- package/examples/shorts/helloWorld.js +1 -1
- package/examples/shorts/hillGlideGame.js +1 -1
- package/examples/shorts/landerGame.js +1 -1
- package/examples/shorts/musicPlayer.js +1 -0
- package/examples/shorts/parallax.js +1 -1
- package/examples/shorts/postProcess.js +1 -1
- package/examples/shorts/sequencer.js +5 -5
- package/examples/shorts/shader.js +29 -0
- package/examples/shorts/spaceGame.js +1 -1
- package/examples/shorts/spriteAtlas.js +6 -6
- package/examples/shorts/starfield.js +1 -1
- package/examples/shorts/tileLayer.js +1 -1
- package/examples/shorts/tileRaycast.js +39 -0
- package/examples/shorts/tiles.png +0 -0
- package/examples/shorts/tiltedView.js +14 -6
- package/examples/shorts/topDown.js +1 -1
- package/examples/starter/game.js +6 -8
- package/examples/starter/index.html +2 -2
- package/examples/style.css +1 -0
- package/examples/typescript/game.js +5 -4
- package/examples/typescript/game.ts +5 -7
- package/examples/uiSystem/game.js +3 -2
- package/package.json +1 -1
- package/plugins/postProcess.js +71 -51
- package/plugins/uiSystem.js +76 -23
- package/src/engine.js +30 -16
- package/src/engineAudio.js +33 -23
- package/src/engineDebug.js +27 -0
- package/src/engineDraw.js +103 -49
- package/src/engineExport.js +13 -0
- package/src/engineInput.js +14 -16
- package/src/engineObject.js +31 -6
- package/src/engineParticles.js +37 -16
- package/src/engineRelease.js +2 -1
- package/src/engineSettings.js +20 -1
- package/src/engineTileLayer.js +89 -94
- package/src/engineUtilities.js +206 -58
- package/src/engineWebGL.js +145 -69
- package/examples/shorts/raycasting.js +0 -79
package/src/engineWebGL.js
CHANGED
|
@@ -29,7 +29,7 @@ let glContext;
|
|
|
29
29
|
let glAntialias = true;
|
|
30
30
|
|
|
31
31
|
// WebGL internal variables not exposed to documentation
|
|
32
|
-
let glShader, glPolyShader, glPolyMode, glAdditive, glBatchAdditive, glActiveTexture, glArrayBuffer, glGeometryBuffer, glPositionData, glColorData, glBatchCount;
|
|
32
|
+
let glShader, glPolyShader, glPolyMode, glAdditive, glBatchAdditive, glActiveTexture, glArrayBuffer, glGeometryBuffer, glPositionData, glColorData, glBatchCount, glTextureInfos, glCanBeEnabled = true;
|
|
33
33
|
|
|
34
34
|
// WebGL internal constants
|
|
35
35
|
const gl_ARRAY_BUFFER_SIZE = 5e5;
|
|
@@ -45,7 +45,14 @@ const gl_MAX_POLY_VERTEXES = gl_ARRAY_BUFFER_SIZE / gl_POLY_VERTEX_BYTE_STRIDE |
|
|
|
45
45
|
// Initialize WebGL, called automatically by the engine
|
|
46
46
|
function glInit()
|
|
47
47
|
{
|
|
48
|
-
if
|
|
48
|
+
// keep set of texture infos so they can be restored if context is lost
|
|
49
|
+
glTextureInfos = new Set;
|
|
50
|
+
|
|
51
|
+
if (!glEnable || headlessMode)
|
|
52
|
+
{
|
|
53
|
+
glCanBeEnabled = false;
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
49
56
|
|
|
50
57
|
// create the canvas and textures
|
|
51
58
|
glCanvas = document.createElement('canvas');
|
|
@@ -56,74 +63,108 @@ function glInit()
|
|
|
56
63
|
console.warn('WebGL2 not supported, falling back to 2D canvas rendering!');
|
|
57
64
|
glCanvas = glContext = undefined;
|
|
58
65
|
glEnable = false;
|
|
66
|
+
glCanBeEnabled = false;
|
|
59
67
|
return;
|
|
60
68
|
}
|
|
61
69
|
|
|
62
|
-
//
|
|
70
|
+
// attach the WebGL canvas
|
|
63
71
|
const rootElement = mainCanvas.parentElement;
|
|
64
72
|
rootElement.appendChild(glCanvas);
|
|
73
|
+
|
|
74
|
+
// startup webgl
|
|
75
|
+
initWebGL();
|
|
65
76
|
|
|
66
|
-
// setup
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
'
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
'
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
77
|
+
// setup context lost and restore handlers
|
|
78
|
+
glCanvas.addEventListener('webglcontextlost', (e)=>
|
|
79
|
+
{
|
|
80
|
+
glEnable = false; // disable WebGL rendering
|
|
81
|
+
glCanvas.style.display = 'none'; // hide the gl canvas
|
|
82
|
+
e.preventDefault(); // prevent default to allow restoration
|
|
83
|
+
LOG('WebGL context lost! Switching to Canvas2d rendering.');
|
|
84
|
+
|
|
85
|
+
// remove WebGL textures
|
|
86
|
+
for (const info of glTextureInfos)
|
|
87
|
+
info.glTexture = undefined;
|
|
88
|
+
glActiveTexture = undefined;
|
|
89
|
+
pluginList.forEach(plugin=>plugin.glContextLost?.());
|
|
90
|
+
});
|
|
91
|
+
glCanvas.addEventListener('webglcontextrestored', ()=>
|
|
92
|
+
{
|
|
93
|
+
glEnable = true; // re-enable WebGL rendering
|
|
94
|
+
glCanvas.style.display = ''; // show the gl canvas
|
|
95
|
+
LOG('WebGL context restored, reinitializing...');
|
|
96
|
+
|
|
97
|
+
// reinit WebGL and restore textures
|
|
98
|
+
initWebGL();
|
|
99
|
+
for (const info of glTextureInfos)
|
|
100
|
+
info.glTexture = glCreateTexture(info.image);
|
|
101
|
+
pluginList.forEach(plugin=>plugin.glContextRestored?.());
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
function initWebGL()
|
|
105
|
+
{
|
|
106
|
+
// setup instanced rendering shader program
|
|
107
|
+
glShader = glCreateProgram(
|
|
108
|
+
'#version 300 es\n' + // specify GLSL ES version
|
|
109
|
+
'precision highp float;'+ // use highp for better accuracy
|
|
110
|
+
'uniform mat4 m;'+ // transform matrix
|
|
111
|
+
'in vec2 g;'+ // in: geometry
|
|
112
|
+
'in vec4 p,u,c,a;'+ // in: position/size, uvs, color, additiveColor
|
|
113
|
+
'in float r;'+ // in: rotation
|
|
114
|
+
'out vec2 v;'+ // out: uv
|
|
115
|
+
'out vec4 d,e;'+ // out: color, additiveColor
|
|
116
|
+
'void main(){'+ // shader entry point
|
|
117
|
+
'vec2 s=(g-.5)*p.zw;'+ // get size offset
|
|
118
|
+
'gl_Position=m*vec4(p.xy+s*cos(r)-vec2(-s.y,s)*sin(r),1,1);'+ // transform position
|
|
119
|
+
'v=mix(u.xw,u.zy,g);'+ // pass uv to fragment shader
|
|
120
|
+
'd=c;e=a;'+ // pass colors to fragment shader
|
|
121
|
+
'}' // end of shader
|
|
122
|
+
,
|
|
123
|
+
'#version 300 es\n' + // specify GLSL ES version
|
|
124
|
+
'precision highp float;'+ // use highp for better accuracy
|
|
125
|
+
'uniform sampler2D s;'+ // texture
|
|
126
|
+
'in vec2 v;'+ // in: uv
|
|
127
|
+
'in vec4 d,e;'+ // in: color, additiveColor
|
|
128
|
+
'out vec4 c;'+ // out: color
|
|
129
|
+
'void main(){'+ // shader entry point
|
|
130
|
+
'c=texture(s,v)*d+e;'+ // modulate texture by color plus additive
|
|
131
|
+
'}' // end of shader
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
// setup poly rendering shaders
|
|
135
|
+
glPolyShader = glCreateProgram(
|
|
136
|
+
'#version 300 es\n' + // specify GLSL ES version
|
|
137
|
+
'precision highp float;'+ // use highp for better accuracy
|
|
138
|
+
'uniform mat4 m;'+ // transform matrix
|
|
139
|
+
'in vec2 p;'+ // in: position
|
|
140
|
+
'in vec4 c;'+ // in: color
|
|
141
|
+
'out vec4 d;'+ // out: color
|
|
142
|
+
'void main(){'+ // shader entry point
|
|
143
|
+
'gl_Position=m*vec4(p,1,1);'+ // transform position
|
|
144
|
+
'd=c;'+ // pass color to fragment shader
|
|
145
|
+
'}' // end of shader
|
|
146
|
+
,
|
|
147
|
+
'#version 300 es\n' + // specify GLSL ES version
|
|
148
|
+
'precision highp float;'+ // use highp for better accuracy
|
|
149
|
+
'in vec4 d;'+ // in: color
|
|
150
|
+
'out vec4 c;'+ // out: color
|
|
151
|
+
'void main(){'+ // shader entry point
|
|
152
|
+
'c=d;'+ // set color
|
|
153
|
+
'}' // end of shader
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
// init buffers
|
|
157
|
+
const glInstanceData = new ArrayBuffer(gl_ARRAY_BUFFER_SIZE);
|
|
158
|
+
glPositionData = new Float32Array(glInstanceData);
|
|
159
|
+
glColorData = new Uint32Array(glInstanceData);
|
|
160
|
+
glArrayBuffer = glContext.createBuffer();
|
|
161
|
+
glGeometryBuffer = glContext.createBuffer();
|
|
162
|
+
|
|
163
|
+
// create the geometry buffer, triangle strip square
|
|
164
|
+
const geometry = new Float32Array([glBatchCount=0,0,1,0,0,1,1,1]);
|
|
165
|
+
glContext.bindBuffer(glContext.ARRAY_BUFFER, glGeometryBuffer);
|
|
166
|
+
glContext.bufferData(glContext.ARRAY_BUFFER, geometry, glContext.STATIC_DRAW);
|
|
167
|
+
}
|
|
127
168
|
}
|
|
128
169
|
|
|
129
170
|
function glSetInstancedMode()
|
|
@@ -201,8 +242,8 @@ function glPreRender()
|
|
|
201
242
|
const s = vec2(2*cameraScale).divide(mainCanvasSize);
|
|
202
243
|
const rotatedCam = cameraPos.rotate(-cameraAngle);
|
|
203
244
|
const p = vec2(-1).subtract(rotatedCam.multiply(s));
|
|
204
|
-
const ca =
|
|
205
|
-
const sa =
|
|
245
|
+
const ca = cos(cameraAngle);
|
|
246
|
+
const sa = sin(cameraAngle);
|
|
206
247
|
const transform = [
|
|
207
248
|
s.x * ca, s.y * sa, 0, 0,
|
|
208
249
|
-s.x * sa, s.y * ca, 0, 0,
|
|
@@ -230,7 +271,7 @@ function glPreRender()
|
|
|
230
271
|
// start with additive blending off
|
|
231
272
|
glAdditive = glBatchAdditive = false;
|
|
232
273
|
|
|
233
|
-
// force it to
|
|
274
|
+
// force it to set instanced mode by first setting poly mode true
|
|
234
275
|
glPolyMode = true;
|
|
235
276
|
glSetInstancedMode();
|
|
236
277
|
}
|
|
@@ -371,6 +412,41 @@ function glSetTextureData(texture, image)
|
|
|
371
412
|
glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture); // rebind active texture
|
|
372
413
|
}
|
|
373
414
|
|
|
415
|
+
/** Tells WebGL to create or update the glTexture and start tracking it
|
|
416
|
+
* @param {TextureInfo} textureInfo
|
|
417
|
+
* @memberof WebGL */
|
|
418
|
+
function glRegisterTextureInfo(textureInfo)
|
|
419
|
+
{
|
|
420
|
+
if (headlessMode) return;
|
|
421
|
+
|
|
422
|
+
// add texture info to tracking list even if gl is not enabled
|
|
423
|
+
glTextureInfos.add(textureInfo);
|
|
424
|
+
|
|
425
|
+
if (!glContext) return;
|
|
426
|
+
|
|
427
|
+
// create or set the texture data
|
|
428
|
+
if (textureInfo.glTexture)
|
|
429
|
+
glSetTextureData(textureInfo.glTexture, textureInfo.image);
|
|
430
|
+
else
|
|
431
|
+
textureInfo.glTexture = glCreateTexture(textureInfo.image);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/** Tells WebGL to destroy the glTexture and stop tracking it
|
|
435
|
+
* @param {TextureInfo} textureInfo
|
|
436
|
+
* @memberof WebGL */
|
|
437
|
+
function glUnregisterTextureInfo(textureInfo)
|
|
438
|
+
{
|
|
439
|
+
if (headlessMode) return;
|
|
440
|
+
|
|
441
|
+
// delete texture info from tracking list even if gl is not enabled
|
|
442
|
+
glTextureInfos.delete(textureInfo);
|
|
443
|
+
|
|
444
|
+
// unset and destroy the texture
|
|
445
|
+
const glTexture = textureInfo.glTexture;
|
|
446
|
+
textureInfo.glTexture = undefined;
|
|
447
|
+
glDeleteTexture(glTexture);
|
|
448
|
+
}
|
|
449
|
+
|
|
374
450
|
/** Draw all sprites and clear out the buffer, called automatically by the system whenever necessary
|
|
375
451
|
* @memberof WebGL */
|
|
376
452
|
function glFlush()
|
|
@@ -472,8 +548,8 @@ function glDrawPointsTransform(points, rgba, x, y, sx, sy, angle, tristrip=true)
|
|
|
472
548
|
// transform the point
|
|
473
549
|
const px = p.x*sx;
|
|
474
550
|
const py = p.y*sy;
|
|
475
|
-
const sa =
|
|
476
|
-
const ca =
|
|
551
|
+
const sa = sin(-angle);
|
|
552
|
+
const ca = cos(-angle);
|
|
477
553
|
pointsOut.push(vec2(x + ca*px - sa*py, y + sa*px + ca*py));
|
|
478
554
|
}
|
|
479
555
|
const drawPoints = tristrip ? glPolyStrip(pointsOut) : pointsOut;
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
let playerPos = vec2(), playerAngle = 0;
|
|
2
|
-
|
|
3
|
-
// a simple function to generate a level
|
|
4
|
-
const levelTest = (X,Y)=> ((X|0)**3&(Y|0)**2)%30>5;
|
|
5
|
-
|
|
6
|
-
// cast a ray and return the distance to the first wall hit (0-1)
|
|
7
|
-
function raycast(pos, angle)
|
|
8
|
-
{
|
|
9
|
-
const maxDistance = 40, delta = .05;
|
|
10
|
-
const rayX = delta*Math.sin(angle);
|
|
11
|
-
const rayY = delta*Math.cos(angle);
|
|
12
|
-
let posX = pos.x, posY = pos.y;
|
|
13
|
-
for (let distance = 0; distance < maxDistance; distance += delta)
|
|
14
|
-
{
|
|
15
|
-
if (levelTest(posX, posY))
|
|
16
|
-
return distance/maxDistance;
|
|
17
|
-
posX += rayX;
|
|
18
|
-
posY += rayY;
|
|
19
|
-
}
|
|
20
|
-
return 1;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function gameUpdate()
|
|
24
|
-
{
|
|
25
|
-
// update camera angle with mouse pointer lock
|
|
26
|
-
if (mouseWasPressed(0))
|
|
27
|
-
pointerLockRequest();
|
|
28
|
-
if (keyWasPressed('Escape'))
|
|
29
|
-
pointerLockExit()
|
|
30
|
-
if (pointerLockIsActive() || isTouchDevice)
|
|
31
|
-
playerAngle += mouseDelta.x * .003;
|
|
32
|
-
|
|
33
|
-
// update player movement, prevent walking through walls
|
|
34
|
-
let velocity = keyDirection();
|
|
35
|
-
if (velocity.y && mouseIsDown(0))
|
|
36
|
-
velocity.y = 1; // forward movement with mouse
|
|
37
|
-
velocity = velocity.rotate(playerAngle).scale(.1);
|
|
38
|
-
const newPos = playerPos.add(velocity);
|
|
39
|
-
if (!levelTest(newPos.x, newPos.y))
|
|
40
|
-
playerPos = newPos;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function gameRender()
|
|
44
|
-
{
|
|
45
|
-
{
|
|
46
|
-
// draw horizontal slizes to create floor and ceiling
|
|
47
|
-
const h = 9;
|
|
48
|
-
let pos = vec2(), size = vec2(39, .15), color = rgb();
|
|
49
|
-
for (let y=-h; y<h; y+=.1)
|
|
50
|
-
{
|
|
51
|
-
const p = 1.01-abs(y/h)
|
|
52
|
-
pos.y = y;
|
|
53
|
-
color.setHSLA(.1, y>0?0:.5, .7-p*.7);
|
|
54
|
-
drawRect(pos, size, color);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
{
|
|
58
|
-
// draw vertical slices to create the walls
|
|
59
|
-
const w = 20;
|
|
60
|
-
const pos = vec2(), size = vec2(.15), color = rgb();
|
|
61
|
-
for (let x=-w; x<w; x+=.1)
|
|
62
|
-
{
|
|
63
|
-
const p = raycast(playerPos, playerAngle + x/w);
|
|
64
|
-
pos.x = x;
|
|
65
|
-
size.y = .4/p;
|
|
66
|
-
color.setHSLA(.6, .5, .7-p*.7);
|
|
67
|
-
drawRect(pos, size, color);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
// draw instructions and pointer lock status
|
|
71
|
-
const instructions = pointerLockIsActive() ?
|
|
72
|
-
'Mouse Control Active - ESC To Exit' :
|
|
73
|
-
'Click To Enable Mouse Control';
|
|
74
|
-
const textPos = vec2(mainCanvasSize.x/2, 50);
|
|
75
|
-
const textSize = 24;
|
|
76
|
-
const textColor = pointerLockIsActive() ? GREEN : WHITE;
|
|
77
|
-
if (!isTouchDevice)
|
|
78
|
-
drawTextScreen(instructions, textPos, textSize, textColor);
|
|
79
|
-
}
|