littlejsengine 1.9.2 → 1.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +4 -2
  2. package/dist/littlejs.d.ts +31 -26
  3. package/dist/littlejs.esm.js +145 -122
  4. package/dist/littlejs.esm.min.js +1 -1
  5. package/dist/littlejs.js +145 -122
  6. package/dist/littlejs.min.js +1 -1
  7. package/dist/littlejs.release.js +140 -121
  8. package/examples/logo.png +0 -0
  9. package/examples/module/game.js +1 -1
  10. package/examples/platformer/data/{gameTileData.tmx → gameLevelData.tmx} +3 -3
  11. package/examples/platformer/game.js +31 -10
  12. package/examples/platformer/gameCharacter.js +7 -6
  13. package/examples/platformer/gameEffects.js +77 -68
  14. package/examples/platformer/gameLevel.js +33 -17
  15. package/examples/platformer/{gameTileData.js → gameLevelData.js} +3 -3
  16. package/examples/platformer/gameObjects.js +14 -14
  17. package/examples/platformer/index.html +1 -1
  18. package/examples/platformer/tiles.png +0 -0
  19. package/examples/screenshot.jpg +0 -0
  20. package/examples/stress/index.html +1 -1
  21. package/examples/typescript/game.js +1 -1
  22. package/examples/typescript/game.ts +1 -1
  23. package/package.json +1 -1
  24. package/reference.md +409 -0
  25. package/src/engine.js +47 -42
  26. package/src/engineAudio.js +19 -10
  27. package/src/engineDebug.js +5 -1
  28. package/src/engineDraw.js +19 -23
  29. package/src/engineInput.js +31 -17
  30. package/src/engineMedals.js +1 -1
  31. package/src/engineObject.js +2 -2
  32. package/src/engineParticles.js +11 -10
  33. package/src/engineSettings.js +3 -3
  34. package/src/engineTileLayer.js +2 -2
  35. package/src/engineUtilities.js +4 -4
  36. package/src/engineWebGL.js +1 -7
  37. /package/examples/platformer/data/{gameTileData.tsx → gameLevelData.tsx} +0 -0
package/reference.md ADDED
@@ -0,0 +1,409 @@
1
+ # LittleJS Engine Quick Reference Sheet
2
+
3
+ ## This cheat sheet contains all LittleJS essentials.
4
+ - [LittleJS on GitHub](https://github.com/KilledByAPixel/LittleJS) - Official LittleJS website with more info
5
+ - [LittleJS Documentation](https://killedbyapixel.github.io/LittleJS/docs) - LittleJS documentation browser
6
+ - [Particle Deigner](https://killedbyapixel.github.io/LittleJS/examples/particles) - Editor for LittleJS Particle Systems
7
+ - [Sound Effect Designer](https://killedbyapixel.github.io/ZzFX) - Tool for creating ZzFX sound effects
8
+ - [Starter Project](https://killedbyapixel.github.io/LittleJS/examples/starter) - Simple LittleJS demo to start with
9
+
10
+ ## LittleJS Setup
11
+
12
+ To start LittleJS, you need to create a few functions and pass them to engineInit.
13
+
14
+ ```javascript
15
+ // Start up LittleJS engine with your callback functions
16
+ engineInit(init, update, updatePost, render, renderPost, imageSources=['tiles.png'])
17
+
18
+ // Destroy and remove all objects
19
+ engineObjectsDestroy()
20
+
21
+ // Trigger a callback for each object within a given area
22
+ engineObjectsCallback(pos, size, callbackFunction, objects=engineObjects)
23
+ ```
24
+
25
+ ## LittleJS Utilities Classes and Functions
26
+ - General purpose math library
27
+ - Vector2 - Fast, simple, easy 2D vector class
28
+ - Color - Holds a rgba color with some math functions
29
+ - Timer - Tracks time automatically
30
+ - RandomGenerator - Seeded random number generator
31
+
32
+ ```javascript
33
+
34
+ // Object Constructors
35
+ vec2(x=0, y=x) // Create a 2D vector with Vector or floats
36
+ rgb(r=1, g=1, b=1, a=1) // Create a color object with RGBA values
37
+ hsl(h=0, s=0, l=1, a=1) // Create a color object with HSLA values
38
+ tile(pos=(0,0), size, textureIndex=0) // Create a tile info object
39
+
40
+ // Helper functions
41
+ abs(value) // Get absoulte value
42
+ min(valueA, valueB) // Get lowest of values
43
+ max(valueA, valueB) // Get highest of values
44
+ sign(value) // Get the sign of value
45
+ mod(dividend, divisor=1) // Get remainder of division
46
+ clamp(value, min=0, max=1) // Clamps between values
47
+ percent(value, valueA, valueB) // Get percentage between values
48
+ lerp(percent, valueA, valueB) // Linearly interpolates between values
49
+ distanceWrap(valueA, valueB, wrapSize=1) // Signed wrapped distance between values
50
+ lerpWrap(percent, valueA, valueB, wrapSize=1) // Linearly interpolates with wrapping
51
+ distanceAngle(angleA, angleB) // Signed wrapped distance between angles
52
+ lerpAngle(percent, angleA, angleB) // Linearly interpolates with wrapping
53
+ smoothStep(percent) // Applies smoothstep function
54
+ nearestPowerOfTwo(value) // Returns the nearest power of two
55
+ isOverlapping(pointA, sizeA, pointB, sizeB) // Checks if bounding boxes overlap
56
+ wave(frequency=1, amplitude=1, t=time) // Returns oscillating wave
57
+ formatTime(t) // Formats seconds for display
58
+
59
+ // Random functions
60
+ rand(valueA=1, valueB=0) // Random float between values
61
+ randInt(valueA, valueB=0) // Random integer between values
62
+ randSign() // Randomly bool either -1 or 1
63
+ randVector(length=1) // Random Vector2 with the passed in length
64
+ randInCircle(radius=1, minRadius=0) // Random Vector2 within a circle
65
+ randColor(colorA, colorB, linear) // Random color between values
66
+
67
+ // 2D vector math
68
+ Vector2(x=0, y=0) // Create a 2D vector
69
+ Vector2.copy() // Copy this vector
70
+ Vector2.add(v) // Add a vector
71
+ Vector2.subtract(v) // Subtract a vector
72
+ Vector2.multiply(v) // Multiply by a vector
73
+ Vector2.divide(v) // Divide by a vector
74
+ Vector2.scale(s) // Scale by a float
75
+ Vector2.length() // Get length
76
+ Vector2.lengthSquared() // Get length squared
77
+ Vector2.distance(v) // Get distance to vector
78
+ Vector2.distanceSquared(v) // Get distance to vector squared
79
+ Vector2.normalize(length=1) // Normalize this vector to length
80
+ Vector2.clampLength(length=1) // Clamp this vector to length
81
+ Vector2.dot(v) // Dot product with vector
82
+ Vector2.cross(v) // Cross product with vector
83
+ Vector2.invert() // Invert this vector
84
+ Vector2.floor() // Floor this vector
85
+ Vector2.area() // Get area covered by this vector as a rectangle
86
+ Vector2.lerp(v, percent) // Interpolate between vectors
87
+ Vector2.arrayCheck(arraySize) // Check if in bounds of array size
88
+ Vector2.angle() // Angle of this vector, up is 0
89
+ Vector2.setAngle(angle=0, length=1) // Set angle and length
90
+ Vector2.rotate(angle) // Rotate by angle
91
+ Vector2.setDirection(direction, length=1) // Set integer direction (0-3) and length
92
+ Vector2.direction() // Get integer direction (0-3)
93
+ Vector2.toString(digits=3) // Get string representation
94
+
95
+ // RGBA color object
96
+ Color(r=1, g=1, b=1, a=1) // Create an RGBA color
97
+ Color.copy() // Copy this color
98
+ Color.add(c) // Add a color
99
+ Color.subtract(c) // Subtract a color
100
+ Color.multiply(c) // Multiply by a color
101
+ Color.divide(c) // Divide by a color
102
+ Color.scale(scale, alphaScale=scale) // Scale by a float
103
+ Color.clamp() // Clamp this color
104
+ Color.lerp(c, percent) // Interpolate between colors
105
+ Color.setHSLA(h=0, s=0, l=1, a=1) // Set the color from HSLA values
106
+ Color.getHSLA() // Get the color in HSLA format
107
+ Color.mutate(amount=.05, alphaAmount=0) // Randomly diverge from this color
108
+ Color.setHex(hex) // Set this color from a hex code
109
+ Color.rgbaInt() // Get this color as 32 bit RGBA value
110
+ Color.toString(useAlpha=true) // Get hex color code as a string
111
+
112
+ // Seeded random number generator
113
+ RandomGenerator(seed) // Create a random number generator
114
+ RandomGenerator.float(valueA=1, valueB=0) // Random float between values
115
+ RandomGenerator.int(valueA, valueB=0) // Random integer between values
116
+ RandomGenerator.sign() // Randomly either -1 or 1
117
+
118
+ // Time tracking system
119
+ Timer(timeLeft) // Create a timer object
120
+ Timer.set(timeLeft=0) // Set the timer with seconds passed in
121
+ Timer.unset() // Unset the timer
122
+ Timer.isSet() // Returns true if set
123
+ Timer.active() // Returns true if set and has not elapsed
124
+ Timer.elapsed() // Returns true if set and elapsed
125
+ Timer.get() // Get how long since elapsed, 0 if not set
126
+ Timer.getPercent() // Get percent elapsed, 0 if not set
127
+ Timer.toString() // Get this timer expressed as a string
128
+ Timer.valueOf() // Get how long since elapsed, 0 if not set
129
+ ```
130
+
131
+ ## LittleJS Drawing System
132
+ - Hybrid system with both Canvas2D and WebGL available
133
+ - Super fast tile sheet rendering with WebGL
134
+ - Can apply rotation, mirror, color and additive color
135
+ - Text and font rendering system with built in engine font
136
+
137
+ ```javascript
138
+ // Drawing functions
139
+ drawTile(pos, size=(1,1), tileInfo, color, angle=0, mirror, additiveColor)
140
+ drawRect(pos, size=(1,1), color=(1,1,1,1), angle=0)
141
+ drawPoly(points, color=(1,1,1,1))
142
+ drawLine(posA, posB, thickness=.1, color=(1,1,1,1))
143
+ drawCanvas2D(pos, size, angle, mirror, drawFunction)
144
+ drawText(text, pos, size=1, color=(1,1,1,1), lineWidth, lineColor)
145
+ drawTextScreen(text, pos, size=1, color=(1,1,1,1), lineWidth, lineColor)
146
+ setBlendMode(additive)
147
+ toggleFullscreen()
148
+ isFullscreen()
149
+
150
+ // Tile Info Object
151
+ TileInfo(pos=(0,0), size, textureIndex=0) // Create a tile info object
152
+ TileInfo.pos // Top left corner of tile in pixels
153
+ TileInfo.size // Size of tile in pixels
154
+ TileInfo.textureIndex // Texture index to use
155
+ TileInfo.offset(offset) // Offset this tile by a certain amount in pixels
156
+ TileInfo.getTextureInfo() // Returns texture info for this tile
157
+
158
+ // Texture Info Object
159
+ TextureInfo(image) // Created automatically for each image
160
+ TextureInfo.image // Image source
161
+ TextureInfo.size // Size of the image
162
+ TextureInfo.glTexture // WebGL texture
163
+
164
+ // Font Image Object draws text using characters in an image
165
+ FontImage(image, tileSize=(8,8), paddingSize=(0,1)) // Create an image font
166
+ FontImage.drawText(text, pos, scale, center) // Draw text in world space
167
+ FontImage.drawTextScreen(text, pos, scale, center) // Draw text in screen space
168
+
169
+ // Camera settings
170
+ cameraPos = (0,0) // Position of camera in world space
171
+ cameraScale = 32 // Scale of camera in world space
172
+ screenToWorld(screenPos) // Convert from screen to world space coordinates
173
+ worldToScreen(worldPos) // Convert from world to screen space coordinates
174
+ getCameraSize() // Get the camera's visible area in world space
175
+
176
+ // Display settings
177
+ canvasMaxSize = (1920, 1200) // The max size of the canvas
178
+ canvasFixedSize = (0, 0) // Fixed size of the canvas
179
+ fontDefault = 'arial' // Default font used for text rendering
180
+ canvasPixelated = true // Disable filtering for crisper pixel art?
181
+ showSplashScreen = false // Show the LittleJS splash screen on startup?
182
+ glEnable = true // Enable fast WebGL rendering?
183
+ glOverlay = true // Prevent compositing the WebGL canvas?
184
+ ```
185
+
186
+ ## LittleJS Audio System
187
+ - Caches sounds and music for fast playback
188
+ - Can attenuate and apply stereo panning to sounds
189
+ - Ability to play mp3, ogg, and wave file
190
+ - [ZzFX Sound Effect Generator](https://killedbyapixel.github.io/ZzFX)
191
+ - [ZzFXM Music System](https://keithclark.github.io/ZzFXM)
192
+
193
+ ```javascript
194
+ // Sound Object
195
+ Sound(zzfxSound) // Create a zzfx sound
196
+ SoundWave(filename, randomness=0) // Load a wave, mp3, and ogg
197
+ Sound.play(pos, volume=1, pitch=1, randomness=1, loop) // Play a sound
198
+ Sound.playNote(semitoneOffset, pos, volume=1) // Play as note with a semitone offset
199
+ Sound.stop() // Stop the last instance that was played
200
+ Sound.getSource() // Get source of most recent instance
201
+ Sound.getDuration() // Get length of sound in seconds
202
+ Sound.isLoading() // Check if sound is loading
203
+
204
+ // ZzFXM - A tiny music system
205
+ Music(..zzfxMusic) // Create a zzfx music object
206
+ Music.playMusic(volume, loop=false) // Play the music
207
+
208
+ // Audio functions
209
+ playAudioFile(filename, volume=1, loop=false) // Play an audio file or url
210
+ speak(text, language='', volume=1, rate=1, pitch=1) // Speak text line
211
+ speakStop() // Stop all queued speech
212
+
213
+ // Audio settings
214
+ soundEnable = true // Should sound be enabled?
215
+ soundVolume = .5 // Volume scale to apply to all sound
216
+ soundDefaultRange = 40 // Default range where sound no longer plays
217
+ soundDefaultTaper = .7 // Default range percent to taper off sound (0-1)
218
+ ```
219
+
220
+ ## LittleJS Input System
221
+ - Tracks keyboard down, pressed, and released
222
+ - Tracks mouse buttons, position, and wheel
223
+ - Tracks multiple analog gamepads
224
+ - Routes touch input to mouse
225
+ - Virtual gamepad for touch devices
226
+
227
+ ```javascript
228
+ // Keyboard
229
+ keyIsDown(key) // Is key down?
230
+ keyWasPressed(key) // Was key pressed this frame?
231
+ keyWasReleased(key) // Was key released this frame?
232
+
233
+ // Mouse / Touch
234
+ mousePos // World space mouse position
235
+ mousePosScreen // Screen space mouse position
236
+ mouseWheel // Delta mouse wheel this frame
237
+ mouseIsDown(button) // Is mouse button down?
238
+ mouseWasPressed(button) // Was mouse button pressed this frame?
239
+ mouseWasReleased(button) // Was mouse button released this frame?
240
+
241
+ // Gamepad
242
+ isUsingGamepad // Is user currently using gamepad?
243
+ gamepadIsDown(button, gamepad=0) // Is gamepad button down?
244
+ gamepadWasPressed(button, gamepad=0) // Was gamepad button pressed this frame?
245
+ gamepadWasReleased(button, gamepad=0) // Was gamepad button released this frame?
246
+ gamepadStick(stickIndex, gamepad=0) // Get gamepad analog stick value
247
+
248
+ // Touch Gamepad
249
+ touchGamepadEnabled // Is on screen touch gamepad enabled?
250
+ touchGamepadAnalog // Is touch gamepad analog or 8 way dpad?
251
+ touchGamepadSize // Size of touch gamepad
252
+ touchGamepadAlpha // Alpha of touch gamepad
253
+
254
+ // Vibration
255
+ vibrate(pattern=100) // Pulse the vibration hardware if it exists
256
+ vibrateStop() // Stop all vibration
257
+
258
+ // Input settings
259
+ gamepadsEnable = true // Should gamepads be allowed?
260
+ gamepadDirectionEmulateStick = true // Should dpad be routed to the left analog stick?
261
+ inputWASDEmulateDirection = true // Should WASD keys be routed to the direction keys?
262
+ vibrateEnable = true // Allow vibration hardware if it exists?
263
+ touchGamepadEnable = false // Should touch gamepad appear on mobile devices?
264
+ touchGamepadAnalog = true // Should touch gamepad be analog or 8 way dpad?
265
+ touchGamepadSize = 99 // Size of virtual gamepad for touch devices
266
+ touchGamepadAlpha = .3 // Transparency of touch gamepad overlay
267
+ ```
268
+
269
+ ## LittleJS Object System
270
+ - Top level object class used by the engine
271
+ - Automatically adds self to object list
272
+ - Will be updated and rendered each frame
273
+ - Renders as a sprite from a tile sheet by default
274
+ - Can have color and addtive color applied
275
+ - 2D Physics and collision system
276
+ - Sorted by renderOrder before drawing
277
+ - Objects can have children in local space
278
+ - Parents are updated before children
279
+ - Call destroy() to get rid of objects
280
+
281
+ ```javascript
282
+ // Engine Object
283
+ EngineObject(pos=(0,0), size=(1,1), tileInfo, angle=0, color, renderOrder=0)
284
+ EngineObject.update() // Update object, called automatically
285
+ EngineObject.render() // Render object, called automatically
286
+ EngineObject.destroy() // Destroy this object and children
287
+ EngineObject.collideWithTile(tileData, pos) // Tile collision resolve check
288
+ EngineObject.collideWithTileRaycast(tileData, pos) // Check if raycast hit
289
+ EngineObject.collideWithObject(object) // Object collision resolve check
290
+ EngineObject.getAliveTime(object) // How long since object was created
291
+ EngineObject.applyAcceleration(acceleration) // Apply acceleration
292
+ EngineObject.applyForce(force) // Apply force
293
+ EngineObject.getMirrorSign() // Get mirror direction (1 or -1)
294
+ EngineObject.addChild(child, localPos, localAngle) // Attach a child
295
+ EngineObject.removeChild(child) // Remove a child
296
+ EngineObject.setCollision(solids, isSolid, tiles) // Set collision
297
+
298
+ // Engine Object Members
299
+ EngineObject.pos // World space position
300
+ EngineObject.size // World space width and height
301
+ EngineObject.drawSize // Size of object used for drawing if set
302
+ EngineObject.tileInfo // Tile info to render object
303
+ EngineObject.angle // Rotation angle for rendering
304
+ EngineObject.color // Color to apply when rendered
305
+ EngineObject.additiveColor // Additive color to apply when rendered
306
+ EngineObject.mirror // Should it flip along y axis when rendered
307
+ EngineObject.mass // Weight of object, static if 0
308
+ EngineObject.damping // How much to slow velocity each frame (0-1)
309
+ EngineObject.angleDamping // How much to slow rotation each frame (0-1)
310
+ EngineObject.elasticity // How bouncy is it when colliding (0-1)
311
+ EngineObject.friction // How much friction when sliding (0-1)
312
+ EngineObject.gravityScale // How much to scale gravity by
313
+ EngineObject.renderOrder // Objects are sorted by render order
314
+ EngineObject.velocity // Velocity of the object
315
+ EngineObject.angleVelocity // Angular velocity of the object
316
+
317
+ // Object settings
318
+ enablePhysicsSolver = true // Enable collisions between objects?
319
+ objectDefaultMass = 1 // Default object mass for collisions
320
+ objectDefaultDamping = 1 // How much to slow velocity by each frame (0-1)
321
+ objectDefaultAngleDamping = 1 // How much to slow angular velocity each frame (0-1)
322
+ objectDefaultElasticity = 0 // How much to bounce when a collision occurs (0-1)
323
+ objectDefaultFriction = .8 // How much to slow when touching (0-1)
324
+ objectMaxSpeed = 1 // Clamp max speed to avoid fast objects missing collisions
325
+ gravity = 0 // How much gravity to apply to objects
326
+ ```
327
+
328
+ ## LittleJS Tile Layer System
329
+ - Caches arrays of tiles to off screen canvas for fast rendering
330
+ - Unlimited numbers of layers, allocates canvases as needed
331
+ - Interfaces with EngineObject for collision
332
+ - Collision layer is separate from visible layers
333
+ - It is recommended to have a visible layer that matches the collision
334
+ - Tile layers can be drawn to using their context with Canvas2d
335
+ - Drawn directly to the main canvas without using WebGL
336
+
337
+ ```javascript
338
+ // Tile Collision System
339
+ tileCollisionSize // Size of the tile collision layer
340
+ initTileCollision(size) // Clear and initialize tile collision
341
+ setTileCollisionData(pos, data=0) // Set tile collision data at pos
342
+ getTileCollisionData(pos) // Get tile collision data at pos
343
+ tileCollisionTest(pos, size=(0,0), object) // Check if collision should occur
344
+ tileCollisionRaycast(posStart, posEnd, object) // Return the center of tile if hit
345
+
346
+ // Tile Layer Object
347
+ TileLayer(position, size, tileInfo, scale) // Create a tile layer object
348
+ TileLayer.setData(layerPos, data, redraw) // Set data at position
349
+ TileLayer.getData(layerPos) // Get data at position
350
+ TileLayer.redraw() // Draw to an offscreen canvas
351
+ TileLayer.drawTileData(layerPos, clear=true) // Draw the tile
352
+ TileLayer.drawRect(pos, size, color, angle) // Draw a rectangle to 2D canvas
353
+ TileLayer.drawTile(pos, size=(1,1), tileInfo, color, angle, mirror) // Draw tile
354
+ TileLayer.drawCanvas2D(pos, size, angle, mirror, drawFunction) // Draw to 2D canvas
355
+
356
+ // Tile Layer Data Object
357
+ TileLayerData(tile, direction=0, mirror=false, color=(1,1,1,1)) // Create tile data object
358
+ TileLayerData.clear() // Clear this tile data
359
+
360
+ // Tile sheet settings
361
+ tileSizeDefault = (16,16) // Default size of tiles in pixels
362
+ tileFixBleedScale = .3 // How much smaller to draw tiles to prevent bleeding
363
+ ```
364
+
365
+ ## LittleJS Particle System
366
+ - Simple kinematic particle system with many parameters
367
+ - [Particle Effect Designer](https://killedbyapixel.github.io/LittleJS/examples/particles) - Editor for creating LittleJS Particle Systems
368
+
369
+ ```javascript
370
+ // Particle Emitter Object
371
+ ParticleEmitter(position, angle, ...settings) // Create a particle system
372
+ ParticleEmitter.emitParticle() // Spawn one particle
373
+
374
+ // Particle Settings
375
+ particleEmitRateScale = 1 // Scales particles emit rate
376
+ ```
377
+
378
+ ## LittleJS Debugging System
379
+ - Press Escape key to toggle debug overlay
380
+ - Number keys toggle debug functions
381
+ - +/- keys apply time scale to update
382
+ - Debug primitive rendering system
383
+ - Debug functions are only active in debug builds
384
+
385
+ ```javascript
386
+ ASSERT(assert, output) // Asserts if the expression is false
387
+ debugRect(pos, size, color='#fff', time=0, angle=0, fill) // Draw debug rectangle
388
+ debugCircle(pos, radius, color='#fff', time=0, fill) // Draw debug circle
389
+ debugPoint(pos, color, time, angle) // Draw debug point
390
+ debugLine(posA, posB, color, thickness=.1, time) // Draw debug line
391
+ debugText(text, pos, size=1, color='#fff', time=0, angle=0) // Draw debug text
392
+ debugAABB(pA, sA, pB, sB, color) // Draw a debug axis aligned box
393
+ debugClear() // Clear all debug primitives
394
+ debugSaveCanvas(canvas, filename) // Save canvas to a file
395
+ debugSaveText(text, filename) // Save text to a file
396
+ debugSaveDataURL(dataURL, filename) // Save url to a file
397
+
398
+ // Debug settings
399
+ debug // Is debug enabled?
400
+ debugPointSize = .5 // Size to render debug points by default
401
+ debugKey = 'Escape' // Key code used to toggle debug mode
402
+ debugOverlay // True if the debug overlay is active
403
+ enableAsserts // True if asserts are enabled
404
+ showWatermark // True if watermark with FPS should be show
405
+ ```
406
+
407
+ [LittleJS Engine](https://github.com/KilledByAPixel/LittleJS) Copyright 2021 Frank Force
408
+
409
+ ![LittleJS Logo](examples/favicon.png)
package/src/engine.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * LittleJS - The Tiny JavaScript Game Engine That Can!
2
+ * LittleJS - The Tiny Fast JavaScript Game Engine
3
3
  * MIT License - Copyright 2021 Frank Force
4
4
  *
5
5
  * Engine Features
@@ -30,9 +30,9 @@ const engineName = 'LittleJS';
30
30
  * @type {String}
31
31
  * @default
32
32
  * @memberof Engine */
33
- const engineVersion = '1.9.2';
33
+ const engineVersion = '1.9.4';
34
34
 
35
- /** Frames per second to update objects
35
+ /** Frames per second to update
36
36
  * @type {Number}
37
37
  * @default
38
38
  * @memberof Engine */
@@ -49,7 +49,7 @@ const timeDelta = 1/frameRate;
49
49
  * @memberof Engine */
50
50
  let engineObjects = [];
51
51
 
52
- /** Array containing only objects that are set to collide with other objects this frame (for optimization)
52
+ /** Array with only objects set to collide with other objects this frame (for optimization)
53
53
  * @type {Array}
54
54
  * @memberof Engine */
55
55
  let engineObjectsCollide = [];
@@ -59,7 +59,7 @@ let engineObjectsCollide = [];
59
59
  * @memberof Engine */
60
60
  let frame = 0;
61
61
 
62
- /** Current engine time since start in seconds, derived from frame
62
+ /** Current engine time since start in seconds
63
63
  * @type {Number}
64
64
  * @memberof Engine */
65
65
  let time = 0;
@@ -85,12 +85,12 @@ let frameTimeLastMS = 0, frameTimeBufferMS = 0, averageFPS = 0;
85
85
 
86
86
  ///////////////////////////////////////////////////////////////////////////////
87
87
 
88
- /** Start up LittleJS engine with your callback functions
89
- * @param {Function} gameInit - Called once after the engine starts up, setup the game
90
- * @param {Function} gameUpdate - Called every frame at 60 frames per second, handle input and update the game state
91
- * @param {Function} gameUpdatePost - Called after physics and objects are updated, setup camera and prepare for render
92
- * @param {Function} gameRender - Called before objects are rendered, draw any background effects that appear behind objects
93
- * @param {Function} gameRenderPost - Called after objects are rendered, draw effects or hud that appear above all objects
88
+ /** Startup LittleJS engine with your callback functions
89
+ * @param {Function} gameInit - Called once after the engine starts up, setup the game
90
+ * @param {Function} gameUpdate - Called every frame at 60 frames per second, handle input and update the game state
91
+ * @param {Function} gameUpdatePost - Called after physics and objects are updated, setup camera and prepare for render
92
+ * @param {Function} gameRender - Called before objects are rendered, draw any background effects that appear behind objects
93
+ * @param {Function} gameRenderPost - Called after objects are rendered, draw effects or hud that appear above all objects
94
94
  * @param {Array} [imageSources=['tiles.png']] - Image to load
95
95
  * @memberof Engine */
96
96
  function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, imageSources=['tiles.png'])
@@ -112,33 +112,8 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
112
112
  timeReal += frameTimeDeltaMS / 1e3;
113
113
  frameTimeBufferMS += paused ? 0 : frameTimeDeltaMS;
114
114
  if (!debugSpeedUp)
115
- frameTimeBufferMS = min(frameTimeBufferMS, 50); // clamp incase of slow framerate
116
-
117
- if (canvasFixedSize.x)
118
- {
119
- // clear canvas and set fixed size
120
- mainCanvas.width = canvasFixedSize.x;
121
- mainCanvas.height = canvasFixedSize.y;
122
-
123
- // fit to window by adding space on top or bottom if necessary
124
- const aspect = innerWidth / innerHeight;
125
- const fixedAspect = mainCanvas.width / mainCanvas.height;
126
- (glCanvas||mainCanvas).style.width = mainCanvas.style.width = overlayCanvas.style.width = aspect < fixedAspect ? '100%' : '';
127
- (glCanvas||mainCanvas).style.height = mainCanvas.style.height = overlayCanvas.style.height = aspect < fixedAspect ? '' : '100%';
128
- }
129
- else
130
- {
131
- // clear canvas and set size to same as window
132
- mainCanvas.width = min(innerWidth, canvasMaxSize.x);
133
- mainCanvas.height = min(innerHeight, canvasMaxSize.y);
134
- }
135
-
136
- // clear overlay canvas and set size
137
- overlayCanvas.width = mainCanvas.width;
138
- overlayCanvas.height = mainCanvas.height;
139
-
140
- // save canvas size
141
- mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
115
+ frameTimeBufferMS = min(frameTimeBufferMS, 50); // clamp in case of slow framerate
116
+ updateCanvas();
142
117
 
143
118
  if (paused)
144
119
  {
@@ -212,6 +187,35 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
212
187
  requestAnimationFrame(engineUpdate);
213
188
  }
214
189
 
190
+ function updateCanvas()
191
+ {
192
+ if (canvasFixedSize.x)
193
+ {
194
+ // clear canvas and set fixed size
195
+ mainCanvas.width = canvasFixedSize.x;
196
+ mainCanvas.height = canvasFixedSize.y;
197
+
198
+ // fit to window by adding space on top or bottom if necessary
199
+ const aspect = innerWidth / innerHeight;
200
+ const fixedAspect = mainCanvas.width / mainCanvas.height;
201
+ (glCanvas||mainCanvas).style.width = mainCanvas.style.width = overlayCanvas.style.width = aspect < fixedAspect ? '100%' : '';
202
+ (glCanvas||mainCanvas).style.height = mainCanvas.style.height = overlayCanvas.style.height = aspect < fixedAspect ? '' : '100%';
203
+ }
204
+ else
205
+ {
206
+ // clear canvas and set size to same as window
207
+ mainCanvas.width = min(innerWidth, canvasMaxSize.x);
208
+ mainCanvas.height = min(innerHeight, canvasMaxSize.y);
209
+ }
210
+
211
+ // clear overlay canvas and set size
212
+ overlayCanvas.width = mainCanvas.width;
213
+ overlayCanvas.height = mainCanvas.height;
214
+
215
+ // save canvas size
216
+ mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
217
+ }
218
+
215
219
  // setup html
216
220
  const styleBody =
217
221
  'margin:0;overflow:hidden;' + // fill the window
@@ -236,6 +240,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
236
240
  const styleCanvas = 'position:absolute;' + // position
237
241
  'top:50%;left:50%;transform:translate(-50%,-50%)'; // center
238
242
  (glCanvas||mainCanvas).style.cssText = mainCanvas.style.cssText = overlayCanvas.style.cssText = styleCanvas;
243
+ updateCanvas();
239
244
 
240
245
  // create promises for loading images
241
246
  const promises = imageSources.map((src, textureIndex)=>
@@ -432,9 +437,9 @@ function drawEngineSplashScreen(t)
432
437
 
433
438
  // big stack
434
439
  rect(50,20,10,-10,color(0,1));
435
- rect(50,20,6,-10,color(0,2));
436
- rect(50,20,3,-10,color(0,3));
437
- rect(50,10,10,10);
440
+ rect(50,20,6.5,-10,color(0,2));
441
+ rect(50,20,3.5,-10,color(0,3));
442
+ rect(50,20,10,-10);
438
443
  circle(55,2,11.4,.5,PI-.5,color(3,3));
439
444
  circle(55,2,11.4,.5,PI/2,color(3,2),1);
440
445
  circle(55,2,11.4,.5,PI-.5);
@@ -453,7 +458,7 @@ function drawEngineSplashScreen(t)
453
458
 
454
459
  // engine outline
455
460
  circle(36,30,10,PI/2,PI*3/2);
456
- circle(47,30,10,PI/2,PI*3/2);
461
+ circle(48,30,10,PI/2,PI*3/2);
457
462
  circle(60,30,10);
458
463
  line(36,20,60,20);
459
464
 
@@ -12,7 +12,7 @@
12
12
  'use strict';
13
13
 
14
14
  /**
15
- * Sound Object - Stores a zzfx sound for later use and can be played positionally
15
+ * Sound Object - Stores a sound for later use and can be played positionally
16
16
  *
17
17
  * <a href=https://killedbyapixel.github.io/ZzFX/>Create sounds using the ZzFX Sound Designer.</a>
18
18
  * @example
@@ -27,7 +27,7 @@ class Sound
27
27
  /** Create a sound object and cache the zzfx samples for later use
28
28
  * @param {Array} zzfxSound - Array of zzfx parameters, ex. [.5,.5]
29
29
  * @param {Number} [range=soundDefaultRange] - World space max range of sound, will not play if camera is farther away
30
- * @param {Number} [taper=soundDefaultTaper] - At what percentage of range should it start tapering off
30
+ * @param {Number} [taper=soundDefaultTaper] - At what percentage of range should it start tapering
31
31
  */
32
32
  constructor(zzfxSound, range=soundDefaultRange, taper=soundDefaultTaper)
33
33
  {
@@ -178,7 +178,7 @@ class SoundWave extends Sound
178
178
  * 1, 0, 9, 1 // channel notes
179
179
  * ],
180
180
  * [ // channel 1
181
- * 0, 1, // instrument 1, right speaker
181
+ * 0, 1, // instrument 0, right speaker
182
182
  * 0, 12, 17, -1 // channel notes
183
183
  * ]
184
184
  * ],
@@ -207,24 +207,24 @@ class Music extends Sound
207
207
 
208
208
  /** Play the music
209
209
  * @param {Number} [volume=1] - How much to scale volume by
210
- * @param {Boolean} [loop=1] - True if the music should loop
210
+ * @param {Boolean} [loop] - True if the music should loop
211
211
  * @return {AudioBufferSourceNode} - The audio source node
212
212
  */
213
- playMusic(volume, loop = false)
213
+ playMusic(volume, loop=false)
214
214
  { return super.play(undefined, volume, 1, 1, loop); }
215
215
  }
216
216
 
217
217
  /** Play an mp3, ogg, or wav audio from a local file or url
218
- * @param {String} url - Location of sound file to play
218
+ * @param {String} filename - Location of sound file to play
219
219
  * @param {Number} [volume] - How much to scale volume by
220
220
  * @param {Boolean} [loop] - True if the music should loop
221
221
  * @return {HTMLAudioElement} - The audio element for this sound
222
222
  * @memberof Audio */
223
- function playAudioFile(url, volume=1, loop=false)
223
+ function playAudioFile(filename, volume=1, loop=false)
224
224
  {
225
225
  if (!soundEnable) return;
226
226
 
227
- const audio = new Audio(url);
227
+ const audio = new Audio(filename);
228
228
  audio.volume = soundVolume * volume;
229
229
  audio.loop = loop;
230
230
  audio.play();
@@ -276,6 +276,11 @@ function getNoteFrequency(semitoneOffset, rootFrequency=220)
276
276
  * @memberof Audio */
277
277
  let audioContext = new AudioContext;
278
278
 
279
+ /** Keep track if audio was suspended when last sound was played
280
+ * @type {Boolean}
281
+ * @memberof Audio */
282
+ let audioSuspended = false;
283
+
279
284
  /** Play cached audio samples with given settings
280
285
  * @param {Array} sampleChannels - Array of arrays of samples to play (for stereo playback)
281
286
  * @param {Number} [volume] - How much to scale volume by
@@ -290,11 +295,15 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sample
290
295
  if (!soundEnable) return;
291
296
 
292
297
  // prevent sounds from building up if they can't be played
293
- if (audioContext.state != 'running')
298
+ const audioWasSuspended = audioSuspended;
299
+ if (audioSuspended = audioContext.state != 'running')
294
300
  {
295
301
  // fix stalled audio
296
302
  audioContext.resume();
297
- return;
303
+
304
+ // prevent suspended sounds from building up
305
+ if (audioWasSuspended)
306
+ return;
298
307
  }
299
308
 
300
309
  // create buffer and source
@@ -52,7 +52,7 @@ let debugPrimitives = [], debugPhysics = false, debugRaycast = false, debugParti
52
52
  ///////////////////////////////////////////////////////////////////////////////
53
53
  // Debug helper functions
54
54
 
55
- /** Asserts if the experssion is false, does not do anything in release builds
55
+ /** Asserts if the expression is false, does not do anything in release builds
56
56
  * @param {Boolean} assert
57
57
  * @param {Object} [output]
58
58
  * @memberof Debug */
@@ -260,6 +260,10 @@ function debugRender()
260
260
  {
261
261
  const saveContext = mainContext;
262
262
  mainContext = overlayContext;
263
+
264
+ // draw red rectangle around screen
265
+ const cameraSize = getCameraSize();
266
+ debugRect(cameraPos, cameraSize.subtract(vec2(.1)), '#f008');
263
267
 
264
268
  // mouse pick
265
269
  let bestDistance = Infinity, bestObject;