Sign in to follow this  

[SOLVED] Properly moving units in 2D along vectors...

This topic is 3840 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

Alright, this should be really simple, but somehow I'm not quite sure how to do this the best way, so I figured I'd ask here. I hope this is the appropriate place for this thread. I am writing a simple 2d RTS-game at the moment à la Command & Conquer 1, StarCraft etc., to the problem: I want my units to move properly on the game-field, I don't care about collisions, tiles etc. at the moment, I just want the units to go straight from their original position to the destination. Simple enough, one would think, I figured I'd construct a vector from unit to destination-point every frame, calculate its length, normalize it with that, then multiply the unit-speed in and move it. Well, that kinda works, but my units always move in diagonal-lines. When I click somewhere on the map and let the unit move, it will for example first go up some time to the point where it takes a complete diagonal left-up to reach the destination. But I want it to go there straight from the beginning. Here's the code from the function (called every frame in cunit::update ( )):
float vector_x, vector_y;
float vector_length;

// construct vector from unit to destination
vector_x = ( float ) ( destination_x - x );
vector_y = ( float ) ( destination_y - y );

// calculate vector length
vector_length = ( float ) ::sqrt ( ( ( vector_x * vector_x ) + ( vector_y * vector_y ) ) );

// normalize vector
vector_x /= vector_length;
vector_y /= vector_length;

// add speed-component (TODO: make different types of units faster/slower here)
vector_x *= 2.0f;
vector_y *= 2.0f;

// make sure unit moves at all
if ( vector_x > 0.0f && vector_x < 1.0f )
	vector_x = 1.0f;

else if ( vector_x < 0.0f && vector_x > -1.0f )
	vector_x = -1.0f;
			
if ( vector_y > 0.0f && vector_y < 1.0f )
	vector_y = 1.0f;

else if ( vector_y < 0.0f && vector_y > -1.0f )
	vector_y = -1.0f;

// now move unit
x += ( int ) vector_x;
y += ( int ) vector_y;



I hope I managed to express my question in a way everybody can understand. Any help is well appreciated. [Edited by - d h k on July 14, 2007 10:55:38 AM]

Share this post


Link to post
Share on other sites
First of all, I have to point out that you're in serious need of a vector class! With a decent math library, this:

float vector_x, vector_y;
float vector_length;

// construct vector from unit to destination
vector_x = ( float ) ( destination_x - x );
vector_y = ( float ) ( destination_y - y );

// calculate vector length
vector_length = ( float ) ::sqrt ( ( ( vector_x * vector_x ) + ( vector_y * vector_y ) ) );

// normalize vector
vector_x /= vector_length;
vector_y /= vector_length;

// add speed-component (TODO: make different types of units faster/slower here)
vector_x *= 2.0f;
vector_y *= 2.0f;

// now move unit
x += ( int ) vector_x;
y += ( int ) vector_y;

Will reduce to something like this:

position += normalize(destination - position) * 2.f;


Much more concise, and much less prone to error.

As for the particular problem you mention, I'm not sure what's causing it, but the clamping and integer casts look a bit suspicious. Are you using ints for proper sprite placement? If so, I'd recommend performing all computations using floats, and then converting to ints at the very end of the process (and then only for display purposes).

Share this post


Link to post
Share on other sites
Hehe, I do have my own vector class written (look here: here), but I only really need vectors for this one calculation, so I quickly wrote those lines up without worrying about a new class, might change that later.

I'll change my unit to have floating-point position and only change that when drawing.

EDIT: Now my unit-position is float and the function looks like this:


float vector_x, vector_y;
float vector_length;

// construct vector from unit to destination
vector_x = ( float ) ( destination_x ) - x;
vector_y = ( float ) ( destination_y ) - y;

// calculate vector length
vector_length = ( float ) ::sqrt ( ( ( vector_x * vector_x ) + ( vector_y * vector_y ) ) );

// normalize vector
vector_x /= vector_length;
vector_y /= vector_length;

// add speed-component (TODO: make different types of units faster/slower here)
vector_x *= 2.0f;
vector_y *= 2.0f;

// make sure unit moves at all
if ( vector_x > 0.0f && vector_x < 1.0f )
vector_x = 1.0f;

else if ( vector_x < 0.0f && vector_x > -1.0f )
vector_x = -1.0f;

if ( vector_y > 0.0f && vector_y < 1.0f )
vector_y = 1.0f;

else if ( vector_y < 0.0f && vector_y > -1.0f )
vector_y = -1.0f;

// now move unit
x += vector_x;
y += vector_y;








...but it still isn't moving properly.

Thanks for your help so far, though...

EDIT 2: Now it works, I figured it out. Was simple enough... :) Thanks again.

[Edited by - d h k on July 14, 2007 10:23:18 AM]

Share this post


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