Public Group

# Need help 2D line speed

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

## Recommended Posts

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){

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 on other sites

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"

Edited by Matt-D

##### Share on other sites

Hi,

Yeah, the x1, x2, y1, y2 are floats

##### Share on other sites

I tried casting everything neccessary to float but it's not working. Does anyone have any other ideas?

##### Share on other sites

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 on other sites

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 on other sites

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

Edited by haegarr

##### Share on other sites

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!

• 18
• 18
• 11
• 21
• 16