littlejsengine 1.14.10 → 1.14.16
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 +264 -120
- package/dist/littlejs.esm.js +603 -288
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +600 -287
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +521 -232
- package/examples/box2d/gameObjects.js +2 -2
- 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 +3 -3
- package/examples/electron/index.html +2 -2
- package/examples/electron/package.json +1 -8
- package/examples/index.html +59 -51
- package/examples/module/game.js +3 -3
- package/examples/platformer/gameCharacter.js +6 -2
- package/examples/platformer/gameEffects.js +4 -4
- package/examples/platformer/gameLevel.js +1 -1
- package/examples/platformer/gameObjects.js +11 -9
- 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 +30 -3
- package/examples/shorts/medals.js +4 -4
- package/examples/shorts/music.js +29 -55
- package/examples/shorts/musicPlayer.js +134 -0
- package/examples/shorts/nineSlice.js +34 -15
- package/examples/shorts/parallax.js +4 -3
- package/examples/shorts/particles.js +16 -16
- package/examples/shorts/piano.js +15 -21
- package/examples/shorts/pongGame.js +6 -4
- package/examples/shorts/raycasting.js +13 -5
- package/examples/shorts/sequencer.js +122 -0
- package/examples/shorts/shapes.js +7 -4
- package/examples/shorts/slidingPuzzle.js +16 -6
- 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 +14 -3
- 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 +3 -3
- package/examples/starter/index.html +2 -2
- package/examples/typescript/game.js +3 -3
- package/examples/typescript/game.ts +3 -3
- package/examples/uiSystem/game.js +6 -6
- package/package.json +4 -2
- package/plugins/box2d.js +18 -3
- package/plugins/newgrounds.js +11 -9
- package/plugins/postProcess.js +5 -2
- package/plugins/uiSystem.js +120 -34
- package/plugins/zzfxm.js +5 -1
- package/reference.md +1 -3
- package/src/engine.js +52 -21
- package/src/engineAudio.js +31 -14
- package/src/engineDebug.js +80 -55
- package/src/engineDraw.js +60 -31
- package/src/engineExport.js +3 -1
- package/src/engineMedals.js +10 -2
- package/src/engineObject.js +14 -10
- package/src/engineParticles.js +59 -46
- package/src/engineRelease.js +1 -0
- package/src/engineSettings.js +7 -7
- package/src/engineTileLayer.js +49 -18
- package/src/engineUtilities.js +79 -34
|
@@ -50,7 +50,7 @@ function loadLevelData()
|
|
|
50
50
|
{
|
|
51
51
|
// load the level data
|
|
52
52
|
const tileMapData = Game.gameLevelData;
|
|
53
|
-
tileLayers = LJS.
|
|
53
|
+
tileLayers = LJS.tileLayersLoad(tileMapData, tile(0,16,1), 0, 1);
|
|
54
54
|
levelSize = tileLayers[0].size;
|
|
55
55
|
playerStartPos = vec2(0, levelSize.y); // default player start
|
|
56
56
|
foregroundTileLayer = tileLayers[0];
|
|
@@ -101,10 +101,14 @@ export class Coin extends LJS.EngineObject
|
|
|
101
101
|
|
|
102
102
|
render()
|
|
103
103
|
{
|
|
104
|
+
// side of coin
|
|
105
|
+
LJS.drawTile(this.pos, vec2(.1, .6), 0, this.color);
|
|
106
|
+
|
|
104
107
|
// make it appear to spin
|
|
105
108
|
const t = LJS.time+this.pos.x/4+this.pos.y/4;
|
|
106
|
-
|
|
107
|
-
|
|
109
|
+
const spinSize = vec2(.5+.5*Math.sin(t*2*LJS.PI), 1);
|
|
110
|
+
if (spinSize.x > .1)
|
|
111
|
+
LJS.drawTile(this.pos, spinSize, this.tileInfo, this.color);
|
|
108
112
|
}
|
|
109
113
|
|
|
110
114
|
update()
|
|
@@ -227,7 +231,7 @@ export class Grenade extends GameObject
|
|
|
227
231
|
|
|
228
232
|
export class Weapon extends LJS.EngineObject
|
|
229
233
|
{
|
|
230
|
-
constructor(pos
|
|
234
|
+
constructor(pos)
|
|
231
235
|
{
|
|
232
236
|
super(pos, vec2(.6), Game.spriteAtlas.gun);
|
|
233
237
|
|
|
@@ -238,20 +242,18 @@ export class Weapon extends LJS.EngineObject
|
|
|
238
242
|
this.damage = 1;
|
|
239
243
|
|
|
240
244
|
// prepare to fire
|
|
241
|
-
this.renderOrder = parent.renderOrder + 1;
|
|
242
245
|
this.fireTimeBuffer = this.localAngle = 0;
|
|
243
246
|
this.recoilTimer = new Timer;
|
|
244
|
-
parent.addChild(this, vec2(.6,0));
|
|
245
247
|
|
|
246
248
|
// shell effect
|
|
247
249
|
this.addChild(this.shellEmitter = new LJS.ParticleEmitter(
|
|
248
|
-
vec2(), 0, 0, 0, 0, .1, // pos, angle,
|
|
250
|
+
vec2(), 0, 0, 0, 0, .1, // pos, angle, size, time, rate, cone
|
|
249
251
|
0, // tileInfo
|
|
250
252
|
rgb(1,.8,.5), rgb(.9,.7,.5), // colorStartA, colorStartB
|
|
251
253
|
rgb(1,.8,.5), rgb(.9,.7,.5), // colorEndA, colorEndB
|
|
252
254
|
3, .1, .1, .15, .1, // time, sizeStart, sizeEnd, speed, angleSpeed
|
|
253
255
|
1, .95, 1, 0, 0, // damp, angleDamp, gravity, particleCone, fade
|
|
254
|
-
.1, 1 // randomness, collide
|
|
256
|
+
.1, 1 // randomness, collide
|
|
255
257
|
), vec2(.1,0), -.8);
|
|
256
258
|
this.shellEmitter.restitution = .5;
|
|
257
259
|
this.shellEmitter.particleDestroyCallback = GameEffects.persistentParticleDestroyCallback;
|
|
@@ -366,13 +368,13 @@ export class Bullet extends LJS.EngineObject
|
|
|
366
368
|
|
|
367
369
|
// spark effects
|
|
368
370
|
const emitter = new LJS.ParticleEmitter(
|
|
369
|
-
this.pos, 0, 0, .1, 100, .5, // pos, angle,
|
|
371
|
+
this.pos, 0, 0, .1, 100, .5, // pos, angle, size, time, rate, cone
|
|
370
372
|
0, // tileInfo
|
|
371
373
|
rgb(1,1,0), rgb(1,0,0), // colorStartA, colorStartB
|
|
372
374
|
rgb(1,1,0), rgb(1,0,0), // colorEndA, colorEndB
|
|
373
375
|
.2, .2, 0, .1, .1, // time, sizeStart, sizeEnd, speed, angleSpeed
|
|
374
376
|
1, 1, .5, 3.14, .1, // damp, angleDamp, gravityScale, particleCone, fade,
|
|
375
|
-
.5, 1, 1 // randomness, collide, additive
|
|
377
|
+
.5, 1, 1 // randomness, collide, additive
|
|
376
378
|
);
|
|
377
379
|
emitter.trailScale = 1;
|
|
378
380
|
emitter.restitution = .3;
|
package/examples/puzzle/game.js
CHANGED
|
@@ -309,7 +309,7 @@ function clearMatches()
|
|
|
309
309
|
const color2 = color1.lerp(hsl(), .5);
|
|
310
310
|
new LJS.ParticleEmitter(
|
|
311
311
|
pos.add(vec2(.5)), 0, // pos, angle
|
|
312
|
-
.5, .1, 200, 3.14, // emitSize, emitTime,
|
|
312
|
+
.5, .1, 200, 3.14, // emitSize, emitTime, rate, cone
|
|
313
313
|
0, // tileInfo
|
|
314
314
|
color1, color2, // colorStartA, colorStartB
|
|
315
315
|
color1.scale(1,0), color2.scale(1,0),// colorEndA, colorEndB
|
|
@@ -1,20 +1,14 @@
|
|
|
1
|
-
// use smooth blending
|
|
2
|
-
setCanvasPixelated(false);
|
|
3
|
-
setTilesPixelated(false);
|
|
4
|
-
|
|
5
1
|
function gameRender()
|
|
6
2
|
{
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
// additive blend
|
|
3
|
+
// additive blending
|
|
10
4
|
setBlendMode(1);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
drawCircle(vec2(-8,-2), 7, rgb(0,0,.5));
|
|
6
|
+
drawCircle(vec2(-6, 2), 7, rgb(0,1,0));
|
|
7
|
+
drawCircle(vec2(-4,-2), 7, rgb(1,0,0));
|
|
14
8
|
|
|
15
|
-
// alpha
|
|
9
|
+
// alpha blending
|
|
16
10
|
setBlendMode(0);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
drawCircle(vec2(4,-2), 7, hsl(time/9 ,1,.5));
|
|
12
|
+
drawCircle(vec2(8,-2), 7, hsl(time/9+1/3,1,.5,.5));
|
|
13
|
+
drawCircle(vec2(6, 2), 7, hsl(time/9+2/3,1,.5,.5));
|
|
20
14
|
}
|
package/examples/shorts/box2d.js
CHANGED
|
@@ -7,13 +7,16 @@ async function gameInit()
|
|
|
7
7
|
canvasClearColor = hsl(0,0,.9);
|
|
8
8
|
|
|
9
9
|
// create ground object
|
|
10
|
-
groundObject = new Box2dObject(vec2(-8), vec2(), 0, 0,
|
|
10
|
+
groundObject = new Box2dObject(vec2(-8), vec2(), 0, 0,
|
|
11
|
+
GRAY, box2d.bodyTypeStatic);
|
|
11
12
|
groundObject.addBox(vec2(100,2));
|
|
12
13
|
|
|
13
14
|
// add some random objects
|
|
14
15
|
for (let i=50; i--;)
|
|
15
16
|
{
|
|
16
|
-
const
|
|
17
|
+
const pos = randInCircle(5);
|
|
18
|
+
const color = randColor();
|
|
19
|
+
const o = new Box2dObject(pos, vec2(), 0, 0, color);
|
|
17
20
|
randInt(2) ? o.addCircle(rand(1,2)) : o.addRandomPoly(rand(1,2));
|
|
18
21
|
}
|
|
19
22
|
}
|
|
@@ -36,7 +39,8 @@ function gameUpdate()
|
|
|
36
39
|
// grab object
|
|
37
40
|
const object = box2d.pointCast(mousePos);
|
|
38
41
|
if (object)
|
|
39
|
-
mouseJoint = new Box2dTargetJoint(object,
|
|
42
|
+
mouseJoint = new Box2dTargetJoint(object,
|
|
43
|
+
groundObject, mousePos);
|
|
40
44
|
}
|
|
41
45
|
}
|
|
42
46
|
|
|
@@ -3,7 +3,8 @@ async function gameInit()
|
|
|
3
3
|
// setup box2d and create the objects
|
|
4
4
|
await box2dInit();
|
|
5
5
|
gravity.y = -20;
|
|
6
|
-
groundObject = new Box2dObject(vec2(-8), vec2(), 0, 0,
|
|
6
|
+
groundObject = new Box2dObject(vec2(-8), vec2(), 0, 0,
|
|
7
|
+
GRAY, box2d.bodyTypeStatic);
|
|
7
8
|
groundObject.addBox(vec2(100,6));
|
|
8
9
|
new CarObject(vec2(0,-2));
|
|
9
10
|
canvasClearColor = hsl(0,0,.9);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
function gameInit()
|
|
2
|
+
{
|
|
3
|
+
// called once after the engine starts up
|
|
4
|
+
// setup the game
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function gameUpdate()
|
|
8
|
+
{
|
|
9
|
+
// called every frame at 60 frames per second
|
|
10
|
+
// handle input and update the game state
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function gameUpdatePost()
|
|
14
|
+
{
|
|
15
|
+
// called after physics and objects are updated
|
|
16
|
+
// setup camera and prepare for render
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function gameRender()
|
|
20
|
+
{
|
|
21
|
+
// called before objects are rendered
|
|
22
|
+
// draw any background effects that appear behind objects
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function gameRenderPost()
|
|
26
|
+
{
|
|
27
|
+
// called after objects are rendered
|
|
28
|
+
// draw effects or hud that appear above all objects
|
|
29
|
+
drawTextScreen('LittleJS Engine', mainCanvasSize.scale(.5), 80);
|
|
30
|
+
}
|
|
@@ -4,7 +4,7 @@ function gameRender()
|
|
|
4
4
|
drawRectGradient(cameraPos, getCameraSize(), BLACK, WHITE);
|
|
5
5
|
|
|
6
6
|
// draw text to the overlay canvas
|
|
7
|
-
drawTextOverlay('
|
|
7
|
+
drawTextOverlay('LittleJS Engine', vec2(0,3), 3);
|
|
8
8
|
|
|
9
9
|
// draw a tile
|
|
10
10
|
drawTile(vec2(Math.sin(time)*3,-2), vec2(7), tile(3,128));
|
|
@@ -2,7 +2,7 @@ class Player extends EngineObject
|
|
|
2
2
|
{
|
|
3
3
|
constructor(pos)
|
|
4
4
|
{
|
|
5
|
-
super(pos, vec2(2), tile(9), 0,
|
|
5
|
+
super(pos, vec2(2), tile(9), 0, RED);
|
|
6
6
|
this.damping = 1; // disable damping
|
|
7
7
|
this.clampSpeed = false; // disable speed clamping
|
|
8
8
|
}
|
|
@@ -11,12 +11,14 @@ class Player extends EngineObject
|
|
|
11
11
|
{
|
|
12
12
|
super.update();
|
|
13
13
|
|
|
14
|
+
// check ground height
|
|
14
15
|
const h = getGroundHeight(this.pos.x);
|
|
15
16
|
if (this.pos.y < h + this.size.y/2)
|
|
16
17
|
{
|
|
17
18
|
// clamp to ground and reflect velocity
|
|
18
19
|
this.pos.y = h + this.size.y/2;
|
|
19
|
-
const
|
|
20
|
+
const h2 = getGroundHeight(this.pos.x+.1);
|
|
21
|
+
const n = vec2((h-h2)/.1, 1).normalize();
|
|
20
22
|
this.velocity = this.velocity.reflect(n,0);
|
|
21
23
|
}
|
|
22
24
|
|
|
@@ -40,13 +42,17 @@ function gameInit()
|
|
|
40
42
|
{
|
|
41
43
|
gravity.y = -.01;
|
|
42
44
|
new Player(vec2(0,5));
|
|
43
|
-
canvasClearColor = hsl(.
|
|
45
|
+
canvasClearColor = hsl(.6,1,.8);
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
function gameRender()
|
|
47
49
|
{
|
|
50
|
+
// draw ground as a series of thin rectangles
|
|
48
51
|
const h = 100, w = 20;
|
|
49
|
-
const pos = vec2()
|
|
52
|
+
const pos = vec2();
|
|
53
|
+
const sizeTop = vec2(.4);
|
|
54
|
+
const size = vec2(.2,h);
|
|
55
|
+
const color = rgb();
|
|
50
56
|
for (let x=cameraPos.x-w; x<cameraPos.x+w; x+=.1)
|
|
51
57
|
{
|
|
52
58
|
pos.x = x;
|
|
@@ -4,14 +4,39 @@ class Player extends EngineObject
|
|
|
4
4
|
{
|
|
5
5
|
super(pos, vec2(1,2), tile(8), 0, RED);
|
|
6
6
|
this.setCollision(); // make object collide
|
|
7
|
+
this.angleDamping = .95;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
update()
|
|
10
11
|
{
|
|
11
12
|
super.update();
|
|
13
|
+
|
|
14
|
+
// space ship controls
|
|
15
|
+
const moveInput = keyDirection();
|
|
16
|
+
this.applyAngularAcceleration(moveInput.x * .002);
|
|
17
|
+
const accel = vec2(0, moveInput.y*.002).rotate(this.angle);
|
|
18
|
+
this.applyAcceleration(accel);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// explode when it collides
|
|
22
|
+
collideWithObject()
|
|
23
|
+
{
|
|
24
|
+
// don't explode if player is almost still and not tilted
|
|
25
|
+
if (abs(this.angle) < .2)
|
|
26
|
+
if (this.velocity.length() < .05)
|
|
27
|
+
return true;
|
|
12
28
|
|
|
13
|
-
//
|
|
14
|
-
this.
|
|
29
|
+
// explode!
|
|
30
|
+
this.destroy();
|
|
31
|
+
new ParticleEmitter(
|
|
32
|
+
this.pos, 0, // pos, angle
|
|
33
|
+
1, .1, 300, 3.14, 0, // emitSize, emitTime, rate, cone, tile
|
|
34
|
+
rgb(1,.5,.1), rgb(1,.1,.1), // colorStartA, colorStartB
|
|
35
|
+
rgb(1,.5,.1,0), rgb(1,.1,.1,0), // colorEndA, colorEndB
|
|
36
|
+
.7, .8, .2, .2, .05, // time, start, end, speed, angleSpeed
|
|
37
|
+
.9, 1, -.2, 3.14, .05, // damp, angleDamp, gravity, cone, fade
|
|
38
|
+
1, 0, 1 // randomness, collide, additive
|
|
39
|
+
);
|
|
15
40
|
}
|
|
16
41
|
}
|
|
17
42
|
|
|
@@ -25,7 +50,9 @@ function gameInit()
|
|
|
25
50
|
for (let i=0, y=0; i<20; ++i)
|
|
26
51
|
{
|
|
27
52
|
y = (y + rand(1,-1)*4) * .5;
|
|
28
|
-
const
|
|
53
|
+
const pos = vec2(i*2-20, y-54);
|
|
54
|
+
const color = hsl(0, 0, .5+i%.29);
|
|
55
|
+
const o = new EngineObject(pos, vec2(2, 99), 0, 0, color);
|
|
29
56
|
o.setCollision(); // make object collide
|
|
30
57
|
o.mass = 0; // make object have static physics
|
|
31
58
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// create example medals
|
|
2
|
-
const medal_openedExample = new Medal(0, '
|
|
3
|
-
const medal_leftClick
|
|
4
|
-
const medal_rightClick
|
|
5
|
-
const medal_spacePressed
|
|
2
|
+
const medal_openedExample = new Medal(0, 'Open', 'Opened this example!');
|
|
3
|
+
const medal_leftClick = new Medal(1, 'Lefty', 'Left clicked!', '🐁');
|
|
4
|
+
const medal_rightClick = new Medal(2, 'Righty', 'Right clicked!', '🐭');
|
|
5
|
+
const medal_spacePressed = new Medal(3, 'Space', 'Pressed spacebar!', '🚀');
|
|
6
6
|
|
|
7
7
|
// setup medals
|
|
8
8
|
const saveName = 'Medals Example';
|
package/examples/shorts/music.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
let playButton, stopButton,
|
|
1
|
+
let musicPlayer, playButton, stopButton, infoText;
|
|
2
2
|
let musicSound = new SoundWave('song.mp3');
|
|
3
3
|
let musicVolume = 1;
|
|
4
|
-
let
|
|
4
|
+
let music;
|
|
5
5
|
|
|
6
6
|
function gameInit()
|
|
7
7
|
{
|
|
@@ -10,27 +10,28 @@ function gameInit()
|
|
|
10
10
|
uiSystem.defaultSoundPress = new Sound([.5,0,220]);
|
|
11
11
|
uiSystem.defaultSoundClick = new Sound([.5,0,440]);
|
|
12
12
|
uiSystem.defaultCornerRadius = 20;
|
|
13
|
-
canvasClearColor = hsl(.9,.3,.2);
|
|
13
|
+
canvasClearColor = hsl(.9,.3,.2);
|
|
14
14
|
|
|
15
15
|
// setup music player UI
|
|
16
|
-
|
|
16
|
+
musicPlayer = new UIObject(mainCanvasSize.scale(.5), vec2(500, 220));
|
|
17
17
|
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
musicPlayer.addChild(
|
|
18
|
+
// infomation text
|
|
19
|
+
infoText = new UIText(vec2(0, -70), vec2(400, 50));
|
|
20
|
+
musicPlayer.addChild(infoText);
|
|
21
21
|
|
|
22
22
|
// volume slider
|
|
23
|
-
const volumeSlider = new UIScrollbar(vec2(0, -
|
|
23
|
+
const volumeSlider = new UIScrollbar(vec2(0, -20), vec2(400, 30),
|
|
24
|
+
musicVolume, 'Music Volume');
|
|
24
25
|
musicPlayer.addChild(volumeSlider);
|
|
25
26
|
volumeSlider.onChange = () =>
|
|
26
27
|
{
|
|
27
28
|
musicVolume = volumeSlider.value;
|
|
28
|
-
if (
|
|
29
|
-
|
|
29
|
+
if (music)
|
|
30
|
+
music.setVolume(musicVolume);
|
|
30
31
|
};
|
|
31
32
|
|
|
32
33
|
// play button
|
|
33
|
-
playButton = new UIButton(vec2(-90,
|
|
34
|
+
playButton = new UIButton(vec2(-90, 50), vec2(140, 50), 'Play');
|
|
34
35
|
musicPlayer.addChild(playButton);
|
|
35
36
|
playButton.onClick = ()=>
|
|
36
37
|
{
|
|
@@ -38,67 +39,40 @@ function gameInit()
|
|
|
38
39
|
return;
|
|
39
40
|
|
|
40
41
|
// handle play/pause toggle
|
|
41
|
-
if (!
|
|
42
|
-
|
|
43
|
-
else if (
|
|
44
|
-
|
|
42
|
+
if (!music)
|
|
43
|
+
music = musicSound.playMusic(musicVolume);
|
|
44
|
+
else if (music.isPaused())
|
|
45
|
+
music.resume();
|
|
45
46
|
else
|
|
46
|
-
|
|
47
|
+
music.pause();
|
|
47
48
|
};
|
|
48
49
|
|
|
49
50
|
// stop button
|
|
50
|
-
stopButton = new UIButton(vec2(90,
|
|
51
|
+
stopButton = new UIButton(vec2(90, 50), vec2(140, 50), 'Stop');
|
|
52
|
+
stopButton.onClick = ()=> music && music.stop();
|
|
51
53
|
musicPlayer.addChild(stopButton);
|
|
52
|
-
stopButton.onClick = ()=>
|
|
53
|
-
{
|
|
54
|
-
if (!musicInstance)
|
|
55
|
-
return;
|
|
56
|
-
|
|
57
|
-
// stop sound
|
|
58
|
-
musicInstance.stop();
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
// progress bar and scrollbar for seeking
|
|
62
|
-
progressBar = new UIScrollbar(vec2(0, 100), vec2(400, 30), 0, 'Progress');
|
|
63
|
-
musicPlayer.addChild(progressBar);
|
|
64
|
-
progressBar.onChange = ()=>
|
|
65
|
-
{
|
|
66
|
-
// control music seek position
|
|
67
|
-
const wasPlaying = musicInstance && musicInstance.isPlaying();
|
|
68
|
-
if (!musicInstance)
|
|
69
|
-
musicInstance = musicSound.playMusic(musicVolume, true, true);
|
|
70
|
-
progressBar.value = min(progressBar.value, .999); // prevent looping around
|
|
71
|
-
const seekTime = progressBar.value * musicSound.getDuration();
|
|
72
|
-
musicInstance.start(seekTime);
|
|
73
|
-
if (!wasPlaying)
|
|
74
|
-
musicInstance.pause();
|
|
75
|
-
};
|
|
76
54
|
}
|
|
77
55
|
|
|
78
56
|
function gameUpdate()
|
|
79
57
|
{
|
|
80
|
-
// disable buttons while loading
|
|
81
|
-
const isDisabled = !musicSound.isLoaded()
|
|
82
|
-
playButton.disabled
|
|
83
|
-
stopButton.disabled = isDisabled
|
|
84
|
-
progressBar.disabled = isDisabled
|
|
58
|
+
// disable buttons while loading
|
|
59
|
+
const isDisabled = !musicSound.isLoaded();
|
|
60
|
+
playButton.disabled = stopButton.disabled = isDisabled;
|
|
85
61
|
|
|
86
62
|
// update ui
|
|
87
|
-
if (
|
|
63
|
+
if (isDisabled)
|
|
88
64
|
{
|
|
89
65
|
// update loading progress
|
|
90
|
-
const loadingPercent = musicSound.loadedPercent * 100;
|
|
91
|
-
|
|
66
|
+
const loadingPercent = musicSound.loadedPercent * 100|0;
|
|
67
|
+
infoText.text = `Loading: ${loadingPercent}%`;
|
|
92
68
|
}
|
|
93
69
|
else
|
|
94
70
|
{
|
|
95
71
|
// update ui text
|
|
96
|
-
|
|
97
|
-
|
|
72
|
+
const isPlaying = music && music.isPlaying();
|
|
73
|
+
playButton.text = isPlaying ? 'Pause' : 'Play';
|
|
74
|
+
const current = music ? music.getCurrentTime() : 0;
|
|
98
75
|
const duration = musicSound.getDuration();
|
|
99
|
-
|
|
100
|
-
progressBar.value = currentTime / duration;
|
|
101
|
-
const timeText = `${formatTime(currentTime)} / ${formatTime(duration)}`;
|
|
102
|
-
progressBar.text = audioIsRunning() ? timeText : 'Click to Enable Audio';
|
|
76
|
+
infoText.text = formatTime(current) +' / '+ formatTime(duration);
|
|
103
77
|
}
|
|
104
78
|
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
let musicPlayer, playButton, stopButton, progressBar;
|
|
2
|
+
let musicSound, music;
|
|
3
|
+
let musicVolume = 1;
|
|
4
|
+
|
|
5
|
+
function gameInit()
|
|
6
|
+
{
|
|
7
|
+
// setup ui system plugin
|
|
8
|
+
new UISystemPlugin;
|
|
9
|
+
uiSystem.defaultSoundPress = new Sound([.5,0,220]);
|
|
10
|
+
uiSystem.defaultSoundClick = new Sound([.5,0,440]);
|
|
11
|
+
uiSystem.defaultCornerRadius = 20;
|
|
12
|
+
canvasClearColor = hsl(.9,.3,.2);
|
|
13
|
+
|
|
14
|
+
// setup music player UI
|
|
15
|
+
musicPlayer = new UIObject(mainCanvasSize.scale(.5), vec2(500, 300));
|
|
16
|
+
const title = new UIText(vec2(0, -100), vec2(500, 40),
|
|
17
|
+
'LittleJS Music Player');
|
|
18
|
+
musicPlayer.addChild(title);
|
|
19
|
+
|
|
20
|
+
// drop zone text
|
|
21
|
+
const dropZoneText = new UIText(vec2(0, -60), vec2(450, 20),
|
|
22
|
+
'Drag & Drop Audio Files Here!');
|
|
23
|
+
dropZoneText.textColor = hsl(.9, .3, .8, .7);
|
|
24
|
+
musicPlayer.addChild(dropZoneText);
|
|
25
|
+
|
|
26
|
+
// volume slider
|
|
27
|
+
const volumeSlider = new UIScrollbar(vec2(0, -20), vec2(400, 30),
|
|
28
|
+
musicVolume, 'Music Volume');
|
|
29
|
+
musicPlayer.addChild(volumeSlider);
|
|
30
|
+
volumeSlider.onChange = () =>
|
|
31
|
+
{
|
|
32
|
+
musicVolume = volumeSlider.value;
|
|
33
|
+
if (music)
|
|
34
|
+
music.setVolume(musicVolume);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// play button
|
|
38
|
+
playButton = new UIButton(vec2(-90, 50), vec2(140, 50), 'Play');
|
|
39
|
+
musicPlayer.addChild(playButton);
|
|
40
|
+
playButton.onClick = ()=>
|
|
41
|
+
{
|
|
42
|
+
if (!musicSound.isLoaded())
|
|
43
|
+
return;
|
|
44
|
+
|
|
45
|
+
// handle play/pause toggle
|
|
46
|
+
if (!music)
|
|
47
|
+
music = musicSound.playMusic(musicVolume);
|
|
48
|
+
else if (music.isPaused())
|
|
49
|
+
music.resume();
|
|
50
|
+
else
|
|
51
|
+
music.pause();
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// stop button
|
|
55
|
+
stopButton = new UIButton(vec2(90, 50), vec2(140, 50), 'Stop');
|
|
56
|
+
stopButton.onClick = ()=> music && music.stop();
|
|
57
|
+
musicPlayer.addChild(stopButton);
|
|
58
|
+
|
|
59
|
+
// progress bar and scrollbar for seeking
|
|
60
|
+
progressBar = new UIScrollbar(vec2(0, 120), vec2(400, 30), 0);
|
|
61
|
+
progressBar.disabledColor = RED;
|
|
62
|
+
progressBar.onChange = ()=>
|
|
63
|
+
{
|
|
64
|
+
// control music seek position
|
|
65
|
+
const wasPlaying = music && music.isPlaying();
|
|
66
|
+
if (!music)
|
|
67
|
+
music = musicSound.playMusic(musicVolume, true, true);
|
|
68
|
+
progressBar.value = min(progressBar.value, .999); // prevent wrap
|
|
69
|
+
const seekTime = progressBar.value * musicSound.getDuration();
|
|
70
|
+
music.start(seekTime);
|
|
71
|
+
if (!wasPlaying)
|
|
72
|
+
music.pause();
|
|
73
|
+
};
|
|
74
|
+
musicPlayer.addChild(progressBar);
|
|
75
|
+
|
|
76
|
+
{
|
|
77
|
+
// setup drag and drop for audio files
|
|
78
|
+
function onDragEnter() { musicPlayer.color = RED; };
|
|
79
|
+
function onDragLeave() { musicPlayer.color = WHITE; };
|
|
80
|
+
function onDrop(e)
|
|
81
|
+
{
|
|
82
|
+
musicPlayer.color = WHITE
|
|
83
|
+
|
|
84
|
+
// get the dropped file
|
|
85
|
+
const file = e.dataTransfer.files[0];
|
|
86
|
+
if (!file || !file.type.startsWith('audio'))
|
|
87
|
+
return;
|
|
88
|
+
|
|
89
|
+
// create new sound from dropped file
|
|
90
|
+
const fileURL = URL.createObjectURL(file);
|
|
91
|
+
musicSound = new SoundWave(fileURL, musicVolume);
|
|
92
|
+
dropZoneText.text = file.name;
|
|
93
|
+
|
|
94
|
+
// reset UI
|
|
95
|
+
music && music.stop();
|
|
96
|
+
music = undefined;
|
|
97
|
+
progressBar.value = 0;
|
|
98
|
+
}
|
|
99
|
+
uiSystem.setupDragAndDrop(onDrop, onDragEnter, onDragLeave);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function gameUpdate()
|
|
104
|
+
{
|
|
105
|
+
// disable buttons while loading
|
|
106
|
+
const isDisabled = !musicSound || !musicSound.isLoaded();
|
|
107
|
+
playButton.disabled = isDisabled
|
|
108
|
+
stopButton.disabled = isDisabled
|
|
109
|
+
progressBar.disabled = isDisabled
|
|
110
|
+
|
|
111
|
+
// update ui
|
|
112
|
+
if (!musicSound)
|
|
113
|
+
{
|
|
114
|
+
// waiting for file
|
|
115
|
+
progressBar.text = 'No File Loaded';
|
|
116
|
+
}
|
|
117
|
+
else if (isDisabled)
|
|
118
|
+
{
|
|
119
|
+
// update loading progress
|
|
120
|
+
const loadingPercent = musicSound.loadedPercent * 100|0;
|
|
121
|
+
progressBar.text = `Loading: ${loadingPercent}%`;
|
|
122
|
+
}
|
|
123
|
+
else
|
|
124
|
+
{
|
|
125
|
+
// update ui text
|
|
126
|
+
const isPlaying = music && music.isPlaying();
|
|
127
|
+
playButton.text = isPlaying ? 'Pause' : 'Play';
|
|
128
|
+
const current = music ? music.getCurrentTime() : 0;
|
|
129
|
+
const duration = musicSound.getDuration();
|
|
130
|
+
progressBar.text = formatTime(current) +' / '+ formatTime(duration);
|
|
131
|
+
if (!progressBar.mouseIsHeld)
|
|
132
|
+
progressBar.value = current / duration;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -3,19 +3,38 @@ function gameRender()
|
|
|
3
3
|
const nineSliceTile = tile(16);
|
|
4
4
|
const threeSliceTile = tile(19);
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
6
|
+
{
|
|
7
|
+
// draw nine slice with thin border and color
|
|
8
|
+
const pos = vec2(-7,4);
|
|
9
|
+
const size = vec2(11+wave(.5,2), 6);
|
|
10
|
+
const color = hsl(.1,.5,.9);
|
|
11
|
+
const border = .5;
|
|
12
|
+
drawNineSlice(pos, size, nineSliceTile, color, border);
|
|
13
|
+
drawTextOverlay('Nine Slice\nThin Border', pos, 1, BLACK);
|
|
14
|
+
}
|
|
15
|
+
{
|
|
16
|
+
// draw nine slice in screen space with thick border and rotation
|
|
17
|
+
const pos = vec2(700,150);
|
|
18
|
+
const size = vec2(250);
|
|
19
|
+
const border = 32;
|
|
20
|
+
const angle = time/2;
|
|
21
|
+
drawNineSliceScreen(pos, size, nineSliceTile, border, 2, angle);
|
|
22
|
+
drawTextScreen('Nine Slice\nScreen Space', pos, 30, BLACK);
|
|
23
|
+
}
|
|
24
|
+
{
|
|
25
|
+
// draw three slice with variable border and additive color
|
|
26
|
+
const pos = vec2(-7,-4);
|
|
27
|
+
const size = vec2(9, 7);
|
|
28
|
+
const border = 2 + wave(.2)*2;
|
|
29
|
+
const additive = hsl(time/30,.5,.5);
|
|
30
|
+
drawThreeSlice(pos, size, threeSliceTile, WHITE, border, additive);
|
|
31
|
+
drawTextOverlay('Three Slice\nVariable\nBorder', pos, 1, BLACK);
|
|
32
|
+
}
|
|
33
|
+
{
|
|
34
|
+
// draw three slice in screen space with changing size
|
|
35
|
+
const pos = vec2(700,420);
|
|
36
|
+
const size = vec2(350-wave(.3,90),120+wave(.3,60));
|
|
37
|
+
drawThreeSliceScreen(pos, size, threeSliceTile);
|
|
38
|
+
drawTextScreen('Three Slice\nScreen Space', pos, 30, BLACK);
|
|
39
|
+
}
|
|
21
40
|
}
|