littlejsengine 1.14.19 → 1.14.28
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 +217 -38
- package/dist/littlejs.esm.js +879 -324
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +861 -324
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +799 -325
- package/examples/box2d/gameObjects.js +6 -10
- package/examples/box2d/scenes.js +2 -2
- package/examples/breakout/gameObjects.js +1 -1
- package/examples/electron/game.js +1 -41
- package/examples/electron/index.html +2 -2
- package/examples/htmlMenu/game.js +1 -1
- package/examples/index.html +19 -10
- package/examples/module/game.js +5 -7
- package/examples/particles/index.html +6 -9
- package/examples/platformer/gameCharacter.js +4 -3
- package/examples/platformer/gameEffects.js +7 -2
- package/examples/platformer/gameObjects.js +6 -11
- package/examples/shorts/animation.js +2 -2
- package/examples/shorts/base.html +4 -1
- package/examples/shorts/box2d.js +2 -2
- package/examples/shorts/box2dCar.js +18 -7
- package/examples/shorts/box2dPool.js +108 -0
- package/examples/shorts/cameraDrag.js +22 -0
- package/examples/shorts/debugDraw.js +37 -0
- package/examples/shorts/flappyGame.js +1 -0
- package/examples/shorts/fps.js +90 -0
- package/examples/shorts/helloWorld.js +1 -1
- package/examples/shorts/hillGlideGame.js +1 -3
- package/examples/shorts/input.js +59 -0
- package/examples/shorts/landerGame.js +1 -3
- package/examples/shorts/medals.js +15 -9
- package/examples/shorts/music.js +15 -17
- package/examples/shorts/musicPlayer.js +24 -24
- package/examples/shorts/platformer.js +0 -2
- package/examples/shorts/postProcess.js +1 -1
- package/examples/shorts/sequencer.js +3 -3
- package/examples/shorts/slidingPuzzle.js +1 -1
- package/examples/shorts/spaceGame.js +1 -3
- package/examples/shorts/spriteAtlas.js +6 -8
- package/examples/shorts/starfield.js +1 -1
- package/examples/shorts/tileRaycast.js +39 -0
- package/examples/shorts/tiles.png +0 -0
- package/examples/shorts/tiltedView.js +1 -4
- package/examples/shorts/timers.js +1 -2
- package/examples/shorts/topDown.js +0 -2
- package/examples/starter/game.js +5 -7
- package/examples/starter/index.html +2 -2
- package/examples/typescript/game.js +3 -2
- package/examples/typescript/game.ts +5 -7
- package/examples/uiSystem/game.js +2 -2
- package/package.json +1 -1
- package/plugins/box2d.js +170 -50
- package/plugins/pluginExport.js +2 -0
- package/plugins/uiSystem.js +55 -27
- package/src/engine.js +19 -16
- package/src/engineAudio.js +27 -15
- package/src/engineDebug.js +64 -0
- package/src/engineDraw.js +88 -32
- package/src/engineExport.js +16 -0
- package/src/engineInput.js +35 -25
- package/src/engineMedals.js +2 -2
- package/src/engineObject.js +55 -10
- package/src/engineParticles.js +36 -20
- package/src/engineRelease.js +2 -1
- package/src/engineSettings.js +20 -1
- package/src/engineTileLayer.js +64 -59
- package/src/engineUtilities.js +213 -59
- package/src/engineWebGL.js +13 -8
- package/examples/shorts/raycasting.js +0 -79
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
const hitSound = new Sound([,,2e3,,,.01]);
|
|
2
|
+
const maxHitDistance = 6;
|
|
3
|
+
|
|
4
|
+
class Ball extends Box2dObject
|
|
5
|
+
{
|
|
6
|
+
constructor(position, number=0)
|
|
7
|
+
{
|
|
8
|
+
const color = hsl(number/9, 1, number? .5 : 1);
|
|
9
|
+
super(position, vec2(), 0, 0, color);
|
|
10
|
+
this.number = number;
|
|
11
|
+
|
|
12
|
+
// setup pool ball physics
|
|
13
|
+
const friction = 0, restitution = .95;
|
|
14
|
+
this.addCircle(1, vec2(), 1, friction, restitution);
|
|
15
|
+
this.setLinearDamping(.4);
|
|
16
|
+
this.setBullet(true);
|
|
17
|
+
this.setFixedRotation(true);
|
|
18
|
+
}
|
|
19
|
+
beginContact()
|
|
20
|
+
{
|
|
21
|
+
const volume = clamp(this.getSpeed()/20);
|
|
22
|
+
hitSound.play(this.pos, clamp(this.getSpeed()/20));
|
|
23
|
+
}
|
|
24
|
+
canHit() { return this == cueBall && this.getSpeed() < 1; }
|
|
25
|
+
getHitOffset()
|
|
26
|
+
{
|
|
27
|
+
// hit from cue ball to mouse position
|
|
28
|
+
const deltaPos = mousePos.subtract(this.pos);
|
|
29
|
+
const length = min(deltaPos.length(), maxHitDistance);
|
|
30
|
+
return deltaPos.normalize(length);
|
|
31
|
+
}
|
|
32
|
+
update()
|
|
33
|
+
{
|
|
34
|
+
if (this.canHit() && mouseWasPressed(0))
|
|
35
|
+
{
|
|
36
|
+
// hit the cue ball
|
|
37
|
+
const accel = this.getHitOffset().scale(8);
|
|
38
|
+
this.applyAcceleration(accel);
|
|
39
|
+
hitSound.play(cueBall.pos);
|
|
40
|
+
}
|
|
41
|
+
if (this.pocketed)
|
|
42
|
+
this.destroy();
|
|
43
|
+
}
|
|
44
|
+
render()
|
|
45
|
+
{
|
|
46
|
+
super.render();
|
|
47
|
+
|
|
48
|
+
// draw white circle and ball number
|
|
49
|
+
drawCircle(this.pos, .6, WHITE);
|
|
50
|
+
const textPos = this.pos.add(vec2(0,-.06));
|
|
51
|
+
if (this.number)
|
|
52
|
+
drawTextOverlay(this.number, textPos, .5, BLACK);
|
|
53
|
+
if (this.canHit())
|
|
54
|
+
{
|
|
55
|
+
// draw the aim line
|
|
56
|
+
const offset = this.getHitOffset();
|
|
57
|
+
const endPos = this.pos.add(offset);
|
|
58
|
+
const width = offset.length()/maxHitDistance;
|
|
59
|
+
drawLine(this.pos, endPos, width, hsl(0,1,.5,.5),
|
|
60
|
+
vec2(), 0, false, false, overlayContext);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
class Pocket extends Box2dStaticObject
|
|
66
|
+
{
|
|
67
|
+
constructor(pos, size)
|
|
68
|
+
{
|
|
69
|
+
super(pos, size, 0, 0, BLACK);
|
|
70
|
+
|
|
71
|
+
// create a sensor circle for pocket
|
|
72
|
+
this.addCircle(size.x);
|
|
73
|
+
this.setSensor(true);
|
|
74
|
+
}
|
|
75
|
+
render()
|
|
76
|
+
{
|
|
77
|
+
// add ball size to pocket size for drawing
|
|
78
|
+
drawCircle(this.pos, this.size.x + 1, BLACK);
|
|
79
|
+
}
|
|
80
|
+
beginContact(other) { other.pocketed = 1; }
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function gameInit()
|
|
84
|
+
{
|
|
85
|
+
// setup box2d
|
|
86
|
+
await box2dInit();
|
|
87
|
+
canvasClearColor = hsl(.4,.5,.5);
|
|
88
|
+
|
|
89
|
+
// create table walls
|
|
90
|
+
const groundObject = new Box2dStaticObject;
|
|
91
|
+
groundObject.color = hsl(.1,1,.2);
|
|
92
|
+
groundObject.addBox(vec2(100,3), vec2( 0, 8.5));
|
|
93
|
+
groundObject.addBox(vec2(100,3), vec2( 0,-8.5));
|
|
94
|
+
groundObject.addBox(vec2(3,100), vec2( 15,0));
|
|
95
|
+
groundObject.addBox(vec2(3,100), vec2(-15,0));
|
|
96
|
+
|
|
97
|
+
// create pockets
|
|
98
|
+
for (let j=0; j<2; ++j)
|
|
99
|
+
for (let i=0; i<3; ++i)
|
|
100
|
+
new Pocket(vec2(i-1, j-.5).scale(13), vec2(.5));
|
|
101
|
+
|
|
102
|
+
// create balls
|
|
103
|
+
let number = 1;
|
|
104
|
+
for (let i=5; i--;)
|
|
105
|
+
for (let j=i+1; j--;)
|
|
106
|
+
new Ball(vec2(6+i*.9, j-i/2), number++);
|
|
107
|
+
cueBall = new Ball(vec2(-6, 0));
|
|
108
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
function gameInit()
|
|
2
|
+
{
|
|
3
|
+
// create some objects
|
|
4
|
+
for (let i=500; i--;)
|
|
5
|
+
{
|
|
6
|
+
const pos = randInCircle(100);
|
|
7
|
+
const size = vec2(rand(2,9),rand(2,9));
|
|
8
|
+
const color = randColor();
|
|
9
|
+
const angle = rand(PI);
|
|
10
|
+
new EngineObject(pos, size, 0, angle, color);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function gameUpdate()
|
|
15
|
+
{
|
|
16
|
+
// drag camera with mouse
|
|
17
|
+
if (mouseIsDown(0))
|
|
18
|
+
cameraPos = cameraPos.subtract(mouseDelta);
|
|
19
|
+
|
|
20
|
+
// zoom camera with mouse wheel
|
|
21
|
+
cameraScale = clamp(cameraScale*(1-mouseWheel/5), 1, 1e3);
|
|
22
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
class BounceObject extends EngineObject
|
|
2
|
+
{
|
|
3
|
+
constructor(pos, size, tile)
|
|
4
|
+
{
|
|
5
|
+
super(pos, size, tile);
|
|
6
|
+
this.velocity = vec2(.1);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
update()
|
|
10
|
+
{
|
|
11
|
+
// show debug info
|
|
12
|
+
debugText('Debug Text', this.pos.add(vec2(0,3)), 1, WHITE);
|
|
13
|
+
debugRect(this.pos, this.size, RED);
|
|
14
|
+
const trianglePoints = [vec2(-2,-1), vec2(0,2), vec2(2,-1)];
|
|
15
|
+
debugPoly(mousePos, trianglePoints, YELLOW);
|
|
16
|
+
debugLine(this.pos, mousePos, BLUE);
|
|
17
|
+
|
|
18
|
+
// bounce off screen edges
|
|
19
|
+
const cameraSize = getCameraSize();
|
|
20
|
+
if (abs(this.pos.x) > cameraSize.x/2)
|
|
21
|
+
{
|
|
22
|
+
debugCircle(this.pos, 3, GREEN, 1);
|
|
23
|
+
this.velocity.x = -this.velocity.x;
|
|
24
|
+
}
|
|
25
|
+
if (abs(this.pos.y) > cameraSize.y/2)
|
|
26
|
+
{
|
|
27
|
+
debugCircle(this.pos, 3, GREEN, 1);
|
|
28
|
+
this.velocity.y = -this.velocity.y;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function gameInit()
|
|
34
|
+
{
|
|
35
|
+
canvasClearColor = GRAY;
|
|
36
|
+
new BounceObject(vec2(), vec2(5), tile(3,128));
|
|
37
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
let playerPos = vec2(), playerAngle = 0;
|
|
2
|
+
setTileFixBleedScale(0);
|
|
3
|
+
|
|
4
|
+
// a simple function to create the level
|
|
5
|
+
const levelTest = (p)=> (floor(p.x)**3&floor(p.y)**2)%30>5;
|
|
6
|
+
|
|
7
|
+
function gameUpdate()
|
|
8
|
+
{
|
|
9
|
+
// update camera angle with mouse pointer lock
|
|
10
|
+
if (mouseWasPressed(0))
|
|
11
|
+
pointerLockRequest();
|
|
12
|
+
if (keyWasPressed('Escape'))
|
|
13
|
+
pointerLockExit()
|
|
14
|
+
if (pointerLockIsActive() || isTouchDevice)
|
|
15
|
+
playerAngle += mouseDelta.x * .03;
|
|
16
|
+
|
|
17
|
+
// update player movement, prevent walking through walls
|
|
18
|
+
const velocity = keyDirection().rotate(playerAngle).scale(.05);
|
|
19
|
+
const normal = vec2();
|
|
20
|
+
let newPos = playerPos.add(velocity);
|
|
21
|
+
if (lineTest(playerPos, newPos, levelTest, normal))
|
|
22
|
+
{
|
|
23
|
+
// adjust velocity to slide along wall
|
|
24
|
+
const d = velocity.dot(normal);
|
|
25
|
+
newPos = newPos.subtract(vec2(d*normal.x, d*normal.y));
|
|
26
|
+
if (!levelTest(newPos))
|
|
27
|
+
playerPos = newPos;
|
|
28
|
+
}
|
|
29
|
+
else
|
|
30
|
+
playerPos = newPos;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function gameRender()
|
|
34
|
+
{
|
|
35
|
+
{
|
|
36
|
+
// draw horizontal slizes to create floor and ceiling
|
|
37
|
+
const h = 9;
|
|
38
|
+
let pos = vec2(), size = vec2(39, .15), color = rgb();
|
|
39
|
+
for (let y=-h; y<h; y+=.1)
|
|
40
|
+
{
|
|
41
|
+
const p = 1.01 - abs(y/h)
|
|
42
|
+
color.setHSLA(.1, y>0?0:.5, .7-p*.7);
|
|
43
|
+
pos.y = y;
|
|
44
|
+
drawRect(pos, size, color);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
{
|
|
48
|
+
// draw vertical slices to create the walls
|
|
49
|
+
// create objects in advance for optimal performance
|
|
50
|
+
const w = 15;
|
|
51
|
+
const maxDistance = 50;
|
|
52
|
+
const pos = vec2(), endPos = vec2(), size = vec2(.15);
|
|
53
|
+
const tileInfo = new TileInfo(vec2(), vec2(0,16));
|
|
54
|
+
const normal = vec2(), light = vec2().setAngle(2);
|
|
55
|
+
const color = rgb();
|
|
56
|
+
for (pos.x=-w; pos.x<w; pos.x+=.1)
|
|
57
|
+
{
|
|
58
|
+
// cast ray for this slice
|
|
59
|
+
const angle = playerAngle + pos.x/w/2;
|
|
60
|
+
endPos.setAngle(angle, maxDistance);
|
|
61
|
+
endPos.x += playerPos.x;
|
|
62
|
+
endPos.y += playerPos.y;
|
|
63
|
+
const p = lineTest(playerPos, endPos, levelTest, normal);
|
|
64
|
+
if (!p) continue;
|
|
65
|
+
|
|
66
|
+
// get texture coordinate
|
|
67
|
+
const t = mod(p.x+p.y, 1);
|
|
68
|
+
tileInfo.pos.x = 161 + 14*t;
|
|
69
|
+
|
|
70
|
+
// apply fog and lighting
|
|
71
|
+
const d = p.distance(playerPos)/maxDistance;
|
|
72
|
+
const l = max(0, normal.dot(light));
|
|
73
|
+
size.y = .5/d;
|
|
74
|
+
color.setHSLA(.6, 1-d, .7-d+l*.3);
|
|
75
|
+
|
|
76
|
+
// draw the section the wall
|
|
77
|
+
drawTile(pos, size, tileInfo, color);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// draw instructions and pointer lock status
|
|
82
|
+
const instructions = pointerLockIsActive() ?
|
|
83
|
+
'Mouse Control Active - ESC To Exit' :
|
|
84
|
+
'Click To Enable Mouse Control';
|
|
85
|
+
const textPos = vec2(mainCanvasSize.x/2, 50);
|
|
86
|
+
const textSize = 30;
|
|
87
|
+
const textColor = pointerLockIsActive() ? GREEN : WHITE;
|
|
88
|
+
if (!isTouchDevice)
|
|
89
|
+
drawTextScreen(instructions, textPos, textSize, textColor);
|
|
90
|
+
}
|
|
@@ -9,8 +9,6 @@ class Player extends EngineObject
|
|
|
9
9
|
|
|
10
10
|
update()
|
|
11
11
|
{
|
|
12
|
-
super.update();
|
|
13
|
-
|
|
14
12
|
// check ground height
|
|
15
13
|
const h = getGroundHeight(this.pos.x);
|
|
16
14
|
if (this.pos.y < h + this.size.y/2)
|
|
@@ -35,7 +33,7 @@ class Player extends EngineObject
|
|
|
35
33
|
|
|
36
34
|
function getGroundHeight(x)
|
|
37
35
|
{
|
|
38
|
-
return
|
|
36
|
+
return sin(x/4)*2 + sin(x/17);
|
|
39
37
|
}
|
|
40
38
|
|
|
41
39
|
function gameInit()
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
function gameUpdate()
|
|
2
|
+
{
|
|
3
|
+
if (isUsingGamepad)
|
|
4
|
+
{
|
|
5
|
+
debugText('Gamepad Mode', vec2(0,4));
|
|
6
|
+
|
|
7
|
+
// analog sticks
|
|
8
|
+
for (let i=2; i--;)
|
|
9
|
+
{
|
|
10
|
+
const stick = gamepadStick(i);
|
|
11
|
+
const pos = vec2(i?2:-2, 1);
|
|
12
|
+
debugCircle(pos, 2, WHITE);
|
|
13
|
+
debugLine(pos, pos.add(stick), GREEN);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// buttons
|
|
17
|
+
for (let i=16; i--;)
|
|
18
|
+
{
|
|
19
|
+
const pos = vec2(-1.5 + i%4, -2 - (i/4|0));
|
|
20
|
+
if (gamepadIsDown(i))
|
|
21
|
+
debugCircle(pos, 1, RED, 0, 1);
|
|
22
|
+
debugCircle(pos, 1, WHITE);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
else if (isTouchDevice)
|
|
26
|
+
{
|
|
27
|
+
debugText('Touch Mode', vec2(0,4));
|
|
28
|
+
|
|
29
|
+
// touch input routed to mouse
|
|
30
|
+
if (mouseIsDown(0))
|
|
31
|
+
debugCircle(mousePos, 4, RED, 0, 1);
|
|
32
|
+
debugCircle(mousePos, 4, WHITE);
|
|
33
|
+
}
|
|
34
|
+
else
|
|
35
|
+
{
|
|
36
|
+
debugText('Mouse and Keyboard Mode', vec2(0,4));
|
|
37
|
+
|
|
38
|
+
// keyboard key (space bar)
|
|
39
|
+
debugRect(vec2(), vec2(2), WHITE);
|
|
40
|
+
if (keyIsDown('Space'))
|
|
41
|
+
debugRect(vec2(), vec2(2), RED, 0, 0, 1);
|
|
42
|
+
|
|
43
|
+
// keyboard direction (arrow keys or WASD)
|
|
44
|
+
const inputDirection = keyDirection();
|
|
45
|
+
debugLine(vec2(), inputDirection, GREEN);
|
|
46
|
+
|
|
47
|
+
// mouse pos
|
|
48
|
+
debugPoint(mousePos, mouseIsDown(0) ? RED : YELLOW);
|
|
49
|
+
|
|
50
|
+
// mouse buttons
|
|
51
|
+
for (let i=3; i--;)
|
|
52
|
+
{
|
|
53
|
+
const pos = vec2(-1 + i, -3);
|
|
54
|
+
if (mouseIsDown(i))
|
|
55
|
+
debugCircle(pos, 1, RED, 0, 1);
|
|
56
|
+
debugCircle(pos, 1, WHITE);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -9,12 +9,10 @@ class Player extends EngineObject
|
|
|
9
9
|
|
|
10
10
|
update()
|
|
11
11
|
{
|
|
12
|
-
super.update();
|
|
13
|
-
|
|
14
12
|
// space ship controls
|
|
15
13
|
const moveInput = keyDirection();
|
|
16
14
|
this.applyAngularAcceleration(moveInput.x * .002);
|
|
17
|
-
const accel =
|
|
15
|
+
const accel = this.getUp(moveInput.y*.002);
|
|
18
16
|
this.applyAcceleration(accel);
|
|
19
17
|
}
|
|
20
18
|
|
|
@@ -4,19 +4,25 @@ const medal_leftClick = new Medal(1, 'Lefty', 'Left clicked!', '🐁');
|
|
|
4
4
|
const medal_rightClick = new Medal(2, 'Righty', 'Right clicked!', '🐭');
|
|
5
5
|
const medal_spacePressed = new Medal(3, 'Space', 'Pressed spacebar!', '🚀');
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
function gameInit()
|
|
8
|
+
{
|
|
9
|
+
// setup medals
|
|
10
|
+
const saveName = 'Medals Example';
|
|
11
|
+
medalsInit(saveName);
|
|
12
|
+
|
|
13
|
+
// clear unlocked medals for testing
|
|
14
|
+
medalsForEach(medal=> medal.unlocked = false);
|
|
10
15
|
|
|
11
|
-
//
|
|
12
|
-
|
|
13
|
-
medal_openedExample.unlock();
|
|
16
|
+
// unlock the example medal
|
|
17
|
+
medal_openedExample.unlock();
|
|
14
18
|
|
|
15
|
-
// set background color
|
|
16
|
-
canvasClearColor = hsl(.5,.3,.2);
|
|
19
|
+
// set background color
|
|
20
|
+
canvasClearColor = hsl(.5,.3,.2);
|
|
21
|
+
}
|
|
17
22
|
|
|
18
23
|
function gameUpdate()
|
|
19
24
|
{
|
|
25
|
+
// unlock example medals based on input
|
|
20
26
|
if (mouseWasPressed(0))
|
|
21
27
|
medal_leftClick.unlock();
|
|
22
28
|
if (mouseWasPressed(2))
|
|
@@ -25,7 +31,7 @@ function gameUpdate()
|
|
|
25
31
|
medal_spacePressed.unlock();
|
|
26
32
|
}
|
|
27
33
|
|
|
28
|
-
function
|
|
34
|
+
function gameRenderPost()
|
|
29
35
|
{
|
|
30
36
|
const size = 80;
|
|
31
37
|
let pos = mainCanvasSize.scale(.5).subtract(vec2(0,40));
|
package/examples/shorts/music.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
let
|
|
3
|
-
let musicVolume = 1;
|
|
4
|
-
let music;
|
|
1
|
+
const musicSound = new SoundWave('song.mp3');
|
|
2
|
+
let musicVolume = 1, musicInstance;
|
|
5
3
|
|
|
6
4
|
function gameInit()
|
|
7
5
|
{
|
|
@@ -13,7 +11,8 @@ function gameInit()
|
|
|
13
11
|
canvasClearColor = hsl(.9,.3,.2);
|
|
14
12
|
|
|
15
13
|
// setup music player UI
|
|
16
|
-
|
|
14
|
+
const center = mainCanvasSize.scale(.5);
|
|
15
|
+
musicPlayer = new UIObject(center, vec2(500, 220));
|
|
17
16
|
|
|
18
17
|
// infomation text
|
|
19
18
|
infoText = new UIText(vec2(0, -70), vec2(400, 50));
|
|
@@ -26,8 +25,7 @@ function gameInit()
|
|
|
26
25
|
volumeSlider.onChange = () =>
|
|
27
26
|
{
|
|
28
27
|
musicVolume = volumeSlider.value;
|
|
29
|
-
|
|
30
|
-
music.setVolume(musicVolume);
|
|
28
|
+
musicInstance?.setVolume(musicVolume);
|
|
31
29
|
};
|
|
32
30
|
|
|
33
31
|
// play button
|
|
@@ -39,17 +37,17 @@ function gameInit()
|
|
|
39
37
|
return;
|
|
40
38
|
|
|
41
39
|
// handle play/pause toggle
|
|
42
|
-
if (!
|
|
43
|
-
|
|
44
|
-
else if (
|
|
45
|
-
|
|
40
|
+
if (!musicInstance)
|
|
41
|
+
musicInstance = musicSound.playMusic(musicVolume);
|
|
42
|
+
else if (musicInstance.isPaused())
|
|
43
|
+
musicInstance.resume();
|
|
46
44
|
else
|
|
47
|
-
|
|
45
|
+
musicInstance.pause();
|
|
48
46
|
};
|
|
49
47
|
|
|
50
48
|
// stop button
|
|
51
49
|
stopButton = new UIButton(vec2(90, 50), vec2(140, 50), 'Stop');
|
|
52
|
-
stopButton.onClick = ()=>
|
|
50
|
+
stopButton.onClick = ()=> musicInstance?.stop();
|
|
53
51
|
musicPlayer.addChild(stopButton);
|
|
54
52
|
}
|
|
55
53
|
|
|
@@ -69,10 +67,10 @@ function gameUpdate()
|
|
|
69
67
|
else
|
|
70
68
|
{
|
|
71
69
|
// update ui text
|
|
72
|
-
const isPlaying =
|
|
70
|
+
const isPlaying = musicInstance?.isPlaying();
|
|
73
71
|
playButton.text = isPlaying ? 'Pause' : 'Play';
|
|
74
|
-
const current =
|
|
75
|
-
const duration = musicSound.getDuration();
|
|
76
|
-
infoText.text =
|
|
72
|
+
const current = formatTime(musicInstance?.getCurrentTime());
|
|
73
|
+
const duration = formatTime(musicSound.getDuration());
|
|
74
|
+
infoText.text = current + ' / ' + duration;
|
|
77
75
|
}
|
|
78
76
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
let musicSound,
|
|
3
|
-
let musicVolume = 1;
|
|
1
|
+
|
|
2
|
+
let musicVolume = 1, musicSound, musicInstance;
|
|
4
3
|
|
|
5
4
|
function gameInit()
|
|
6
5
|
{
|
|
@@ -13,7 +12,8 @@ function gameInit()
|
|
|
13
12
|
canvasClearColor = hsl(.9,.3,.2);
|
|
14
13
|
|
|
15
14
|
// setup music player UI
|
|
16
|
-
|
|
15
|
+
const center = mainCanvasSize.scale(.5);
|
|
16
|
+
musicPlayer = new UIObject(center, vec2(500, 300));
|
|
17
17
|
const title = new UIText(vec2(0, -100), vec2(500, 40),
|
|
18
18
|
'LittleJS Music Player');
|
|
19
19
|
musicPlayer.addChild(title);
|
|
@@ -21,7 +21,7 @@ function gameInit()
|
|
|
21
21
|
// drop zone text
|
|
22
22
|
const dropZoneText = new UIText(vec2(0, -60), vec2(450, 20),
|
|
23
23
|
'Drag & Drop Audio Files Here!');
|
|
24
|
-
dropZoneText.textColor =
|
|
24
|
+
dropZoneText.textColor = GRAY;
|
|
25
25
|
musicPlayer.addChild(dropZoneText);
|
|
26
26
|
|
|
27
27
|
// volume slider
|
|
@@ -31,8 +31,7 @@ function gameInit()
|
|
|
31
31
|
volumeSlider.onChange = () =>
|
|
32
32
|
{
|
|
33
33
|
musicVolume = volumeSlider.value;
|
|
34
|
-
|
|
35
|
-
music.setVolume(musicVolume);
|
|
34
|
+
musicInstance?.setVolume(musicVolume);
|
|
36
35
|
};
|
|
37
36
|
|
|
38
37
|
// play button
|
|
@@ -44,17 +43,17 @@ function gameInit()
|
|
|
44
43
|
return;
|
|
45
44
|
|
|
46
45
|
// handle play/pause toggle
|
|
47
|
-
if (!
|
|
48
|
-
|
|
49
|
-
else if (
|
|
50
|
-
|
|
46
|
+
if (!musicInstance)
|
|
47
|
+
musicInstance = musicSound.playMusic(musicVolume);
|
|
48
|
+
else if (musicInstance.isPaused())
|
|
49
|
+
musicInstance.resume();
|
|
51
50
|
else
|
|
52
|
-
|
|
51
|
+
musicInstance.pause();
|
|
53
52
|
};
|
|
54
53
|
|
|
55
54
|
// stop button
|
|
56
55
|
stopButton = new UIButton(vec2(90, 50), vec2(140, 50), 'Stop');
|
|
57
|
-
stopButton.onClick = ()=>
|
|
56
|
+
stopButton.onClick = ()=> musicInstance?.stop();
|
|
58
57
|
musicPlayer.addChild(stopButton);
|
|
59
58
|
|
|
60
59
|
// progress bar and scrollbar for seeking
|
|
@@ -63,14 +62,14 @@ function gameInit()
|
|
|
63
62
|
progressBar.onChange = ()=>
|
|
64
63
|
{
|
|
65
64
|
// control music seek position
|
|
66
|
-
const wasPlaying =
|
|
67
|
-
if (!
|
|
68
|
-
|
|
65
|
+
const wasPlaying = musicInstance?.isPlaying();
|
|
66
|
+
if (!musicInstance)
|
|
67
|
+
musicInstance = musicSound.playMusic(musicVolume, 1, 1);
|
|
69
68
|
progressBar.value = min(progressBar.value, .999); // prevent wrap
|
|
70
69
|
const seekTime = progressBar.value * musicSound.getDuration();
|
|
71
|
-
|
|
70
|
+
musicInstance.start(seekTime);
|
|
72
71
|
if (!wasPlaying)
|
|
73
|
-
|
|
72
|
+
musicInstance.pause();
|
|
74
73
|
};
|
|
75
74
|
musicPlayer.addChild(progressBar);
|
|
76
75
|
|
|
@@ -93,8 +92,8 @@ function gameInit()
|
|
|
93
92
|
dropZoneText.text = file.name;
|
|
94
93
|
|
|
95
94
|
// reset UI
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
musicInstance?.stop();
|
|
96
|
+
musicInstance = undefined;
|
|
98
97
|
progressBar.value = 0;
|
|
99
98
|
}
|
|
100
99
|
uiSystem.setupDragAndDrop(onDrop, onDragEnter, onDragLeave);
|
|
@@ -124,12 +123,13 @@ function gameUpdate()
|
|
|
124
123
|
else
|
|
125
124
|
{
|
|
126
125
|
// update ui text
|
|
127
|
-
const isPlaying =
|
|
126
|
+
const isPlaying = musicInstance?.isPlaying();
|
|
128
127
|
playButton.text = isPlaying ? 'Pause' : 'Play';
|
|
129
|
-
const current =
|
|
128
|
+
const current = musicInstance?.getCurrentTime() || 0;
|
|
130
129
|
const duration = musicSound.getDuration();
|
|
131
|
-
progressBar.text = formatTime(current) +
|
|
132
|
-
|
|
130
|
+
progressBar.text = formatTime(current) +
|
|
131
|
+
' / ' + formatTime(duration);
|
|
132
|
+
if (!progressBar.isActiveObject())
|
|
133
133
|
progressBar.value = current / duration;
|
|
134
134
|
}
|
|
135
135
|
}
|
|
@@ -34,7 +34,7 @@ class UISequencerButton extends UIButton
|
|
|
34
34
|
this.hue = track*.15;
|
|
35
35
|
if (track >= pianoStart)
|
|
36
36
|
{
|
|
37
|
-
const octave =
|
|
37
|
+
const octave = floor((track-pianoStart) / scale.length);
|
|
38
38
|
const scaleNote = (track-pianoStart) % scale.length;
|
|
39
39
|
this.semitone = scale[scaleNote] + 12*octave;
|
|
40
40
|
this.sound = sound_piano;
|
|
@@ -93,7 +93,7 @@ function gameInit()
|
|
|
93
93
|
tempoSlider.onChange = ()=>
|
|
94
94
|
{
|
|
95
95
|
tempo = lerp(minTempo, maxTempo, tempoSlider.value);
|
|
96
|
-
tempo =
|
|
96
|
+
tempo = floor(tempo/10) * 10; // round to nearest 10th
|
|
97
97
|
tempoSlider.text = `${tempo} BPM`;
|
|
98
98
|
};
|
|
99
99
|
tempoSlider.onChange();
|
|
@@ -108,7 +108,7 @@ function gameUpdate()
|
|
|
108
108
|
const lastStepTime = stepTime;
|
|
109
109
|
const lastStep = currentStep;
|
|
110
110
|
stepTime += timeDelta*tempo/60;
|
|
111
|
-
currentStep =
|
|
111
|
+
currentStep = floor(stepTime) % stepCount;
|
|
112
112
|
if (currentStep == lastStep && lastStepTime)
|
|
113
113
|
return;
|
|
114
114
|
|
|
@@ -20,7 +20,7 @@ class PuzzlePiece extends EngineObject
|
|
|
20
20
|
const deltaX = emptyGridPos.x - this.gridPos.x;
|
|
21
21
|
const deltaY = emptyGridPos.y - this.gridPos.y;
|
|
22
22
|
if (mouseWasPressed(0))
|
|
23
|
-
if (isOverlapping(
|
|
23
|
+
if (this.isOverlapping(mousePos))
|
|
24
24
|
if (abs(deltaX) + abs(deltaY) === 1)
|
|
25
25
|
{
|
|
26
26
|
// swap with empty space when clicked on
|
|
@@ -10,8 +10,6 @@ class Player extends EngineObject
|
|
|
10
10
|
|
|
11
11
|
update()
|
|
12
12
|
{
|
|
13
|
-
super.update();
|
|
14
|
-
|
|
15
13
|
// space ship controls
|
|
16
14
|
const moveInput = keyDirection();
|
|
17
15
|
this.applyAngularAcceleration(moveInput.x * .005);
|
|
@@ -23,7 +21,7 @@ class Player extends EngineObject
|
|
|
23
21
|
// shoot bullet
|
|
24
22
|
const pos = this.pos.add(vec2(0,1).rotate(cameraAngle));
|
|
25
23
|
const bullet = new EngineObject(pos, vec2(.2,.5), 0, this.angle);
|
|
26
|
-
bullet.velocity =
|
|
24
|
+
bullet.velocity = this.getUp(.5);
|
|
27
25
|
bullet.velocity = bullet.velocity.add(this.velocity);
|
|
28
26
|
this.shootTimer.set(.1);
|
|
29
27
|
}
|