Skip to content

Commit

Permalink
Merge pull request #1202 from starwed/cascade-origin-changes
Browse files Browse the repository at this point in the history
Update dependent positions on origin change
  • Loading branch information
starwed authored Dec 8, 2018
2 parents e8e27f0 + 27c03c4 commit f3982ba
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 15 deletions.
64 changes: 49 additions & 15 deletions src/spatial/2d.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ var M = Math,
PI = M.PI,
DEG_TO_RAD = PI / 180;

// These versions of cos and sin ensure that rotations very close to 0 return 0.
// This avoids some problems where entities are not quite aligned with the grid.
var rounded_cos = function(drad) {
var cos = Math.cos(drad);
cos = -1e-10 < cos && cos < 1e-10 ? 0 : cos;
return cos;
};

var rounded_sin = function(drad) {
var sin = Math.sin(drad);
sin = -1e-10 < sin && sin < 1e-10 ? 0 : sin;
return sin;
};

/**@
* #2D
* @category 2D
Expand Down Expand Up @@ -364,11 +378,8 @@ Crafty.c("2D", {
dy1 = this._y - this._by1 - oy,
dy2 = this._y + this._h + this._by2 - oy;

var ct = Math.cos(rad),
st = Math.sin(rad);
// Special case 90 degree rotations to prevent rounding problems
ct = ct < 1e-10 && ct > -1e-10 ? 0 : ct;
st = st < 1e-10 && st > -1e-10 ? 0 : st;
var ct = rounded_cos(rad),
st = rounded_sin(rad);

// Calculate the new points relative to the origin, then find the new (absolute) bounding coordinates!
var x0 = dx1 * ct + dy1 * st,
Expand Down Expand Up @@ -695,18 +706,22 @@ Crafty.c("2D", {
* moves in the same way.
*/
_cascade: function(e) {
if (!e) return; //no change in position
var i = 0,
children = this._children,
l = children.length,
obj;
if (!e) return;

//use current position
var dx = this._x - e._x,
dy = this._y - e._y,
dw = this._w - e._w,
dh = this._h - e._h;

this._cascadeInner(dx, dy, dw, dh);
},

_cascadeInner: function(dx, dy, dw, dh) {
var i = 0,
children = this._children,
l = children.length,
obj;
for (; i < l; ++i) {
obj = children[i];
if (obj.__frozen) continue;
Expand Down Expand Up @@ -736,11 +751,8 @@ Crafty.c("2D", {
obj;
// precalculate rotation info
var drad = deg * DEG_TO_RAD;
var cos = Math.cos(drad);
var sin = Math.sin(drad);
// Avoid some rounding problems
cos = -1e-10 < cos && cos < 1e-10 ? 0 : cos;
sin = -1e-10 < sin && sin < 1e-10 ? 0 : sin;
var cos = rounded_cos(drad);
var sin = rounded_sin(drad);
var ox = this._origin.x + this._x;
var oy = this._origin.y + this._y;

Expand Down Expand Up @@ -892,9 +904,31 @@ Crafty.c("2D", {
}
}

// When entity is rotated, we'll need to shift attached entities on origin change
// The below transformation is equivalent to unrotating, shifting the origin,
// and then rotating around this new origin
if (this.rotation) {
var rad = -this._rotation * DEG_TO_RAD;
var d_ox = x - this._origin.x;
var d_oy = y - this._origin.y;
var cos = rounded_cos(rad);
var sin = rounded_sin(rad);
var dx = d_ox * (1 - cos) - d_oy * sin;
var dy = d_oy * (1 - cos) + d_ox * sin;
this._cascadeInner(dx, dy, 0, 0);
}
this._origin.x = x;
this._origin.y = y;

if (this._mbr) {
this._calculateMBR();
}

// Update position in spatial map
this._entry.update(this._cbr || this._mbr || this);

this.trigger("OriginChanged");
this.trigger("Invalidate");
return this;
},

Expand Down
74 changes: 74 additions & 0 deletions tests/unit/spatial/2d.js
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,80 @@
_.strictEqual(child._rotation, 90, "child also rotates 90deg");
});

test("origin change affects children", function(_) {
var parent = Crafty.e("2D").attr({
x: 0,
y: 0,
w: 50,
h: 50
});
var child = Crafty.e("2D").attr({
x: 100,
y: 0,
w: 50,
h: 50
});
parent.attach(child);
parent.rotation = 90;
_.strictEqual(
child._y,
100,
"child rotates around top left corner (x position)"
);
_.strictEqual(
child._x,
0,
"child rotates around top left corner (y position)"
);

parent.origin(50, 0);
_.strictEqual(
child._y,
50,
"child rotates around top right corner (x position)"
);
_.strictEqual(
child._x,
50,
"child rotates around top right corner (y position)"
);
});

test("origin change affects MBR", function(_) {
var parent = Crafty.e("2D").attr({
x: 0,
y: 0,
w: 50,
h: 50
});

parent.rotation = 90;
var mbr1 = parent.mbr();
_.strictEqual(
mbr1._x,
-50,
"MBR rotates around top left corner (x position)"
);
_.strictEqual(
mbr1._y,
0,
"MBR rotates around top left corner (y position)"
);

parent.origin(50, 0);
var mbr2 = parent.mbr();
_.strictEqual(
mbr2._x,
0,
"MBR rotates around top right corner (x position)"
);
_.strictEqual(
mbr2._y,
-50,
"MBR rotates around top right corner (y position)"
);
});

test("origin properties", function(_) {
var player = Crafty.e("2D, Centered").attr({
x: 0,
Expand Down

0 comments on commit f3982ba

Please sign in to comment.