littlejsengine 1.12.4 → 1.13.1
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/box2d.wasm.js +630 -0
- package/dist/box2d.wasm.wasm +0 -0
- package/dist/littlejs.d.ts +437 -219
- package/dist/littlejs.esm.js +5950 -5307
- package/dist/littlejs.esm.min.js +4 -1
- package/dist/littlejs.js +5921 -5295
- package/dist/littlejs.min.js +4 -1
- package/dist/littlejs.release.js +5485 -4886
- package/examples/box2d/game.js +37 -42
- package/examples/box2d/gameObjects.js +41 -37
- package/examples/box2d/index.html +2 -2
- package/examples/box2d/scenes.js +24 -20
- package/examples/box2d/tiles.png +0 -0
- package/examples/breakout/game.js +1 -1
- package/examples/breakout/gameObjects.js +2 -2
- package/examples/breakout/index.html +1 -1
- package/examples/breakoutTutorial/README.md +2 -2
- package/examples/breakoutTutorial/game.js +1 -1
- package/examples/breakoutTutorial/index.html +1 -1
- package/examples/empty/index.html +1 -1
- package/examples/htmlMenu/index.html +1 -1
- package/examples/index.html +410 -159
- package/examples/module/game.js +1 -1
- package/examples/module/index.html +1 -1
- package/examples/platformer/game.js +6 -15
- package/examples/platformer/gameCharacter.js +6 -6
- package/examples/platformer/gameEffects.js +74 -57
- package/examples/platformer/gameLevel.js +61 -70
- package/examples/platformer/gameObjects.js +4 -4
- package/examples/platformer/index.html +1 -1
- package/examples/puzzle/index.html +1 -1
- package/examples/shorts/base.html +24 -3
- package/examples/shorts/box2d.js +46 -0
- package/examples/shorts/box2dCar.js +45 -0
- package/examples/shorts/flappyGame.js +52 -0
- package/examples/shorts/helloWorld.js +6 -3
- package/examples/shorts/hillGlideGame.js +56 -0
- package/examples/shorts/landerGame.js +32 -0
- package/examples/shorts/maze.js +47 -0
- package/examples/shorts/medals.js +42 -0
- package/examples/shorts/nineSlice.js +21 -0
- package/examples/shorts/piano.js +52 -0
- package/examples/shorts/platformer.js +24 -20
- package/examples/shorts/{pong.js → pongGame.js} +1 -1
- package/examples/shorts/postProcess.js +45 -0
- package/examples/shorts/raycasting.js +71 -0
- package/examples/shorts/slidingPuzzle.js +42 -0
- package/examples/shorts/spaceGame.js +56 -0
- package/examples/shorts/starfield.js +17 -0
- package/examples/shorts/tileLayer.js +3 -5
- package/examples/shorts/tiles.png +0 -0
- package/examples/shorts/tiltedView.js +8 -7
- package/examples/shorts/topDown.js +18 -26
- package/examples/shorts/uiSystem.js +36 -0
- package/examples/starter/build.bat +6 -1
- package/examples/starter/game.js +4 -2
- package/examples/starter/index.html +23 -13
- package/examples/stress/index.html +2 -3
- package/examples/style.css +136 -0
- package/examples/typescript/build.js +1 -2
- package/examples/typescript/game.js +2 -2
- package/examples/typescript/game.ts +1 -1
- package/examples/typescript/index.html +1 -1
- package/examples/uiSystem/game.js +9 -25
- package/examples/uiSystem/index.html +1 -1
- package/package.json +1 -1
- package/plugins/box2d.js +29 -35
- package/plugins/drawUtilities.js +126 -0
- package/plugins/newgrounds.js +1 -1
- package/plugins/pluginExport.js +8 -2
- package/plugins/postProcess.js +2 -2
- package/plugins/uiSystem.js +162 -68
- package/plugins/zzfxm.js +1 -1
- package/reference.md +10 -10
- package/src/engine.js +59 -39
- package/src/engineAudio.js +38 -20
- package/src/engineBuild.bat +6 -1
- package/src/engineBuild.js +32 -7
- package/src/engineDebug.js +53 -26
- package/src/engineDraw.js +108 -57
- package/src/engineExport.js +22 -9
- package/src/engineInput.js +112 -40
- package/src/engineObject.js +68 -67
- package/src/engineParticles.js +26 -9
- package/src/engineSettings.js +15 -16
- package/src/engineTileLayer.js +312 -153
- package/src/engineUtilities.js +198 -130
- package/src/engineWebGL.js +58 -35
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
async function gameInit()
|
|
2
|
+
{
|
|
3
|
+
// setup box2d and create the objects
|
|
4
|
+
await box2dInit();
|
|
5
|
+
gravity.y = -20;
|
|
6
|
+
groundObject = new Box2dObject(vec2(-8), vec2(), 0, 0, GRAY, box2d.bodyTypeStatic);
|
|
7
|
+
groundObject.addBox(vec2(100,6));
|
|
8
|
+
new CarObject(vec2(0,-2));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
class CarObject extends Box2dObject
|
|
12
|
+
{
|
|
13
|
+
constructor(pos)
|
|
14
|
+
{
|
|
15
|
+
super(pos, vec2(), 0, 0, RED);
|
|
16
|
+
|
|
17
|
+
// create car with wheels
|
|
18
|
+
this.addBox(vec2(7,2));
|
|
19
|
+
const frequency = 4, maxTorque = 250;
|
|
20
|
+
this.wheels = [];
|
|
21
|
+
for(let i=2; i--;)
|
|
22
|
+
{
|
|
23
|
+
const wheelPos = pos.add(vec2(i?2:-2, -1));
|
|
24
|
+
const wheel = new Box2dObject(wheelPos, vec2(2), tile(7));
|
|
25
|
+
const joint = new Box2dWheelJoint(this, wheel);
|
|
26
|
+
joint.setSpringFrequencyHz(frequency);
|
|
27
|
+
joint.setMaxMotorTorque(maxTorque);
|
|
28
|
+
joint.enableMotor(!i);
|
|
29
|
+
wheel.addCircle(2, vec2(), 1, 1);
|
|
30
|
+
wheel.motorJoint = joint;
|
|
31
|
+
this.wheels[i] = wheel;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
update()
|
|
35
|
+
{
|
|
36
|
+
super.update();
|
|
37
|
+
|
|
38
|
+
// car controls - use mouse, arrow keys, or A/D to drive
|
|
39
|
+
const maxSpeed = 40;
|
|
40
|
+
const input = keyDirection().x || mouseIsDown(0);
|
|
41
|
+
let s = this.wheels[0].motorJoint.getMotorSpeed();
|
|
42
|
+
s = input ? clamp(s - input, -maxSpeed, maxSpeed) : 0;
|
|
43
|
+
this.wheels[0].motorJoint.setMotorSpeed(s);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
class Wall extends EngineObject
|
|
2
|
+
{
|
|
3
|
+
constructor(pos, size)
|
|
4
|
+
{
|
|
5
|
+
super(pos, size, 0, 0, hsl(.4,.5,.4));
|
|
6
|
+
this.setCollision(); // make object collide
|
|
7
|
+
}
|
|
8
|
+
update()
|
|
9
|
+
{
|
|
10
|
+
this.pos.x -= .1; // move walls to the left
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class Player extends EngineObject
|
|
15
|
+
{
|
|
16
|
+
constructor(pos)
|
|
17
|
+
{
|
|
18
|
+
super(pos, vec2(1), tile(9), 0, YELLOW);
|
|
19
|
+
this.drawSize = vec2(2);
|
|
20
|
+
this.setCollision(); // make object collide
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
update()
|
|
24
|
+
{
|
|
25
|
+
super.update();
|
|
26
|
+
|
|
27
|
+
// flappy movement controls
|
|
28
|
+
if (mouseWasPressed(0) || keyWasPressed('Space'))
|
|
29
|
+
this.velocity = vec2(0,.2);
|
|
30
|
+
this.angle = -this.velocity.y*2;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
collideWithObject(object)
|
|
34
|
+
{
|
|
35
|
+
// reset game
|
|
36
|
+
engineObjectsDestroy();
|
|
37
|
+
gameInit();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function gameInit()
|
|
42
|
+
{
|
|
43
|
+
// setup level
|
|
44
|
+
gravity.y = -.01;
|
|
45
|
+
for (let i=100; i--;)
|
|
46
|
+
{
|
|
47
|
+
const h=50, y=-h/2-6+rand(9), spacing=15, gap=5;
|
|
48
|
+
new Wall(vec2(14 + i*spacing,y+h + gap), vec2(3,h));
|
|
49
|
+
new Wall(vec2(14 + i*spacing,y), vec2(3,h));
|
|
50
|
+
}
|
|
51
|
+
new Player(vec2(-7,6));
|
|
52
|
+
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
function gameRender()
|
|
2
2
|
{
|
|
3
|
-
// draw
|
|
4
|
-
|
|
3
|
+
// draw background rect
|
|
4
|
+
drawRect(cameraPos, vec2(30), hsl(0,0,.2));
|
|
5
|
+
|
|
6
|
+
// draw text to the overlay canvas
|
|
7
|
+
drawTextOverlay('Hello World', vec2(0,3), 3);
|
|
5
8
|
|
|
6
9
|
// draw a tile
|
|
7
|
-
drawTile(vec2(
|
|
10
|
+
drawTile(vec2(Math.sin(time)*3,-2), vec2(7), tile(3,128));
|
|
8
11
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
class Player extends EngineObject
|
|
2
|
+
{
|
|
3
|
+
constructor(pos)
|
|
4
|
+
{
|
|
5
|
+
super(pos, vec2(2), tile(9), 0, CYAN);
|
|
6
|
+
this.damping = 1; // disable damping
|
|
7
|
+
this.clampSpeed = false; // disable speed clamping
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
update()
|
|
11
|
+
{
|
|
12
|
+
super.update();
|
|
13
|
+
|
|
14
|
+
const h = getGroundHeight(this.pos.x);
|
|
15
|
+
if (this.pos.y < h + this.size.y/2)
|
|
16
|
+
{
|
|
17
|
+
// clamp to ground and reflect velocity
|
|
18
|
+
this.pos.y = h + this.size.y/2;
|
|
19
|
+
const n = vec2((h-getGroundHeight(this.pos.x+.1))/.1, 1).normalize();
|
|
20
|
+
this.velocity = this.velocity.reflect(n,0);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// apply movement controls
|
|
24
|
+
if (mouseIsDown(0) || keyIsDown('Space'))
|
|
25
|
+
this.applyAcceleration(vec2(0,-.05));
|
|
26
|
+
this.velocity.x = max(this.velocity.x,.4);
|
|
27
|
+
this.angle = this.velocity.angle() - PI/2;
|
|
28
|
+
|
|
29
|
+
// move camera with player
|
|
30
|
+
cameraPos = vec2(this.pos.x+9,5);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function getGroundHeight(x)
|
|
35
|
+
{
|
|
36
|
+
return Math.sin(x/4)*2 + Math.sin(x/17);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function gameInit()
|
|
40
|
+
{
|
|
41
|
+
gravity.y = -.01;
|
|
42
|
+
new Player(vec2(0,5));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function gameRender()
|
|
46
|
+
{
|
|
47
|
+
const h = 100, w = 20;
|
|
48
|
+
const pos = vec2(), size = vec2(.2,h), color = WHITE;
|
|
49
|
+
for (let x=cameraPos.x-w; x<cameraPos.x+w; x+=.1)
|
|
50
|
+
{
|
|
51
|
+
pos.x = x;
|
|
52
|
+
pos.y = getGroundHeight(x)-h/2;
|
|
53
|
+
color.setHSLA(.2+.2*wave(.2,1,x), .5, .5);
|
|
54
|
+
drawRect(pos, size, color);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
class Player extends EngineObject
|
|
2
|
+
{
|
|
3
|
+
constructor(pos)
|
|
4
|
+
{
|
|
5
|
+
super(pos, vec2(1,2), tile(8), 0, RED);
|
|
6
|
+
this.setCollision(); // make object collide
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
update()
|
|
10
|
+
{
|
|
11
|
+
super.update();
|
|
12
|
+
|
|
13
|
+
// apply movement controls
|
|
14
|
+
this.applyAcceleration(keyDirection().scale(.002));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function gameInit()
|
|
19
|
+
{
|
|
20
|
+
// setup level
|
|
21
|
+
gravity.y = -.001;
|
|
22
|
+
new Player(vec2(0,4));
|
|
23
|
+
|
|
24
|
+
// create ground
|
|
25
|
+
for (let i=0, y=0; i<20; ++i)
|
|
26
|
+
{
|
|
27
|
+
y = (y + rand(1,-1)*4) * .5;
|
|
28
|
+
const o = new EngineObject(vec2(i*2-20, y-54), vec2(2, 99), 0, 0, hsl(0,0,.5+i%.29));
|
|
29
|
+
o.setCollision(); // make object collide
|
|
30
|
+
o.mass = 0; // make object have static physics
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
function generateMaze(size)
|
|
2
|
+
{
|
|
3
|
+
const maze = [], w = size.x, h = size.y;
|
|
4
|
+
maze[1 + w] = 1; // start point
|
|
5
|
+
for(let k=w*h*9|0; k--;)
|
|
6
|
+
{
|
|
7
|
+
// get a random position on odd coordinates
|
|
8
|
+
const jx = randInt(w/2-(w%2?0:2)|0)*2 + 1;
|
|
9
|
+
const jy = randInt(h/2-(h%2?1:2)|0)*2 + 1;
|
|
10
|
+
const j = jx + jy*w;
|
|
11
|
+
|
|
12
|
+
// get a random direction
|
|
13
|
+
const d = randSign() * (randBool() ? 1 : w);
|
|
14
|
+
|
|
15
|
+
// check if we are not the same line or column
|
|
16
|
+
if (j%w != (j+d*2)%w && (j/w|0) != ((j+d*2)/w|0))
|
|
17
|
+
continue;
|
|
18
|
+
|
|
19
|
+
// check if pos is open and the next 2 cells are closed
|
|
20
|
+
if (maze[j] && !maze[j+d] && !maze[j+d*2])
|
|
21
|
+
maze[j+d] = maze[j+d*2] = 1;
|
|
22
|
+
}
|
|
23
|
+
return maze;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function gameInit()
|
|
27
|
+
{
|
|
28
|
+
// generate maze data
|
|
29
|
+
const mazeSize = vec2(27,15);
|
|
30
|
+
const maze = generateMaze(mazeSize);
|
|
31
|
+
|
|
32
|
+
// create tile layer
|
|
33
|
+
const pos = vec2();
|
|
34
|
+
const tileLayer = new TileCollisionLayer(pos, mazeSize);
|
|
35
|
+
for (pos.x = tileLayer.size.x; pos.x--;)
|
|
36
|
+
for (pos.y = tileLayer.size.y; pos.y--;)
|
|
37
|
+
{
|
|
38
|
+
// check if tile should be solid
|
|
39
|
+
if (maze[pos.x + pos.y*mazeSize.x])
|
|
40
|
+
continue;
|
|
41
|
+
|
|
42
|
+
// set tile data
|
|
43
|
+
tileLayer.setData(pos, new TileLayerData(1));
|
|
44
|
+
}
|
|
45
|
+
tileLayer.redraw(); // redraw tile layer with new data
|
|
46
|
+
cameraPos = mazeSize.scale(.5); // center camera
|
|
47
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// create example medals
|
|
2
|
+
const medal_openedExample = new Medal(0, 'Opened Example', 'You opened this example!');
|
|
3
|
+
const medal_leftClick = new Medal(1, 'Left Clicked', 'You left clicked!', '🐁');
|
|
4
|
+
const medal_rightClick = new Medal(2, 'Right Clicked', 'You right clicked!', '🐭');
|
|
5
|
+
const medal_spacePressed = new Medal(3, 'Pressed Spacebar', 'You pressed spacebar!', '🚀');
|
|
6
|
+
|
|
7
|
+
// setup medals
|
|
8
|
+
const saveName = 'Medals Example';
|
|
9
|
+
medalsInit(saveName);
|
|
10
|
+
|
|
11
|
+
// clear medals for testing
|
|
12
|
+
medalsForEach(medal=> medal.unlocked = false);
|
|
13
|
+
medal_openedExample.unlock();
|
|
14
|
+
|
|
15
|
+
function gameUpdate()
|
|
16
|
+
{
|
|
17
|
+
if (mouseWasPressed(0))
|
|
18
|
+
medal_leftClick.unlock();
|
|
19
|
+
if (mouseWasPressed(2))
|
|
20
|
+
medal_rightClick.unlock();
|
|
21
|
+
if (keyWasPressed('Space'))
|
|
22
|
+
medal_spacePressed.unlock();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function gameRender()
|
|
26
|
+
{
|
|
27
|
+
const size = 80;
|
|
28
|
+
let pos = mainCanvasSize.scale(.5).subtract(vec2(0,40));
|
|
29
|
+
drawTextScreen('Unlocked Medals', pos, size);
|
|
30
|
+
|
|
31
|
+
// show unlocked medals
|
|
32
|
+
let medalsCount = 0;
|
|
33
|
+
medalsForEach(medal=> medal.unlocked && medalsCount++);
|
|
34
|
+
pos = pos.add(vec2((1-medalsCount)*size/2, 100));
|
|
35
|
+
medalsForEach(medal=>
|
|
36
|
+
{
|
|
37
|
+
if (!medal.unlocked)
|
|
38
|
+
return;
|
|
39
|
+
medal.renderIcon(pos, size);
|
|
40
|
+
pos.x += size + 8;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
function gameRender()
|
|
2
|
+
{
|
|
3
|
+
const nineSliceTile = tile(16);
|
|
4
|
+
const threeSliceTile = tile(19);
|
|
5
|
+
|
|
6
|
+
// draw nine slice with thin border and color
|
|
7
|
+
drawNineSlice(vec2(-7,4), vec2(13, 6), nineSliceTile, hsl(.1,.5,.9), .5);
|
|
8
|
+
drawTextOverlay('Nine Slice\nThin Border', vec2(-7,4), 1, BLACK);
|
|
9
|
+
|
|
10
|
+
// draw nine slice in screen space with thick border
|
|
11
|
+
drawNineSliceScreen(vec2(700,150), vec2(250), nineSliceTile);
|
|
12
|
+
drawTextScreen('Nine Slice\nScreen Space', vec2(700,150), 30, BLACK);
|
|
13
|
+
|
|
14
|
+
// draw three slice with thick border and additive color
|
|
15
|
+
drawThreeSlice(vec2(-7,-4), vec2(9, 7), threeSliceTile, WHITE, 2, hsl(.6,1,.5));
|
|
16
|
+
drawTextOverlay('Three Slice\nThick Border', vec2(-7,-4), 1, BLACK);
|
|
17
|
+
|
|
18
|
+
// draw three slice in screen space with thick border
|
|
19
|
+
drawThreeSliceScreen(vec2(700,400), vec2(400,150), threeSliceTile);
|
|
20
|
+
drawTextScreen('Three Slice\nScreen Space', vec2(700,400), 30, BLACK);
|
|
21
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const pianoSound = new Sound([,0,220,,9]), keys = [];
|
|
2
|
+
|
|
3
|
+
class PianoKey extends EngineObject
|
|
4
|
+
{
|
|
5
|
+
constructor(pos, size, semitone, isWhite)
|
|
6
|
+
{
|
|
7
|
+
const keySize = 2;
|
|
8
|
+
size = size.scale(keySize);
|
|
9
|
+
pos = pos.scale(keySize).add(vec2(0,4-size.y/2));
|
|
10
|
+
super(pos, size, 0, 0, hsl(0,0,isWhite ? 1 : .3));
|
|
11
|
+
this.drawSize = size.subtract(vec2(.1,0));
|
|
12
|
+
this.semitone = semitone;
|
|
13
|
+
}
|
|
14
|
+
press()
|
|
15
|
+
{
|
|
16
|
+
if (!this.isDown)
|
|
17
|
+
pianoSound.playNote(this.semitone);
|
|
18
|
+
this.isDown = true;
|
|
19
|
+
}
|
|
20
|
+
release()
|
|
21
|
+
{
|
|
22
|
+
if (this.isDown)
|
|
23
|
+
pianoSound.stop(.2);
|
|
24
|
+
this.isDown = false;
|
|
25
|
+
}
|
|
26
|
+
render()
|
|
27
|
+
{
|
|
28
|
+
const color = this.isDown ? RED : this.color;
|
|
29
|
+
drawRect(this.pos, this.drawSize, color);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function gameInit()
|
|
34
|
+
{
|
|
35
|
+
// create piano keyboard
|
|
36
|
+
for(let i=15; i--;)
|
|
37
|
+
keys.unshift(new PianoKey(vec2(i-7,0), vec2(1,4), [0,2,4,5,7,9,11][i%7]+(i/7|0)*12, 1));
|
|
38
|
+
for(let i=10; i--;)
|
|
39
|
+
keys.unshift(new PianoKey(vec2([1,2,4,5,6][i%5]+(i/5|0)*7-7.5,0), vec2(1,2), [1,3,6,8,10][i%5]+(i/5|0)*12));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function gameUpdate()
|
|
43
|
+
{
|
|
44
|
+
// update state of piano keys
|
|
45
|
+
const pressedKey = keys.find(k=>k.isDown);
|
|
46
|
+
const newPressedKey = mouseIsDown(0) && keys.find(k=>isOverlapping(k.pos, k.size, mousePos));
|
|
47
|
+
if (newPressedKey != pressedKey)
|
|
48
|
+
{
|
|
49
|
+
pressedKey && pressedKey.release();
|
|
50
|
+
newPressedKey && newPressedKey.press();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -1,31 +1,23 @@
|
|
|
1
|
-
class
|
|
2
|
-
{
|
|
3
|
-
constructor(pos, size, color)
|
|
4
|
-
{
|
|
5
|
-
super(pos, size, 0, 0, color);
|
|
6
|
-
this.setCollision(); // make object collide
|
|
7
|
-
this.mass = 0; // make object have static physics
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
class Player extends PhysicsObject
|
|
1
|
+
class Player extends EngineObject
|
|
12
2
|
{
|
|
13
3
|
constructor(pos)
|
|
14
4
|
{
|
|
15
|
-
super(pos, vec2(2,4), RED);
|
|
16
|
-
this.
|
|
5
|
+
super(pos, vec2(2,4), 0, 0, RED);
|
|
6
|
+
this.setCollision(); // make object collide
|
|
17
7
|
}
|
|
18
8
|
|
|
19
9
|
update()
|
|
20
10
|
{
|
|
11
|
+
super.update();
|
|
12
|
+
|
|
21
13
|
// apply movement controls
|
|
22
14
|
const moveInput = keyDirection();
|
|
23
15
|
this.velocity.x += moveInput.x * (this.groundObject ? .1: .01);
|
|
24
16
|
if (this.groundObject && moveInput.y > 0)
|
|
25
17
|
this.velocity.y = .9; // jump
|
|
26
18
|
|
|
27
|
-
|
|
28
|
-
cameraPos = vec2(this.pos.x, 9);
|
|
19
|
+
// move camera with player
|
|
20
|
+
cameraPos = vec2(this.pos.x, 9);
|
|
29
21
|
}
|
|
30
22
|
}
|
|
31
23
|
|
|
@@ -33,10 +25,22 @@ function gameInit()
|
|
|
33
25
|
{
|
|
34
26
|
// setup level
|
|
35
27
|
gravity.y = -.05;
|
|
36
|
-
new Player(vec2(
|
|
28
|
+
new Player(vec2(5,6));
|
|
37
29
|
|
|
38
|
-
// create
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
30
|
+
// create tile layer
|
|
31
|
+
const pos = vec2();
|
|
32
|
+
const tileLayer = new TileCollisionLayer(pos, vec2(256));
|
|
33
|
+
for (pos.x = tileLayer.size.x; pos.x--;)
|
|
34
|
+
for (pos.y = tileLayer.size.y; pos.y--;)
|
|
35
|
+
{
|
|
36
|
+
// check if tile should be solid
|
|
37
|
+
const levelHeight = pos.x<9 ? 2 : (pos.x/4|0)**3.1%7;
|
|
38
|
+
if (pos.y > levelHeight)
|
|
39
|
+
continue;
|
|
40
|
+
|
|
41
|
+
// set tile data
|
|
42
|
+
tileLayer.setData(pos, new TileLayerData(1));
|
|
43
|
+
tileLayer.setCollisionData(pos);
|
|
44
|
+
}
|
|
45
|
+
tileLayer.redraw(); // redraw tile layer with new data
|
|
42
46
|
}
|
|
@@ -32,7 +32,7 @@ function gameUpdate()
|
|
|
32
32
|
ball && ball.destroy(); // destroy old ball
|
|
33
33
|
ball = new PhysicsObject(cameraPos); // create a ball
|
|
34
34
|
ball.velocity = vec2(.2); // give ball some movement
|
|
35
|
-
ball.
|
|
35
|
+
ball.restitution = 1; // make ball bounce
|
|
36
36
|
ball.mass = 1; // make ball have dynamic physics
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
function gameInit()
|
|
2
|
+
{
|
|
3
|
+
new PostProcessPlugin(tvShader);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
function gameRender()
|
|
7
|
+
{
|
|
8
|
+
drawRect(vec2(), vec2(99), GRAY);
|
|
9
|
+
drawTile(vec2(), vec2(12), tile(3,128));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const tvShader = `
|
|
13
|
+
// Simple TV Shader Code
|
|
14
|
+
float hash(vec2 p)
|
|
15
|
+
{
|
|
16
|
+
p=fract(p*.3197);
|
|
17
|
+
return fract(1.+sin(51.*p.x+73.*p.y)*13753.3);
|
|
18
|
+
}
|
|
19
|
+
float noise(vec2 p)
|
|
20
|
+
{
|
|
21
|
+
vec2 i=floor(p),f=fract(p),u=f*f*(3.-2.*f);
|
|
22
|
+
return mix(mix(hash(i),hash(i+vec2(1,0)),u.x),mix(hash(i+vec2(0,1)),hash(i+1.),u.x),u.y);
|
|
23
|
+
}
|
|
24
|
+
void mainImage(out vec4 c, vec2 p)
|
|
25
|
+
{
|
|
26
|
+
// setup the shader
|
|
27
|
+
p /= iResolution.xy;
|
|
28
|
+
c = texture(iChannel0, p);
|
|
29
|
+
|
|
30
|
+
// static noise
|
|
31
|
+
const float staticAlpha = .1;
|
|
32
|
+
const float staticScale = .005;
|
|
33
|
+
c += staticAlpha * hash(floor(p/staticScale) + mod(iTime*500., 1e3));
|
|
34
|
+
|
|
35
|
+
// scan lines
|
|
36
|
+
const float scanlineScale = 2.;
|
|
37
|
+
const float scanlineAlpha = .3;
|
|
38
|
+
c *= 1. - scanlineAlpha*cos(p.y*2.*iResolution.y/scanlineScale);
|
|
39
|
+
|
|
40
|
+
// black vignette around edges
|
|
41
|
+
const float vignette = 2.;
|
|
42
|
+
const float vignettePow = 6.;
|
|
43
|
+
float dx = 2.*p.x-1., dy = 2.*p.y-1.;
|
|
44
|
+
c *= 1.-pow((dx*dx + dy*dy)/vignette, vignettePow);
|
|
45
|
+
}`;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
let playerPos = vec2(), playerAngle = 0;
|
|
2
|
+
|
|
3
|
+
// a simple function to generate a level
|
|
4
|
+
const levelTest = (X,Y)=> ((X|0)**3&(Y|0)**2)%30>5;
|
|
5
|
+
|
|
6
|
+
// cast a ray and return the distance to the first wall hit (0-1)
|
|
7
|
+
function raycast(pos, angle)
|
|
8
|
+
{
|
|
9
|
+
const maxDistance = 40, delta = .05;
|
|
10
|
+
const rayX = delta*Math.sin(angle);
|
|
11
|
+
const rayY = delta*Math.cos(angle);
|
|
12
|
+
let posX = pos.x, posY = pos.y;
|
|
13
|
+
for (let distance = 0; distance < maxDistance; distance += delta)
|
|
14
|
+
{
|
|
15
|
+
if (levelTest(posX, posY))
|
|
16
|
+
return distance/maxDistance;
|
|
17
|
+
posX += rayX;
|
|
18
|
+
posY += rayY;
|
|
19
|
+
}
|
|
20
|
+
return 1;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function gameUpdate()
|
|
24
|
+
{
|
|
25
|
+
// update camera angle with mouse pointer lock
|
|
26
|
+
if (mouseWasPressed(0))
|
|
27
|
+
pointerLockRequest();
|
|
28
|
+
if (keyWasPressed('Escape'))
|
|
29
|
+
pointerLockExit()
|
|
30
|
+
if (pointerLockIsActive() || isTouchDevice)
|
|
31
|
+
playerAngle += mouseDelta.x * .003;
|
|
32
|
+
|
|
33
|
+
// update player movement, prevent walking through walls
|
|
34
|
+
const velocity = keyDirection().scale(.1).rotate(playerAngle);
|
|
35
|
+
const newPos = playerPos.add(velocity);
|
|
36
|
+
if (!levelTest(newPos.x, newPos.y))
|
|
37
|
+
playerPos = newPos;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function gameRender()
|
|
41
|
+
{
|
|
42
|
+
{
|
|
43
|
+
// draw horizontal slizes to create floor and ceiling
|
|
44
|
+
const h = 9;
|
|
45
|
+
let pos = vec2(), size = vec2(39, .11), color = WHITE;
|
|
46
|
+
for (let y=-h; y<h; y+=.1)
|
|
47
|
+
{
|
|
48
|
+
const p = 1.01-abs(y/h)
|
|
49
|
+
pos.y = y;
|
|
50
|
+
color.setHSLA(.1, y>0?0:.5, .7-p*.7);
|
|
51
|
+
drawRect(pos, size, color);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
{
|
|
55
|
+
// draw vertical slices to create the walls
|
|
56
|
+
const w = 20;
|
|
57
|
+
const pos = vec2(), size = vec2(.11), color = WHITE;
|
|
58
|
+
for (let x=-w; x<w; x+=.1)
|
|
59
|
+
{
|
|
60
|
+
const p = raycast(playerPos, playerAngle + x/w);
|
|
61
|
+
pos.x = x;
|
|
62
|
+
size.y = .4/p;
|
|
63
|
+
color.setHSLA(.6, .5, .7-p*.7);
|
|
64
|
+
drawRect(pos, size, color);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// draw instructions and pointer lock status
|
|
68
|
+
const instructions = pointerLockIsActive() ? 'Mouse Control Active - ESC To Exit' : 'Click To Enable Mouse Control';
|
|
69
|
+
if (!isTouchDevice)
|
|
70
|
+
drawTextScreen(instructions, vec2(mainCanvasSize.x/2, 50), 24, pointerLockIsActive() ? GREEN : WHITE);
|
|
71
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const gridSize = vec2(4,3);
|
|
2
|
+
const pieceSize = vec2(5,4);
|
|
3
|
+
let emptyGridPos = vec2();
|
|
4
|
+
|
|
5
|
+
class PuzzlePiece extends EngineObject
|
|
6
|
+
{
|
|
7
|
+
constructor(gridPos, size)
|
|
8
|
+
{
|
|
9
|
+
const color = rgb(gridPos.x/(gridSize.x-1), gridPos.y/(gridSize.y-1), 1);
|
|
10
|
+
super(gridPos.multiply(size), size, 0, 0, color);
|
|
11
|
+
this.gridPos = gridPos;
|
|
12
|
+
this.text = gridPos.x + gridPos.y*gridSize.x;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
update()
|
|
16
|
+
{
|
|
17
|
+
if (mouseWasPressed(0) && isOverlapping(this.pos, this.size, mousePos))
|
|
18
|
+
if (abs(this.gridPos.x-emptyGridPos.x) + abs(this.gridPos.y-emptyGridPos.y) == 1)
|
|
19
|
+
{
|
|
20
|
+
// swap with empty space when clicked on
|
|
21
|
+
this.pos = emptyGridPos.multiply(this.size);
|
|
22
|
+
[emptyGridPos, this.gridPos] = [this.gridPos, emptyGridPos];
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
render()
|
|
27
|
+
{
|
|
28
|
+
super.render();
|
|
29
|
+
drawTextOverlay(this.text, this.pos, 2.5, BLACK);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function gameInit()
|
|
34
|
+
{
|
|
35
|
+
// create puzzle pieces
|
|
36
|
+
for(let x=gridSize.x; x--;)
|
|
37
|
+
for(let y=gridSize.y; y--;)
|
|
38
|
+
(x||y) && new PuzzlePiece(vec2(x,y), pieceSize);
|
|
39
|
+
|
|
40
|
+
// center camera on grid
|
|
41
|
+
cameraPos = gridSize.subtract(vec2(1)).multiply(pieceSize).scale(.5);
|
|
42
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
class Player extends EngineObject
|
|
2
|
+
{
|
|
3
|
+
constructor(pos)
|
|
4
|
+
{
|
|
5
|
+
super(pos, vec2(1,2), tile(8), 0, CYAN);
|
|
6
|
+
this.damping = .97;
|
|
7
|
+
this.angleDamping = .95;
|
|
8
|
+
this.shootTimer = new Timer;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
update()
|
|
12
|
+
{
|
|
13
|
+
super.update();
|
|
14
|
+
|
|
15
|
+
// space ship controls
|
|
16
|
+
const moveInput = keyDirection();
|
|
17
|
+
this.applyAngularAcceleration(moveInput.x * .005);
|
|
18
|
+
this.applyAcceleration(vec2().setAngle(this.angle, moveInput.y*.02));
|
|
19
|
+
if (!this.shootTimer.active() && (keyIsDown('Space') || mouseIsDown(0)))
|
|
20
|
+
{
|
|
21
|
+
// shoot bullet
|
|
22
|
+
const pos = this.pos.add(vec2(0,1).rotate(cameraAngle));
|
|
23
|
+
const bullet = new EngineObject(pos, vec2(.2,.5), 0, this.angle, YELLOW);
|
|
24
|
+
bullet.velocity = this.velocity.add(vec2(0,.5).rotate(this.angle));
|
|
25
|
+
this.shootTimer.set(.1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// move camera with player
|
|
29
|
+
cameraPos = this.pos;
|
|
30
|
+
cameraAngle = this.angle;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function gameInit()
|
|
35
|
+
{
|
|
36
|
+
new Player(vec2(0,4));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function gameRender()
|
|
40
|
+
{
|
|
41
|
+
// draw wrapped starfield with parallax
|
|
42
|
+
const range = 32, halfRange = range/2;
|
|
43
|
+
|
|
44
|
+
// precreate variables to avoid overhead
|
|
45
|
+
const pos = vec2(), size = vec2(), color = WHITE;
|
|
46
|
+
for (let i=1e3; i--;)
|
|
47
|
+
{
|
|
48
|
+
// use math to generate random star positions
|
|
49
|
+
const parallax = i%.13-1;
|
|
50
|
+
pos.x = mod(i**2.1 + cameraPos.x*parallax, range) + cameraPos.x - halfRange;
|
|
51
|
+
pos.y = mod(i**3.1 + cameraPos.y*parallax, range) + cameraPos.y - halfRange;
|
|
52
|
+
size.x = size.y = i%.07+.03;
|
|
53
|
+
color.a = .1+i%.9;
|
|
54
|
+
drawRect(pos, size, color);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
function gameRender()
|
|
2
|
+
{
|
|
3
|
+
setBlendMode(1);
|
|
4
|
+
// precreate variables to avoid overhead
|
|
5
|
+
const pos = vec2(), size = vec2(), color = WHITE;
|
|
6
|
+
for(let i=2e3; i--;)
|
|
7
|
+
{
|
|
8
|
+
// use math to generate random star positions
|
|
9
|
+
const offset = time*(9+i**2.1%15) + i**2.3;
|
|
10
|
+
pos.x = offset%70-35;
|
|
11
|
+
pos.y = i/120-8;
|
|
12
|
+
size.x = size.y = i%.11+.07;
|
|
13
|
+
color.setHSLA(0, 0, Math.sin(i)**4);
|
|
14
|
+
drawRect(pos, size, color);
|
|
15
|
+
}
|
|
16
|
+
setBlendMode(0);
|
|
17
|
+
}
|