Skip to content

Commit 190f6fe

Browse files
authored
Merge pull request #48 from hexus/ignormals
Ignormals
2 parents 0e22f48 + 5c31569 commit 190f6fe

11 files changed

+703
-1319
lines changed

CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# Arcade Slopes Change Log
22

3+
## Unreleased
4+
- Removed the snap feature (#34)
5+
- Removed heuristics in favour of a custom SAT implementation that prevents
6+
internal edge collisions (#36, #38, #40)
7+
- Implemented debug rendering for tile normals and ignored tile normals
8+
- Implemented simple object pooling for less memory-hungry calculations (#42)
9+
- Improved the consistency of SAT responses and overlap values set on physics
10+
bodies
11+
312
## v0.2.1 - 1st August 2017
413
- Dropped bower in favour of npm to load in the SAT.js dependency.
514
- Added a banner to the minified distributive as part of the build process.

ROADMAP.md

+19-7
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,29 @@
2727
- [x] Tile collision direction flags
2828
- [x] Clearer yet more in-depth readme
2929
- [ ] v0.3.0
30-
- [ ] Custom SAT.js implementation that can prevent internal edge collisions
30+
- [x] Custom SAT.js implementation that can prevent internal edge collisions
3131
([like this](http://www.wildbunny.co.uk/blog/2012/10/31/2d-polygonal-collision-detection-and-internal-edges/comment-page-1/#comment-1978))
32-
- [ ] More consistent naming
33-
- [ ] Tile slope type constants
34-
- [ ] Direction/neighbour names
32+
- [x] Debug rendering
33+
- [x] Tile edge collision normals
34+
- [x] Memory consumption improvements
35+
- [ ] v0.4.0
36+
- [ ] Automatically set colliding tiles for Tilemaps
37+
- [ ] Automatically update sprite body polygons
3538
- [ ] Tunnelling solutions
3639
- [ ] Swept intersection tests
3740
- [ ] Raycasting
38-
- [ ] Raycasting for sticky slopes
41+
- [ ] v0.5.0
3942
- [ ] Automatic sprite rotation
4043
- [ ] Omni-directional
4144
- [ ] Selective
42-
- [ ] AABB collision margins
43-
- [ ] Memory consumption improvements
45+
- [ ] Raycasting for sticky slopes
46+
- [ ] Dynamic tilemap support
47+
- [ ] v1.0.0
48+
- [ ] AMD/UMD
49+
- [ ] More consistent naming
50+
- [ ] Tile slope type constants
51+
- [ ] Direction/neighbour names
52+
53+
## Ideas
54+
55+
- [ ] AABB collision margins

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "phaser-arcade-slopes",
3-
"version": "0.2.1",
3+
"version": "0.3.0-dev",
44
"description": "A Phaser plugin that brings sloped tile collision handling to Phaser's Arcade Physics engine",
55
"main": "dist/phaser-arcade-slopes.js",
66
"scripts": {},

src/ArcadeSlopes.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ Phaser.Plugin.ArcadeSlopes.prototype.constructor = Phaser.Plugin.ArcadeSlopes;
5454
* @constant
5555
* @type {string}
5656
*/
57-
Phaser.Plugin.ArcadeSlopes.VERSION = '0.2.1';
57+
Phaser.Plugin.ArcadeSlopes.VERSION = '0.3.0-dev';
5858

5959
/**
6060
* The Separating Axis Theorem collision solver type.

src/ArcadeSlopes/Facade.js

-5
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ Phaser.Plugin.ArcadeSlopes.Facade.prototype.enableBody = function (body) {
102102
body.slopes = body.slopes || {
103103
debug: false,
104104
friction: new Phaser.Point(),
105-
heuristics: null,
106105
preferY: false,
107106
pullUp: 0,
108107
pullDown: 0,
@@ -116,10 +115,6 @@ Phaser.Plugin.ArcadeSlopes.Facade.prototype.enableBody = function (body) {
116115
response: null,
117116
},
118117
skipFriction: false,
119-
snapUp: 0,
120-
snapDown: 0,
121-
snapLeft: 0,
122-
snapRight: 0,
123118
tile: null,
124119
velocity: new SAT.Vector()
125120
};

src/ArcadeSlopes/Overrides.js

+89-35
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,18 @@ Phaser.Plugin.ArcadeSlopes.Overrides = {};
1717
* Collide a sprite against a single tile.
1818
*
1919
* @method Phaser.Plugin.ArcadeSlopes.Overrides#collideSpriteVsTile
20-
* @param {integer} i - The tile index.
21-
* @param {Phaser.Sprite} sprite - The sprite to check.
22-
* @param {Phaser.Tile} tile - The tile to check.
23-
* @param {Phaser.TilemapLayer} tilemapLayer - The tilemap layer the tile belongs to.
24-
* @param {function} collideCallback - An optional collision callback.
25-
* @param {function} processCallback - An optional overlap processing callback.
26-
* @param {object} callbackContext - The context in which to run the callbacks.
27-
* @param {boolean} overlapOnly - Whether to only check for an overlap.
28-
* @return {boolean} - Whether a collision occurred.
20+
* @param {integer} i - The tile index.
21+
* @param {Phaser.Sprite} sprite - The sprite to check.
22+
* @param {Phaser.Tile} tile - The tile to check.
23+
* @param {Phaser.TilemapLayer} tilemapLayer - The tilemap layer the tile belongs to.
24+
* @param {function} [collideCallback] - An optional collision callback.
25+
* @param {function} [processCallback] - An optional overlap processing callback.
26+
* @param {object} [callbackContext] - The context in which to run the callbacks.
27+
* @param {boolean} [overlapOnly] - Whether to only check for an overlap.
28+
* @return {boolean} - Whether a collision occurred.
2929
*/
3030
Phaser.Plugin.ArcadeSlopes.Overrides.collideSpriteVsTile = function (i, sprite, tile, tilemapLayer, collideCallback, processCallback, callbackContext, overlapOnly) {
31-
if (!sprite.body) {
31+
if (!sprite.body || !tile || !tilemapLayer) {
3232
return false;
3333
}
3434

@@ -59,22 +59,22 @@ Phaser.Plugin.ArcadeSlopes.Overrides.collideSpriteVsTile = function (i, sprite,
5959
* Collide a sprite against a set of tiles.
6060
*
6161
* @method Phaser.Plugin.ArcadeSlopes.Overrides#collideSpriteVsTiles
62-
* @param {Phaser.Sprite} sprite - The sprite to check.
63-
* @param {Phaser.Tile[]} tiles - The tiles to check.
64-
* @param {Phaser.TilemapLayer} tilemapLayer - The tilemap layer the tiles belong to.
65-
* @param {function} collideCallback - An optional collision callback.
66-
* @param {function} processCallback - An optional overlap processing callback.
67-
* @param {object} callbackContext - The context in which to run the callbacks.
68-
* @param {boolean} overlapOnly - Whether to only check for an overlap.
69-
* @return {boolean} - Whether a collision occurred.
62+
* @param {Phaser.Sprite} sprite - The sprite to check.
63+
* @param {Phaser.Tile[]} tiles - The tiles to check.
64+
* @param {Phaser.TilemapLayer} tilemapLayer - The tilemap layer the tiles belong to.
65+
* @param {function} [collideCallback] - An optional collision callback.
66+
* @param {function} [processCallback] - An optional overlap processing callback.
67+
* @param {object} [callbackContext] - The context in which to run the callbacks.
68+
* @param {boolean} [overlapOnly] - Whether to only check for an overlap.
69+
* @return {boolean} - Whether a collision occurred.
7070
*/
7171
Phaser.Plugin.ArcadeSlopes.Overrides.collideSpriteVsTiles = function (sprite, tiles, tilemapLayer, collideCallback, processCallback, callbackContext, overlapOnly) {
72-
var collided = false;
73-
74-
if (!sprite.body) {
75-
return collided;
72+
if (!sprite.body || !tiles || !tiles.length || !tilemapLayer) {
73+
return false;
7674
}
7775

76+
var collided = false;
77+
7878
for (var i = 0; i < tiles.length; i++) {
7979
if (processCallback) {
8080
if (processCallback.call(callbackContext, sprite, tiles[i])) {
@@ -104,7 +104,7 @@ Phaser.Plugin.ArcadeSlopes.Overrides.collideSpriteVsTiles = function (sprite, ti
104104
* @return {boolean} - Whether a collision occurred.
105105
*/
106106
Phaser.Plugin.ArcadeSlopes.Overrides.collideSpriteVsTilemapLayer = function (sprite, tilemapLayer, collideCallback, processCallback, callbackContext, overlapOnly) {
107-
if (!sprite.body) {
107+
if (!sprite.body || !tilemapLayer) {
108108
return false;
109109
}
110110

@@ -113,20 +113,17 @@ Phaser.Plugin.ArcadeSlopes.Overrides.collideSpriteVsTilemapLayer = function (spr
113113
sprite.body.position.y - sprite.body.tilePadding.y - tilemapLayer.getCollisionOffsetY(),
114114
sprite.body.width + sprite.body.tilePadding.x,
115115
sprite.body.height + sprite.body.tilePadding.y,
116-
false,
116+
true,
117117
false
118118
);
119119

120120
if (tiles.length === 0) {
121121
return false;
122122
}
123123

124-
var collided = this.collideSpriteVsTiles(sprite, tiles, tilemapLayer, collideCallback, processCallback, callbackContext, overlapOnly);
124+
// TODO: Sort by distance from body center to tile center?
125125

126-
if (!collided && !overlapOnly) {
127-
// TODO: This call is too hacky and solver-specific
128-
this.game.slopes.solvers.sat.snap(sprite.body, tiles, tilemapLayer);
129-
}
126+
var collided = this.collideSpriteVsTiles(sprite, tiles, tilemapLayer, collideCallback, processCallback, callbackContext, overlapOnly);
130127

131128
return collided;
132129
};
@@ -254,8 +251,13 @@ Phaser.Plugin.ArcadeSlopes.Overrides.renderDebug = function () {
254251
var height = this.layer.height;
255252
var tw = this._mc.tileWidth * scaleX;
256253
var th = this._mc.tileHeight * scaleY;
254+
var htw = tw / 2;
255+
var hth = th / 2;
256+
var qtw = tw / 4;
257+
var qth = th / 4;
257258
var cw = this._mc.cw * scaleX;
258259
var ch = this._mc.ch * scaleY;
260+
var m = this._mc.edgeMidpoint;
259261

260262
var left = Math.floor(scrollX / tw);
261263
var right = Math.floor((renderW - 1 + scrollX) / tw);
@@ -281,7 +283,7 @@ Phaser.Plugin.ArcadeSlopes.Overrides.renderDebug = function () {
281283
var normStartX = (left + ((1 << 20) * width)) % width;
282284
var normStartY = (top + ((1 << 20) * height)) % height;
283285

284-
var tx, ty, x, y, xmax, ymax, polygon, i, j;
286+
var tx, ty, x, y, xmax, ymax, polygon, i, j, a, b, norm, gx, gy;
285287

286288
for (y = normStartY, ymax = bottom - top, ty = baseY; ymax >= 0; y++, ymax--, ty += th) {
287289
if (y >= height) {
@@ -369,8 +371,9 @@ Phaser.Plugin.ArcadeSlopes.Overrides.renderDebug = function () {
369371
}
370372
}
371373

372-
// Stroke the colliding edges
374+
// Stroke the colliding edges and edge normals
373375
if (this.debugSettings.slopeCollidingEdgeStroke) {
376+
// Colliding edges
374377
context.beginPath();
375378

376379
context.lineWidth = this.debugSettings.slopeCollidingEdgeStrokeWidth || 1;
@@ -379,11 +382,12 @@ Phaser.Plugin.ArcadeSlopes.Overrides.renderDebug = function () {
379382
polygon = tile.slope.polygon;
380383

381384
for (i = 0; i < polygon.points.length; i++) {
382-
j = (i + 1) % polygon.points.length;
383-
384-
// Skip internal edges
385-
if (polygon.points[i].internal)
385+
// Skip the edges with ignored normals
386+
if (polygon.normals[i].ignore) {
386387
continue;
388+
}
389+
390+
j = (i + 1) % polygon.points.length;
387391

388392
context.moveTo(tx + polygon.points[i].x * scaleX, ty + polygon.points[i].y * scaleY);
389393
context.lineTo(tx + polygon.points[j].x * scaleX, ty + polygon.points[j].y * scaleY);
@@ -392,6 +396,56 @@ Phaser.Plugin.ArcadeSlopes.Overrides.renderDebug = function () {
392396
context.closePath();
393397

394398
context.stroke();
399+
400+
// Edge normals
401+
for (i = 0; i < polygon.points.length; i++) {
402+
context.beginPath();
403+
404+
if (polygon.normals[i].ignore) {
405+
context.lineWidth = this.debugSettings.slopeNormalStrokeWidth;
406+
context.strokeStyle = this.debugSettings.slopeNormalStroke;
407+
} else {
408+
context.lineWidth = this.debugSettings.slopeCollidingNormalStrokeWidth;
409+
context.strokeStyle = this.debugSettings.slopeCollidingNormalStroke;
410+
}
411+
412+
413+
j = (i + 1) % polygon.points.length;
414+
415+
a = polygon.points[i];
416+
b = polygon.points[j];
417+
norm = polygon.normals[i];
418+
419+
// Midpoint of the edge
420+
m.x = (a.x + b.x) / 2;
421+
m.y = (a.y + b.y) / 2;
422+
423+
// Draw from the midpoint outwards using the normal
424+
context.moveTo(tx + m.x * scaleX, ty + m.y * scaleY);
425+
context.lineTo(tx + m.x * scaleX + norm.x * qtw, ty + m.y * scaleY + norm.y * qth);
426+
427+
context.closePath();
428+
context.stroke();
429+
}
430+
431+
// Ignormals
432+
if (tile.slope.ignormals) {
433+
for (i = 0; i < tile.slope.ignormals.length; i++) {
434+
context.beginPath();
435+
436+
context.lineWidth = 1;
437+
context.strokeStyle = 'rgba(255, 0, 0, 1)';
438+
439+
gx = tile.slope.ignormals[i].x;
440+
gy = tile.slope.ignormals[i].y;
441+
442+
context.moveTo(tx + htw, ty + hth);
443+
context.lineTo(tx + htw + gx * qtw, ty + hth + gy * qth);
444+
445+
context.closePath();
446+
context.stroke();
447+
}
448+
}
395449
}
396450
}
397451
}

0 commit comments

Comments
 (0)