littlejsengine 1.11.17 → 1.12.4
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 +112 -43
- package/dist/littlejs.esm.js +586 -500
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +2993 -122
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +2992 -119
- package/examples/box2d/game.js +70 -39
- package/examples/box2d/gameObjects.js +81 -77
- package/examples/box2d/index.html +2 -7
- package/examples/box2d/scenes.js +80 -90
- package/examples/breakout/game.js +63 -28
- package/examples/breakout/gameObjects.js +45 -47
- package/examples/breakout/index.html +1 -5
- package/examples/breakoutTutorial/game.js +36 -29
- package/examples/breakoutTutorial/index.html +1 -3
- package/examples/empty/game.js +5 -2
- package/examples/empty/index.html +1 -3
- package/examples/htmlMenu/game.js +24 -15
- package/examples/htmlMenu/index.html +5 -7
- package/examples/index.html +2 -3
- package/examples/module/game.js +32 -34
- package/examples/module/index.html +1 -1
- package/examples/particles/index.html +27 -22
- package/examples/platformer/game.js +71 -45
- package/examples/platformer/gameCharacter.js +42 -34
- package/examples/platformer/gameEffects.js +82 -75
- package/examples/platformer/gameLevel.js +67 -38
- package/examples/platformer/{gameLevelData.js → gameLevelData.json} +1 -11
- package/examples/platformer/gameObjects.js +70 -64
- package/examples/platformer/gamePlayer.js +12 -7
- package/examples/platformer/index.html +1 -9
- package/examples/puzzle/game.js +59 -40
- package/examples/puzzle/index.html +1 -3
- package/examples/shorts/base.html +2 -2
- package/examples/shorts/particles.js +1 -1
- package/examples/shorts/platformer.js +1 -1
- package/examples/shorts/tileLayer.js +5 -6
- package/examples/shorts/tiles.png +0 -0
- package/examples/starter/game.js +9 -12
- package/examples/starter/index.html +13 -13
- package/examples/stress/index.html +44 -44
- package/examples/typescript/build.js +17 -18
- package/examples/typescript/game.js +32 -34
- package/examples/typescript/game.ts +32 -34
- package/examples/typescript/index.html +1 -1
- package/examples/uiSystem/game.js +34 -31
- package/examples/uiSystem/index.html +1 -5
- package/package.json +1 -1
- package/plugins/box2d.js +6 -2
- package/plugins/pluginExport.js +1 -2
- package/reference.md +29 -27
- package/src/engine.js +1 -1
- package/src/engineBuild.js +13 -6
- package/src/engineDebug.js +1 -3
- package/src/engineExport.js +2 -6
- package/src/engineInput.js +3 -1
- package/src/engineObject.js +18 -14
- package/src/engineSettings.js +6 -6
- package/src/engineTileLayer.js +179 -96
- package/examples/typescript/build/dist/littlejs.esm.js +0 -4834
- package/examples/typescript/build/examples/typescript/build.js +0 -24
- package/examples/typescript/build/examples/typescript/game.js +0 -102
package/src/engineObject.js
CHANGED
|
@@ -158,7 +158,10 @@ class EngineObject
|
|
|
158
158
|
this.velocity.x *= this.damping;
|
|
159
159
|
this.velocity.y *= this.damping;
|
|
160
160
|
if (this.mass) // don't apply gravity to static objects
|
|
161
|
-
|
|
161
|
+
{
|
|
162
|
+
this.velocity.x += gravity.x * this.gravityScale;
|
|
163
|
+
this.velocity.y += gravity.y * this.gravityScale;
|
|
164
|
+
}
|
|
162
165
|
this.pos.x += this.velocity.x;
|
|
163
166
|
this.pos.y += this.velocity.y;
|
|
164
167
|
this.angle += this.angleVelocity *= this.angleDamping;
|
|
@@ -173,9 +176,9 @@ class EngineObject
|
|
|
173
176
|
if (this.groundObject)
|
|
174
177
|
{
|
|
175
178
|
// apply friction in local space of ground object
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
this.velocity.x = groundSpeed + (this.velocity.x - groundSpeed) *
|
|
179
|
+
const friction = max(this.friction, this.groundObject.friction);
|
|
180
|
+
const groundSpeed = this.groundObject.velocity ? this.groundObject.velocity.x : 0;
|
|
181
|
+
this.velocity.x = groundSpeed + (this.velocity.x - groundSpeed) * friction;
|
|
179
182
|
this.groundObject = undefined;
|
|
180
183
|
//debugOverlay && debugPhysics && debugPoint(this.pos.subtract(vec2(0,this.size.y/2)), '#0f0');
|
|
181
184
|
}
|
|
@@ -217,7 +220,7 @@ class EngineObject
|
|
|
217
220
|
|
|
218
221
|
// check for collision
|
|
219
222
|
const sizeBoth = this.size.add(o.size);
|
|
220
|
-
const smallStepUp = (oldPos.y - o.pos.y)*2 > sizeBoth.y + gravity; // prefer to push up if small delta
|
|
223
|
+
const smallStepUp = (oldPos.y - o.pos.y)*2 > sizeBoth.y + gravity.y; // prefer to push up if small delta
|
|
221
224
|
const isBlockedX = abs(oldPos.y - o.pos.y)*2 < sizeBoth.y;
|
|
222
225
|
const isBlockedY = abs(oldPos.x - o.pos.x)*2 < sizeBoth.x;
|
|
223
226
|
const elasticity = max(this.elasticity, o.elasticity);
|
|
@@ -279,19 +282,21 @@ class EngineObject
|
|
|
279
282
|
if (this.collideTiles)
|
|
280
283
|
{
|
|
281
284
|
// check collision against tiles
|
|
282
|
-
|
|
285
|
+
const hitLayer = tileCollisionTest(this.pos, this.size, this)
|
|
286
|
+
if (hitLayer)
|
|
283
287
|
{
|
|
284
288
|
// if already was stuck in collision, don't do anything
|
|
285
289
|
// this should not happen unless something starts in collision
|
|
286
290
|
if (!tileCollisionTest(oldPos, this.size, this))
|
|
287
291
|
{
|
|
288
292
|
// test which side we bounced off (or both if a corner)
|
|
289
|
-
const
|
|
290
|
-
const
|
|
291
|
-
if (
|
|
293
|
+
const blockedLayerY = tileCollisionTest(vec2(oldPos.x, this.pos.y), this.size, this);
|
|
294
|
+
const blockedLayerX = tileCollisionTest(vec2(this.pos.x, oldPos.y), this.size, this);
|
|
295
|
+
if (blockedLayerY || !blockedLayerX)
|
|
292
296
|
{
|
|
293
297
|
// bounce velocity
|
|
294
|
-
|
|
298
|
+
const elasticity = max(this.elasticity, hitLayer.elasticity);
|
|
299
|
+
this.velocity.y *= -elasticity;
|
|
295
300
|
|
|
296
301
|
if (wasMovingDown)
|
|
297
302
|
{
|
|
@@ -300,9 +305,8 @@ class EngineObject
|
|
|
300
305
|
const epsilon = .0001;
|
|
301
306
|
this.pos.y = (oldPos.y-this.size.y/2|0)+this.size.y/2+epsilon;
|
|
302
307
|
|
|
303
|
-
// set ground object
|
|
304
|
-
|
|
305
|
-
this.groundObject = this;
|
|
308
|
+
// set ground object for tile collision
|
|
309
|
+
this.groundObject = hitLayer;
|
|
306
310
|
}
|
|
307
311
|
else
|
|
308
312
|
{
|
|
@@ -311,7 +315,7 @@ class EngineObject
|
|
|
311
315
|
this.groundObject = undefined;
|
|
312
316
|
}
|
|
313
317
|
}
|
|
314
|
-
if (
|
|
318
|
+
if (blockedLayerX)
|
|
315
319
|
{
|
|
316
320
|
// move to previous position and bounce
|
|
317
321
|
this.pos.x = oldPos.x;
|
package/src/engineSettings.js
CHANGED
|
@@ -37,7 +37,7 @@ let canvasMaxSize = vec2(1920, 1080);
|
|
|
37
37
|
* @memberof Settings */
|
|
38
38
|
let canvasFixedSize = vec2();
|
|
39
39
|
|
|
40
|
-
/** Use nearest neighbor scaling
|
|
40
|
+
/** Use nearest neighbor canvas scaling for more pixelated look
|
|
41
41
|
* - Must be set before startup to take effect
|
|
42
42
|
* - If enabled sets css image-rendering:pixelated
|
|
43
43
|
* @type {boolean}
|
|
@@ -147,11 +147,11 @@ let objectDefaultFriction = .8;
|
|
|
147
147
|
* @memberof Settings */
|
|
148
148
|
let objectMaxSpeed = 1;
|
|
149
149
|
|
|
150
|
-
/** How much gravity to apply to objects
|
|
151
|
-
* @type {
|
|
150
|
+
/** How much gravity to apply to objects, negative Y is down
|
|
151
|
+
* @type {Vector2}
|
|
152
152
|
* @default
|
|
153
153
|
* @memberof Settings */
|
|
154
|
-
let gravity =
|
|
154
|
+
let gravity = vec2();
|
|
155
155
|
|
|
156
156
|
/** Scales emit rate of particles, useful for low graphics mode (0 disables particle emitters)
|
|
157
157
|
* @type {number}
|
|
@@ -377,8 +377,8 @@ function setObjectDefaultFriction(friction) { objectDefaultFriction = friction;
|
|
|
377
377
|
* @memberof Settings */
|
|
378
378
|
function setObjectMaxSpeed(speed) { objectMaxSpeed = speed; }
|
|
379
379
|
|
|
380
|
-
/** Set how much gravity to apply to objects
|
|
381
|
-
* @param {
|
|
380
|
+
/** Set how much gravity to apply to objects
|
|
381
|
+
* @param {Vector2} newGravity
|
|
382
382
|
* @memberof Settings */
|
|
383
383
|
function setGravity(newGravity) { gravity = newGravity; }
|
|
384
384
|
|
package/src/engineTileLayer.js
CHANGED
|
@@ -2,75 +2,47 @@
|
|
|
2
2
|
* LittleJS Tile Layer System
|
|
3
3
|
* - Caches arrays of tiles to off screen canvas for fast rendering
|
|
4
4
|
* - Unlimited numbers of layers, allocates canvases as needed
|
|
5
|
-
* - Interfaces with EngineObject for collision
|
|
6
|
-
* - Collision layer is separate from visible layers
|
|
7
|
-
* - It is recommended to have a visible layer that matches the collision
|
|
8
5
|
* - Tile layers can be drawn to using their context with canvas2d
|
|
9
6
|
* - Drawn directly to the main canvas without using WebGL
|
|
7
|
+
* - Tile layers can also have collision with EngineObjects
|
|
10
8
|
* @namespace TileCollision
|
|
11
9
|
*/
|
|
12
10
|
|
|
13
11
|
'use strict';
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* @memberof TileCollision */
|
|
18
|
-
let tileCollision = [];
|
|
19
|
-
|
|
20
|
-
/** Size of the tile collision layer 2d grid
|
|
21
|
-
* @type {Vector2}
|
|
22
|
-
* @memberof TileCollision */
|
|
23
|
-
let tileCollisionSize = vec2();
|
|
13
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
14
|
+
// Tile Layer System
|
|
24
15
|
|
|
25
|
-
/**
|
|
26
|
-
* @
|
|
16
|
+
/** Keep track of all tile layers with collision
|
|
17
|
+
* @type {Array<TileCollisionLayer>}
|
|
27
18
|
* @memberof TileCollision */
|
|
28
|
-
|
|
29
|
-
{
|
|
30
|
-
tileCollisionSize = size;
|
|
31
|
-
tileCollision = [];
|
|
32
|
-
for (let i=tileCollision.length = tileCollisionSize.area(); i--;)
|
|
33
|
-
tileCollision[i] = 0;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/** Set tile collision data for a given cell in the grid
|
|
37
|
-
* @param {Vector2} pos
|
|
38
|
-
* @param {number} [data]
|
|
39
|
-
* @memberof TileCollision */
|
|
40
|
-
function setTileCollisionData(pos, data=0)
|
|
41
|
-
{
|
|
42
|
-
pos.arrayCheck(tileCollisionSize) && (tileCollision[(pos.y|0)*tileCollisionSize.x+pos.x|0] = data);
|
|
43
|
-
}
|
|
19
|
+
let tileCollisionLayers = [];
|
|
44
20
|
|
|
45
21
|
/** Get tile collision data for a given cell in the grid
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
22
|
+
* @param {Vector2} pos
|
|
23
|
+
* @return {number}
|
|
24
|
+
* @memberof TileCollision */
|
|
49
25
|
function getTileCollisionData(pos)
|
|
50
26
|
{
|
|
51
|
-
|
|
27
|
+
// check all tile collision layers
|
|
28
|
+
for (const layer of tileCollisionLayers)
|
|
29
|
+
if (pos.arrayCheck(layer.size))
|
|
30
|
+
return layer.getCollisionData(pos);
|
|
31
|
+
return 0;
|
|
52
32
|
}
|
|
53
33
|
|
|
54
|
-
/** Check if
|
|
34
|
+
/** Check if a tile layer collides with another object
|
|
55
35
|
* @param {Vector2} pos
|
|
56
36
|
* @param {Vector2} [size=(0,0)]
|
|
57
37
|
* @param {EngineObject} [object]
|
|
58
|
-
* @return {
|
|
38
|
+
* @return {TileCollisionLayer}
|
|
59
39
|
* @memberof TileCollision */
|
|
60
40
|
function tileCollisionTest(pos, size=vec2(), object)
|
|
61
41
|
{
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
for (let y = minY; y < maxY; ++y)
|
|
67
|
-
for (let x = minX; x < maxX; ++x)
|
|
68
|
-
{
|
|
69
|
-
const tileData = tileCollision[y*tileCollisionSize.x+x];
|
|
70
|
-
if (tileData && (!object || object.collideWithTile(tileData, vec2(x, y))))
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
return false;
|
|
42
|
+
// check all tile collision layers
|
|
43
|
+
for (const layer of tileCollisionLayers)
|
|
44
|
+
if (layer.collisionTest(pos, size, object))
|
|
45
|
+
return layer;
|
|
74
46
|
}
|
|
75
47
|
|
|
76
48
|
/** Return the center of first tile hit, undefined if nothing was hit.
|
|
@@ -82,49 +54,17 @@ function tileCollisionTest(pos, size=vec2(), object)
|
|
|
82
54
|
* @memberof TileCollision */
|
|
83
55
|
function tileCollisionRaycast(posStart, posEnd, object)
|
|
84
56
|
{
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
const delta = posEnd.subtract(posStart);
|
|
88
|
-
const totalLength = delta.length();
|
|
89
|
-
const normalizedDelta = delta.normalize();
|
|
90
|
-
const unit = vec2(abs(1/normalizedDelta.x), abs(1/normalizedDelta.y));
|
|
91
|
-
const flooredPosStart = posStart.floor();
|
|
92
|
-
|
|
93
|
-
// setup iteration variables
|
|
94
|
-
let pos = flooredPosStart;
|
|
95
|
-
let xi = unit.x * (delta.x < 0 ? posStart.x - pos.x : pos.x - posStart.x + 1);
|
|
96
|
-
let yi = unit.y * (delta.y < 0 ? posStart.y - pos.y : pos.y - posStart.y + 1);
|
|
97
|
-
|
|
98
|
-
while (true)
|
|
57
|
+
// check all tile collision layers
|
|
58
|
+
for (const layer of tileCollisionLayers)
|
|
99
59
|
{
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
{
|
|
104
|
-
debugRaycast && debugLine(posStart, posEnd, '#f00', .02);
|
|
105
|
-
debugRaycast && debugPoint(pos.add(vec2(.5)), '#ff0');
|
|
106
|
-
return pos.add(vec2(.5));
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// check if past the end
|
|
110
|
-
if (xi > totalLength && yi > totalLength)
|
|
111
|
-
break;
|
|
112
|
-
|
|
113
|
-
// get coordinates of the next tile to check
|
|
114
|
-
if (xi > yi)
|
|
115
|
-
pos.y += sign(delta.y), yi += unit.y;
|
|
116
|
-
else
|
|
117
|
-
pos.x += sign(delta.x), xi += unit.x;
|
|
60
|
+
const hitPos = layer.collisionRaycast(posStart, posEnd, object)
|
|
61
|
+
if (hitPos)
|
|
62
|
+
return hitPos;
|
|
118
63
|
}
|
|
119
|
-
|
|
120
|
-
debugRaycast && debugLine(posStart, posEnd, '#00f', .02);
|
|
121
64
|
}
|
|
122
65
|
|
|
123
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
124
|
-
// Tile Layer Rendering System
|
|
125
|
-
|
|
126
66
|
/**
|
|
127
|
-
* Tile layer data object stores info about how to
|
|
67
|
+
* Tile layer data object stores info about how to draw a tile
|
|
128
68
|
* @example
|
|
129
69
|
* // create tile layer data with tile index 0 and random orientation and color
|
|
130
70
|
* const tileIndex = 0;
|
|
@@ -156,28 +96,27 @@ class TileLayerData
|
|
|
156
96
|
clear() { this.tile = this.direction = 0; this.mirror = false; this.color = new Color; }
|
|
157
97
|
}
|
|
158
98
|
|
|
99
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
159
100
|
/**
|
|
160
101
|
* Tile Layer - cached rendering system for tile layers
|
|
161
102
|
* - Each Tile layer is rendered to an off screen canvas
|
|
162
103
|
* - To allow dynamic modifications, layers are rendered using canvas 2d
|
|
163
104
|
* - Some devices like mobile phones are limited to 4k texture resolution
|
|
164
|
-
* -
|
|
105
|
+
* - For with 16x16 tiles this limits layers to 256x256 on mobile devices
|
|
165
106
|
* @extends EngineObject
|
|
166
107
|
* @example
|
|
167
|
-
*
|
|
168
|
-
* initTileCollision(vec2(200,100));
|
|
169
|
-
* const tileLayer = new TileLayer();
|
|
108
|
+
* const tileLayer = new TileLayer(vec2(), vec2(200,100));
|
|
170
109
|
*/
|
|
171
110
|
class TileLayer extends EngineObject
|
|
172
111
|
{
|
|
173
112
|
/** Create a tile layer object
|
|
174
|
-
* @param {Vector2} [position=(0,0)]
|
|
175
|
-
* @param {Vector2} [size=
|
|
176
|
-
* @param {TileInfo} [tileInfo]
|
|
177
|
-
* @param {Vector2} [scale=(1,1)]
|
|
178
|
-
* @param {number} [renderOrder]
|
|
113
|
+
* @param {Vector2} [position=(0,0)] - World space position
|
|
114
|
+
* @param {Vector2} [size=(1,1)] - World space size
|
|
115
|
+
* @param {TileInfo} [tileInfo] - Tile info for layer
|
|
116
|
+
* @param {Vector2} [scale=(1,1)] - How much to scale this layer when rendered
|
|
117
|
+
* @param {number} [renderOrder] - Objects are sorted by renderOrder
|
|
179
118
|
*/
|
|
180
|
-
constructor(position, size
|
|
119
|
+
constructor(position, size, tileInfo=tile(), scale=vec2(1), renderOrder=0)
|
|
181
120
|
{
|
|
182
121
|
super(position, size, tileInfo, 0, undefined, renderOrder);
|
|
183
122
|
|
|
@@ -189,6 +128,10 @@ class TileLayer extends EngineObject
|
|
|
189
128
|
this.scale = scale;
|
|
190
129
|
/** @property {boolean} - If true this layer will render to overlay canvas and appear above all objects */
|
|
191
130
|
this.isOverlay = false;
|
|
131
|
+
// set no friction by default, applied friction is max of both objects
|
|
132
|
+
this.friction = 0;
|
|
133
|
+
// set no elasticity by default, applied elasticity is max of both objects
|
|
134
|
+
this.elasticity = 0;
|
|
192
135
|
|
|
193
136
|
// init tile data
|
|
194
137
|
this.data = [];
|
|
@@ -385,4 +328,144 @@ class TileLayer extends EngineObject
|
|
|
385
328
|
* @param {number} [angle=0] */
|
|
386
329
|
drawRect(pos, size, color, angle)
|
|
387
330
|
{ this.drawTile(pos, size, undefined, color, angle); }
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
334
|
+
/**
|
|
335
|
+
* Tile Collision Layer - a tile layer with collision
|
|
336
|
+
* - adds collision data and functions to TileLayer
|
|
337
|
+
* - there can be multiple tile collision layers
|
|
338
|
+
* - tile collison layers should not overlap each other
|
|
339
|
+
* @extends TileLayer
|
|
340
|
+
*/
|
|
341
|
+
class TileCollisionLayer extends TileLayer
|
|
342
|
+
{
|
|
343
|
+
/** Create a tile layer object
|
|
344
|
+
* @param {Vector2} [position=(0,0)] - World space position
|
|
345
|
+
* @param {Vector2} [size=(0,0)] - World space size
|
|
346
|
+
* @param {TileInfo} [tileInfo] - Tile info for layer
|
|
347
|
+
* @param {number} [renderOrder] - Objects are sorted by renderOrder
|
|
348
|
+
*/
|
|
349
|
+
constructor(position, size, tileInfo=tile(), renderOrder=0)
|
|
350
|
+
{
|
|
351
|
+
const scale = vec2(1); // collision layers are not scaled
|
|
352
|
+
super(position, size.floor(), tileInfo, scale, renderOrder);
|
|
353
|
+
|
|
354
|
+
/** @property {Array<number>} - The tile collision grid */
|
|
355
|
+
this.collisionData = [];
|
|
356
|
+
this.initCollision(this.size);
|
|
357
|
+
|
|
358
|
+
// keep track of all collision layers
|
|
359
|
+
tileCollisionLayers.push(this);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/** Destroy this collision layer */
|
|
363
|
+
destroy()
|
|
364
|
+
{
|
|
365
|
+
if (this.destroyed)
|
|
366
|
+
return;
|
|
367
|
+
|
|
368
|
+
// remove from collision layers array and destroy
|
|
369
|
+
const index = tileCollisionLayers.indexOf(this);
|
|
370
|
+
ASSERT(index >= 0, 'tile collision layer not found in array');
|
|
371
|
+
tileCollisionLayers.splice(index, 1);
|
|
372
|
+
super.destroy();
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/** Clear and initialize tile collision to new size
|
|
376
|
+
* @param {Vector2} size - width and height of tile collision 2d grid */
|
|
377
|
+
initCollision(size)
|
|
378
|
+
{
|
|
379
|
+
this.size = size.floor();
|
|
380
|
+
this.collisionData = [];
|
|
381
|
+
this.collisionData.length = size.area();
|
|
382
|
+
this.collisionData.fill(0);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/** Set tile collision data for a given cell in the grid
|
|
386
|
+
* @param {Vector2} pos
|
|
387
|
+
* @param {number} [data] */
|
|
388
|
+
setCollisionData(pos, data=1)
|
|
389
|
+
{
|
|
390
|
+
const i = (pos.y|0)*this.size.x + pos.x|0;
|
|
391
|
+
pos.arrayCheck(this.size) && (this.collisionData[i] = data);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/** Get tile collision data for a given cell in the grid
|
|
395
|
+
* @param {Vector2} pos
|
|
396
|
+
* @return {number} */
|
|
397
|
+
getCollisionData(pos)
|
|
398
|
+
{
|
|
399
|
+
const i = (pos.y|0)*this.size.x + pos.x|0;
|
|
400
|
+
return pos.arrayCheck(this.size) ? this.collisionData[i] : 0;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/** Check if collision with another object should occur
|
|
404
|
+
* @param {Vector2} pos
|
|
405
|
+
* @param {Vector2} [size=(0,0)]
|
|
406
|
+
* @param {EngineObject} [object]
|
|
407
|
+
* @return {boolean} */
|
|
408
|
+
collisionTest(pos, size=vec2(), object)
|
|
409
|
+
{
|
|
410
|
+
const minX = max(pos.x - size.x/2|0, 0);
|
|
411
|
+
const minY = max(pos.y - size.y/2|0, 0);
|
|
412
|
+
const maxX = min(pos.x + size.x/2, this.size.x);
|
|
413
|
+
const maxY = min(pos.y + size.y/2, this.size.y);
|
|
414
|
+
for (let y = minY; y < maxY; ++y)
|
|
415
|
+
for (let x = minX; x < maxX; ++x)
|
|
416
|
+
{
|
|
417
|
+
// check if the object should collide with this tile
|
|
418
|
+
const tileData = this.collisionData[y*this.size.x+x];
|
|
419
|
+
if (tileData && (!object || object.collideWithTile(tileData, vec2(x, y))))
|
|
420
|
+
return true;
|
|
421
|
+
}
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/** Return the center of first tile hit, undefined if nothing was hit.
|
|
426
|
+
* This does not return the exact intersection, but the center of the tile hit.
|
|
427
|
+
* @param {Vector2} posStart
|
|
428
|
+
* @param {Vector2} posEnd
|
|
429
|
+
* @param {EngineObject} [object]
|
|
430
|
+
* @return {Vector2} */
|
|
431
|
+
collisionRaycast(posStart, posEnd, object)
|
|
432
|
+
{
|
|
433
|
+
// test if a ray collides with tiles from start to end
|
|
434
|
+
// todo: a way to get the exact hit point, it must still be inside the hit tile
|
|
435
|
+
const delta = posEnd.subtract(posStart);
|
|
436
|
+
const totalLength = delta.length();
|
|
437
|
+
const normalizedDelta = delta.normalize();
|
|
438
|
+
const unit = vec2(abs(1/normalizedDelta.x), abs(1/normalizedDelta.y));
|
|
439
|
+
const flooredPosStart = posStart.floor();
|
|
440
|
+
|
|
441
|
+
// setup iteration variables
|
|
442
|
+
let pos = flooredPosStart;
|
|
443
|
+
let xi = unit.x * (delta.x < 0 ? posStart.x - pos.x : pos.x - posStart.x + 1);
|
|
444
|
+
let yi = unit.y * (delta.y < 0 ? posStart.y - pos.y : pos.y - posStart.y + 1);
|
|
445
|
+
|
|
446
|
+
// use line drawing algorithm to test for collisions
|
|
447
|
+
while (true)
|
|
448
|
+
{
|
|
449
|
+
// check for tile collision
|
|
450
|
+
const tileData = this.getCollisionData(pos);
|
|
451
|
+
if (tileData && (!object || object.collideWithTile(tileData, pos)))
|
|
452
|
+
{
|
|
453
|
+
debugRaycast && debugLine(posStart, posEnd, '#f00', .02);
|
|
454
|
+
debugRaycast && debugPoint(pos.add(vec2(.5)), '#ff0');
|
|
455
|
+
return pos.add(vec2(.5));
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// check if past the end
|
|
459
|
+
if (xi > totalLength && yi > totalLength)
|
|
460
|
+
break;
|
|
461
|
+
|
|
462
|
+
// get coordinates of next tile to check
|
|
463
|
+
if (xi > yi)
|
|
464
|
+
pos.y += sign(delta.y), yi += unit.y;
|
|
465
|
+
else
|
|
466
|
+
pos.x += sign(delta.x), xi += unit.x;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
debugRaycast && debugLine(posStart, posEnd, '#00f', .02);
|
|
470
|
+
}
|
|
388
471
|
}
|