littlejsengine 1.17.11 → 1.17.15
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/AI.md +162 -0
- package/README.md +50 -63
- package/dist/littlejs.d.ts +150 -68
- package/dist/littlejs.esm.js +323 -105
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +320 -104
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +318 -101
- package/examples/electron/{build.js → build.mjs} +26 -23
- package/examples/electron/game.js +5 -50
- package/examples/electron/index.html +2 -2
- package/examples/index.html +1 -0
- package/examples/module/{build.js → build.mjs} +22 -19
- package/examples/shorts/base.html +1 -1
- package/examples/shorts/hillGlideGame.js +1 -1
- package/examples/shorts/nineSlice.js +3 -3
- package/examples/shorts/shapes.js +1 -1
- package/examples/shorts/uiSystem.js +17 -16
- package/examples/starter/build.bat +1 -1
- package/examples/starter/{build.js → build.mjs} +25 -22
- package/examples/starter/index.html +2 -2
- package/examples/typescript/build.mjs +60 -0
- package/examples/typescript/game.js +2 -2
- package/examples/typescript/tsconfig.json +11 -2
- package/package.json +2 -2
- package/plugins/pluginExport.js +1 -0
- package/plugins/uiSystem.js +143 -20
- package/reference.md +0 -1
- package/src/engine.js +16 -14
- package/src/engineAudio.js +9 -6
- package/src/{engineBuild.js → engineBuild.mjs} +95 -78
- package/src/engineDebug.js +8 -5
- package/src/engineDraw.js +16 -14
- package/src/engineExport.js +2 -1
- package/src/engineInput.js +29 -8
- package/src/engineMath.js +46 -14
- package/src/engineMedals.js +6 -3
- package/src/engineObject.js +14 -3
- package/src/engineParticles.js +8 -3
- package/src/engineRelease.js +6 -2
- package/src/engineTileLayer.js +8 -4
- package/src/engineUtilities.js +6 -2
- package/src/engineWebGL.js +11 -8
- package/src/jsconfig.json +2 -1
- package/examples/electron/build.bat +0 -7
- package/examples/module/build.bat +0 -7
- package/examples/typescript/build.bat +0 -5
- package/examples/typescript/build.js +0 -31
package/dist/littlejs.release.js
CHANGED
|
@@ -8,18 +8,20 @@
|
|
|
8
8
|
* MIT License - Copyright 2021 Frank Force
|
|
9
9
|
*
|
|
10
10
|
* Engine Features
|
|
11
|
-
* - Object oriented system with base class
|
|
12
|
-
* -
|
|
13
|
-
* - Engine helper classes
|
|
14
|
-
* -
|
|
15
|
-
* -
|
|
16
|
-
* - Input
|
|
17
|
-
* - Tile layer rendering and collision
|
|
18
|
-
* - Particle effect system
|
|
19
|
-
* - Medal system
|
|
20
|
-
* -
|
|
21
|
-
* -
|
|
22
|
-
* -
|
|
11
|
+
* - Object oriented system with EngineObject base class
|
|
12
|
+
* - Automatic object lifecycle (update, physics, collision, rendering)
|
|
13
|
+
* - Engine helper classes: Vector2, Color, Timer, RandomGenerator
|
|
14
|
+
* - Hybrid rendering with WebGL batching and Canvas2D fallback
|
|
15
|
+
* - Audio system with wave, mp3, or ZzFX sound effects
|
|
16
|
+
* - Input system with keyboard, mouse, gamepad, and touch support
|
|
17
|
+
* - Tile layer rendering and collision detection
|
|
18
|
+
* - Particle effect system with emitters
|
|
19
|
+
* - Medal/achievement system with local storage
|
|
20
|
+
* - Comprehensive debug tools and visualizations
|
|
21
|
+
* - Fixed 60 FPS timestep with configurable time scale
|
|
22
|
+
* - Raycast and spatial query utilities
|
|
23
|
+
* - Plugin system for extending engine functionality
|
|
24
|
+
* - Start with engineInit() and provide your game callbacks
|
|
23
25
|
* @namespace Engine
|
|
24
26
|
*/
|
|
25
27
|
|
|
@@ -33,7 +35,7 @@ const engineName = 'LittleJS';
|
|
|
33
35
|
* @type {string}
|
|
34
36
|
* @default
|
|
35
37
|
* @memberof Engine */
|
|
36
|
-
const engineVersion = '1.17.
|
|
38
|
+
const engineVersion = '1.17.15';
|
|
37
39
|
|
|
38
40
|
/** Frames per second to update
|
|
39
41
|
* @type {number}
|
|
@@ -607,7 +609,7 @@ function drawEngineLogo(t)
|
|
|
607
609
|
const color = (c,l)=> l?`hsl(${[.95,.56,.13][c%3]*360} 99%${[0,50,75][l]}%`:'#000';
|
|
608
610
|
|
|
609
611
|
// center and fit tos screen
|
|
610
|
-
const alpha =
|
|
612
|
+
const alpha = oscillate(1,1,t);
|
|
611
613
|
const p = percent(alpha, .1, .5);
|
|
612
614
|
const size = min(6, min(w,h)/99);
|
|
613
615
|
x.translate(w/2,h/2);
|
|
@@ -685,8 +687,12 @@ function drawEngineLogo(t)
|
|
|
685
687
|
}
|
|
686
688
|
/**
|
|
687
689
|
* LittleJS - Release Mode
|
|
688
|
-
* -
|
|
689
|
-
* -
|
|
690
|
+
* - Replaces engineDebug.js in production builds
|
|
691
|
+
* - All debug functions are stubbed out as no-ops
|
|
692
|
+
* - Removes ASSERT and LOG calls to reduce file size
|
|
693
|
+
* - Disables debug overlay, watermark, and visualizations
|
|
694
|
+
* - Improves performance by eliminating debug overhead
|
|
695
|
+
* - Significantly reduces final bundle size
|
|
690
696
|
*/
|
|
691
697
|
|
|
692
698
|
let debugWatermark = 0;
|
|
@@ -723,10 +729,17 @@ function debugVideoCaptureUpdate(){}
|
|
|
723
729
|
function debugProtectConstant(o){ return o; }
|
|
724
730
|
/**
|
|
725
731
|
* LittleJS Math Classes and Functions
|
|
726
|
-
* -
|
|
727
|
-
* -
|
|
728
|
-
* -
|
|
729
|
-
* -
|
|
732
|
+
* - Comprehensive math utilities for game development
|
|
733
|
+
* - Vector2 class for 2D positions, directions, and math operations
|
|
734
|
+
* - Color class for RGBA colors with interpolation and manipulation
|
|
735
|
+
* - RandomGenerator for seeded pseudo-random number generation
|
|
736
|
+
* - Math shortcuts (PI, abs, floor, ceil, min, max, sin, cos, etc.)
|
|
737
|
+
* - Interpolation functions (lerp, smoothStep, percent)
|
|
738
|
+
* - Clamping, wrapping, and modulo operations
|
|
739
|
+
* - Angle utilities with wrap-around support
|
|
740
|
+
* - Collision detection (overlapping, intersection, line tests)
|
|
741
|
+
* - Random number generation and seeding
|
|
742
|
+
* - Type checking utilities
|
|
730
743
|
* @namespace Math
|
|
731
744
|
*/
|
|
732
745
|
|
|
@@ -975,10 +988,24 @@ function isIntersecting(start, end, pos, size)
|
|
|
975
988
|
* @param {number} [amplitude] - Amplitude (max height) of the wave
|
|
976
989
|
* @param {number} [t=time] - Value to use for time of the wave
|
|
977
990
|
* @param {number} [offset] - Value to use for time offset of the wave
|
|
991
|
+
* @param {number} [type] - Wave type: 0=sine, 1=triangle, 2=square, 3=sawtooth
|
|
978
992
|
* @return {number} - Value waving between 0 and amplitude
|
|
979
993
|
* @memberof Math */
|
|
980
|
-
function
|
|
981
|
-
{
|
|
994
|
+
function oscillate(frequency=1, amplitude=1, t=time, offset=0, type=0)
|
|
995
|
+
{
|
|
996
|
+
const phase = (offset + t*frequency) % 1;
|
|
997
|
+
let value;
|
|
998
|
+
|
|
999
|
+
if (type === 1) // triangle
|
|
1000
|
+
value = 2 * abs(2 * phase - 1) - 1;
|
|
1001
|
+
else if (type === 2) // square
|
|
1002
|
+
value = phase < .5 ? -1 : 1;
|
|
1003
|
+
else if (type === 3) // sawtooth
|
|
1004
|
+
value = 2 * phase - 1;
|
|
1005
|
+
else // sine
|
|
1006
|
+
value = -cos(phase * 2*PI);
|
|
1007
|
+
return amplitude/2 * (value + 1);
|
|
1008
|
+
}
|
|
982
1009
|
|
|
983
1010
|
/**
|
|
984
1011
|
* Check if object is a valid number, not NaN or undefined, but it may be infinite
|
|
@@ -1060,15 +1087,17 @@ function lineTest(posStart, posEnd, testFunction, normal)
|
|
|
1060
1087
|
// set hit point
|
|
1061
1088
|
const hitPos = vec2(posStart.x + dirX*t, posStart.y + dirY*t);
|
|
1062
1089
|
|
|
1063
|
-
//
|
|
1090
|
+
// ensure result is inside the tile
|
|
1064
1091
|
const e = 1e-9;
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
hitPos.y
|
|
1092
|
+
const hitPosFloor = hitPos.floor();
|
|
1093
|
+
if (hitPosFloor.x < pos.x)
|
|
1094
|
+
hitPos.x = pos.x;
|
|
1095
|
+
else if (hitPosFloor.x > pos.x)
|
|
1096
|
+
hitPos.x = pos.x + 1 - e;
|
|
1097
|
+
if (hitPosFloor.y < pos.y)
|
|
1098
|
+
hitPos.y = pos.y;
|
|
1099
|
+
else if (hitPosFloor.y > pos.y)
|
|
1100
|
+
hitPos.y = pos.y + 1 - e;
|
|
1072
1101
|
|
|
1073
1102
|
// set normal
|
|
1074
1103
|
if (normal)
|
|
@@ -1461,6 +1490,15 @@ class Vector2
|
|
|
1461
1490
|
* @return {Vector2} */
|
|
1462
1491
|
floor() { return new Vector2(floor(this.x), floor(this.y)); }
|
|
1463
1492
|
|
|
1493
|
+
/** Returns a copy of this vector snapped to a grid
|
|
1494
|
+
* @param {number} grid - grid size to snap to
|
|
1495
|
+
* @return {Vector2} */
|
|
1496
|
+
snap(grid)
|
|
1497
|
+
{
|
|
1498
|
+
ASSERT_NUMBER_VALID(grid);
|
|
1499
|
+
return new Vector2(floor(this.x*grid)/grid, floor(this.y*grid)/grid);
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1464
1502
|
/** Returns new vec2 with modded values
|
|
1465
1503
|
* @param {number} [divisor]
|
|
1466
1504
|
* @return {Vector2} */
|
|
@@ -1835,8 +1873,12 @@ const PURPLE = debugProtectConstant(rgb(.5,0,1));
|
|
|
1835
1873
|
const MAGENTA = debugProtectConstant(rgb(1,0,1));
|
|
1836
1874
|
/**
|
|
1837
1875
|
* LittleJS Utility Classes and Functions
|
|
1838
|
-
* -
|
|
1839
|
-
* -
|
|
1876
|
+
* - Timer - tracks time automatically with support for pause and real-time modes
|
|
1877
|
+
* - Time formatting helper
|
|
1878
|
+
* - JSON file fetching
|
|
1879
|
+
* - File saving (text, canvas, data URLs)
|
|
1880
|
+
* - Native share dialog support
|
|
1881
|
+
* - Local storage save data management
|
|
1840
1882
|
* @namespace Utilities
|
|
1841
1883
|
*/
|
|
1842
1884
|
|
|
@@ -2629,6 +2671,13 @@ function setDebugWatermark(show) { debugWatermark = show; }
|
|
|
2629
2671
|
function setDebugKey(key) { debugKey = key; }
|
|
2630
2672
|
/**
|
|
2631
2673
|
* LittleJS Object System
|
|
2674
|
+
* - EngineObject is the base class for all game objects
|
|
2675
|
+
* - Handles automatic updating, rendering, physics, and collision
|
|
2676
|
+
* - Supports parent-child hierarchies with transform inheritance
|
|
2677
|
+
* - 2D physics with velocity, acceleration, damping, and gravity
|
|
2678
|
+
* - Collision system with tiles and other objects
|
|
2679
|
+
* - Renders sprites from tile sheets with color and rotation
|
|
2680
|
+
* - Objects sorted by renderOrder for layered rendering
|
|
2632
2681
|
*/
|
|
2633
2682
|
|
|
2634
2683
|
/**
|
|
@@ -3141,33 +3190,38 @@ class EngineObject
|
|
|
3141
3190
|
{
|
|
3142
3191
|
if (!debug) return;
|
|
3143
3192
|
|
|
3193
|
+
// check if there is anything to show
|
|
3194
|
+
const hasPhysics = this.collideTiles || this.collideSolidObjects || this.isSolid;
|
|
3195
|
+
if (!hasPhysics && !this.parent) return;
|
|
3196
|
+
|
|
3144
3197
|
// show object info for debugging
|
|
3145
3198
|
const size = vec2(max(this.size.x, .2), max(this.size.y, .2));
|
|
3146
3199
|
const color = rgb(this.collideTiles?1:0, this.collideSolidObjects?1:0, this.isSolid?1:0, .5);
|
|
3147
|
-
|
|
3200
|
+
debugRect(this.pos, size, color, 0, this.angle, hasPhysics);
|
|
3148
3201
|
if (this.parent)
|
|
3149
|
-
|
|
3150
|
-
this.parent &&
|
|
3202
|
+
debugRect(this.pos, size.scale(.8), rgb(1,1,1,.5), 0, this.angle);
|
|
3203
|
+
this.parent && debugLine(this.pos, this.parent.pos, rgb(1,1,1,.5), .5);
|
|
3151
3204
|
}
|
|
3152
3205
|
}
|
|
3153
3206
|
/**
|
|
3154
3207
|
* LittleJS Drawing System
|
|
3155
|
-
* - Hybrid
|
|
3156
|
-
* -
|
|
3157
|
-
* -
|
|
3158
|
-
* -
|
|
3159
|
-
* -
|
|
3208
|
+
* - Hybrid rendering with both Canvas2D and WebGL support
|
|
3209
|
+
* - Optimized tile sheet sprite rendering using WebGL batching
|
|
3210
|
+
* - Primitive drawing for polygons, ellipses, and lines
|
|
3211
|
+
* - Tile-based rendering with TileInfo and TextureInfo classes
|
|
3212
|
+
* - Text rendering with custom fonts and FontImage support
|
|
3213
|
+
* - Color and additive color blending for effects
|
|
3214
|
+
* - Rotation, mirroring, and scaling transformations
|
|
3215
|
+
* - Camera system with position, scale, and rotation
|
|
3216
|
+
* - Multiple canvas support (main, WebGL, work canvases)
|
|
3217
|
+
* - Gradient fills and outlined shapes
|
|
3218
|
+
* - Image manipulation and color tinting
|
|
3160
3219
|
*
|
|
3161
|
-
*
|
|
3162
|
-
*
|
|
3163
|
-
* mainCanvas
|
|
3164
|
-
*
|
|
3220
|
+
* Rendering Architecture:
|
|
3221
|
+
* - glCanvas: WebGL canvas for accelerated sprite batch rendering
|
|
3222
|
+
* - mainCanvas: Canvas2D overlay for text, UI, and custom drawing
|
|
3223
|
+
* - All draw functions default to WebGL when enabled, can force Canvas2D with useWebGL parameter
|
|
3165
3224
|
*
|
|
3166
|
-
* The WebGL rendering system is very fast with some caveats...
|
|
3167
|
-
* - Switching blend modes (additive) or textures causes another draw call which is expensive in excess
|
|
3168
|
-
* - Group additive rendering together using renderOrder to mitigate this issue
|
|
3169
|
-
*
|
|
3170
|
-
* The LittleJS rendering solution is intentionally simple, feel free to adjust it for your needs!
|
|
3171
3225
|
* @namespace Draw
|
|
3172
3226
|
*/
|
|
3173
3227
|
|
|
@@ -3258,6 +3312,7 @@ function tile(index=new Vector2, size=tileDefaultSize, texture=0, padding=tileDe
|
|
|
3258
3312
|
// create tile info object
|
|
3259
3313
|
const textureInfo = typeof texture === 'number' ?
|
|
3260
3314
|
textureInfos[texture] : texture;
|
|
3315
|
+
ASSERT(textureInfo instanceof TextureInfo, 'tile texture is not loaded');
|
|
3261
3316
|
|
|
3262
3317
|
// get the position of the tile
|
|
3263
3318
|
const sizePaddedX = size.x + padding*2;
|
|
@@ -4301,11 +4356,14 @@ async function fontImageInit()
|
|
|
4301
4356
|
}
|
|
4302
4357
|
/**
|
|
4303
4358
|
* LittleJS Input System
|
|
4304
|
-
* -
|
|
4305
|
-
* -
|
|
4306
|
-
* -
|
|
4307
|
-
* - Touch input
|
|
4308
|
-
* - Virtual gamepad for
|
|
4359
|
+
* - Keyboard input with key down, pressed, and released states
|
|
4360
|
+
* - Mouse input with position (world and screen space), buttons, and wheel
|
|
4361
|
+
* - Gamepad support for multiple controllers with analog sticks and buttons
|
|
4362
|
+
* - Touch input mapped to mouse position and buttons
|
|
4363
|
+
* - Virtual on-screen gamepad for mobile devices
|
|
4364
|
+
* - Automatic gamepad vs keyboard/mouse detection
|
|
4365
|
+
* - Input event prevention for canvas focus
|
|
4366
|
+
* - Clipboard copy/paste support
|
|
4309
4367
|
* @namespace Input
|
|
4310
4368
|
*/
|
|
4311
4369
|
|
|
@@ -4635,7 +4693,19 @@ function inputInit()
|
|
|
4635
4693
|
inputData[0][remapKey(e.code)] = 3;
|
|
4636
4694
|
}
|
|
4637
4695
|
|
|
4638
|
-
// prevent
|
|
4696
|
+
// try to prevent default browser handling of input
|
|
4697
|
+
if (!inputPreventDefault || !document.hasFocus() || !e.cancelable) return;
|
|
4698
|
+
|
|
4699
|
+
// don't break browser shortcuts
|
|
4700
|
+
if (e.ctrlKey || e.metaKey || e.altKey) return;
|
|
4701
|
+
|
|
4702
|
+
// don't interfere with user typing into UI fields
|
|
4703
|
+
if (isTextInput(e.target) || isTextInput(document.activeElement)) return;
|
|
4704
|
+
|
|
4705
|
+
// fix browser setting "Search for text when you start typing"
|
|
4706
|
+
const printable = typeof e.key === 'string' && e.key.length === 1;
|
|
4707
|
+
|
|
4708
|
+
// prevent arrow key and other default keys from messing with stuff
|
|
4639
4709
|
const preventDefaultKeys =
|
|
4640
4710
|
[
|
|
4641
4711
|
'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', // scrolling
|
|
@@ -4643,9 +4713,15 @@ function inputInit()
|
|
|
4643
4713
|
'Tab', // focus navigation
|
|
4644
4714
|
'Backspace', // browser back
|
|
4645
4715
|
];
|
|
4646
|
-
if (preventDefaultKeys.includes(e.code))
|
|
4647
|
-
if (inputPreventDefault && document.hasFocus() && e.cancelable)
|
|
4716
|
+
if (preventDefaultKeys.includes(e.code) || printable)
|
|
4648
4717
|
e.preventDefault();
|
|
4718
|
+
|
|
4719
|
+
function isTextInput(element)
|
|
4720
|
+
{
|
|
4721
|
+
const tag = element?.tagName;
|
|
4722
|
+
const editable = element?.isContentEditable;
|
|
4723
|
+
return editable || ['INPUT','TEXTAREA','SELECT'].includes(tag);
|
|
4724
|
+
}
|
|
4649
4725
|
}
|
|
4650
4726
|
function onKeyUp(e)
|
|
4651
4727
|
{
|
|
@@ -5078,12 +5154,15 @@ function touchGamepadButtonCenter()
|
|
|
5078
5154
|
}
|
|
5079
5155
|
/**
|
|
5080
5156
|
* LittleJS Audio System
|
|
5081
|
-
* -
|
|
5082
|
-
* - <a href=https://
|
|
5083
|
-
* -
|
|
5084
|
-
* -
|
|
5085
|
-
* -
|
|
5086
|
-
* -
|
|
5157
|
+
* - Play audio files (mp3, ogg, wave) and generate sounds with ZzFX
|
|
5158
|
+
* - ZzFX sound generator integration: <a href=https://killedbyapixel.github.io/ZzFX/>ZzFX</a>
|
|
5159
|
+
* - Sound caching for fast playback and memory efficiency
|
|
5160
|
+
* - Volume control with attenuation and stereo panning
|
|
5161
|
+
* - 2D spatial audio based on camera position with distance-based falloff
|
|
5162
|
+
* - Sound instance management (pause, resume, stop)
|
|
5163
|
+
* - Speech synthesis for text-to-speech
|
|
5164
|
+
* - Music playback with ZzFXM support
|
|
5165
|
+
* - Web Audio API integration with master gain control
|
|
5087
5166
|
* @namespace Audio
|
|
5088
5167
|
*/
|
|
5089
5168
|
|
|
@@ -5752,10 +5831,14 @@ function zzfxG
|
|
|
5752
5831
|
}
|
|
5753
5832
|
/**
|
|
5754
5833
|
* LittleJS Tile Layer System
|
|
5755
|
-
* -
|
|
5756
|
-
* - Unlimited
|
|
5757
|
-
* -
|
|
5758
|
-
* -
|
|
5834
|
+
* - Renders large tile-based levels efficiently using cached canvases
|
|
5835
|
+
* - Unlimited tile layers with automatic canvas allocation
|
|
5836
|
+
* - Layers support both rendering and collision detection
|
|
5837
|
+
* - Direct canvas2d drawing access for custom tile rendering
|
|
5838
|
+
* - TileLayer for rendering, TileCollisionLayer for physics
|
|
5839
|
+
* - Collision callbacks for tile interactions with objects
|
|
5840
|
+
* - Optimized raycast support for tile-based physics
|
|
5841
|
+
* - Integration with Box2D physics via Box2DTileLayer plugin
|
|
5759
5842
|
* @namespace TileLayers
|
|
5760
5843
|
*/
|
|
5761
5844
|
|
|
@@ -6460,9 +6543,14 @@ class TileCollisionLayer extends TileLayer
|
|
|
6460
6543
|
}
|
|
6461
6544
|
/**
|
|
6462
6545
|
* LittleJS Particle System
|
|
6463
|
-
* -
|
|
6464
|
-
* -
|
|
6465
|
-
* -
|
|
6546
|
+
* - Fast and flexible particle effects system
|
|
6547
|
+
* - ParticleEmitter spawns and manages lightweight Particle objects
|
|
6548
|
+
* - Particles support color gradients, fading, rotation, and scaling
|
|
6549
|
+
* - Physics simulation with velocity, gravity, and damping
|
|
6550
|
+
* - Collision detection with tile layers
|
|
6551
|
+
* - Additive blending for glowing effects
|
|
6552
|
+
* - Cone-based emission with randomization
|
|
6553
|
+
* - Particle design tool available for easy emitter creation
|
|
6466
6554
|
* @namespace Particles
|
|
6467
6555
|
*/
|
|
6468
6556
|
|
|
@@ -6981,9 +7069,12 @@ class Particle
|
|
|
6981
7069
|
}
|
|
6982
7070
|
/**
|
|
6983
7071
|
* LittleJS Medal System
|
|
6984
|
-
* -
|
|
6985
|
-
* -
|
|
6986
|
-
* -
|
|
7072
|
+
* - Achievement/trophy system for games
|
|
7073
|
+
* - Medal class with name, description, icon, and unlock tracking
|
|
7074
|
+
* - Automatic saving to local storage
|
|
7075
|
+
* - Visual display queue with slide-in notifications
|
|
7076
|
+
* - Newgrounds API integration for online achievements
|
|
7077
|
+
* - Debug mode to unlock/reset medals during development
|
|
6987
7078
|
* @namespace Medals
|
|
6988
7079
|
*/
|
|
6989
7080
|
|
|
@@ -7172,14 +7263,17 @@ class Medal
|
|
|
7172
7263
|
}
|
|
7173
7264
|
/**
|
|
7174
7265
|
* LittleJS WebGL Interface
|
|
7175
|
-
* -
|
|
7176
|
-
* -
|
|
7177
|
-
* -
|
|
7178
|
-
* -
|
|
7179
|
-
* -
|
|
7180
|
-
* -
|
|
7181
|
-
* -
|
|
7182
|
-
* -
|
|
7266
|
+
* - WebGL2 rendering engine for high-performance graphics
|
|
7267
|
+
* - Batched sprite rendering for drawing thousands of sprites efficiently
|
|
7268
|
+
* - Instanced rendering using vertex array objects (VAOs)
|
|
7269
|
+
* - Polygon rendering with triangle strip support
|
|
7270
|
+
* - Shader system with custom vertex and fragment shaders
|
|
7271
|
+
* - Texture management with automatic atlas support
|
|
7272
|
+
* - Post-processing effects via framebuffer and shader plugins
|
|
7273
|
+
* - Automatic fallback to Canvas2D if WebGL is unavailable
|
|
7274
|
+
* - Context loss and restoration handling
|
|
7275
|
+
* - Can be disabled with glEnable setting
|
|
7276
|
+
* - Advanced users can create custom shaders and render targets
|
|
7183
7277
|
* @namespace WebGL
|
|
7184
7278
|
*/
|
|
7185
7279
|
|
|
@@ -8670,9 +8764,16 @@ class UISystemPlugin
|
|
|
8670
8764
|
this.lastHoverObject = undefined;
|
|
8671
8765
|
/** @property {UIObject} - Current confirm menu being shown */
|
|
8672
8766
|
this.confirmDialog = undefined;
|
|
8767
|
+
/** @property {UIObject} - Object to send keyboard input to */
|
|
8768
|
+
this.keyInputObject = undefined;
|
|
8673
8769
|
|
|
8674
8770
|
engineAddPlugin(uiUpdate, uiRender);
|
|
8675
8771
|
|
|
8772
|
+
// key down handler
|
|
8773
|
+
function onKeyDown(e)
|
|
8774
|
+
{ uiSystem.keyInputObject?.onKeyDown(e); }
|
|
8775
|
+
document.addEventListener('keydown', onKeyDown);
|
|
8776
|
+
|
|
8676
8777
|
// set object position in parent space
|
|
8677
8778
|
function updateTransforms(o)
|
|
8678
8779
|
{
|
|
@@ -8691,9 +8792,18 @@ class UISystemPlugin
|
|
|
8691
8792
|
// reset hover object at start of update
|
|
8692
8793
|
uiSystem.lastHoverObject = uiSystem.hoverObject;
|
|
8693
8794
|
uiSystem.hoverObject = undefined;
|
|
8694
|
-
|
|
8795
|
+
|
|
8695
8796
|
if (mouseWasPressed(0))
|
|
8696
8797
|
{
|
|
8798
|
+
// exit navigation mode on mouse press
|
|
8799
|
+
uiSystem.navigationMode = false;
|
|
8800
|
+
uiSystem.navigationObject = undefined;
|
|
8801
|
+
}
|
|
8802
|
+
if (uiSystem.keyInputObject)
|
|
8803
|
+
{
|
|
8804
|
+
// handle text input
|
|
8805
|
+
uiSystem.activeObject = uiSystem.keyInputObject;
|
|
8806
|
+
uiSystem.hoverObject = uiSystem.keyInputObject;
|
|
8697
8807
|
uiSystem.navigationMode = false;
|
|
8698
8808
|
uiSystem.navigationObject = undefined;
|
|
8699
8809
|
}
|
|
@@ -8702,7 +8812,7 @@ class UISystemPlugin
|
|
|
8702
8812
|
const navigableObjects = uiSystem.getNavigableObjects();
|
|
8703
8813
|
if (!navigableObjects.length)
|
|
8704
8814
|
uiSystem.navigationObject = undefined;
|
|
8705
|
-
else
|
|
8815
|
+
else if (!uiSystem.keyInputObject)
|
|
8706
8816
|
{
|
|
8707
8817
|
// unselect object if it is no longer navigable
|
|
8708
8818
|
if (!navigableObjects.includes(uiSystem.navigationObject))
|
|
@@ -9015,6 +9125,7 @@ class UISystemPlugin
|
|
|
9015
9125
|
this.activeObject = undefined;
|
|
9016
9126
|
this.hoverObject = undefined;
|
|
9017
9127
|
this.lastHoverObject = undefined;
|
|
9128
|
+
this.keyInputObject = undefined;
|
|
9018
9129
|
}
|
|
9019
9130
|
|
|
9020
9131
|
/** Get all navigable UI objects sorted by navigationIndex
|
|
@@ -9295,7 +9406,7 @@ class UIObject
|
|
|
9295
9406
|
}
|
|
9296
9407
|
}
|
|
9297
9408
|
|
|
9298
|
-
/** Check if the mouse is overlapping
|
|
9409
|
+
/** Check if the mouse is overlapping this ui object
|
|
9299
9410
|
* @return {boolean} - True if overlapping */
|
|
9300
9411
|
isMouseOverlapping()
|
|
9301
9412
|
{
|
|
@@ -9314,8 +9425,16 @@ class UIObject
|
|
|
9314
9425
|
this.onUpdate();
|
|
9315
9426
|
|
|
9316
9427
|
// unset active if disabled
|
|
9317
|
-
if (this.disabled
|
|
9318
|
-
|
|
9428
|
+
if (this.disabled)
|
|
9429
|
+
{
|
|
9430
|
+
if (this === uiSystem.activeObject)
|
|
9431
|
+
uiSystem.activeObject = undefined;
|
|
9432
|
+
if (this === uiSystem.keyInputObject)
|
|
9433
|
+
uiSystem.keyInputObject = undefined;
|
|
9434
|
+
}
|
|
9435
|
+
|
|
9436
|
+
if (uiSystem.keyInputObject)
|
|
9437
|
+
return;
|
|
9319
9438
|
|
|
9320
9439
|
const wasHover = uiSystem.lastHoverObject === this;
|
|
9321
9440
|
const isActive = this.isActiveObject();
|
|
@@ -9342,19 +9461,12 @@ class UIObject
|
|
|
9342
9461
|
uiSystem.activeObject = this;
|
|
9343
9462
|
|
|
9344
9463
|
if (uiSystem.activateOnPress)
|
|
9345
|
-
|
|
9346
|
-
this.onClick();
|
|
9347
|
-
if (!this.soundPress && this.soundClick)
|
|
9348
|
-
this.soundClick.play();
|
|
9349
|
-
}
|
|
9464
|
+
this.click(!this.soundPress);
|
|
9350
9465
|
}
|
|
9351
9466
|
}
|
|
9352
9467
|
if (!uiSystem.activateOnPress)
|
|
9353
9468
|
if (!mouseDown && this.isActiveObject() && this.interactive)
|
|
9354
|
-
|
|
9355
|
-
this.onClick();
|
|
9356
|
-
this.soundClick && this.soundClick.play();
|
|
9357
|
-
}
|
|
9469
|
+
this.click();
|
|
9358
9470
|
}
|
|
9359
9471
|
|
|
9360
9472
|
// clear mouse was pressed state even when disabled
|
|
@@ -9406,11 +9518,7 @@ class UIObject
|
|
|
9406
9518
|
}
|
|
9407
9519
|
|
|
9408
9520
|
/** Called when the navigation button is pressed on this object */
|
|
9409
|
-
navigatePressed()
|
|
9410
|
-
{
|
|
9411
|
-
this.onClick();
|
|
9412
|
-
this.soundClick && this.soundClick.play();
|
|
9413
|
-
}
|
|
9521
|
+
navigatePressed() { this.click(); }
|
|
9414
9522
|
|
|
9415
9523
|
/** @return {boolean} - Is the mouse hovering over this element */
|
|
9416
9524
|
isHoverObject() { return uiSystem.hoverObject === this; }
|
|
@@ -9421,6 +9529,9 @@ class UIObject
|
|
|
9421
9529
|
/** @return {boolean} - Is the gamepad or keyboard navigation object */
|
|
9422
9530
|
isNavigationObject() { return uiSystem.navigationObject === this; }
|
|
9423
9531
|
|
|
9532
|
+
/** @return {boolean} - Is this object in keyboard input mode */
|
|
9533
|
+
isKeyInputObject() { return uiSystem.keyInputObject === this; }
|
|
9534
|
+
|
|
9424
9535
|
/** @return {boolean} - Can it be interacted with */
|
|
9425
9536
|
isInteractive() { return this.interactive && this.visible && !this.disabled;}
|
|
9426
9537
|
|
|
@@ -9457,6 +9568,15 @@ class UIObject
|
|
|
9457
9568
|
uiSystem.drawRect(this.pos, this.size, CLEAR_BLACK, 4, color);
|
|
9458
9569
|
}
|
|
9459
9570
|
|
|
9571
|
+
/** Internal function called when object is clicked
|
|
9572
|
+
* @param {boolean} [playSound] */
|
|
9573
|
+
click(playSound)
|
|
9574
|
+
{
|
|
9575
|
+
this.onClick();
|
|
9576
|
+
if (playSound && this.soundClick)
|
|
9577
|
+
this.soundClick.play();
|
|
9578
|
+
}
|
|
9579
|
+
|
|
9460
9580
|
/** Called each frame before object updates */
|
|
9461
9581
|
onUpdate() {}
|
|
9462
9582
|
|
|
@@ -9532,6 +9652,102 @@ class UIText extends UIObject
|
|
|
9532
9652
|
}
|
|
9533
9653
|
}
|
|
9534
9654
|
|
|
9655
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
9656
|
+
/**
|
|
9657
|
+
* UITextInput - An editable text input field
|
|
9658
|
+
* - A simple text entry field that supports basic editing
|
|
9659
|
+
* - Suitable for short text input like names or numbers
|
|
9660
|
+
* @extends UIObject
|
|
9661
|
+
* @memberof UISystem
|
|
9662
|
+
*/
|
|
9663
|
+
class UITextInput extends UIObject
|
|
9664
|
+
{
|
|
9665
|
+
/** Create a UITextInput object
|
|
9666
|
+
* @param {Vector2} [pos]
|
|
9667
|
+
* @param {Vector2} [size]
|
|
9668
|
+
* @param {string} [text]
|
|
9669
|
+
*/
|
|
9670
|
+
constructor(pos, size, text='')
|
|
9671
|
+
{
|
|
9672
|
+
super(pos, size);
|
|
9673
|
+
|
|
9674
|
+
ASSERT(isString(text), 'ui text must be a string');
|
|
9675
|
+
|
|
9676
|
+
/** @property {number} - Max length of input (0 = no limit) */
|
|
9677
|
+
this.maxLength = 0;
|
|
9678
|
+
|
|
9679
|
+
// set properties
|
|
9680
|
+
this.text = text;
|
|
9681
|
+
this.interactive = true;
|
|
9682
|
+
this.canBeHover = true;
|
|
9683
|
+
}
|
|
9684
|
+
|
|
9685
|
+
click()
|
|
9686
|
+
{
|
|
9687
|
+
// start editing the text
|
|
9688
|
+
uiSystem.keyInputObject = this;
|
|
9689
|
+
this.onClick();
|
|
9690
|
+
}
|
|
9691
|
+
|
|
9692
|
+
/** Stop editing the text edited */
|
|
9693
|
+
stopEditing()
|
|
9694
|
+
{
|
|
9695
|
+
if (!this.isKeyInputObject())
|
|
9696
|
+
return;
|
|
9697
|
+
|
|
9698
|
+
if (this.soundRelease)
|
|
9699
|
+
this.soundRelease.play();
|
|
9700
|
+
uiSystem.activeObject = undefined;
|
|
9701
|
+
uiSystem.keyInputObject = undefined;
|
|
9702
|
+
this.onChange();
|
|
9703
|
+
}
|
|
9704
|
+
|
|
9705
|
+
/** Key down event handler if this object is being edited
|
|
9706
|
+
* @param {KeyboardEvent} [e] */
|
|
9707
|
+
onKeyDown(e)
|
|
9708
|
+
{
|
|
9709
|
+
const code = e.code, key = e.key
|
|
9710
|
+
if (code === 'Backspace')
|
|
9711
|
+
this.text = this.text.slice(0, -1);
|
|
9712
|
+
else if (code === 'Enter' || code === 'Escape')
|
|
9713
|
+
this.stopEditing();
|
|
9714
|
+
else if (key.length === 1) // printable characters
|
|
9715
|
+
{
|
|
9716
|
+
if (!this.maxLength || this.text.length < this.maxLength)
|
|
9717
|
+
this.text += key;
|
|
9718
|
+
}
|
|
9719
|
+
}
|
|
9720
|
+
|
|
9721
|
+
update()
|
|
9722
|
+
{
|
|
9723
|
+
super.update();
|
|
9724
|
+
|
|
9725
|
+
if (!this.isKeyInputObject())
|
|
9726
|
+
return;
|
|
9727
|
+
|
|
9728
|
+
// click off object to stop editing
|
|
9729
|
+
if (mouseWasPressed(0) && !this.isMouseOverlapping() ||
|
|
9730
|
+
gamepadWasPressed(0, gamepadPrimary))
|
|
9731
|
+
{
|
|
9732
|
+
this.stopEditing();
|
|
9733
|
+
inputClearKey(0,0);
|
|
9734
|
+
}
|
|
9735
|
+
}
|
|
9736
|
+
|
|
9737
|
+
render()
|
|
9738
|
+
{
|
|
9739
|
+
super.render();
|
|
9740
|
+
|
|
9741
|
+
// draw the text scaled to fit
|
|
9742
|
+
const textSize = this.getTextSize();
|
|
9743
|
+
let text = this.text;
|
|
9744
|
+
if (this.isKeyInputObject()) // add a cursor to end of text
|
|
9745
|
+
text += timeReal%1 < .5 ? '█' : '░';
|
|
9746
|
+
uiSystem.drawText(text, this.pos, textSize,
|
|
9747
|
+
this.textColor, this.textLineWidth, this.textLineColor, this.align, this.font, this.fontStyle, true, this.textShadow);
|
|
9748
|
+
}
|
|
9749
|
+
}
|
|
9750
|
+
|
|
9535
9751
|
///////////////////////////////////////////////////////////////////////////////
|
|
9536
9752
|
/**
|
|
9537
9753
|
* UITile - A UI object that displays a tile image
|
|
@@ -9643,9 +9859,10 @@ class UICheckbox extends UIObject
|
|
|
9643
9859
|
this.color = color.copy();
|
|
9644
9860
|
this.interactive = true;
|
|
9645
9861
|
}
|
|
9646
|
-
|
|
9862
|
+
click()
|
|
9647
9863
|
{
|
|
9648
9864
|
this.checked = !this.checked;
|
|
9865
|
+
this.onClick();
|
|
9649
9866
|
this.onChange();
|
|
9650
9867
|
}
|
|
9651
9868
|
render()
|