Jump to content
  • Advertisement
Sign in to follow this  
pulpfist

problems with calculating the angle

This topic is 4321 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a member function to process different actions for my game objects. The only case implemeted so far is the "move to location" action. Here is the function to process one step on the top action:
void LifeForm::process_todo()
{
	if(todo.size())
	{
		float slope, dx, dy;

		AI::Action *a = todo.top();
		AI::Travel *t;

		switch(a->type)
		{
		case AI::Action::type_none: break;		
		case AI::Action::type_move_to_location:

			t = dynamic_cast<AI::Travel*>(a);

			if(t->destination.x == pos.x)
			{
				todo.pop();
				delete t;
				return;
			}
			
			slope = (t->destination.y - pos.y) / (t->destination.x - pos.x);
			forward_angle = std::atan(slope);
			dx = std::cos(forward_angle);
			dy = std::sin(forward_angle);
			pos.x += dx;
			pos.y += dy;

			if(pos.x > t->destination.x - 2.0f && pos.x < t->destination.x + 2.0f
				&& pos.y > t->destination.y - 2.0f && pos.y < t->destination.y + 2.0f)
			{
				todo.pop();
				delete t;
			}
			break;
		case AI::Action::type_attack_target: break;
		case AI::Action::type_evade_target: break;
		case AI::Action::type_find_resource: break;			
		default: break;
		}
	}
}

I have set up the main function to add a new "move to random location" action for each object that runs out of actions in their todo queue. So my demo at this point has a bunch of objects moving to random locations and when a location is reached, that object gets a new "move to random location" action added to its action queue. The problem I have is that all my objects is moving to the right. The dy variable seems to be fine, but it appeares that the dx variable is always positive. Hence, the objects always moves into the 1st or 4th planes. The objects keep moving around but eventually thay all has gone out of the tile map universe on the right and bottom side. One thing that crossed my mind was that the random function used a too big interval but that is not the case. What I want to ask is if anyone recognize this problem or if anyone can see if there is something wrong with my code. I thought the slope and angle formulas Im using would work for all coordinate planes, but Im starting to wonder...

Share this post


Link to post
Share on other sites
Advertisement
Just a shoot in the dark but is there a chance that std::atan(I've never used it) returns the trigonometric atan? In which you'd have to check in what quadrant the angle lies to get the real angle?

Is there an std::atan2(dy,dx). If there is I would suggest you use it.

Or just use

asm FPATAN.

Share this post


Link to post
Share on other sites
For a quick fix to your problem, std::atan2(t->destination.y - pos.y), (t->destination.x - pos.x)) is indeed what you would want to use, instead of calculating slope.

But a better way to do it would be to avoid trigonometry altogether. Since you already know the overall delta-x and delta-y (t->destination.x - pos.x) and (t->destination.y - pos.y), respectively), you can use that vector as the direction in which you want to move. The only problem is that the vector's magnitude (length) is (usually) too long; it is the whole distance from your current position to the destination. There is a fix for this, however. If we normalize the vector, then we will have a vector of length 1.0, but in the same direction as the original. This vector will specify your final delta-x and delta-y, if you want to move a distance of 1.0 each frame. Even better, if you want to move more or less than that each frame, just multiply this new (dx, dy) pair by the appropriate length. Multiplying each value by 3.0 will mean that you move a distance of 3.0 each frame.

Here is how I would write the short section of code that updates the position:
//Get the original (dx, dy) vector.
dx = (t->destination.x - pos.x);
dy = (t->destination.y - pos.y);

//Calculate the length of this vector (distance
// from current position to destination) using
// the Pythagorean theorem.
float length = std::sqrt(dx * dx + dy * dy);

//Normalize the original (dx, dy) vector so that
// its new length will be 1.0.
dx /= length;
dy /= length;

//Alter each component of the (dx, dy) vector so
// that it is the new length we desire the object
// to move per frame.
dx *= distance_per_frame;
dy *= distance_per_frame;

//Alter the objects position.
pos.x += dx;
pos.y += dy;

One square root, two divides, and some miscellaneous other mathematical operations. Plus, we have the added advantage of being able to specify how much we move each frame. (This last ability would be easy to add to your atan/sin/cos version as well, by the way; it isn't unique to this particular method.) And of course, some of those lines above can be combined to shorten the code. I simply separated it out to make it clearer.

Share this post


Link to post
Share on other sites
Thats awsome guys.
Thanks a lot.

You were both right

The fix

void LifeForm::process_todo(float frametime)
{
if(todo.size())
{
float length, dx, dy;

AI::Action *a = todo.top();
AI::Travel *t;

switch(a->type())
{
case AI::Action::type_none: break;
case AI::Action::type_move_to_location:

t = dynamic_cast<AI::Travel*>(a);

if(t->destination.x == pos.x)
{
todo.pop();
delete t;
return;
}

dx = t->destination.x - pos.x;
dy = t->destination.y - pos.y;
length = std::sqrt(dx * dx + dy * dy);
dx /= length;
dy /= length;
pos.x += dx * (frametime * 50);
pos.y += dy * (frametime * 50);

/*
forward_angle = std::atan2(t->destination.y - pos.y, t->destination.x - pos.x);
dx = std::cos(forward_angle) * (frametime * 50);
dy = std::sin(forward_angle) * (frametime * 50);
pos.x += dx;
pos.y += dy;
*/

if(pos.x > t->destination.x - 2.0f && pos.x < t->destination.x + 2.0f
&& pos.y > t->destination.y - 2.0f && pos.y < t->destination.y + 2.0f)
{
todo.pop();
delete t;
}
break;
case AI::Action::type_attack_target: break;
case AI::Action::type_evade_target: break;
case AI::Action::type_find_resource: break;
default: break;
}
}
}




Ill get rid of the extra multipliactions when I get to it ^^
Cheers

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!