littlejsengine 1.9.6 → 1.9.8
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/LICENSE +22 -0
- package/README.md +13 -8
- package/dist/littlejs.d.ts +85 -84
- package/dist/littlejs.esm.js +370 -390
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +365 -386
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +302 -355
- package/examples/box2d/game.js +138 -0
- package/examples/box2d/index.html +25 -0
- package/examples/box2d/scenes.js +412 -0
- package/examples/box2d/tiles.png +0 -0
- package/examples/breakout/game.js +3 -3
- package/examples/breakout/index.html +1 -0
- package/examples/platformer/gameEffects.js +2 -2
- package/examples/platformer/gameLevel.js +0 -1
- package/package.json +1 -1
- package/plugins/Box2D_v2.3.1_min.wasm.js +630 -0
- package/plugins/Box2D_v2.3.1_min.wasm.wasm +0 -0
- package/plugins/box2d.js +873 -0
- package/plugins/newgrounds.js +169 -0
- package/plugins/postProcess.js +101 -0
- package/src/engine.js +45 -26
- package/src/engineAudio.js +72 -47
- package/src/engineDebug.js +68 -33
- package/src/engineDraw.js +1 -1
- package/src/engineExport.js +5 -4
- package/src/engineMedals.js +39 -171
- package/src/engineObject.js +47 -4
- package/src/engineParticles.js +3 -0
- package/src/engineRelease.js +5 -2
- package/src/engineSettings.js +8 -3
- package/src/engineUtilities.js +81 -7
- package/src/engineWebGL.js +1 -94
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Little JS Box2d Demo
|
|
3
|
+
- Demonstrates how to use Box2D with LittleJS
|
|
4
|
+
- Several scenes to demonstrate Box2D features
|
|
5
|
+
- Every type of shape and joint
|
|
6
|
+
- Contact begin and end callbacks
|
|
7
|
+
- Raycasting and querying
|
|
8
|
+
- Collision filtering
|
|
9
|
+
- User Interaction
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
// show the LittleJS splash screen
|
|
15
|
+
setShowSplashScreen(true);
|
|
16
|
+
//box2dDebug = 1; // enable box2d debug draw
|
|
17
|
+
|
|
18
|
+
// game variables
|
|
19
|
+
const maxScenes = 9;
|
|
20
|
+
let scene = 0;
|
|
21
|
+
let sceneName;
|
|
22
|
+
let groundObject;
|
|
23
|
+
let mouseJoint;
|
|
24
|
+
let carWheelJoint;
|
|
25
|
+
|
|
26
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
27
|
+
function gameInit()
|
|
28
|
+
{
|
|
29
|
+
loadScene(scene);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
33
|
+
function gameUpdate()
|
|
34
|
+
{
|
|
35
|
+
// scale canvas to fit based on 1080p
|
|
36
|
+
cameraScale = mainCanvasSize.y * 48 / 1080;
|
|
37
|
+
|
|
38
|
+
// mouse controls
|
|
39
|
+
if (mouseWasPressed(0))
|
|
40
|
+
{
|
|
41
|
+
// grab object
|
|
42
|
+
sound_click.play(mousePos);
|
|
43
|
+
const object = box2dPointCast(mousePos);
|
|
44
|
+
if (object)
|
|
45
|
+
mouseJoint = box2dCreateMouseJoint(object, groundObject, mousePos);
|
|
46
|
+
}
|
|
47
|
+
if (mouseWasReleased(0))
|
|
48
|
+
{
|
|
49
|
+
// release object
|
|
50
|
+
sound_click.play(mousePos, 1, .5);
|
|
51
|
+
if (mouseJoint)
|
|
52
|
+
{
|
|
53
|
+
box2dDestroyJoint(mouseJoint);
|
|
54
|
+
mouseJoint = 0;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (mouseWasPressed(1))
|
|
58
|
+
spawnRandomObject(mousePos);
|
|
59
|
+
if (mouseWasPressed(2))
|
|
60
|
+
explosion(mousePos);
|
|
61
|
+
if (mouseJoint)
|
|
62
|
+
mouseJoint.SetTarget(mousePos.getBox2d());
|
|
63
|
+
|
|
64
|
+
if (keyWasPressed('ArrowUp') || keyWasPressed('ArrowDown'))
|
|
65
|
+
{
|
|
66
|
+
// change scene
|
|
67
|
+
scene += keyWasPressed('ArrowUp') ? 1 : -1;
|
|
68
|
+
scene = mod(scene, maxScenes);
|
|
69
|
+
loadScene(scene);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (carWheelJoint)
|
|
73
|
+
{
|
|
74
|
+
// update car control
|
|
75
|
+
const control = keyIsDown('ArrowLeft') - keyIsDown('ArrowRight');
|
|
76
|
+
let s = carWheelJoint.GetMotorSpeed();
|
|
77
|
+
s = control ? clamp(s + control, -40, 40) : s * .8;
|
|
78
|
+
carWheelJoint.SetMotorSpeed(s);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
83
|
+
function gameUpdatePost()
|
|
84
|
+
{
|
|
85
|
+
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
89
|
+
function gameRender()
|
|
90
|
+
{
|
|
91
|
+
// draw a grey square in the background without using webgl
|
|
92
|
+
drawRect(vec2(20,8), vec2(100), hsl(0,0,.8), 0, 0);
|
|
93
|
+
|
|
94
|
+
if (scene == 5)
|
|
95
|
+
{
|
|
96
|
+
// raycast test
|
|
97
|
+
const count = 100;
|
|
98
|
+
const distance = 10;
|
|
99
|
+
for (let i=count;i--;)
|
|
100
|
+
{
|
|
101
|
+
const start = mousePos;
|
|
102
|
+
const end = mousePos.add(vec2(distance,0).rotate(i/count*PI*2));
|
|
103
|
+
const result = box2dRaycast(start, end);
|
|
104
|
+
const color = result ? hsl(0,1,.5,.5) : hsl(.5,1,.5,.5);
|
|
105
|
+
drawLine(start, result ? result.point : end, .1, color);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
111
|
+
function gameRenderPost()
|
|
112
|
+
{
|
|
113
|
+
// draw to overlay canvas for hud rendering
|
|
114
|
+
const pos = vec2(mainCanvasSize.x/2, 50);
|
|
115
|
+
drawText('LittleJS Box2D Demo', 80, 80);
|
|
116
|
+
drawText(sceneName, 60, 90);
|
|
117
|
+
if (scene == 0)
|
|
118
|
+
{
|
|
119
|
+
drawText('Mouse Left = Grab');
|
|
120
|
+
drawText('Mouse Middle = Spawn');
|
|
121
|
+
drawText('Mouse Right = Explode');
|
|
122
|
+
drawText('Mouse Middle = Spawn');
|
|
123
|
+
drawText('Arrows = Next Scene');
|
|
124
|
+
}
|
|
125
|
+
if (scene == 3)
|
|
126
|
+
{
|
|
127
|
+
drawText('Right = Accelerate');
|
|
128
|
+
drawText('Left = Reverse');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function drawText(text, size=40, gap=50)
|
|
132
|
+
{ drawTextScreen(text, pos, size, WHITE, 6); pos.y += gap; }
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
136
|
+
// Startup LittleJS Engine with Box2D
|
|
137
|
+
|
|
138
|
+
box2dEngineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!DOCTYPE html><head>
|
|
2
|
+
<title>Little JS Starter Project</title>
|
|
3
|
+
<meta name=apple-mobile-web-app-capable content=yes>
|
|
4
|
+
<meta name=mobile-web-app-capable content=yes>
|
|
5
|
+
<link rel=icon type=image/png href=../favicon.png>
|
|
6
|
+
</head><body>
|
|
7
|
+
|
|
8
|
+
<!-- LittleJS Engine -->
|
|
9
|
+
<script src=../../src/engineDebug.js?196></script>
|
|
10
|
+
<script src=../../src/engineUtilities.js?196></script>
|
|
11
|
+
<script src=../../src/engineSettings.js?196></script>
|
|
12
|
+
<script src=../../src/engineObject.js?196></script>
|
|
13
|
+
<script src=../../src/engineDraw.js?196></script>
|
|
14
|
+
<script src=../../src/engineInput.js?196></script>
|
|
15
|
+
<script src=../../src/engineAudio.js?196></script>
|
|
16
|
+
<script src=../../src/engineTileLayer.js?196></script>
|
|
17
|
+
<script src=../../src/engineParticles.js?196></script>
|
|
18
|
+
<script src=../../src/engineMedals.js?196></script>
|
|
19
|
+
<script src=../../src/engineWebGL.js?196></script>
|
|
20
|
+
<script src=../../src/engine.js?196></script>
|
|
21
|
+
|
|
22
|
+
<script src=../../plugins/Box2D_v2.3.1_min.wasm.js?196></script>
|
|
23
|
+
<script src=../../plugins/box2d.js?196></script>
|
|
24
|
+
<script src=scenes.js?196></script>
|
|
25
|
+
<script src=game.js?196></script>
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
/*
|
|
2
|
+
LittleJS Box2D Example - Secenes
|
|
3
|
+
- Each scene demonstrates a feature of Box2D
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
function loadScene(_scene)
|
|
9
|
+
{
|
|
10
|
+
scene = _scene;
|
|
11
|
+
|
|
12
|
+
// setup
|
|
13
|
+
cameraPos = vec2(20,10);
|
|
14
|
+
setGravity(-20);
|
|
15
|
+
|
|
16
|
+
// destroy old scene
|
|
17
|
+
engineObjectsDestroy();
|
|
18
|
+
carWheelJoint = 0;
|
|
19
|
+
mouseJoint = 0;
|
|
20
|
+
|
|
21
|
+
// create walls
|
|
22
|
+
groundObject = spawnBox(vec2(0,-4), vec2(1e3,8), hsl(0,0,.2), box2dBodyTypeStatic);
|
|
23
|
+
spawnBox(vec2(-4, 0), vec2(8,1e3), BLACK, box2dBodyTypeStatic);
|
|
24
|
+
spawnBox(vec2(44, 0), vec2(8,1e3), BLACK, box2dBodyTypeStatic);
|
|
25
|
+
spawnBox(vec2(0,100), vec2(1e3,8), BLACK, box2dBodyTypeStatic);
|
|
26
|
+
|
|
27
|
+
if (scene == 0)
|
|
28
|
+
{
|
|
29
|
+
sceneName = 'Shapes';
|
|
30
|
+
spawnRandomEdges();
|
|
31
|
+
spawnBox(vec2(11,8), 4, randColor(), box2dBodyTypeStatic, false);
|
|
32
|
+
spawnCircle(vec2(20,8), 4, randColor(), box2dBodyTypeStatic, false);
|
|
33
|
+
spawnRandomPoly(vec2(29,8), 4, randColor(), box2dBodyTypeStatic, false);
|
|
34
|
+
for (let i=500;i--;)
|
|
35
|
+
spawnRandomObject(vec2(rand(1,39), rand(10,50)));
|
|
36
|
+
}
|
|
37
|
+
if (scene == 1)
|
|
38
|
+
{
|
|
39
|
+
sceneName = 'Pyramid';
|
|
40
|
+
spawnPyramid(vec2(20,0), 15);
|
|
41
|
+
spawnBox(vec2(10,2), 4, randColor());
|
|
42
|
+
spawnCircle(vec2(30,2), 4, randColor());
|
|
43
|
+
}
|
|
44
|
+
if (scene == 2)
|
|
45
|
+
{
|
|
46
|
+
sceneName = 'Dominoes';
|
|
47
|
+
spawnDominoes(vec2(11,11), 12);
|
|
48
|
+
spawnDominoes(vec2(2,0), 16, vec2(1,3));
|
|
49
|
+
spawnCircle(vec2(10,20), 2, randColor());
|
|
50
|
+
spawnCircle(vec2(31,12), 2, randColor());
|
|
51
|
+
spawnBox(vec2(16,11), vec2(32,1), randColor(), box2dBodyTypeStatic, false);
|
|
52
|
+
spawnBox(vec2(24,6.5), vec2(32,1), randColor(), box2dBodyTypeStatic, false, -.15);
|
|
53
|
+
}
|
|
54
|
+
if (scene == 3)
|
|
55
|
+
{
|
|
56
|
+
sceneName = 'Car';
|
|
57
|
+
spawnCar(vec2(10,5));
|
|
58
|
+
spawnBox(vec2(20,0), vec2(10,2), randColor(), box2dBodyTypeStatic, false, -.2);
|
|
59
|
+
spawnPyramid(vec2(32,0), 6);
|
|
60
|
+
}
|
|
61
|
+
if (scene == 4)
|
|
62
|
+
{
|
|
63
|
+
sceneName = 'Rope';
|
|
64
|
+
const startPos = vec2(20, 14);
|
|
65
|
+
const angle = PI/2;
|
|
66
|
+
const color = randColor();
|
|
67
|
+
const count = 10;
|
|
68
|
+
const endObject = spawnRope(startPos, count, angle, color);
|
|
69
|
+
|
|
70
|
+
// connect box to end
|
|
71
|
+
const endPos = endObject.localToWorld(vec2(0,-endObject.size.y/2));
|
|
72
|
+
const o = spawnBox(endPos, 3, randColor());
|
|
73
|
+
o.setAngularDamping(.5);
|
|
74
|
+
o.setFilterData(2, 2);
|
|
75
|
+
box2dCreateRevoluteJoint(endObject, o);
|
|
76
|
+
spawnPyramid(vec2(20,0), 7);
|
|
77
|
+
}
|
|
78
|
+
if (scene == 5)
|
|
79
|
+
{
|
|
80
|
+
sceneName = 'Raycast';
|
|
81
|
+
spawnRandomEdges();
|
|
82
|
+
for (let i=100;i--;)
|
|
83
|
+
spawnRandomObject(vec2(rand(1,39), rand(20)), 2, box2dBodyTypeStatic, rand(PI*2));
|
|
84
|
+
}
|
|
85
|
+
if (scene == 6)
|
|
86
|
+
{
|
|
87
|
+
sceneName = 'Joints';
|
|
88
|
+
{
|
|
89
|
+
// prismatic joint
|
|
90
|
+
const o1 = spawnBox(vec2(20,8), vec2(3,2), randColor());
|
|
91
|
+
box2dCreatePrismaticJoint(groundObject, o1, o1.pos, vec2(1,0), true);
|
|
92
|
+
const o2 = spawnBox(vec2(20,15), vec2(2,3), randColor());
|
|
93
|
+
box2dCreatePrismaticJoint(groundObject, o2, o2.pos, vec2(0,1), true);
|
|
94
|
+
|
|
95
|
+
// lines to make it look line a track
|
|
96
|
+
const l1 = new EngineObject(vec2(20, 8), vec2(39,.5), 0, 0, GRAY);
|
|
97
|
+
const l2 = new EngineObject(vec2(20,50), vec2(.5,99), 0, 0, GRAY);
|
|
98
|
+
l1.gravityScale = l2.gravityScale = 0;
|
|
99
|
+
l1.renderOrder = l2.renderOrder = -2;
|
|
100
|
+
}
|
|
101
|
+
{
|
|
102
|
+
// pulley object renders a rope to connected point
|
|
103
|
+
class PulleyObjects extends Box2dObject
|
|
104
|
+
{
|
|
105
|
+
constructor(pos, size, color, connectionPos)
|
|
106
|
+
{
|
|
107
|
+
super(pos, size, tile(3), 0, color);
|
|
108
|
+
this.addBox(size);
|
|
109
|
+
this.connectionPos = connectionPos;
|
|
110
|
+
}
|
|
111
|
+
render()
|
|
112
|
+
{
|
|
113
|
+
// draw rope
|
|
114
|
+
const topPos = this.localToWorld(vec2(0,this.size.y/2));
|
|
115
|
+
drawLine(topPos, this.connectionPos, .2, BLACK);
|
|
116
|
+
super.render();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// pulley joint
|
|
121
|
+
const anchorA = vec2(14,15);
|
|
122
|
+
const anchorB = vec2(26,15);
|
|
123
|
+
const oA = new PulleyObjects(vec2(15,8), vec2(1,2), randColor(), anchorA);
|
|
124
|
+
const oB = new PulleyObjects(vec2(25,8), vec2(1,2), randColor(), anchorB);
|
|
125
|
+
const aA = spawnCircle(anchorA, 2, randColor(), box2dBodyTypeStatic);
|
|
126
|
+
const aB = spawnCircle(anchorB, 2, randColor(), box2dBodyTypeStatic);
|
|
127
|
+
const oaA = oA.localToWorld(vec2(0,oA.size.y/2));
|
|
128
|
+
const oaB = oB.localToWorld(vec2(0,oB.size.y/2));
|
|
129
|
+
box2dCreatePulleyJoint(oA, oB, aA.pos, aB.pos, oaA, oaB);
|
|
130
|
+
|
|
131
|
+
// a line to make it look like conneting rope
|
|
132
|
+
const line = new EngineObject(vec2(20,15), vec2(10,.2), 0, 0, BLACK);
|
|
133
|
+
line.gravityScale = 0;
|
|
134
|
+
line.renderOrder = -1;
|
|
135
|
+
}
|
|
136
|
+
{
|
|
137
|
+
// gear joint
|
|
138
|
+
const o1 = spawnCircle(vec2(23.5,3), 3, randColor());
|
|
139
|
+
const j1 = box2dCreateRevoluteJoint(groundObject, o1, o1.pos);
|
|
140
|
+
const o2 = spawnCircle(vec2(28,3), 6, randColor());
|
|
141
|
+
o1.tileInfo = o2.tileInfo = tile(5);
|
|
142
|
+
const j2 = box2dCreateRevoluteJoint(groundObject, o2, o2.pos);
|
|
143
|
+
box2dCreateGearJoint(o1, o2, j1, j2, 2);
|
|
144
|
+
}
|
|
145
|
+
{
|
|
146
|
+
// weld joint
|
|
147
|
+
const o1 = spawnBox(vec2(15,2), 4, randColor());
|
|
148
|
+
const o2 = spawnBox(vec2(17,2), 2, randColor());
|
|
149
|
+
box2dCreateWeldJoint(o1, o2);
|
|
150
|
+
}
|
|
151
|
+
{
|
|
152
|
+
// distance joint
|
|
153
|
+
const o1 = new Box2dObject(vec2(30,11), vec2(4), tile(2), 0, randColor(), box2dBodyTypeStatic);
|
|
154
|
+
o1.renderOrder = -2;
|
|
155
|
+
const o2 = spawnCircle(vec2(30,8), 2, randColor());
|
|
156
|
+
box2dCreateDistanceJoint(o1, o2);
|
|
157
|
+
}
|
|
158
|
+
{
|
|
159
|
+
// motor object renders a rope to connected point
|
|
160
|
+
class MotorObject extends Box2dObject
|
|
161
|
+
{
|
|
162
|
+
constructor(pos, size, color, otherObject)
|
|
163
|
+
{
|
|
164
|
+
super(pos, size, tile(4), 0, color);
|
|
165
|
+
this.addCircle(size.x);
|
|
166
|
+
this.connectionPos = pos;
|
|
167
|
+
const joint = box2dCreateMotorJoint(otherObject, this);
|
|
168
|
+
joint.SetMaxForce(500);
|
|
169
|
+
joint.SetMaxTorque(500);
|
|
170
|
+
}
|
|
171
|
+
render()
|
|
172
|
+
{
|
|
173
|
+
// draw rope
|
|
174
|
+
const width = 2/(1+this.pos.distance(this.connectionPos));
|
|
175
|
+
drawLine(this.pos, this.connectionPos, width, BLACK);
|
|
176
|
+
super.render();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// motor joint
|
|
181
|
+
const o = new Box2dObject(vec2(10,8), vec2(4), tile(2), 0, randColor(), box2dBodyTypeStatic);
|
|
182
|
+
o.renderOrder = -2;
|
|
183
|
+
new MotorObject(vec2(10,8), vec2(2), randColor(), o);
|
|
184
|
+
}
|
|
185
|
+
{
|
|
186
|
+
// friction joint
|
|
187
|
+
const o = spawnBox(vec2(10,15), 3, randColor());
|
|
188
|
+
o.tileInfo = tile(6);
|
|
189
|
+
const joint = box2dCreateFrictionJoint(groundObject, o);
|
|
190
|
+
joint.SetMaxForce(200);
|
|
191
|
+
joint.SetMaxTorque(200);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (scene == 7)
|
|
195
|
+
{
|
|
196
|
+
sceneName = 'Contacts';
|
|
197
|
+
// changes objects color when touched
|
|
198
|
+
class ContactTester extends Box2dObject
|
|
199
|
+
{
|
|
200
|
+
constructor(pos, size, color, contactColor, isSensor=false)
|
|
201
|
+
{
|
|
202
|
+
super(pos, size, 0, 0, color, box2dBodyTypeStatic);
|
|
203
|
+
if (isSensor)
|
|
204
|
+
{
|
|
205
|
+
this.addCircle(size.x);
|
|
206
|
+
this.setSensor(isSensor);
|
|
207
|
+
}
|
|
208
|
+
else
|
|
209
|
+
this.addBox(size);
|
|
210
|
+
this.contactColor = contactColor;
|
|
211
|
+
}
|
|
212
|
+
beginContact(other) { other.color = this.contactColor; }
|
|
213
|
+
endContact(other) { other.color = WHITE; }
|
|
214
|
+
}
|
|
215
|
+
new ContactTester(vec2(15,8), vec2(5), hsl(0,0,0,.3), RED, true);
|
|
216
|
+
new ContactTester(vec2(25,8), vec2(5), hsl(0,0,.1), GREEN);
|
|
217
|
+
for (let i=200;i--;)
|
|
218
|
+
spawnRandomObject(vec2(rand(1,39), rand(10,50)));
|
|
219
|
+
}
|
|
220
|
+
if (scene == 8)
|
|
221
|
+
{
|
|
222
|
+
sceneName = 'Mobile';
|
|
223
|
+
const pos = vec2(20, 16);
|
|
224
|
+
const mobile = spawnMobile(pos, 12, 2, 5);
|
|
225
|
+
box2dCreateRevoluteJoint(groundObject, mobile, pos);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// helper functions
|
|
229
|
+
function spawnRandomEdges()
|
|
230
|
+
{
|
|
231
|
+
// edge list along bottom
|
|
232
|
+
const edgePoints = [];
|
|
233
|
+
edgePoints.push(vec2(40,0));
|
|
234
|
+
for (let i=40, y=0; i--;)
|
|
235
|
+
edgePoints.push(vec2(i, y=clamp(y+rand(-2,2),0,5)));
|
|
236
|
+
edgePoints.push(vec2(0,0));
|
|
237
|
+
const o = new Box2dObject(vec2(), vec2(), 0, 0, BLACK, box2dBodyTypeStatic);
|
|
238
|
+
o.addEdgeList(edgePoints);
|
|
239
|
+
}
|
|
240
|
+
function spawnRope(startPos, count, angle=PI, color=WHITE, size=vec2(.3,1))
|
|
241
|
+
{
|
|
242
|
+
let lastObject = groundObject;
|
|
243
|
+
for (let i=0; i<count; ++i)
|
|
244
|
+
{
|
|
245
|
+
const pos = startPos.add(size.multiply(vec2(0,i+.5)).rotate(-angle));
|
|
246
|
+
const o = spawnBox(pos, size, color, box2dBodyTypeDynamic, false, angle);
|
|
247
|
+
o.setFilterData(2, 2);
|
|
248
|
+
const anchorPos = pos.add(vec2(0,-size.y/2).rotate(-angle));
|
|
249
|
+
box2dCreateRevoluteJoint(lastObject, o, anchorPos);
|
|
250
|
+
lastObject = o;
|
|
251
|
+
}
|
|
252
|
+
const endPos = lastObject.localToWorld(vec2(0,-size.y/2));
|
|
253
|
+
box2dCreateRopeJoint(groundObject, lastObject, startPos, endPos);
|
|
254
|
+
return lastObject;
|
|
255
|
+
}
|
|
256
|
+
function spawnPyramid(pos, count)
|
|
257
|
+
{
|
|
258
|
+
for (let i=count+1;i--;)
|
|
259
|
+
for (let j=i;j--;)
|
|
260
|
+
spawnBox(pos.add(vec2(j-i/2+.5,count-i+.5)), 1, randColor());
|
|
261
|
+
}
|
|
262
|
+
function spawnDominoes(pos, count, size=vec2(.5,2))
|
|
263
|
+
{
|
|
264
|
+
for (let i=count; i--;)
|
|
265
|
+
spawnBox(pos.add(vec2(i*size.y*.8,size.y/2)), size, randColor());
|
|
266
|
+
}
|
|
267
|
+
function spawnCar(pos)
|
|
268
|
+
{
|
|
269
|
+
// car object
|
|
270
|
+
const car = new Box2dObject(pos, vec2(), 0, 0, randColor());
|
|
271
|
+
const carPoints = [
|
|
272
|
+
vec2(-1.5,-.5),
|
|
273
|
+
vec2(1.5, -.5),
|
|
274
|
+
vec2(1.5, 0),
|
|
275
|
+
vec2(0, .9),
|
|
276
|
+
vec2(-1.15,.9),
|
|
277
|
+
vec2(-1.5, .2),
|
|
278
|
+
];
|
|
279
|
+
car.addPoly(carPoints);
|
|
280
|
+
|
|
281
|
+
// wheel settings
|
|
282
|
+
const frequencyHz = 4;
|
|
283
|
+
const dampingRatio = .7;
|
|
284
|
+
const wheelDensity = 1;
|
|
285
|
+
const wheelFriction = 2;
|
|
286
|
+
const wheelRestitution = 0;
|
|
287
|
+
const wheelSize = .8;
|
|
288
|
+
|
|
289
|
+
// back wheel
|
|
290
|
+
const wheel1Pos = pos.add(vec2(-1, -.65));
|
|
291
|
+
const wheel1 = new Box2dObject(wheel1Pos, vec2(wheelSize), tile(4));
|
|
292
|
+
wheel1.addCircle(wheelSize,vec2(),wheelDensity,wheelFriction,wheelRestitution);
|
|
293
|
+
const joint1 = box2dCreateWheelJoint(car,wheel1);
|
|
294
|
+
joint1.SetSpringDampingRatio(dampingRatio);
|
|
295
|
+
joint1.SetSpringFrequencyHz(frequencyHz);
|
|
296
|
+
joint1.SetMaxMotorTorque(50);
|
|
297
|
+
joint1.EnableMotor(true);
|
|
298
|
+
carWheelJoint = joint1;
|
|
299
|
+
|
|
300
|
+
// front wheel
|
|
301
|
+
const wheel2Pos = pos.add(vec2(1, -.6));
|
|
302
|
+
const wheel2 = new Box2dObject(wheel2Pos, vec2(wheelSize), tile(4));
|
|
303
|
+
wheel2.addCircle(wheelSize,vec2(),wheelDensity,wheelFriction,wheelRestitution);
|
|
304
|
+
const joint2 = box2dCreateWheelJoint(car,wheel2);
|
|
305
|
+
joint2.SetSpringDampingRatio(dampingRatio);
|
|
306
|
+
joint2.SetSpringFrequencyHz(frequencyHz);
|
|
307
|
+
}
|
|
308
|
+
function spawnMobile(anchor, w, h, depth)
|
|
309
|
+
{
|
|
310
|
+
// tall box
|
|
311
|
+
const pos = anchor.add(vec2(0,-h/2));
|
|
312
|
+
const o = spawnBox(pos, vec2(h/4, h), randColor(), box2dBodyTypeDynamic, false);
|
|
313
|
+
if (--depth)
|
|
314
|
+
{
|
|
315
|
+
// long box on bottom
|
|
316
|
+
o.addBox(vec2(w, h/4), vec2(0, -h/2));
|
|
317
|
+
|
|
318
|
+
// spawn smaller mobiles attached to each side
|
|
319
|
+
for(let i=2; i--;)
|
|
320
|
+
{
|
|
321
|
+
const a = anchor.add(vec2( w/2*(i?1:-1), -h));
|
|
322
|
+
const o2 = spawnMobile(a, w/2, h, depth);
|
|
323
|
+
box2dCreateRevoluteJoint(o, o2, a);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return o;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
331
|
+
// Spawn object functions
|
|
332
|
+
|
|
333
|
+
function spawnBox(pos, size=1, color=WHITE, type=box2dBodyTypeDynamic, applyTexture=true, angle=0)
|
|
334
|
+
{
|
|
335
|
+
size = typeof size == 'number' ? vec2(size) : size; // square
|
|
336
|
+
const o = new Box2dObject(pos, size, applyTexture && tile(3), angle, color, type);
|
|
337
|
+
o.addBox(size);
|
|
338
|
+
return o;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function spawnCircle(pos, diameter=1, color=WHITE, type=box2dBodyTypeDynamic, applyTexture=true, angle=0)
|
|
342
|
+
{
|
|
343
|
+
const size = vec2(diameter);
|
|
344
|
+
const o = new Box2dObject(pos, size, applyTexture && tile(2), angle, color, type);
|
|
345
|
+
o.addCircle(diameter);
|
|
346
|
+
return o;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function spawnRandomPoly(pos, diameter=1, color=WHITE, type=box2dBodyTypeDynamic, angle=0)
|
|
350
|
+
{
|
|
351
|
+
const o = new Box2dObject(pos, vec2(), 0, angle, color, type);
|
|
352
|
+
o.addRandomPoly(diameter);
|
|
353
|
+
return o;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function spawnRandomObject(pos, scale=1, type=box2dBodyTypeDynamic, angle=0)
|
|
357
|
+
{
|
|
358
|
+
if (randInt(2))
|
|
359
|
+
{
|
|
360
|
+
const size = vec2(scale*rand(.5,1), scale*rand(.5,1));
|
|
361
|
+
return spawnBox(pos, size, randColor(), type, true, angle);
|
|
362
|
+
}
|
|
363
|
+
else
|
|
364
|
+
{
|
|
365
|
+
const diameter = scale*rand(.5,1);
|
|
366
|
+
return spawnCircle(pos, diameter, randColor(), type, true, angle);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
371
|
+
// Effects
|
|
372
|
+
|
|
373
|
+
const sound_click = new Sound([,.1]);
|
|
374
|
+
const sound_explosion = new Sound([,.2,72,.01,.01,.2,4,,,,,,,1,,.5,.1,.5,.02]);
|
|
375
|
+
|
|
376
|
+
function explosion(pos, radius=3, strength=500)
|
|
377
|
+
{
|
|
378
|
+
sound_explosion.play(pos);
|
|
379
|
+
const objects = box2dCircleCastAll(pos, (radius*2));
|
|
380
|
+
const newColor = randColor();
|
|
381
|
+
for (const o of objects)
|
|
382
|
+
{
|
|
383
|
+
const p = percent(o.pos.distance(pos), 2*radius, radius);
|
|
384
|
+
const force = o.pos.subtract(pos).normalize(p*radius*strength);
|
|
385
|
+
o.applyForce(force);
|
|
386
|
+
o.color = newColor;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// smoke
|
|
390
|
+
new ParticleEmitter(
|
|
391
|
+
pos, 0, // pos, angle
|
|
392
|
+
radius/2, .2, 50*radius, PI,// emitSize, emitTime, emitRate, emiteCone
|
|
393
|
+
tile(1), // tileInfo
|
|
394
|
+
hsl(0,0,0), hsl(0,0,0), // colorStartA, colorStartB
|
|
395
|
+
hsl(0,0,0,0), hsl(0,0,0,0), // colorEndA, colorEndB
|
|
396
|
+
1, 1, 2, .1, .1, // time, sizeStart, sizeEnd, speed, angleSpeed
|
|
397
|
+
.9, 1, -.5, PI, .1, // damp, angleDamp, gravity, particleCone, fade
|
|
398
|
+
1, 0, 0, 0, 1e8 // randomness, collide, additive, colorLinear, renderOrder
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
// fire
|
|
402
|
+
new ParticleEmitter(
|
|
403
|
+
pos, 0, // pos, angle
|
|
404
|
+
radius, .1, 100*radius, PI, // emitSize, emitTime, emitRate, emiteCone
|
|
405
|
+
tile(1), // tileInfo
|
|
406
|
+
hsl(0,1,.5), hsl(.15,1,.5), // colorStartA, colorStartB
|
|
407
|
+
hsl(0,1,.5,0), hsl(.1, 1,.5,0), // colorEndA, colorEndB
|
|
408
|
+
.7, 1, .5, .1, .1, // time, sizeStart, sizeEnd, speed, angleSpeed
|
|
409
|
+
.9, 1, 0, PI, .05, // damp, angleDamp, gravity, particleCone, fade
|
|
410
|
+
1, 0, 1, 0, 1e9 // randomness, collide, additive, colorLinear, renderOrder
|
|
411
|
+
);
|
|
412
|
+
}
|
|
Binary file
|
|
@@ -38,7 +38,7 @@ function gameInit()
|
|
|
38
38
|
new Wall(vec2(levelSize.x+.5,levelSize.y/2), vec2(1,100)) // left
|
|
39
39
|
new Wall(vec2(levelSize.x/2,levelSize.y+.5), vec2(100,1)) // right
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
setupPostProcess(); // set up a post processing shader
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -80,7 +80,7 @@ function gameRenderPost()
|
|
|
80
80
|
|
|
81
81
|
///////////////////////////////////////////////////////////////////////////////
|
|
82
82
|
// an example shader that can be used to apply a post processing effect
|
|
83
|
-
function
|
|
83
|
+
function setupPostProcess()
|
|
84
84
|
{
|
|
85
85
|
const televisionShader = `
|
|
86
86
|
// Simple TV Shader Code
|
|
@@ -130,7 +130,7 @@ function initPostProcess()
|
|
|
130
130
|
}`;
|
|
131
131
|
|
|
132
132
|
const includeOverlay = true;
|
|
133
|
-
|
|
133
|
+
initPostProcess(televisionShader, includeOverlay);
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -58,6 +58,8 @@ function explosion(pos, radius=3)
|
|
|
58
58
|
{
|
|
59
59
|
ASSERT(radius > 0);
|
|
60
60
|
|
|
61
|
+
sound_explosion.play(pos);
|
|
62
|
+
|
|
61
63
|
// destroy level
|
|
62
64
|
for (let x = -radius; x < radius; ++x)
|
|
63
65
|
{
|
|
@@ -94,8 +96,6 @@ function explosion(pos, radius=3)
|
|
|
94
96
|
o.angleVelocity += randSign()*rand(p*radius/4,.3);
|
|
95
97
|
});
|
|
96
98
|
|
|
97
|
-
sound_explosion.play(pos);
|
|
98
|
-
|
|
99
99
|
// smoke
|
|
100
100
|
new ParticleEmitter(
|
|
101
101
|
pos, 0, // pos, angle
|