Collision detection using Sector

Started by
24 comments, last by jonathanc 15 years ago
whoops , forgot about unsigned_angle

here it is:

float Player::unsigned_angle(CVector2 a, CVector2 b){    return abs(atan2(perp_dot(a,b), vec_dot(a,b)));}//and the vector functions called :CVector2 perp (CVector2 v){	return CVector2 (-v.y, v.x);}float vec_dot (CVector2 v1, CVector2 v2){	D3DXVECTOR2 v1_d3d (v1.x, v1.y);	D3DXVECTOR2 v2_d3d (v2.x, v2.y);	return D3DXVec2Dot (&v1_d3d, &v2_d3d);}float perp_dot (CVector2 v1, CVector2 v2){	D3DXVECTOR2 v1_d3d (v1.x, v1.y);	D3DXVECTOR2 v2_d3d (v2.x, v2.y);	CVector2 v1_perp = perp (v1);	D3DXVECTOR2 v1_d3d_perp (v1_perp.x, v1_perp.y);	return D3DXVec2Dot (&v1_d3d_perp, &v2_d3d);}class CVector2{public:	float x;	float y;	friend float vec_dot (CVector2 v1, CVector2 v2);	friend float perp_dot (CVector2 v1, CVector2 v2);	friend CVector2 vec_sub(CVector2 v1, CVector2 v2);	CVector2 perp (CVector2 v);	CVector2 (float x_in, float y_in)	{		x = x_in;		y = y_in;	}};


Should be all I hope. It's a bit messy because I am cut and pasting from all over the place :P
Advertisement
I haven't looked over all the code yet, but the first thing I see is that unsigned_angle() returns the angle in radians (assuming C++), but it looks like you're comparing it to an angle in degrees. I'd start by fixing this, and see if that solves the problem.
Hmm, well spotted. And yes, I'm programming in C++. Was a bit tired last night when coding this. Ive made the following changes:

bool Player::check_fov(CVector2 Zombiepos, CVector2 zombieOrient, float zombiefov, CVector2 playerPos){	   // return unsigned_angle(zombieOrient, vec_sub(Get2Dpos() , Zombiepos)) < zombiefov / 2;	return unsigned_angle(zombieOrient, vec_sub(Get2Dpos() , Zombiepos)) < DEG2RAD(zombiefov) / 2;	}//with the following defines:#define PI 3.141592#define DEG2RAD(x) (x * (PI / 180.0f)) 


Will try to do some testing now

[Edited by - jonathanc on April 18, 2009 3:36:16 PM]
Right, test results:

Player starts @ (0,0). I set his orientation locked to (0,1) so this means he will head dead north. His radius is set as 1.

Test 1:
Zombie positioned @ (0,3) Orientation set to (0, -1). Radius is 1. (Zombie will never move nor change orientation)

My bool Player::Attacked(float x, float z, float r, CVector2 Tarpos, CVector2 TarOrient, float tarFOV ) function returns positive @ around (0,1.1).

I guess this is normal as the player is both in the bounding circle range and also the zombie is facing him.

Test 2:
Zombie same position but Orientation set to (0, 1). Player starts back (0,0). Player moves in the same direction as Test 1.

No collision happens whatsoever. Shouldn't Player::Attacked return positive the player goes beyond (0, 3) ? This means the zone where the player will be attacked.

Conclusion
So far it seems that Player::Attacked only works if zombie if facing towards the player. Haven't tested other variables though such as different zombie positions and orientations.
However, I think that this test should be successful since its the most basic test for this case.

[Edited by - jonathanc on April 18, 2009 4:46:16 PM]
Yes, if the zombie is at 0,3 and facing north (0,1), and if the player starts at 0,0 and moves north, then the test should return true once the player has passed the position 0,3.

I'll look at the code a little more, but in the meantime, I recommend doing some debugging. Start by positioning the player at, say, 0,3.5, and run the app. The easiest way to see what's going on would probably be to step through the program in the debugger, if the tools you're using offer this feature. If not, and if you have a console of some sort available, add debug output that indicates what exactly is happening.

What you want to determine is where and why the test is failing. Is the bounding circle test returning false? Or the FOV test? If the latter, why? What is the computed angle between the zombie's forward direction vector and the vector to the player? (In your test case, it should be around zero.) What value is it being compared to? Is the field of view that's passed in correct? And so on.

If I spot anything else in the code that looks suspect though, I'll let you know.
Just a couple additional comments after looking over the code a little more.

I would double-check again that you're handling degree-radian conversions correctly. I suggested that perhaps you were comparing radians to degrees in your FOV test function because you had a comment to that effect there, but I also see that you're converting the field of view argument to radians when you call that function. Anyway, make sure you're not missing any conversions anywhere, or converting more than once (e.g. converting degrees to radians, and then converting to radians again, which will give you garbage).

From a debugging standpoint, it might be easier if you worked with degrees consistently (for math library functions such as atan2 that return an angle in radians, just convert the return value to degrees immediately before doing anything with it). This might make it easier to confirm the correctness of the computed values at a glance.

Beyond that, the code is currently a little hard to follow, so without really digging into it I can't really tell what's happening where. This is mostly due to variable and function naming, and general code organization. It's probably clear enough to you (since you wrote it!), but it's probably still worth double-checking to make sure that you're working with the right data (e.g. player position, zombie position, zombie field of view, etc.) in the right places.
Aye I know its pretty messy because there's a lot of other code here and there and I didn't paste the complete class (which would be VERY long :P )

I have a separate console window to output my printf for debugging purposes.
AllocConsole();	freopen("CONOUT$", "wb", stdout);
and I am using VS2005 and trying my best to debug things

Hmm, about the conversion, should I just convert the return of
float Player::unsigned_angle(CVector2 a, CVector2 b){    return abs(atan2(perp_dot(a,b), vec_dot(a,b)));}

so that it will return a value in degrees? For example:
return RAD2DEG(abs(atan2(perp_dot(a,b), vec_dot(a,b)))); 


edit: Will attempt to explain the code out a little :P
bool Player::Attacked(float x, float z, float r, CVector2 Tarpos, CVector2 TarOrient, float tarFOV )

is basically the star of the show. It's called every frame and compared to all the alive zombies (not so efficient I know:P) which at the moment is just one. Zombies like the player have 3 important stats, their pos (ZXplane), their orientation(0-1 range on the ZX plane) and lastly the radius (for bounding circle computation). At the present, the zombies don't move/turn at all.

Float x,z in this function is the zombie's pos, float r is the zombie's radius. Tarpos means the zombie's position again as CVector2 type, TarOrient is the zombie's orientation (0,1 etc etc) and the fov is the zombie's FoV in degrees.

Player::Attacked first test for Bounding Circle comparing the player's current pos and the zombies. If that passes , it will then test for fov using
bool Player::check_fov(CVector2 Zombiepos, CVector2 zombieOrient, float zombiefov, CVector2 playerPos)

This is basicallly the code that you showed me earlier except I use the player as the "target" here. If that passes as well Player::Attacked will return positive. It will return false in all other circumstances. Player::Attack is specifically just used to see if the player is attacked by zombies.
Zombiepos = the zombie's position, zombieOrient = the zombie's orientation, zombiefov = zombie's fov. Yeah I know the naming conventions are very confusing and probably the code is not efficiently or well written but I am just trying to keep things simple and of course make it work :P

Hmm I hope that cleared things up a bit .Will do further testing but its all numbers at the moment and as you probably know I am not so good with numbers :(
This is a game for the visually impaired so there's no graphics to compare or debug with.

Quote:Hmm, about the conversion, should I just convert the return of
float Player::unsigned_angle(CVector2 a, CVector2 b){    return abs(atan2(perp_dot(a,b), vec_dot(a,b)));}

so that it will return a value in degrees? For example:
return RAD2DEG(abs(atan2(perp_dot(a,b), vec_dot(a,b)))); 
Yes, that would work. The key though is consistency - just remember that if you miss a conversion, or if you inadvertently compare a value in degrees to a value in radians, the results will be incorrect in most cases and your program will not behave as you expect.

A reasonable approach would be to work with degrees consistently within your program, and then only perform conversions when interfacing with C/C++ math library functions (like in your example above).
Hey , made a lil edit on the previous post to clear things up a bit.

I made the changes to the return and it seems to still have the same impact as before so I reckon the conversion is not the issue here. Perhaps a way I apply some function , such as the check_fov which I did make some changes from what you have suggested. I probably didn't get the direction vectors (orientation vectors) right...
One small tip: just because the final game won't incorporate graphics doesn't mean you can't create a graphical representation for debugging purposes.

If you don't have any support in place for graphics though, it may or may not be worth the trouble to add such support. (It depends on the scope of the project, I suppose - if the eventual scope of the simulation will be significantly greater than a player and a few zombies, spending a day or two getting some debug graphics in place might very well pay off in terms of development time saved.)

Since at the moment you don't have any graphical debug output, I would just suggest that you not take the correctness of any of your data for granted; for example, the direction vectors themselves could be incorrect, as you mentioned.

This topic is closed to new replies.

Advertisement