Archived

This topic is now archived and is closed to further replies.

BlackEye

Spent 13 hours on this, still broke !! :(

Recommended Posts

Hi, I know this comes up alot, i have looked at previous articles but still cannot get this to work!? Please help, its simply a rotation of a point in 2D around point 2. Basicly a bounding box around its centre. I know the sprite size is 32, hence centre is 16. and my bounding box solids are (13,10) for the TopLeft and (20,20) for the bottom right. This is what I have done so far, i have included everything so its easy and obvious hopefully to you why it may not work!? ARGGHHHHH!!! (The problem appears to be that it just does not rotate the points!?)
struct cord
	{

		float X;
		float Y;
	};

	cord centre;
	
	centre.X = 16;
	centre.Y = 16;

	cord temp;
	cord newXY;
	cord rotated;
	float rotatedX;
	float rotatedY;

	float angle_rad;
	angle_rad = D3DXToRadian(-m_Angle);
	
	cord rectangle[1];

	rectangle[0].X = m_SolidTL.X;
	rectangle[0].Y = m_SolidTL.Y;
	rectangle[1].X = m_SolidBR.X;
	rectangle[1].Y = m_SolidBR.Y;

	for(int i=0;i<2;i++)
	{  
		temp.X = rectangle[i].X - centre.X;
		temp.Y = rectangle[i].Y - centre.Y;

		rotatedX = temp.X * cos(angle_rad) - temp.Y * sin(angle_rad);
		rotatedY = temp.X * sin(angle_rad) + temp.Y * cos(angle_rad);
				
		newXY.X = rotatedX + centre.X;
		newXY.Y = rotatedY + centre.Y;
		
		rectangle[i].X = newXY.X;
		rectangle[i].Y = newXY.Y;
	};

	// Now Get my object World Cords


	rectangle[0].X += GetX(); // Now update them in the world cords ! GetX returns the topleft pixel location in the world

	rectangle[0].Y += GetY();
	rectangle[1].X += GetX();
	rectangle[1].Y += GetY();

Share this post


Link to post
Share on other sites
to rotate a point around another point



coord RotateAround(coord P, coord C, float angle)
{
coord t;

float cos_a = cos(angle);
float sin_a = cos(angle);

float dx = P.x - C.x;
float dy = P.y - C.y;

float ex = dx * cos_a - dy * sin_a;
float ey = dx * sin_a + dy * cos_a;

t.x = C.x + ex;
t.y = C.y + ey;

return t;
}




[edited by - oliii on October 23, 2003 8:08:47 PM]

Share this post


Link to post
Share on other sites
BlackEye,

Your code looks good. Have you tried actually inspecting the values to see that the points change? Also, how are you actually drawing the sprites? As a textured quad? Or some other way?

Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.

Share this post


Link to post
Share on other sites
My Sprite is in a cSprite class, which uses an DirectX LPD3DXSPRITE. I then call the rotate function and pass it m_Angle to rotate to the players correct angle.

From the m_Angle i also want to turn my collsion box accordingly?

Here is a link to a picture which may help..
http://www.2ndchancegames.co.uk/Image.jpg

I really dont want to waste another day getting nowhere!! (



Share this post


Link to post
Share on other sites
as I told you in the mail, you cannot just use just two (X, Y) points to define a rotated box. Only for axis aligned. You need either 4 corners, or an extent vector, and two orthogonal direction vectors.

If you just want the axis aligned bounding box around a rotated sprite, what you can do is


// the orthogonal axes of the rotated box

vector U(cos(angle), sin(angle))
vector V(sin(angle), -cos(angle));

// the centre of the box

vector C = (max + min) * 0.5f;

// the extents (dimensions) of the box, not rotated

vector E = (max - min) * 0.5f;

// the new dimensions (''radius'') of the box when rotated

float rx = fabs(U.x) * E.x + fabs(V.x) * E.y;
float ry = fabs(U.y) * E.x + fabs(V.y) * E.y;
Vector R(rx, ry);

// the axis aligned bounding box around the rotated box

vector newmin = C - R;
vector newmax = C + R;


a drawing


newmin
*----+-------------------------*
| / . |
| . . |
| / . U*E.x . |
|/ . . |
+ . C . |
| . * . |
| . / +
| . / V*E.y /|
| . / |
| . / |
| . / |
*-------------------------+----*
newmax

Share this post


Link to post
Share on other sites
Aha!

I get oliii''s point now, and it is good! If you only specify two points, and rotate those, then all you are doing is making the rectangle more or less wide and more or less tall. With just the two points the rectangle variable does not encapsulate any rotation, and therefore cannot actually be used to represent a rotated sprite. Hopefully my comment and oliii''s latest detailed post will clear that up.

I also discovered a serious, crash-inducing bug in your code. See the following:


cord rectangle[1];
rectangle[0].X = m_SolidTL.X;
rectangle[0].Y = m_SolidTL.Y;
rectangle[1].X = m_SolidBR.X;
rectangle[1].Y = m_SolidBR.Y;


Note that you''ve allocated variable rectangle as an array of exactly 1 cord structure. Therefore, only memory for rectangle[0] has been allocated. The memory location for rectangle[1] is invalid and when you try to set values in rectangle[1] you are actually creating an access violation. It is possible that you didn''t see a crash, and you could just simply get lucky and have the function work (more likely for a debug build than for a release build)----the fact is you need to allocate rectangle as follows:

cord rectangle[2];

Actually, once you follow oliii''s advice, you are going to have:

cord rectangle[4];

Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.

Share this post


Link to post
Share on other sites
Guys,
Good news!!
I see olliiis(how many i''s!) point aswell, but i was testing it drawing a line between the 2 thinking it would spin round the origin(centre). Then from my points i can build up a rectange as the top right corner is the topleft Y and bottom right X etc etc. But i have gone back to the drawing board as oli said in an email. I have built up a polygon class which can rotate and render itself to screen for testing purposes. I just need to take into account camera position over its world location before rendering and im home!

O and good spot on the bug! Damn wonder how many of those have crept in due to my latenight keyboard bashing!

Thanks guys i can smile again and put this behind me!
Onto... DirectX mp3 and joystick control!

Share this post


Link to post
Share on other sites
I saw that bug yesterday, but then it slipped my mind, and came back again!

So, for a collision box, either use a axis aligned bounding box that encompass the rotated box, or use a different structure like this one.


struct COBox
{
Vector C;
Vector E;
Vector U;
Vector V;

COBox(const Vector& min, const Vecor& max, float angle)
: U(cos(angle), sin(angle))
, V(sin(angle), -cos(angle))
, C((max + min) * 0.5f)
, E((max - min) * 0.5f)
{}

//-----------------------------------

// get the tight axis aligned box around an oriented box

//-----------------------------------

void GetAABBox(Vector& min, Vector& max) const
{
float rx = fabs(U.x) * E.x + fabs(V.x) * E.y;
float ry = fabs(U.y) * E.x + fabs(V.y) * E.y;
Vector R(rx, ry);

min = C - R;
max = C + R;
}

//-----------------------------------

// simple axis aligned collision test.

//-----------------------------------

bool AABBoxIntersect(const COBox& Box) const
{
Vector min0, max0;
Vector min1, max1;
GetAABox(min0, max0);
Box.GetAABox(min1, max1);

if (min0.x > max1.x || max0.x < min1.x)
return false;
if (min0.y > max1.y || max0.y < min1.y)
return false;
if (min0.z > max1.z || max0.z < min1.z)
return false;

return true;
}

//-----------------------------------

// more complex oriented box / oriented box

// intersection test

//-----------------------------------

bool Intersect(const COBox& Box) const;

private:
//-----------------------------------

// collision detection sub-routines

//-----------------------------------

void GetExtentsAlongAxis(const Vector& N, float& min, float& max) const;

bool ProjectionOverlap(const Vector& N, const COBox& B1);
};


The collision detection with a box like that is a more difficult than with an axis aligned box obviously, but not too difficult.


//----------------------------------------------------

// test if two oriented box intersect.

//----------------------------------------------------

bool COBox::Intersect(const COBox& Box) const
{
if (!ProjectionOverlap(U, Box))
return false;

if (!ProjectionOverlap(V, Box))
return false;

if (!ProjectionOverlap(Box.U, Box))
return false;

if (!ProjectionOverlap(Box.V, Box))
return false;

return true;
}

//----------------------------------------------------

// test if the projections of two boxes on an arbitrary

// axis overlap or not.

//----------------------------------------------------

bool COBox::ProjectionOverlap(const Vector& N, const COBox& B1)
{
float min0, max0;
float min1, max1;

GetExtentsAlongAxis(N, min0, max0);
B1.GetExtentsAlongAxis(N, min1, max1);

if (min0 > max1 || max0 < min1)
return false;

return true;
}

//----------------------------------------------------

// find the extents of a box along an arbitrary axis

//----------------------------------------------------

void COBox::GetExtentsAlongAxis(const Vector& N, float& min, float& max) const
{
float c = N * C;
float r = fabs(U * N) * E.x + fabs(V * N) * E.y;
min = c - r;
max = c + r;
}


the algorithm is a separation axis, transposed in 2D. You find the extents of both boxes along one axis, and if their projections overlap on every axes, they intersect.

Else, if they don''t overlap on one of the axis, it means that there is a line that exists and that separate the boxes, so they can''t possibly intersect.

the test in 3D is basically the same, but with more axes to test (15 in the case of two oriented boxes).

Share this post


Link to post
Share on other sites
by the way, if you want to use a structure like vector rectangle[4], a similar algorithm exists to do collision detection an only shapes, as long as it is convex.



struct CPolygon
{
Vertices* pVertices;
int NumVertices;

CPolygon(Vector* V, int Vnum)
{
pVertices = new Vector[Vnum+1];
NumVertices = Vnum;

for(int i = 0; i < Vnum; i ++)
{
pVertices[i] = V[i];
}
pVertices[Vnum] = V[0];
}

~CPolygon()
{
delete[] pVerices;
}

bool Intersect(const CPolygon& Poly) const
{
for(int i = 0; i < NumVertices; i ++)
{
Vector E(pVertices[i+1] - pVertices[i]);
Vector N(E.y, -E.x);

if (!ProjectionOverlap(N, Poly))
return false;
}

for(int i = 0; i < Poly.NumVertices; i ++)
{
Vector E(Poly.pVertices[i+1] - Poly.pVertices[i]);
Vector N(E.y, -E.x);

if (!ProjectionOverlap(N, Poly))
return false;
}
return true;
}

private:
GetExtentsAlongAxis(const Vector& N, float& min, float& max) const
{
min = pVertices[0] * N;
max = pVertices[0] * N;

for(int i = 1; i < NumVertices; i++)
{
float d = pVertices[i] * N;

if (d < min)
min = d;
else if (d > max)
max = d;
}
}
};



[edited by - oliii on October 24, 2003 11:22:31 AM]

Share this post


Link to post
Share on other sites