littlejsengine 1.14.11 → 1.14.19
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 +303 -137
- package/dist/littlejs.esm.js +936 -463
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +934 -462
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +859 -417
- package/examples/box2d/game.js +3 -2
- package/examples/box2d/gameObjects.js +2 -2
- package/examples/box2d/tiles.png +0 -0
- package/examples/breakout/game.js +5 -5
- package/examples/breakout/gameObjects.js +2 -2
- package/examples/breakoutTutorial/README.md +32 -32
- package/examples/breakoutTutorial/game.js +1 -1
- package/examples/electron/game.js +4 -4
- package/examples/electron/index.html +2 -2
- package/examples/electron/package.json +1 -8
- package/examples/index.html +67 -56
- package/examples/module/game.js +4 -4
- package/examples/platformer/gameEffects.js +5 -5
- package/examples/platformer/gameLevel.js +1 -1
- package/examples/platformer/gameObjects.js +4 -4
- package/examples/puzzle/game.js +1 -1
- package/examples/shorts/animation.js +1 -1
- package/examples/shorts/base.html +1 -1
- package/examples/shorts/blending.js +8 -14
- package/examples/shorts/box2d.js +7 -3
- package/examples/shorts/box2dCar.js +2 -1
- package/examples/shorts/empty.js +30 -0
- package/examples/shorts/helloWorld.js +1 -1
- package/examples/shorts/hillGlideGame.js +10 -4
- package/examples/shorts/landerGame.js +11 -8
- package/examples/shorts/medals.js +4 -4
- package/examples/shorts/music.js +29 -56
- package/examples/shorts/musicPlayer.js +135 -0
- package/examples/shorts/nineSlice.js +34 -15
- package/examples/shorts/parallax.js +5 -4
- package/examples/shorts/particles.js +15 -15
- package/examples/shorts/piano.js +15 -21
- package/examples/shorts/pongGame.js +6 -4
- package/examples/shorts/raycasting.js +9 -4
- package/examples/shorts/sequencer.js +122 -0
- package/examples/shorts/shader.js +29 -0
- package/examples/shorts/shapes.js +7 -4
- package/examples/shorts/slidingPuzzle.js +4 -2
- package/examples/shorts/sound.js +18 -9
- package/examples/shorts/spaceGame.js +12 -8
- package/examples/shorts/spriteAtlas.js +7 -7
- package/examples/shorts/starfield.js +1 -1
- package/examples/shorts/systemFont.js +2 -2
- package/examples/shorts/texture.js +2 -2
- package/examples/shorts/tileLayer.js +10 -10
- package/examples/shorts/tiltedView.js +24 -5
- package/examples/shorts/timers.js +10 -0
- package/examples/shorts/topDown.js +4 -1
- package/examples/shorts/uiSystem.js +8 -5
- package/examples/starter/game.js +4 -4
- package/examples/starter/index.html +2 -2
- package/examples/style.css +1 -0
- package/examples/typescript/game.js +4 -4
- package/examples/typescript/game.ts +4 -4
- package/examples/uiSystem/game.js +4 -3
- package/package.json +4 -2
- package/plugins/box2d.js +17 -2
- package/plugins/newgrounds.js +7 -5
- package/plugins/postProcess.js +76 -53
- package/plugins/uiSystem.js +192 -53
- package/plugins/zzfxm.js +5 -1
- package/reference.md +1 -1
- package/src/engine.js +60 -23
- package/src/engineAudio.js +44 -17
- package/src/engineDebug.js +75 -45
- package/src/engineDraw.js +94 -59
- package/src/engineExport.js +2 -1
- package/src/engineMedals.js +10 -2
- package/src/engineObject.js +14 -10
- package/src/engineParticles.js +60 -47
- package/src/engineSettings.js +7 -7
- package/src/engineTileLayer.js +73 -56
- package/src/engineUtilities.js +67 -20
- package/src/engineWebGL.js +134 -63
package/examples/box2d/game.js
CHANGED
|
@@ -56,10 +56,9 @@ async function gameInit()
|
|
|
56
56
|
// start up LittleJS Box2D plugin
|
|
57
57
|
await LJS.box2dInit();
|
|
58
58
|
//LJS.box2dSetDebug(true); // enable box2d debug draw
|
|
59
|
-
LJS.setCanvasClearColor(hsl(0,0,.8));
|
|
60
59
|
|
|
61
60
|
// create a table of all sprites
|
|
62
|
-
const gameTile = (i)=> LJS.tile(i,
|
|
61
|
+
const gameTile = (i)=> LJS.tile(i, 124, 0, 2);
|
|
63
62
|
spriteAtlas =
|
|
64
63
|
{
|
|
65
64
|
circle: gameTile(0),
|
|
@@ -71,6 +70,8 @@ async function gameInit()
|
|
|
71
70
|
squareOutline2: gameTile(6),
|
|
72
71
|
};
|
|
73
72
|
|
|
73
|
+
// startup the demo
|
|
74
|
+
LJS.setCanvasClearColor(hsl(0,0,.8));
|
|
74
75
|
setScene(startScene);
|
|
75
76
|
}
|
|
76
77
|
|
|
@@ -471,7 +471,7 @@ export function explosion(pos, radius=3, strength=300)
|
|
|
471
471
|
// smoke
|
|
472
472
|
new LJS.ParticleEmitter(
|
|
473
473
|
pos, 0, // pos, angle
|
|
474
|
-
radius/2, .2, 50*radius, 3.14,// emitSize, emitTime,
|
|
474
|
+
radius/2, .2, 50*radius, 3.14,// emitSize, emitTime, rate, cone
|
|
475
475
|
Game.spriteAtlas.dot, // tileInfo
|
|
476
476
|
hsl(0,0,0), hsl(0,0,0), // colorStartA, colorStartB
|
|
477
477
|
hsl(0,0,0,0), hsl(0,0,0,0), // colorEndA, colorEndB
|
|
@@ -483,7 +483,7 @@ export function explosion(pos, radius=3, strength=300)
|
|
|
483
483
|
// fire
|
|
484
484
|
new LJS.ParticleEmitter(
|
|
485
485
|
pos, 0, // pos, angle
|
|
486
|
-
radius, .1, 100*radius, 3.14, // emitSize, emitTime,
|
|
486
|
+
radius, .1, 100*radius, 3.14, // emitSize, emitTime, rate, cone
|
|
487
487
|
Game.spriteAtlas.dot, // tileInfo
|
|
488
488
|
hsl(0,1,.5), hsl(.15,1,.5), // colorStartA, colorStartB
|
|
489
489
|
hsl(0,1,.5,0), hsl(.1, 1,.5,0), // colorEndA, colorEndB
|
package/examples/box2d/tiles.png
CHANGED
|
Binary file
|
|
@@ -104,11 +104,12 @@ function gameRenderPost()
|
|
|
104
104
|
{
|
|
105
105
|
// use built in image font for text
|
|
106
106
|
const font = new LJS.FontImage;
|
|
107
|
-
|
|
107
|
+
|
|
108
|
+
font.drawTextOverlay('Score: ' + score, LJS.cameraPos.add(vec2(0,9.7)), .15, true);
|
|
108
109
|
if (!brickCount)
|
|
109
|
-
font.
|
|
110
|
+
font.drawTextOverlay('You Win!', LJS.cameraPos.add(vec2(0,-5)), .2, true);
|
|
110
111
|
else if (!ball)
|
|
111
|
-
font.
|
|
112
|
+
font.drawTextOverlay('Click to Play', LJS.cameraPos.add(vec2(0,-5)), .2, true);
|
|
112
113
|
}
|
|
113
114
|
|
|
114
115
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -167,8 +168,7 @@ function setupPostProcess()
|
|
|
167
168
|
c *= 1.-pow((dx*dx + dy*dy)/vignette, vignettePow);
|
|
168
169
|
}`;
|
|
169
170
|
|
|
170
|
-
|
|
171
|
-
new LJS.PostProcessPlugin(televisionShader, includeOverlay);
|
|
171
|
+
new LJS.PostProcessPlugin(televisionShader);
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -74,7 +74,7 @@ export class Brick extends PhysicsObject
|
|
|
74
74
|
const color2 = color1.lerp(hsl(), .5);
|
|
75
75
|
new LJS.ParticleEmitter(
|
|
76
76
|
this.pos, 0, // pos, angle
|
|
77
|
-
this.size, .1, 200, 3.14, // emitSize, emitTime,
|
|
77
|
+
this.size, .1, 200, 3.14, // emitSize, emitTime, rate, cone
|
|
78
78
|
tile(0, 16), // tileIndex, tileSize
|
|
79
79
|
color1, color2, // colorStartA, colorStartB
|
|
80
80
|
color1.scale(1,0), color2.scale(1,0), // colorEndA, colorEndB
|
|
@@ -110,7 +110,7 @@ export class Ball extends PhysicsObject
|
|
|
110
110
|
const color = hsl(0,0,.2);
|
|
111
111
|
this.trailEffect = new LJS.ParticleEmitter(
|
|
112
112
|
this.pos, 0, // pos, angle
|
|
113
|
-
this.size, 0, 80, 3.14, // emitSize, emitTime,
|
|
113
|
+
this.size, 0, 80, 3.14, // emitSize, emitTime, rate, cone
|
|
114
114
|
tile(0, 16), // tileIndex, tileSize
|
|
115
115
|
color, color, // colorStartA, colorStartB
|
|
116
116
|
color.scale(0), color.scale(0), // colorEndA, colorEndB
|
|
@@ -33,11 +33,11 @@ That will make a square of 20×20 engine objects, we can adjust it as we go. It
|
|
|
33
33
|
|
|
34
34
|

|
|
35
35
|
|
|
36
|
-
It is completely off center and may not look like much yet, but it
|
|
36
|
+
It is completely off center and may not look like much yet, but it's a start!
|
|
37
37
|
|
|
38
38
|
## Improve the Bricks
|
|
39
39
|
|
|
40
|
-
Let
|
|
40
|
+
Let's make the bricks more rectangular by passing vec2(2,1) to the size parameter of Engine Object. We will need to adjust the loop to add 2 for each x iteration. Also we can use a Vector2 to describe the size of the level.
|
|
41
41
|
|
|
42
42
|
```javascript
|
|
43
43
|
// create bricks
|
|
@@ -52,7 +52,7 @@ for (let y=0; y<=levelSize.y; y+=1)
|
|
|
52
52
|
|
|
53
53
|
## Move the Camera
|
|
54
54
|
|
|
55
|
-
Let
|
|
55
|
+
Let's move the camera to the center of our level by setting the cameraPos variable to half the level size.
|
|
56
56
|
You can also change the camera zoom by using camaraScale which controls the number of pixels for each world space unit.
|
|
57
57
|
For this example the camera will just remain stationary, but in other types of games it is very useful!
|
|
58
58
|
|
|
@@ -60,7 +60,7 @@ For this example the camera will just remain stationary, but in other types of g
|
|
|
60
60
|
LJS.setCameraPos(levelSize.scale(.5)); // center camera in level
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
We
|
|
63
|
+
We'll also start with a blank slate by commenting out the default “Hello World!” text in gameRenderPost.
|
|
64
64
|
|
|
65
65
|
```javascript
|
|
66
66
|
// LJS.drawTextScreen('Hello World!', LJS.mainCanvasSize.scale(.5), 80);
|
|
@@ -68,11 +68,11 @@ We’ll also start with a blank slate by commenting out the default “Hello Wor
|
|
|
68
68
|
|
|
69
69
|

|
|
70
70
|
|
|
71
|
-
It
|
|
71
|
+
It is getting closer! The camera is now centered and blocks are rectangular.
|
|
72
72
|
|
|
73
73
|
## Modify the Level Size
|
|
74
74
|
|
|
75
|
-
For this example we will use a fixed size canvas. This will let the drawing canvas always be the same resolution, even if the window size changes. Black space is added on the sides to compensate. It
|
|
75
|
+
For this example we will use a fixed size canvas. This will let the drawing canvas always be the same resolution, even if the window size changes. Black space is added on the sides to compensate. It is a great option for any game that uses a single screen like this.
|
|
76
76
|
|
|
77
77
|
To enable it we will set canvasFixedSize in gameInit to use 720p resolution.
|
|
78
78
|
|
|
@@ -80,7 +80,7 @@ To enable it we will set canvasFixedSize in gameInit to use 720p resolution.
|
|
|
80
80
|
LJS.setCanvasFixedSize(vec2(1280, 720)); // use a 720p fixed size canvas
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
-
Before we tweak the level size, let
|
|
83
|
+
Before we tweak the level size, let's add this bit of code to gameRender to show the size of the level. This will cause some rects to be drawn each frame before the engine objects. To create color objects we pass in RGB values between 0 and 1.
|
|
84
84
|
|
|
85
85
|
```javascript
|
|
86
86
|
LJS.drawRect(LJS.cameraPos, vec2(100), rgb(.5,.5,.5)); // draw background
|
|
@@ -112,7 +112,7 @@ Now that looks almost like a breakout game!
|
|
|
112
112
|
|
|
113
113
|
## Create the Player Paddle
|
|
114
114
|
|
|
115
|
-
For the player
|
|
115
|
+
For the player's paddle, let's create a new class of object that extends the built in EngineObject. This will allow us to control movement with the mouse. In this Paddle class we will just add some new code to the update function which is automatically called each frame by the engine.
|
|
116
116
|
|
|
117
117
|
```javascript
|
|
118
118
|
class Paddle extends LJS.EngineObject
|
|
@@ -132,7 +132,7 @@ new Paddle; // create player's paddle
|
|
|
132
132
|
|
|
133
133
|
There is now a square paddle that moves along the bottom of the screen.
|
|
134
134
|
|
|
135
|
-
Let
|
|
135
|
+
Let's make the paddle wider and move it up a smidge by adding a constructor to the Paddle class.
|
|
136
136
|
|
|
137
137
|
```javascript
|
|
138
138
|
constructor()
|
|
@@ -153,7 +153,7 @@ this.pos.x = LJS.clamp(this.pos.x, this.size.x/2, levelSize.x - this.size.x/2);
|
|
|
153
153
|
```
|
|
154
154
|
|
|
155
155
|
## Create the Ball
|
|
156
|
-
The final missing piece is of course that ball that moves around and bounces off of stuff. We will leverage the built in physics solver to handle all the ball
|
|
156
|
+
The final missing piece is of course that ball that moves around and bounces off of stuff. We will leverage the built in physics solver to handle all the ball's physics and collision math.
|
|
157
157
|
|
|
158
158
|
We can create a Ball class the same way we created the paddle. In this case we will also apply some velocity to ball so it starts moving right away.
|
|
159
159
|
|
|
@@ -169,7 +169,7 @@ class Ball extends LJS.EngineObject
|
|
|
169
169
|
}
|
|
170
170
|
```
|
|
171
171
|
|
|
172
|
-
Then we just need to create the ball in gameInit, passing in the camera position for
|
|
172
|
+
Then we just need to create the ball in gameInit, passing in the camera position for its location.
|
|
173
173
|
|
|
174
174
|
```javascript
|
|
175
175
|
{
|
|
@@ -186,13 +186,13 @@ You may have noticed that the ball goes right through the paddle and bricks. To
|
|
|
186
186
|
this.setCollision(); // make object collide
|
|
187
187
|
```
|
|
188
188
|
|
|
189
|
-
Now the ball collides but unfortunately also pushes the paddle away, not quite what we want. To prevent the paddle from being moved by physics we will make it use static physics by setting
|
|
189
|
+
Now the ball collides but unfortunately also pushes the paddle away, not quite what we want. To prevent the paddle from being moved by physics we will make it use static physics by setting its mass to 0 in the paddle constructor.
|
|
190
190
|
|
|
191
191
|
```javascript
|
|
192
192
|
this.mass = 0; // make object have static physics
|
|
193
193
|
```
|
|
194
194
|
|
|
195
|
-
Getting closer, the paddle is not pushed away but the ball doesn
|
|
195
|
+
Getting closer, the paddle is not pushed away but the ball doesn't bounce either. To make it bounce, we need to set the ball's restitution which controls how much it will bounce.
|
|
196
196
|
|
|
197
197
|
```javascript
|
|
198
198
|
this.restitution = 1; // make object bounce
|
|
@@ -202,7 +202,7 @@ this.restitution = 1; // make object bounce
|
|
|
202
202
|
|
|
203
203
|
It works! The ball now bounces off the paddle, still not the walls or blocks yet though.
|
|
204
204
|
|
|
205
|
-
Before we continue, let
|
|
205
|
+
Before we continue, let's make the ball a bit smaller by changing the super call in its constructor.
|
|
206
206
|
|
|
207
207
|
```javascript
|
|
208
208
|
super(pos, vec2(.5)); // set object position and size
|
|
@@ -210,7 +210,7 @@ super(pos, vec2(.5)); // set object position and size
|
|
|
210
210
|
|
|
211
211
|
## Make the Ball Bounce Off Walls
|
|
212
212
|
|
|
213
|
-
Next, let
|
|
213
|
+
Next, let's make the ball bounce when it hits the top or sides of the screen. To do this, we will make a Wall object class that works similar to the paddle but without an update function.
|
|
214
214
|
|
|
215
215
|
```javascript
|
|
216
216
|
class Wall extends LJS.EngineObject
|
|
@@ -275,11 +275,11 @@ if (!ball || ball.pos.y < -1)
|
|
|
275
275
|
}
|
|
276
276
|
```
|
|
277
277
|
|
|
278
|
-
Don
|
|
278
|
+
Don't forget to destroy the old ball before creating the new one! Though it doesn't really matter for this simple example, it would cause the old balls to continue existing while being updated and rendered. That could really slow things in bigger games with thousands of objects.
|
|
279
279
|
|
|
280
280
|
## Break the Bricks
|
|
281
281
|
|
|
282
|
-
Still, the ball doesn
|
|
282
|
+
Still, the ball doesn't collide with the bricks much less breaks them and it wouldn't be breakout without that. So we need to make the brick collide with the ball, just like the walls, so let's start with Brick class that is the same as Wall.
|
|
283
283
|
|
|
284
284
|
```javascript
|
|
285
285
|
class Brick extends LJS.EngineObject
|
|
@@ -300,7 +300,7 @@ And we will just change the for loop in gameInit to use the Brick class.
|
|
|
300
300
|
const brick = new Brick(vec2(x,y), vec2(2,1)); // create a brick
|
|
301
301
|
```
|
|
302
302
|
|
|
303
|
-
Now the ball will bounce off the bricks, but we want it to break the bricks. To do this we can override the brick
|
|
303
|
+
Now the ball will bounce off the bricks, but we want it to break the bricks. To do this we can override the brick's collideWithObject function which is called by the engine when the ball hits it. Instead of the default collide behavior, we just destroy the brick.
|
|
304
304
|
|
|
305
305
|
```javascript
|
|
306
306
|
collideWithObject(o)
|
|
@@ -319,7 +319,7 @@ return true; // allow object to collide
|
|
|
319
319
|
|
|
320
320
|
Success, we have breakout! All the core components are here though there are a few more changes we can make that will greatly increase the playability.
|
|
321
321
|
|
|
322
|
-
## Track the Player
|
|
322
|
+
## Track the Player's Score
|
|
323
323
|
|
|
324
324
|
We can easily add a score tracker to the game by making a global score variable called score.
|
|
325
325
|
|
|
@@ -343,7 +343,7 @@ LJS.drawTextScreen('Score ' + score, vec2(LJS.mainCanvasSize.x/2, 70), 50); // s
|
|
|
343
343
|
|
|
344
344
|
## Add Sound Effects
|
|
345
345
|
|
|
346
|
-
So far the game is completely silent. Let
|
|
346
|
+
So far the game is completely silent. Let's add sounds using ZzFX. This is a tiny sound effect generator that works in conjunction with LittleJS and can be used on its own too.
|
|
347
347
|
|
|
348
348
|
We will start with the ball bounce sound. [You can use the official ZzFX sound designer to create your own sound.](https://killedbyapixel.github.io/ZzFX/) I recommend using the Blip preset for this one.
|
|
349
349
|
|
|
@@ -364,7 +364,7 @@ collideWithObject(o)
|
|
|
364
364
|
return true; // allow object to collide
|
|
365
365
|
}
|
|
366
366
|
```
|
|
367
|
-
Let
|
|
367
|
+
Let's also make a brick break sound. You can use the ZzFX sound designer again to create your own sound, for this one try the Hit preset.
|
|
368
368
|
|
|
369
369
|
Create a global object for this sound the same way we did for the bounce sound. You can replace it with your own generated sound or use mine.
|
|
370
370
|
|
|
@@ -372,17 +372,17 @@ Create a global object for this sound the same way we did for the bounce sound.
|
|
|
372
372
|
const sound_break = new LJS.Sound([,,90,,.01,.03,4,,,,,,,9,50,.2,,.2,.01], 0);
|
|
373
373
|
```
|
|
374
374
|
|
|
375
|
-
Then in the Brick
|
|
375
|
+
Then in the Brick's collideWithObject function just add some code to play that sound.
|
|
376
376
|
|
|
377
377
|
```javascript
|
|
378
378
|
sound_break.play(); // play brick break sound
|
|
379
379
|
```
|
|
380
380
|
|
|
381
|
-
Now you should hear sound as the ball bounces around and breaks bricks! Of course it
|
|
381
|
+
Now you should hear sound as the ball bounces around and breaks bricks! Of course it is easy to swap out these sounds with other ones, feel free to experiment.
|
|
382
382
|
|
|
383
383
|
## Add Click To Start Interaction
|
|
384
384
|
|
|
385
|
-
Let
|
|
385
|
+
Let's improve the gameplay by letting the player click to start, instead of creating the ball right away. This will also ensure that the player has clicked which is requirement for audio to play in most browsers.
|
|
386
386
|
|
|
387
387
|
We can also add a special sound that plays on startup. Try making an interesting start from the ZzFX sound designer, maybe using the Powerup preset.
|
|
388
388
|
|
|
@@ -408,9 +408,9 @@ if (!ball && LJS.mouseWasPressed(0)) // if there is no ball and left mouse is pr
|
|
|
408
408
|
|
|
409
409
|
## Add Particle Effects
|
|
410
410
|
|
|
411
|
-
Let
|
|
411
|
+
Let's add some effects when the bricks break. You can use the LittleJS particle system designer to create an explosion effect.
|
|
412
412
|
|
|
413
|
-
This will be a one shot type of effect, not a continuous emitter so change emitTime to something small like .1 for this example. Now before you play with it too much, let
|
|
413
|
+
This will be a one shot type of effect, not a continuous emitter so change emitTime to something small like .1 for this example. Now before you play with it too much, let's test it by pasting in the code it generated into the Brick's collideWithObject function.
|
|
414
414
|
|
|
415
415
|
Make sure you replace the first parameter, vec2(), with this.pos so the effect appears wherever the brick is, otherwise it will spawn at the world origin.
|
|
416
416
|
|
|
@@ -419,14 +419,14 @@ Make sure you replace the first parameter, vec2(), with this.pos so the effect a
|
|
|
419
419
|
new LJS.ParticleEmitter(this.pos, 0, 0, 0.1, 100, 3.14, 0, rgb(1, 1, 1, 1), rgb(1, 1, 1, 1), rgb(1, 1, 1, 0), rgb(1, 1, 1, 0), 0.5, 0.1, 1, 0.1, 0.05, 1, 1, 0, 3.14, 0.1, 0.2, 0, 0, 1);
|
|
420
420
|
```
|
|
421
421
|
|
|
422
|
-
Now you should see this simple particle effect play wherever a brick breaks. You can continue tweaking the parameters to make your own effect or use the one I made which also uses this.color to change the particle
|
|
422
|
+
Now you should see this simple particle effect play wherever a brick breaks. You can continue tweaking the parameters to make your own effect or use the one I made which also uses this.color to change the particle's color so it matches the brick.
|
|
423
423
|
|
|
424
424
|
```javascript
|
|
425
425
|
// create explosion effect
|
|
426
426
|
const color = this.color;
|
|
427
427
|
new LJS.ParticleEmitter(
|
|
428
428
|
this.pos, 0, // pos, angle
|
|
429
|
-
this.size, .1, 200, 3.14,// emitSize, emitTime,
|
|
429
|
+
this.size, .1, 200, 3.14,// emitSize, emitTime, rate, cone
|
|
430
430
|
undefined, // tileInfo
|
|
431
431
|
color, color, // colorStartA, colorStartB
|
|
432
432
|
color.scale(1,0), color.scale(1,0), // colorEndA, colorEndB
|
|
@@ -440,7 +440,7 @@ new LJS.ParticleEmitter(
|
|
|
440
440
|
|
|
441
441
|
## Improve the Gameplay
|
|
442
442
|
|
|
443
|
-
Last but certainly not least, let
|
|
443
|
+
Last but certainly not least, let's make a few small improvements to the gameplay. It would help to give the player some more control of where the ball goes when it hits the paddle. We can do this by adding some code to the ball's collideWithObject function.
|
|
444
444
|
|
|
445
445
|
This code will use the rotate function to modify the bounce angle based on the distance from the center of the paddle.
|
|
446
446
|
|
|
@@ -484,7 +484,7 @@ And assign that paddle object when it is created in gameInit.
|
|
|
484
484
|
paddle = new Paddle; // create player's paddle
|
|
485
485
|
```
|
|
486
486
|
|
|
487
|
-
While we are working in the ball
|
|
487
|
+
While we are working in the ball's collideWithObject function, let's also make it speed up a little bit each time it bounces.
|
|
488
488
|
|
|
489
489
|
```javascript
|
|
490
490
|
// speed up the ball
|
|
@@ -494,13 +494,13 @@ this.velocity = this.velocity.normalize(speed);
|
|
|
494
494
|
|
|
495
495
|
## Improve the Sound
|
|
496
496
|
|
|
497
|
-
|
|
497
|
+
Let's make the sound a bit more interesting by using positional audio. This lets the volume and panning be adjusted based on the sound's on screen location. To enable this, just pass a position to the sound's play function.
|
|
498
498
|
|
|
499
499
|
```javascript
|
|
500
500
|
sound_break.play(this.pos); // play brick break sound
|
|
501
501
|
```
|
|
502
502
|
|
|
503
|
-
For the ball bounce sound, let
|
|
503
|
+
For the ball bounce sound, let's also tweak the pitch by how fast the ball is moving. For the sound play function, the second parameter takes a scalar for volume and the third parameter takes a scalar for pitch.
|
|
504
504
|
|
|
505
505
|
```javascript
|
|
506
506
|
sound_bounce.play(this.pos, 1, speed); // play bounce sound with pitch scaled by speed
|
|
@@ -117,7 +117,7 @@ class Brick extends LJS.EngineObject
|
|
|
117
117
|
const color = this.color;
|
|
118
118
|
new LJS.ParticleEmitter(
|
|
119
119
|
this.pos, 0, // pos, angle
|
|
120
|
-
this.size, .1, 200, 3.14,// emitSize, emitTime,
|
|
120
|
+
this.size, .1, 200, 3.14,// emitSize, emitTime, rate, cone
|
|
121
121
|
undefined, // tileInfo
|
|
122
122
|
color, color, // colorStartA, colorStartB
|
|
123
123
|
color.scale(1,0), color.scale(1,0), // colorEndA, colorEndB
|
|
@@ -65,16 +65,16 @@ function gameInit()
|
|
|
65
65
|
// create particle emitter
|
|
66
66
|
particleEmitter = new ParticleEmitter(
|
|
67
67
|
vec2(16,9), 0, // emitPos, emitAngle
|
|
68
|
-
0, 0, 500, PI, // emitSize, emitTime,
|
|
68
|
+
0, 0, 500, PI, // emitSize, emitTime, rate, cone
|
|
69
69
|
tile(0, 16), // tileIndex, tileSize
|
|
70
70
|
hsl(1,1,1), hsl(0,0,0), // colorStartA, colorStartB
|
|
71
71
|
hsl(0,0,0,0), hsl(0,0,0,0), // colorEndA, colorEndB
|
|
72
|
-
|
|
72
|
+
1, .2, .2, .1, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
|
|
73
73
|
.99, 1, 1, PI, // damping, angleDamping, gravityScale, cone
|
|
74
74
|
.05, .5, true, true // fadeRate, randomness, collide, additive
|
|
75
75
|
);
|
|
76
76
|
particleEmitter.restitution = .3; // bounce when it collides
|
|
77
|
-
particleEmitter.trailScale = 2;
|
|
77
|
+
particleEmitter.trailScale = 2; // stretch as it moves
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -86,7 +86,7 @@ function gameUpdate()
|
|
|
86
86
|
sound_click.play(mousePos);
|
|
87
87
|
|
|
88
88
|
// change particle color and set to fade out
|
|
89
|
-
particleEmitter.colorStartA =
|
|
89
|
+
particleEmitter.colorStartA = randColor();
|
|
90
90
|
particleEmitter.colorStartB = randColor();
|
|
91
91
|
particleEmitter.colorEndA = particleEmitter.colorStartA.scale(1,0);
|
|
92
92
|
particleEmitter.colorEndB = particleEmitter.colorStartB.scale(1,0);
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
</head><body>
|
|
8
8
|
|
|
9
9
|
<!-- LittleJS Engine -->
|
|
10
|
-
<script src=../../dist/littlejs.js?
|
|
10
|
+
<script src=../../dist/littlejs.js?11417></script>
|
|
11
11
|
|
|
12
12
|
<!-- Add your game scripts here -->
|
|
13
|
-
<script src=game.js?
|
|
13
|
+
<script src=game.js?11417></script>
|
package/examples/index.html
CHANGED
|
@@ -4,6 +4,17 @@
|
|
|
4
4
|
<link rel=stylesheet href=style.css?9>
|
|
5
5
|
<meta charset=utf-8>
|
|
6
6
|
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
|
|
7
|
+
<!-- meta tags for social media -->
|
|
8
|
+
<meta name='twitter:title' content='LittleJS Example Browser'>
|
|
9
|
+
<meta property='og:title' content='LittleJS Example Browser'>
|
|
10
|
+
<meta name='description' content='Tiny fast HTML5 game engine!'>
|
|
11
|
+
<meta name='twitter:description' content='Tiny fast HTML5 game engine!'>
|
|
12
|
+
<meta property='og:description' content='Tiny fast HTML5 game engine!'>
|
|
13
|
+
<meta name='twitter:image' content='https://3d2k.com/images/LittleJSExamples.png'>
|
|
14
|
+
<meta property='og:image' content='https://3d2k.com/images/LittleJSExamples.png'>
|
|
15
|
+
<meta name='keywords' content='JavaScript, HTML5, Game, Engine'>
|
|
16
|
+
<meta name='twitter:creator' content='@KilledByAPixel'>
|
|
17
|
+
<meta name='twitter:card' content='summary_large_image'>
|
|
7
18
|
</head><body>
|
|
8
19
|
<div id=container1>
|
|
9
20
|
<div id=container3>
|
|
@@ -21,8 +32,7 @@ Theme:
|
|
|
21
32
|
<option value=20px>L</option>
|
|
22
33
|
<option value=24px>XL</option>
|
|
23
34
|
</select>
|
|
24
|
-
<span class=nowrap><input type=checkbox id=checkboxLiveEdit checked>Live Edit</span>
|
|
25
|
-
<span class=nowrap><input type=checkbox id=checkboxJumpToErrors>Jump to Errors</span>
|
|
35
|
+
<span class=nowrap><input type=checkbox id=checkboxLiveEdit onchange=writeSaveData() checked>Live Edit</span>
|
|
26
36
|
</div>
|
|
27
37
|
<div id=divTextareas>
|
|
28
38
|
<textarea id=textareaCode oninput=codeInput() spellcheck=false></textarea>
|
|
@@ -75,7 +85,8 @@ class ExampleInfo
|
|
|
75
85
|
const exampleList =
|
|
76
86
|
[
|
|
77
87
|
new ExampleInfo('--- SHORT EXAMPLES ---'),
|
|
78
|
-
new ExampleInfo('Hello World', 'helloWorld.js', '
|
|
88
|
+
new ExampleInfo('Hello World', 'helloWorld.js', 'Simple starter example', false, 'beginner, gradient, text, tiles'),
|
|
89
|
+
new ExampleInfo('Empty', 'empty.js', 'Empty example template', false, 'beginner, text'),
|
|
79
90
|
new ExampleInfo('Texture', 'texture.js', 'Texture display and manipulation', false, 'sprites, loading, tiles'),
|
|
80
91
|
new ExampleInfo('Animation', 'animation.js', 'Sprite animation system', false, 'frames, loop, tiles, sprites'),
|
|
81
92
|
new ExampleInfo('Shapes', 'shapes.js', 'Draw geometric shapes and primitives', false, 'circle, ellipses, rectangles, polygon, lines'),
|
|
@@ -87,13 +98,16 @@ const exampleList =
|
|
|
87
98
|
new ExampleInfo('Particles', 'particles.js', 'Particle system', false, 'effects, emitter, physics, fire, smoke'),
|
|
88
99
|
new ExampleInfo('Timers', 'timers.js', 'Timer objects and UI', false, 'delay, interval, slider'),
|
|
89
100
|
new ExampleInfo('Sound Effects', 'sound.js', 'ZzFX sound effect generator', false, 'audio, volume, ui'),
|
|
90
|
-
new ExampleInfo('Music', 'music.js', '
|
|
101
|
+
new ExampleInfo('Music', 'music.js', 'Basic music load, play, pause, and stop', false, 'music, sound, audio, streaming, volume, ui'),
|
|
91
102
|
new ExampleInfo('Font Image', 'systemFont.js', 'Bitmap font system with built-in system font', false, 'text, characters'),
|
|
92
103
|
new ExampleInfo('Parallax', 'parallax.js', 'Parallax scrolling mountains', false, 'generative, canvas, background'),
|
|
93
104
|
new ExampleInfo('Maze Generator', 'maze.js', 'Procedural maze generation', false, 'generative, level, tiles, map, grid'),
|
|
94
105
|
new ExampleInfo('Medals', 'medals.js', 'Achievement system', false, 'unlock, progress, newgrounds'),
|
|
95
|
-
new ExampleInfo('Piano', 'piano.js', 'Interactive piano keyboard', false, 'music, notes, ui, instrument'),
|
|
96
106
|
new ExampleInfo('Clock', 'clock.js', 'Animated analog clock', false, 'time, rotation, lines, rectangles'),
|
|
107
|
+
new ExampleInfo('Piano', 'piano.js', 'Interactive piano keyboard', false, 'music, sound, audio, notes, ui, instrument'),
|
|
108
|
+
new ExampleInfo('Step Sequencer', 'sequencer.js', 'Simple music loop creation tool', false, 'music, sound, audio, notes, ui, instrument'),
|
|
109
|
+
new ExampleInfo('Music Player', 'musicPlayer.js', 'Advanced music player with audio seeking and drag and drop', false, 'music, sound, audio, streaming, volume, ui'),
|
|
110
|
+
new ExampleInfo('WebGL Shader', 'shader.js', 'Full canvas webgl shader', false, 'webgl, visual, effect'),
|
|
97
111
|
new ExampleInfo('--- MINI GAMES ---'),
|
|
98
112
|
new ExampleInfo('Pong Game', 'pongGame.js', 'Classic paddle ball bouncing', false, 'objects, collision'),
|
|
99
113
|
new ExampleInfo('Platformer Game', 'platformer.js', 'Jump and run side view', false, 'objects, gravity, level, tiles, camera'),
|
|
@@ -138,7 +152,7 @@ function initExampleBrowser()
|
|
|
138
152
|
// set the selected example from the URL parameters
|
|
139
153
|
const urlParams = new URLSearchParams(window.location.search);
|
|
140
154
|
const selectedExample = urlParams.get('example') || '';
|
|
141
|
-
let exampleIndex = exampleList.findIndex((example) => example.
|
|
155
|
+
let exampleIndex = exampleList.findIndex((example) => example.name === selectedExample);
|
|
142
156
|
if (exampleIndex < 0)
|
|
143
157
|
exampleIndex = 1;
|
|
144
158
|
selectExample.selectedIndex = exampleIndex;
|
|
@@ -233,11 +247,11 @@ function setExample()
|
|
|
233
247
|
exampleInfo.innerText = example.text;
|
|
234
248
|
const filename = 'examples/' + example.filename;
|
|
235
249
|
exampleLink.href = 'https://github.com/KilledByAPixel/LittleJS/tree/main/' + filename;
|
|
236
|
-
exampleLink.innerText = 'View
|
|
250
|
+
exampleLink.innerText = 'View on GitHub: ' + example.filename;
|
|
237
251
|
|
|
238
252
|
// update URL parameter
|
|
239
253
|
const url = new URL(window.location);
|
|
240
|
-
url.searchParams.set('example', example.
|
|
254
|
+
url.searchParams.set('example', example.name);
|
|
241
255
|
window.history.replaceState({}, '', url);
|
|
242
256
|
|
|
243
257
|
loadFile(example.filename, example.largeExample);
|
|
@@ -522,13 +536,13 @@ function setCode(code, filename)
|
|
|
522
536
|
iframeContent.engineInit(iframeContent.gameInit, iframeContent.gameUpdate, iframeContent.gameUpdatePost, iframeContent.gameRender, iframeContent.gameRenderPost, ['tiles.png?'+Date.now()])
|
|
523
537
|
.catch(error =>
|
|
524
538
|
{
|
|
525
|
-
const errorLine = getErrorLine(error.stack);
|
|
539
|
+
const errorLine = error ? getErrorLine(error.stack) : -1;
|
|
526
540
|
if (errorLine >= 0)
|
|
527
541
|
setErrorLine(errorLine);
|
|
528
542
|
let message = error;
|
|
529
|
-
if (error.message)
|
|
543
|
+
if (error && error.message)
|
|
530
544
|
message = error.message;
|
|
531
|
-
if (error.stack)
|
|
545
|
+
if (error && error.stack)
|
|
532
546
|
message += '\n' + error.stack;
|
|
533
547
|
setErrorMessage(message);
|
|
534
548
|
throw error;
|
|
@@ -613,35 +627,6 @@ function setErrorLine(lineNumber)
|
|
|
613
627
|
clearErrorLine();
|
|
614
628
|
--lineNumber; // codeMirror uses 0-based line numbers
|
|
615
629
|
errorLineMarker = codeMirror.getDoc().addLineClass(lineNumber, 'background', 'error-line');
|
|
616
|
-
if (checkboxJumpToErrors.checked)
|
|
617
|
-
{
|
|
618
|
-
codeMirror.scrollIntoView({line: lineNumber, ch: 0});
|
|
619
|
-
codeMirror.focus();
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
else if (textareaCode && checkboxJumpToErrors.checked)
|
|
623
|
-
{
|
|
624
|
-
// for textarea, calculate character position and set cursor
|
|
625
|
-
const lines = textareaCode.value.split('\n');
|
|
626
|
-
let charPos = 0;
|
|
627
|
-
for (let i = 0; i < lineNumber - 1 && i < lines.length; i++)
|
|
628
|
-
{
|
|
629
|
-
charPos += lines[i].length + 1; // +1 for newline character
|
|
630
|
-
}
|
|
631
|
-
textareaCode.setSelectionRange(charPos, charPos);
|
|
632
|
-
if (checkboxJumpToErrors.checked)
|
|
633
|
-
{
|
|
634
|
-
const line = textareaCode.value.split('\n');
|
|
635
|
-
lineNumber = Math.min(Math.max(0, lineNumber-1), lines.length-1);
|
|
636
|
-
|
|
637
|
-
// select error line in textarea
|
|
638
|
-
let start = 0;
|
|
639
|
-
for (let i = 0; i < lineNumber; i++)
|
|
640
|
-
start += lines[i].length + 1;
|
|
641
|
-
textareaCode.selectionStart = start;
|
|
642
|
-
textareaCode.selectionEnd = start + lines[lineNumber].length;
|
|
643
|
-
textareaCode.focus();
|
|
644
|
-
}
|
|
645
630
|
}
|
|
646
631
|
}
|
|
647
632
|
|
|
@@ -666,13 +651,41 @@ textareaConsole.addEventListener('scroll', onScrollConsole);
|
|
|
666
651
|
|
|
667
652
|
///////////////////////////////////////////////////////////////////////////////
|
|
668
653
|
// load saved preferences from localStorage
|
|
669
|
-
const
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
654
|
+
const saveName = 'LittleJSExamples';
|
|
655
|
+
let savedTheme;
|
|
656
|
+
|
|
657
|
+
function readSaveData()
|
|
658
|
+
{
|
|
659
|
+
// load saved preferences
|
|
660
|
+
const defaultTheme = 'littlejs';
|
|
661
|
+
const defaultFontSize = '16px';
|
|
662
|
+
const saveDataJSON = localStorage.getItem(saveName);
|
|
663
|
+
const saveData = saveDataJSON ? JSON.parse(saveDataJSON) : {};
|
|
664
|
+
selectTheme.value = savedTheme = saveData.theme ?? defaultTheme;
|
|
665
|
+
selectFontSize.value = saveData.fontSize ?? defaultFontSize;
|
|
666
|
+
}
|
|
667
|
+
readSaveData();
|
|
668
|
+
|
|
669
|
+
function writeSaveData()
|
|
670
|
+
{
|
|
671
|
+
// Save preferences to localStorage
|
|
672
|
+
const theme = selectTheme.value;
|
|
673
|
+
const fontSize = selectFontSize.value;
|
|
674
|
+
const saveData =
|
|
675
|
+
{
|
|
676
|
+
theme,
|
|
677
|
+
fontSize
|
|
678
|
+
};
|
|
679
|
+
const saveDataJSON = JSON.stringify(saveData);
|
|
680
|
+
localStorage.setItem(saveName, saveDataJSON);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
function resetDefaults()
|
|
684
|
+
{
|
|
685
|
+
localStorage.removeItem(saveName);
|
|
686
|
+
readSaveData();
|
|
687
|
+
loadTheme();
|
|
688
|
+
}
|
|
676
689
|
|
|
677
690
|
///////////////////////////////////////////////////////////////////////////////
|
|
678
691
|
// setup code mirror
|
|
@@ -750,20 +763,18 @@ function addCodeMirrorElement(filename, type, rel)
|
|
|
750
763
|
|
|
751
764
|
function loadTheme()
|
|
752
765
|
{
|
|
753
|
-
const theme = selectTheme.value;
|
|
754
|
-
const size = selectFontSize.value;
|
|
755
|
-
|
|
756
|
-
// Save preferences to localStorage
|
|
757
|
-
localStorage.setItem(savePrefix+'theme', theme);
|
|
758
|
-
localStorage.setItem(savePrefix+'fontSize', size);
|
|
759
|
-
|
|
760
766
|
// Apply the theme and font size
|
|
761
|
-
|
|
767
|
+
const theme = selectTheme.value;
|
|
768
|
+
const fontSize = selectFontSize.value;
|
|
769
|
+
textareaCode.style.fontSize = fontSize;
|
|
762
770
|
if (codeMirror)
|
|
763
771
|
{
|
|
764
|
-
codeMirror.getWrapperElement().style.fontSize =
|
|
772
|
+
codeMirror.getWrapperElement().style.fontSize = fontSize;
|
|
765
773
|
codeMirror.setOption('theme', theme);
|
|
766
774
|
}
|
|
775
|
+
|
|
776
|
+
// Save preferences to localStorage
|
|
777
|
+
writeSaveData();
|
|
767
778
|
}
|
|
768
779
|
|
|
769
780
|
///////////////////////////////////////////////////////////////////////////////
|