Collision does not work for rotated entities with updated origin
adbo28 opened this issue · 7 comments
I am using the following piece of code to check for collisions and to prevent them from moving, if needed.
It works well until I change the rotation origin (this.origin("center")
) and rotate the this
object. The erroneous behavior can be easily shown by adding the SolidHitBox
component to the respective entity.
var hitDatas, hitData;
if ((hitDatas = this.hit('Wall'))) { // check for collision with walls
hitData = hitDatas[0]; // resolving collision for just one collider
if (hitData.type === 'SAT') { // SAT, advanced collision resolution
// move player back by amount of overlap
this.x -= hitData.overlap * hitData.nx;
this.y -= hitData.overlap * hitData.ny;
} else { // MBR, simple collision resolution
// move player to previous position
this.x = evt._x;
this.y = evt._y;
}
}
It works well until I change the rotation origin (this.origin("center")) and rotate the this object. The erroneous behavior can be easily shown by adding the SolidHitBox component to the respective entity.
Thanks for the bug report! Could you describe the error in a bit more detail? (Or provide a self-contained example?)
Hi, sure the subset of my code which displays the reported behaviour follows:
`
<div id="game"></div>
<script type="text/javascript" src="https://rawgithub.com/craftyjs/Crafty/release/dist/crafty-min.js">
</script>
<script>
Crafty.init(500,500, document.getElementById('game'));
Crafty.c("Rocket", {
init: function() {
this.addComponent("2D, DOM, Color, Motion, Collision, SolidHitBox");
this.rotating = 0;
this.rotation = Crafty.math.randomNumber(0, 359);
this.x = Crafty.math.randomNumber(50, 450);
this.y = Crafty.math.randomNumber(50, 450);
this.w = 30;
this.h = 30;
this.origin("center");
},
moveOneStep: function(evt) {
//rotation
this.rotation += this.rotating;
//check for collision after rotation
var hitDatas, hitData;
if ((hitDatas = this.hit('Wall'))) { // check for collision with walls
hitData = hitDatas[0]; // resolving collision for just one collider
this.rotation -= this.rotating;
return this;
}
//move
diff_x = Math.cos(this.rotation/180*Math.PI);
this.x += diff_x;
diff_y = Math.sin(this.rotation/180*Math.PI);
this.y += diff_y;
//check for collision after move
if ((hitDatas = this.hit('Wall'))) { // check for collision with walls
hitData = hitDatas[0]; // resolving collision for just one collider
if (hitData.type === 'SAT') { // SAT, advanced collision resolution
// move player back by amount of overlap
this.x -= diff_x;
this.y -= diff_y;
} else { // MBR, simple collision resolution
// move player to previous position
this.x = evt._x;
this.y = evt._y;
}
}
return this;
}
});
Crafty.e('Collision, Wall, 2D, DOM, Color').attr({x: 0, y: 0, w: 20, h: 500}).color('black');
Crafty.e('Collision, Wall, 2D, DOM, Color').attr({x: 0, y: 0, w: 500, h: 20}).color('black');
Crafty.e('Collision, Wall, 2D, DOM, Color').attr({x: 480, y: 0, w: 20, h: 500}).color('black');
Crafty.e('Collision, Wall, 2D, DOM, Color').attr({x: 0, y: 480, w: 500, h: 20}).color('black');
//--- rocket1 ---
var rocket = Crafty.e('Rocket, Keyboard')
.color('blue');
rocket.bind("KeyDown", function(e) {
if(e.key == Crafty.keys.LEFT_ARROW) {
rocket.rotating = +5;
}
if(e.key == Crafty.keys.RIGHT_ARROW) {
rocket.rotating = -5;
}
});
rocket.bind("KeyUp", function(e) {
if(e.key == Crafty.keys.RIGHT_ARROW || e.key == Crafty.keys.LEFT_ARROW) {
rocket.rotating = 0;
}
});
rocket.bind("UpdateFrame", rocket.moveOneStep);
</script>
</body>
`
my previous comment does not contain the inital lines, but they are quite obvious:
< html >
<head >
</head >
<body >
If I skip the line this.origin("center");
in my code, the SolidHitBox overlaps well with my square. Once this line is included, the SolidHitBox and my square divide.
Looks like something is going wrong when you set the width, origin, rotation, and hitbox in a specific order.
I'll look into this further, but setting the origin after the dimensions, but before the other properties works around the bug:
this.addComponent("2D, DOM, Color, Motion, Collision, SolidHitBox");
this.rotating = 0;
this.w = 30;
this.h = 30;
this.origin("center");
this.rotation = Crafty.math.randomNumber(0, 359);
this.x = Crafty.math.randomNumber(50, 450);
this.y = Crafty.math.randomNumber(50, 450);
e: originally suggested setting the origin first, but that produces a slightly different bug. I think the root issue is that the collision hitbox isn't recalculated correctly when the origin is applied, and it's manifesting in a couple of different ways.
thanks a lot. the workaround works fine :)