PDA

View Full Version : walkTo() void?



lucas92
12-30-2008, 08:22 PM
Might also post at AG.

Alright, what I need is a walkTo(int x1,int x2,int y1, int y2, int speed) void that would move something to x1 to x2 and to y1 to y2... I don't have any idea of how to do it, and I need it so much... I don't know much about trigonometry and such thing, so that's why I would need that one void... Help?

And no loop... It's for use for scripts and such things.

EDIT-Also, speed is how much to move the thing in pixels each time the void is executed.

pkmnfrk
12-30-2008, 09:17 PM
Might also post at AG.

Alright, what I need is a walkTo(int x1,int x2,int y1, int y2, int speed) void that would move something to x1 to x2 and to y1 to y2... I don't have any idea of how to do it, and I need it so much... I don't know much about trigonometry and such thing, so that's why I would need that one void... Help?

And no loop... It's for use for scripts and such things.

EDIT-Also, speed is how much to move the thing in pixels each time the void is executed.

ARGH! The word you're looking for is "function". "void" is a return type. It means that a function does not return anything!

*pant pant pant*

As for your request. So, you want a function that moves... uh, a thing speed pixels in the direction of (x,y)?

Well, an accurate implementation of the function would require an ATan function, which we don't have for some reason. Instead, I propose this naive substitute until we get such a function:


void moveTowards(ffc this, int x, int y, int speed) {
if(this->X < x) {
this->X += speed;
} else if(this->X > x) {
this->X -= speed;
}

if(this->Y < y) {
this->Y += speed;
} else if(this->Y > y) {
this->Y -= speed;
}

}

lucas92
12-30-2008, 09:27 PM
Oh that's great. :)

Thank you. It was simpler than I thought. :)

lucas92
12-30-2008, 10:00 PM
Wait a minute... It's not so much perfect that function... I mean, it would only go in a direction with a 45 degrees angle... And it isn't what I want... :(

I guess I will use that one for now...

pkmnfrk
12-30-2008, 10:01 PM
Well, I just circumvented the lack of ATan, and so you can use this supplemental script (http://armageddongames.net/forums/showthread.php?t=104621), and take its findAngle function to write this script:


import "std.zh"
import "advmath.zh"

void moveTowards(ffc this, int x, int y, int speed) {
int angle = findAngle(this->X, this->Y, x, y);
float dx = Sin(angle) * speed;
float dy = Sin(angle) * speed;

this->X += dx;
this->Y += dx;
}

lucas92
12-30-2008, 10:07 PM
Wow. Just wow.

No doubt I couldn't have done it.
That's just great. Thanks. :)

pkmnfrk
12-30-2008, 10:08 PM
DISCLAIMER: I have not tested any of this code, and only know that it compiles. However, if there's any problem with it, please let me know, and I will actually test it.

lucas92
12-31-2008, 10:27 PM
void moveTowards(ffc this, int x, int y, int speed) {
int angle = findAngle(this->X, this->Y, x, y);
float dx = Cos(angle) * speed;
float dy = Sin(angle) * speed;
if(this->X<x)this->X += dx;
if(this->X>x)this->X -= dx;
if(this->Y<y)this->Y += dy;
if(this->Y>y)this->Y -= dy;
}

Even with the mistakes I fixed, it seems to always follow a 45 degrees line then go up with a 0 degree line...

I've made an example quest... Also try to avoid the armos, it will kill you in one hit... Anyway, I needed that function when it climbs the ceiling.

http://www.mediafire.com/download.php?ytmzfjeemmc


Also there are some mistakes in your advmath.zh file. Missed semicolons and such things.

Gleeok
12-31-2008, 10:42 PM
That's because pkmnfrk is modifying x,y coordinates based off floats instead of storing them in a seperate variable (such as Vx, Vy), I think. Try changing it to this->V and see if that works, or, use this instead:



void Homing(int speed, int ffc_num, int target_x, int target_y){
ffc F=Screen->LoadFFC(ffc_num);
int dx = target_x - F->X;
int dy = target_x - F->Y;
float norm = Sqrt(dx*dx+dy*dy);
if(norm > 0){
F->Vx = dx/norm*speed;
F->Vy = dy/norm*speed;
}
}



edit: Had a spontanious idea to make it better. (untested):



void Homing(int speed, ffc f, int target_x, int target_y){
ffc F=f;
int dx = target_x - F->X;
int dy = target_x - F->Y;
float norm = Sqrt(dx*dx+dy*dy);
if(norm > 0){
F->Vx = dx/norm*speed;
F->Vy = dy/norm*speed;
}
}

pkmnfrk
12-31-2008, 11:01 PM
Well, my code should work if you change the second Sin to a Cos (brain fart).

But, I would recommend against using the Vx and Vy variables for this purpose. Reason? If for some reason you stop calling moveTo(), the Vx and Vy variables won't magically revert to zero, and the ffc will continue to move.

Gleeok
12-31-2008, 11:12 PM
Heh, I didn't see that either. :eyebrow:

I've had less than adequate results in the past with ZC trying to modify an objects screen position with decimal places though. (I stopped doing it altogether actually) Just thought I'd point that out.

pkmnfrk
12-31-2008, 11:18 PM
Well, I don't see any particular reason why it wouldn't work (assuming the engine doesn't truncate the positions), but if you're concerned about it:


import "std.zh"
import "advmath.zh"

void moveTowards(ffc this, int x, int y, int speed) {
int angle = findAngle(this->X, this->Y, x, y);
float dx = Sin(angle) * speed;
float dy = Cos(angle) * speed;

this->X += Floor(dx);
this->Y += Floor(dx);
}

lucas92
01-01-2009, 12:17 AM
Cool I'll try that out... Btw, happy new year! :)

Joe123
01-01-2009, 07:00 AM
I've had less than adequate results in the past with ZC trying to modify an objects screen position with decimal places though. (I stopped doing it altogether actually) Just thought I'd point that out.


while(true){
Link->X += move(this->Vx,counterx);
Link->Y += move(this->Vy,countery);
counterx = (counterx+1)%(100/factors100(Abs(this->Vx)));
countery = (countery+1)%(100/factors100(Abs(this->Vy)));
}
int move(int s,int c){
int as = Abs(s);
int ret;
if(as < 1){
if(c < as*100/factors100(as)) ret = 1;
else ret = 0;
}else if(as < 2){
if(c < (as-1)*100/factors100(as-1)) ret = 2;
else ret = 1;
}
if(s < 0) ret = -ret;
return ret;
}
int factors100(int s){
for(int i=50;i>0;i--) if((s*100)%i == 0) return i;
}

Takes a speed, and moves an object that doesn't have a Vx/Vy value at that speed. Currently works (well, it works mostly. Some speeds are a little out) for speeds from 0 to 2 (not inclusive).

I'm sure it's not the best way, but I'm quite proud of it. Took me a while to think up.

Obviously you can't actually move an object by half a pixel, that just doesn't make sense.

lucas92
01-01-2009, 02:14 PM
Well, I don't see any particular reason why it wouldn't work (assuming the engine doesn't truncate the positions), but if you're concerned about it:


import "std.zh"
import "advmath.zh"

void moveTowards(ffc this, int x, int y, int speed) {
int angle = findAngle(this->X, this->Y, x, y);
float dx = Sin(angle) * speed;
float dy = Cos(angle) * speed;

this->X += Floor(dx);
this->Y += Floor(dx);
}

That still doesn't work... It goes an another time with a 45 degrees line... :(
Also goes always right when it has to go left...

pkmnfrk
01-01-2009, 02:49 PM
That still doesn't work... It goes an another time with a 45 degrees line... :(
Also goes always right when it has to go left...

Hang on, maybe I'll just, you know, test it.

EDIT: For cripes sake. I figured out why I was stupid.


import "advmath.zh"

void moveTowards(ffc this, int x, int y, int speed) {
int angle = findAngle(this->X, this->Y, x, y);
float dx = RadianSin(angle) * speed;
float dy = RadianCos(angle) * speed;

this->X += dx;
this->Y += dy;
}

ffc script followLink {
void run() {
while(true) {
moveTowards(this, Link->X, Link->Y, 1);
Waitframe();
}
}
}

I fixed a typo, and remembered that findAngle uses Radians, not Degrees. So, I switched Sin and Cos to RadianSin and RadianCos, and it works. It works without rounding off the decimal place, too.

And, since I tested it, I can now say that I guarantee this will work, or your money back.

lucas92
01-02-2009, 09:50 AM
Still doesn't work... When it has to go up, it goes down, and also it goes left when it has to go right(when it has to go up)... And I did tested your ffc script... :(

CaRmAgE
01-02-2009, 01:23 PM
Hold on a minute...

Shouldn't the code be...


import "advmath.zh"

void moveTowards(ffc this, int x, int y, int speed) {
int angle = findAngle(this->X, this->Y, x, y);
float dx = RadianCos(angle) * speed;
float dy = RadianSin(angle) * speed;

this->X += dx;
this->Y += dy;
}

ffc script followLink {
void run() {
while(true) {
moveTowards(this, Link->X, Link->Y, 1);
Waitframe();
}
}
}

Changes I made are in bold.

Joe123
01-02-2009, 01:33 PM
It doesn't matter which way round you use them.

pkmnfrk
01-02-2009, 02:12 PM
Well, it does matter, but either way, I tested my script, and it worked. So... I dunno what to say. Make sure you're passing a positive speed... that's the only way I can think of to make it go backwards...

Joe123
01-02-2009, 02:29 PM
?

Plotting y=sint,x=cost is exactly the same as plotting y=cost,x=sint

pkmnfrk
01-02-2009, 02:39 PM
That doesn't make any sense. For that to be true, COS(t) would have to equal SIN(t), which it does not.

http://www.themathpage.com/atrig/graphs-trig.htm#sine%20graph
http://www.themathpage.com/atrig/graphs-trig.htm#cosine

It's the same wave, but offset by 1/2 Pi

Joe123
01-02-2009, 03:37 PM
I know the difference between sine and cosine.

It does, however, make sense.
When plotting a circle parametrically, it doesn't matter whether you use sine or cosine on the x or y, provided you don't use them for both (otherwise you'll get a diagonal line, which makes sense as y = x).

Have a look:

ffc script circle{
void run(){
int x = 80; int y = 80;
int r = 32;
while(true){
for(int i;i<360;i++){
int x2 = y+r*Cos(i);
int y2 = x+r*Sin(i);
Screen->PutPixel(6,x2,y2,Rand(10),0,0,0,128);
}
Waitframe();
}
}
}

Will produce the exact same result as:

ffc script circle{
void run(){
int x = 80; int y = 80;
int r = 32;
while(true){
for(int i;i<360;i++){
int x2 = y+r*Sin(i);
int y2 = x+r*Cos(i);
Screen->PutPixel(6,x2,y2,Rand(10),0,0,0,128);
}
Waitframe();
}
}
}

pkmnfrk
01-02-2009, 05:54 PM
Maybe for plotting a circle, but I believe in experimental data.

The script:

import "advmath.zh"

void moveTowards1(ffc this, int x, int y, int speed) {
int angle = findAngle(this->X, this->Y, x, y);
float dx = RadianSin(angle) * speed;
float dy = RadianCos(angle) * speed;

this->X += dx;
this->Y += dy;
}

void moveTowards2(ffc this, int x, int y, int speed) {
int angle = findAngle(this->X, this->Y, x, y);
float dx = RadianCos(angle) * speed;
float dy = RadianSin(angle) * speed;

this->X += dx;
this->Y += dy;
}

ffc script followLink {
void run(int method) {
while(true) {
if(method==1) {
moveTowards1(this, Link->X, Link->Y, 1);
} else if(method==2) {
moveTowards2(this, Link->X, Link->Y, 1);
}
Waitframe();
}
}
}

The results:

On YouTube (http://www.youtube.com/watch?v=jVSzlbeJc1c)

FFC #1 calls "moveTowards1", while #2 calls "moveTowards2". Only #1 behaves properly.

Joe123
01-02-2009, 07:35 PM
Oh, you're making triangles.
Should've read the thread a bit more carefully before I posted really.

It does work for circles though, trust me =P

Gleeok
01-02-2009, 09:15 PM
Hahaha.. "ALL YOUR BASE ARE BELONG TO US!!!" I forgot about that shit. :D

Yeah, you're both right, and on a related note, It took me way too long to figure out this one:


x += cos(rad)*speed;
y += sin(rad)*speed;

That's the way it goes though, you feel like a dumbass, then a genius, then a dumbass again when you realize that you just figured out something everyone uses already that you probably could've googled in the first place.



I'll take a look at that script a little later joe, thanks...although watching pkmnfrk's video, there doesn't seem to be a problem with that...(maybe it was a bug in an older build?) So FFC's coordinates are stored in floats I guess.

pkmnfrk
01-02-2009, 09:53 PM
Just be careful about checking absolute position if you use my script, since FFCs won't necessarily be pixel-aligned any more.

So, if you need to check an exact position, do something like:


if(Floor(theffc->X) == 120 && Floor(theffc->Y) == 80) //do something

Mega Link
01-02-2009, 11:44 PM
If I use this on Link (assuming I can); will Link walk, or will he "float"?

Pielord
01-03-2009, 12:50 AM
Ya, I think you can. Just change "this->" into "Link->". However, he won't animate, he'll just float like you said. And you will probably need to stop the player from pressing any of the direction buttons.

Mega Link
01-03-2009, 01:23 AM
Ok. I know how to get link to walk.

If Link walks over a tile/side warp, will he go where the warp says to go?

pkmnfrk
01-03-2009, 01:36 AM
That's a good question. I don't know. Probably, but I can't say for sure.

Either way, for completeness, here's the moveLinkTowards function:


void moveLinkTowards(int x, int y, int speed) {
int angle = findAngle(Link->X, Link->Y, x, y);
float dx = RadianSin(angle) * speed;
float dy = RadianCos(angle) * speed;

Link->X += dx;
Link->Y += dy;
}

Note that the first parameter is missing; there's only one Link (currently).

EDIT: For other variations on this script, ask this guy (http://www.natural20s.com/archive/072.htm)

Joe123
01-03-2009, 07:56 AM
Hahaha, that comic was pretty funny =P

Mega Link
01-03-2009, 07:42 PM
It's not working! :(


Link->Dir = DIR_UP;
Link->Action = LA_WALKING;
moveLinkTowards(168,120,5);
Link->Action = LA_FROZEN;
Screen->Message(25);
Link->Dir = DIR_DOWN;
Link->Action = LA_WALKING;
moveLinkTowards(168,168,5);
Link->Action = LA_NONE;


It plays the message but doesn't make Link walk.

Pielord
01-03-2009, 08:20 PM
It's in a while loop right? I don't know much about scripting but i believe this just changes link position once then plays the message the changes links position one again. I think the code need to be:


bool a;
while(true) {
if(a == false) {
Link->Dir = DIR_UP;
Link->Action = LA_WALKING;
moveLinkTowards(168,120,5);
}
if(Link->X == 168 && Link->Y == 120) {
Link->Action = LA_FROZEN;
Screen->Message(25);
Link->Dir = DIR_DOWN;
a = true;
}
if(a) {
Link->Action = LA_WALKING;
moveLinkTowards(168,168,5);
Link->Action = LA_NONE;
}
}

There's probably a better way to do this(if this even works; I haven't tested it) Also, I think you need the quest rule "Messages freeze all action" for this to work.

Mega Link
01-03-2009, 08:59 PM
Worse. ZC froze completely except for the music. I wouldn't even let me close it without using task manager.

pkmnfrk
01-03-2009, 10:21 PM
Mega Link: /slap

First thing: This moves Link one step toward the intended target. You have to call it more than once, until Link gets there.


Pielord: /slap


Just be careful about checking absolute position if you use my script, since FFCs won't necessarily be pixel-aligned any more.

So, if you need to check an exact position, do something like:


if(Floor(theffc->X) == 120 && Floor(theffc->Y) == 80) //do something

What you mean to do is something like:


Link->Dir = DIR_UP;
Link->Action = LA_WALKING; //I don't think this does what you think it does...

//I also made Link move at 4 pixels/tick, since that will actually get him where he's going
while(Abs(Link->X - 168) > 4 || Abs(Link->Y - 120) > 4) {
moveLinkTowards(168,120,4);
Waitframe();
}

Link->Action = LA_FROZEN;
Screen->Message(25);


Link->Dir = DIR_DOWN;
Link->Action = LA_WALKING;

while(Abs(Link->X - 168) > 4 || Abs(Link->Y - 168) > 4) {
moveLinkTowards(168,168,4);
Waitframe();
}

Link->Action = LA_NONE;

To both of you: /slap

To make Link move up and down along the Y axis, you don't need advanced trigonometry! This will suffice:


Link->Dir = DIR_UP;
Link->Action = LA_WALKING;

if(Link->Y > 120) {
while(Link->Y > 120) {
Link->Y -= 4; //in reality, you probably want him to walk slower.
Waitframe();
}
} else {
while(Link->Y < 120) {
Link->Y += 4; //in reality, you probably want him to walk slower.
Waitframe();
}
}

Link->Action = LA_FROZEN;
Screen->Message(25);


Link->Dir = DIR_DOWN;
Link->Action = LA_WALKING;

while(Link->Y < 168) {
Link->Y += 4; //in reality, you probably want him to walk slower.
Waitframe();
}

Link->Action = LA_NONE;

Mega Link
01-03-2009, 10:34 PM
Link is walking too fast, and he faces down before the message is done playing.

Btw, yes the side warp did get triggered. ;)

pkmnfrk
01-03-2009, 10:51 PM
Try changing the loops to look like this:


while(Link->Y < 168) {
Link->Y += 1;
Waitframes(4); //note the 's'
}

Mega Link
01-03-2009, 11:22 PM
I tried that but Link walked too slow, so I changed the 1 to a 2, and it works. To fix the problem where he faces down before the message is done, I added a Waitframe(); after Screen->Message(25);.


Link->Dir = DIR_UP;
Link->Action = LA_WALKING;

if(Link->Y > 120) {
while(Link->Y > 120) {
Link->Y -= 2; //in reality, you probably want him to walk slower.
Waitframes(4);
}
} else {
while(Link->Y < 120) {
Link->Y += 2; //in reality, you probably want him to walk slower.
Waitframes(4);
}
}

Link->Action = LA_FROZEN;
Screen->Message(25);
Waitframe();

Link->Dir = DIR_DOWN;
Link->Action = LA_WALKING;

while(Link->Y < 168) {
Link->Y += 2; //in reality, you probably want him to walk slower.
Waitframes(4);
}

Link->Action = LA_NONE;

Pielord
01-04-2009, 12:04 AM
Ya like I said, I don't know to much about ZScript. I should probably learn more before I try to help people. Anyways, glad to hear you got it working Mega Link.