Box rotations for 2d collisions (Directx C++)

Started by
5 comments, last by Crazyfool 13 years, 5 months ago
Hey, so I am trying to rotate 4 vectors representing a box around a sprite. I am trying to have it mimic the way sprites are actually rotated, and I and I am doing something like:

for(u_int i = 0; i < 4; ++i) {	vertex.x -= center.x;	vertex.y -= center.y;	tempX = cos(angle) * vertex.x - sin(angle) * vertex.y;	tempY = sin(angle) * vertex.x + cos(angle) * vertex.y;	vertex.x = center.x + tempX;	vertex.y = center.y + tempY;}


This appears to work sometimes, and other times it goes completely wrong. I am drawing points at each vertex, so I can see where the box is. What seems to be happening is the vertexes progressively get an incorrect value, which alter the computations of center, which increase the inaccuracy, etc etc. I am not sure where it is going wrong.

If I rotate around a vertex, things look fine, but are offset a variable amount (depending on the angle). I tried for a while to find some existing help, and I couldn't find anything but I might have missed it. Thanks in advanced.
Advertisement
You might just be seeing cumulative rounding error.

In any case, this isn't how oriented boxes are usually handled. First, for most collision tests it's not the corners you're interested in (at least not explicitly), so you don't necessarily need to track those as you're doing. Also, the typical approach is to store the relevant data in local space and transform it as needed (this will fix the 'rounding error' problem).

For an oriented box, a typical representation is a center point, 2 (or 3) extents, and 2 (or 3) orthonormal axes. The extents you can precompute and store with the object (usually, at least), and the center point and axes can be derived from the object's current transform.
Thanks for your quick response. I assumed the rounding errors would "go away" because center/vertices are recalculated every frame. I've looked at other code samples that have this kind of collision detection and rotated polygons, and the vertices are calculated the same way.

You've given me some keywords to use in my searches, so thanks :)
Quote:I assumed the rounding errors would "go away" because center/vertices are recalculated every frame.
Based on what you posted at least, it looks to me like the transformations are cumulative. But, maybe that's just because I'm not seeing all the code.
Quote:I've looked at other code samples that have this kind of collision detection and rotated polygons, and the vertices are calculated the same way.
I'd be interested to know what code samples those were. Generally speaking it shouldn't be necessary to perform those sorts of operations for collision detection purposes, so I suspect either you misinterpreted what you saw, or the code in question was using suboptimal methods.
Hi, thanks for the help so far. I tried following this tutorial, but I am not getting results that I expect.

It seems to be returning true almost always. I only perform collision tests when the player is near, and the tile is non-walkable. As soon as that happens, a collision is detected. I appreciate any help.

bool Polygon2D::detectCollision(Polygon2D* other){	VECTOR2 axis1(vertex[UR] - vertex);	VECTOR2 axis2(vertex[UR] - vertex[LR]);	VECTOR2 axis3(other->vertex - other->vertex[LL]);	VECTOR2 axis4(other->vertex - other->vertex[UR]);	if(!collisionOnAxis(other, axis1)) {		return false;	}	if(!collisionOnAxis(other, axis2)) {		return false;	}	if(!collisionOnAxis(other, axis3)) {		return false;	}	if(!collisionOnAxis(other, axis4)) {		return false;	}	return true;}bool Polygon2D::collisionOnAxis(Polygon2D* other, VECTOR2& axis){	float minOther, maxOther;	float minSelf, maxSelf;	findScalars(other, axis, minOther, maxOther);	findScalars(this, axis, minSelf, maxSelf);	if(maxOther >= minSelf || minOther <= maxSelf)		return true;	return false;}float Polygon2D::projectAndFindScalar(VECTOR2& coord, VECTOR2& axis){	float val = ((coord.x * axis.x) + (coord.y * axis.y)) / ((axis.x * axis.x) + (axis.y * axis.y));	VECTOR2 projected(val * axis.x, val * axis.y);	return (projected.x * axis.x + projected.y * axis.y);}void Polygon2D::findScalars(Polygon2D* other, VECTOR2& axis, float& min, float& max){	max = min = projectAndFindScalar(other->vertex, axis);	for(u_int i = 1; i < 4; ++i)	{		float temp = projectAndFindScalar(other->vertex, axis);		if(temp < min)			min = temp;		else if(temp > max)			max = temp;	}}
Quote:Hi, thanks for the help so far. I tried following this tutorial, but I am not getting results that I expect.
That tutorial kind of has it backwards. The tutorial suggests that the box axes be computed from the corners. But how are you going to compute the corners in the first place? Most likely, by transforming the local-space corners to world space using the object's transform. And if you have the transform, guess what? You already *have* the axes. So the whole 'transforming the corners and deducing the axes from them' step is backwards and unnecessary.

Furthermore, you don't actually need the corners at all to determine whether the two boxes intersect. All you actually need to know is the box's local-space extents (which, along with the object transform, gives you all the information about the box that you need).

Anyway, I'd recommend maybe checking out some other tutorials on the topic, such as this one.

As for your code, it looks like the problem might be here:
if(maxOther >= minSelf || minOther <= maxSelf)
This can return true even when the intervals do not overlap, which I don't think is what you want.

Also, your projectAndFindScalar() function doesn't need to be that complicated; it can simply return the dot product of the input point and axis.
Thanks a bundle. I read that I can use dot product only for true/false check, but I wanted to first make sure things worked using the tutorial method, and then move to improving it however I can.

I appreciate your help so far!

This topic is closed to new replies.

Advertisement