#### Archived

This topic is now archived and is closed to further replies.

# Walk in one straight line, damn you!

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

## Recommended Posts

I'm trying to make a LucasArts-type point-and-click adventure game, but I'm having trouble getting the character to walk right. I click diagonally from the character's current position, and he'll start walking at an angle, but never enough of one to get straight to his destination, so he eventually ends up walking straight up/down or right/left to cover the rest of the distance. I checked Sam and Max just now, and Sam doesn't have any such silly problems, he goes walks straight to where you click, so this should be possible. So, here's my messy code involved, abridged. I'm using OpenGL in a 640x480 window with an orthographic projection that sets the upper-left corner as 0,0 and lower-right as 640,-480. Everything is done to this coordinate system.
// walking info struct
struct baffWalkingInfo
{
bool bIsWalking; // whether we're walking
int tickstarted; // when walking started in milliseconds
baffPosition destination; // struct containing integers x and y
int lastxmove; // last time character moved in the x direction, in milliseconds
int lastymove; // last time character moved in the y direction, in milliseconds
baffTPP tixperpix; /* struct containing doubles x and y which store the number of
milliseconds to wait between movements of 1 pixel in the
corresponding direction */
};

// stores the number of milliseconds since the start of the game, updated every cycle
int baffTicks;

/* general number of milliseconds between movements of one pixel, will change from area
to area (currently should make character walk 100 pixels per second, but actual speed
in game is much much slower) */
double areaspeed = 10.0

// struct containing x and y position of main character, pretend it's initialized to something
baffPosition frenchyPosition;

/* this is called when the player clicks somewhere, and the place the player clicked
is sent through x and y */
void baffSetWalkInfo(short int x, short int y)
{
baffWalkingInfo.bIsWalking = true;
baffWalkingInfo.tickstarted = baffTicks;
baffWalkingInfo.destination.x = x;
baffWalkingInfo.destination.y = y;
baffWalkingInfo.lastxmove = baffTicks;
baffWalkingInfo.lastymove = baffTicks;

// x and y distance of destination from current position, in pixels
double deltaX = double(baffWalkingInfo.destination.x) - double(frenchyPosition.x);
double deltaY = double(baffWalkingInfo.destination.y) - double(frenchyPosition.y);

// absolute value of distances
double absdeltaX = sqrt(deltaX*deltaX);
double absdeltaY = sqrt(deltaY*deltaY);

if (absdeltaX < 20.0 && deltaY > -1.0 && deltaY < 20.0)
{
// too small a change to waste any more time on
baffWalkingInfo.bIsWalking = false;
return;
}

// length of straight line between location and destination, hypothetically in pixels
double deltaUber = sqrt(deltaX*deltaX + deltaY*deltaY);

// total milliseconds the traveling should take
double ticks = areaspeed * deltaUber;

// speed of character in **pixels per millisecond** along direct diagonal line
double speed = deltaUber / ticks;

// angle of movement
double angle;
if (deltaX != 0.0) // Dividing by zero is bad, mmkay?
angle = atan(deltaY/deltaX);
else
{
baffWalkingInfo.tixperpix.x = 0.0;
baffWalkingInfo.tixperpix.y = areaspeed;
return;
}

double cosine = cos(angle);
double sine = sin(angle);

// get absolute values sine and cosine
cosine = sqrt(cosine*cosine);
sine = sqrt(sine*sine);

// find x and y components of speed and invert them to milliseconds per pixel
baffWalkingInfo.tixperpix.x = 1 / (speed * cosine));
baffWalkingInfo.tixperpix.y = 1 / (speed * sine));
}

/* updates walking info and Frenchy's position, called every cycle while
baffWalkingInfo.bIsWalking is true */
void baffUpdateWalkInfo()
{
if (frenchyPosition.x == baffWalkingInfo.destination.x &&
frenchyPosition.y == baffWalkingInfo.destination.y)
{
// Frenchy's reached his destination, no more walking
baffWalkingInfo.bIsWalking = false;
return;
}

// if enough time has passed since we last moved in the x direction, move again
if (baffTicks - baffWalkingInfo.lastxmove > baffWalkingInfo.tixperpix.x
&& baffWalkingInfo.tixperpix.x > 0.0)
{
// if destination is to the right, move right
if (frenchyPosition.x < baffWalkingInfo.destination.x)
frenchyPosition.x++;
// if destination is to the left, move left
else if (frenchyPosition.x > baffWalkingInfo.destination.x)
frenchyPosition.x--;
// update the last time we moved in x to now
baffWalkingInfo.lastxmove = baffTicks;
}

// if enough time has passed since we last moved in the y direction, move again
if (baffTicks - baffWalkingInfo.lastymove > baffWalkingInfo.tixperpix.y
&& baffWalkingInfo.tixperpix.y > 0.0)
{
// if destination is above, move up
if (frenchyPosition.y < baffWalkingInfo.destination.y)
frenchyPosition.y++;
// if destination is below, move down
else if (frenchyPosition.y > baffWalkingInfo.destination.y)
frenchyPosition.y--;
// update the last time we moved in y to now
baffWalkingInfo.lastymove = baffTicks;
}
}

Then there's the function that draws the main character at the position that this code has set. So what's the problem? Why won't my character move in a single straight line in a timely manner, and how can I fix it? It seems like this should be easy. [edited by - PsiRadish on November 30, 2003 4:40:02 PM]

##### Share on other sites
I just briefly scanned your code so perhaps i''m overlooking something, but i think i know where your problem lies:

first off, everything you are doing is in screen coord. Screen coord. should NEVER be negative, only positive. So have a 0x0 by 640 x -480 is a big NONO :-D. change your coor so it is at least positive.

secondly, you can''t simply say playerpos.x++ or something similar. You have to use vectors. a vector just represents the x,y distance from your cursor position to your player. so:

double vectorx = cursorx - playerx;

so now you have a vector. If you want to animate him walking for 30 frames to reach that point, you simply do:

vectorx /= 30;

playerx += vectorx;

what you seem to be doing is simply adding or subtracting 1 every frame during your walk sequence, which means he will walk in a 45 degree angle, not perhaps a 25 degree, etc etc.

hope that helps

##### Share on other sites
I had the screen coordinates set up all positive before, and I didn''t like it. I find the current setup much more intuitive. Also, x and y movement are calculated completely seperately, so it''s not stuck in a 1/1 slope (45 degree angle)

Your algorithm would probably work, but so would mine, except for the problem that was in it, which I have now found and fixed. The problem was it would inc/decrement 1 and only 1 if the elapsed time was greater than the corresponding tixperpix, no matter how much greater it was, and then the last move time would be set to the current time, whiping out any time unaccounted for. So if the elapsed time between cycles was big enough that the character should move, say, 5 pixels at once, they would still move just 1, and this was WRONG. It has now been fixed with while loops and stuff, and now I am GIDDY, like a SCHOOL GIRL. XD

##### Share on other sites
fixed with loops?

x++;

and you changed it to

for(int i=0;i<5;i++) { x++; }

x+=5;

?

##### Share on other sites
More like...

/* Psuedo-code */// how it was, brokenif (now - time last moved > desired time between movements){	move 1;	time last moved = now;}// how it is now, fixedwhile (now - time last moved > desired time between movements){	move 1;	time last moved += desired time between movements;}

1. 1
2. 2
3. 3
Rutin
22
4. 4
5. 5

• 13
• 19
• 14
• 9
• 9
• ### Forum Statistics

• Total Topics
632933
• Total Posts
3009300
• ### Who's Online (See full list)

There are no registered users currently online

×