Sign in to follow this  
too_many_stars

Need help 2D line speed

Recommended Posts

too_many_stars    336

Hi guys,

 

I am stuck and not sure how to fix the problem. Working on a 2D platformer, where there's a bird floating and if the player comes close, the bird fires shots at the player. Here's the constructor.

BirdShot::BirdShot(int the_x,int the_y,int player_x,int player_y):Entity(the_x,the_y,0){

	image=load_surface("images/bird_shot.jpg");


	box.w=WIDTH;
	box.h=HEIGHT;

	damage=5;
	dx=1;

	x1=the_x;
	x2=player_x+15;
	y1=the_y;
	y2=player_y+15;


	if(the_x>player_x)
		dx=-dx;


	slope=(y2-y1)/(x2-x1);

}

and here's the move function...

void BirdShot::move(){

	box.y=slope*(box.x-x1)+y1;

	box.x+=dx;

}

Everything works as it should, except for one problem. When the player starts coming closer to the bird, the bird shot fires out faster and faster. For example, if the player is standing right underneath the bird, the shot comes out almost instantenously.

 

Is there a way to make the speed constant no matter where the player is compared to the bird?

 

Thanks,

 

Mike

Share this post


Link to post
Share on other sites
Matt-D    1574

x1=the_x; x2=player_x+15; y1=the_y; y2=player_y+15; if(the_x>player_x) dx=-dx; slope=(y2-y1)/(x2-x1);

 

Perhaps a silly question, but are the x1, x2, y1, y2 floating point numbers or ints (like the_x, the_y, player_x, player_y)?

If they're also ints, your "slope" may calculation may not be very precise (truncation) or a generally good idea (div-by-zero risk)...

 

// EDIT: and if they are floating point, then it's probably a good idea to make the_x, the_y, player_x, player_y floating point as well and write:

// float increment = 15.f; // or: double increment 15.0;

// x2 = player_x + increment; y1 = the_y; y2=player_y + increment;

// you generally shouldn't mix numbers at different precision (performance and expressing intent / code readability);

// see:

// "14.7 Don't mix float and double"

// "14.8 Conversions between floating point numbers and integers"

// in: http://www.agner.org/optimize/optimizing_cpp.pdf

Edited by Matt-D

Share this post


Link to post
Share on other sites
Pink Horror    2459

box.y=slope*(box.x-x1)+y1;

box.x+=dx;

 

Save a dx and dy in your shot class, instead of saving a slope. Make sure (dx * dx + dy * dy) is always the same no matter the direction. Your problem is that you do not keep the magnitude of your velocity vector constant. Your error is because you set a constant dx and let dy be whatever you happen to compute based on the slope.

Edited by Pink Horror

Share this post


Link to post
Share on other sites
too_many_stars    336

Thanks for the help pink horror, but before I tinker with the code I am confused about the dx*dx+dy*dy=C. Why do I have to make sure it's a constant? Where does dx*dx+dy*dy=C come from when dealing with straight lines, this appears to be something having to do with a circle.

 

Thanks,

 

Mike

Share this post


Link to post
Share on other sites
haegarr    7372

1. Seconding Pink Horror, don't use a slope but a direction vector for things like, well, directions. In your case the direction goes from the bird to the center of the player's avatar (if I interpret your code snippet correctly), so computing the difference vector from the bird to the avatar like so:

 

   Dx = player_x + 15 - the_x

   Dy = player_y + 15 - the_y

 
Notice that this works fine for each location of the bird relative to the avatar, i.e. it doesn't suffer from division by zero problems.
 
2. Now compute the length of the difference vector above. The length is computed by applying the so-called Euclidean norm to the vector:
 
   L = sqrt( Dx*Dx + Dy*Dy )
 
Obviously, the length is greater the farer bird and avatar are away on screen.

 

3. To yield in the "pure" direction, i.e. a vector regardless of the distance between bird and avatar, just make the length of the vector 1 without changing its direction. This is known as "normalize the vector":

 

   dx = Dx / L

   dy = Dy / L

 

Obviously, this is allowed only if L is not zero, what means that bird and avatar's center must not be at the same location!

 

4. Notice please what this means with respect to Pink Horror's post: Regardless where bird and avatar are (as long as not at the same location), the vector ever has the same length, so that computing its length gives a constant, 1 in this case

 

   sqrt( dx*dx + dy*dy ) = 1

 

and hence also the inner part dx*dy + dy*dy must be constant.

 

5. Multiply the direction vector with a speed s to yield in a velocity. The speed is a (positive) scalar value, while the velocity is a vector.

 

   vx = dx * s

   vy = dy * s

 

You find the speed again if you compute the length of the velocity vector:

 

   sqrt ( vx*vx + vy*vy ) = sqrt( dx*s*dx*s + dy*s*dy*s ) = sqrt( (dx*dx + dy*dy ) * s*s ) = sqrt( dx*dx + dy*dy ) * s = s

 

6. Now, for a constant speed impression (i.e. what the player sees), you need to know how much time has elapsed between this and the previous rendering. This time delta t is then multiplied with the velocity vector, giving you the distance of motion:

 

   box_x += vx * t

   box_y += vy * t

 

However, this is the tricky part. If you have a fixed frame rate, then t is a constant value. If your frame rate varies, then you need to fetch the system time and compute the difference to the previous fetch. There are several threads here in GDnet that handle this topic.

 

 

Hope that helps smile.png

Edited by haegarr

Share this post


Link to post
Share on other sites
too_many_stars    336

Wow haegarr, thanks a lot. That's what I call a reply. Unfortunatelly, I am at work right now and can't put this to the test, but as soon as I get home, I will implement your solution. I thought all that need to be done, was draw a straight line between two points, and propel the line forward, but I see it's not that easy.

 

Thanks again!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this