AI for Circular Motion

Need help with using DizzyAGE then look here
User avatar
Noggin the Nog
Hard Boiled Egg
Posts: 412
Joined: Sun Jul 01, 2012 12:04 am

AI for Circular Motion

Post by Noggin the Nog » Thu Apr 25, 2013 7:19 pm

EDIT - THE CODE IN THE FIRST TWO POSTS DOESN'T DISPLAY PROPERLY. THE CORRECT CODE IS IN POST #4

Hi, I wanted to share with you all a little thing I've been working on. This is a bit of AI for moving an object in a circle.

It works much like AIUpdateTrain. You use one waypoint, which goes at the centre of the circle. O_WAYPOINTSPEED is the same as usual, but I've used O_WAYPOINTFLIP to set the direction of motion (0 = clockwise, 1 = anti) - try setting an Action Object to switch it!

I've also added another variable O_WAYPOINTRADIUS, which you'll have to add a #def for. It does what it says on the tin. You'll probably want to set it to the same as the seperation between the starting positions on the map, but the AI will correct it anyway. Again, try changing it with an Action object.

Code: Select all

func AIUpdateCircle( idx )
{
	if(idx==-1) return;
	if(ObjGet(idx,O_DISABLE)) return;
	if(!IsUpdate(ObjGet(idx,O_DELAY))) return;
	if(ObjGet(idx,O_STATUS)!=1) return;
	id2 = ObjGet(idx,O_TARGET);
	if(id2==0) return;
	idx2 = ObjFind(id2);
	if(idx2==-1) return;

	speed = ObjGet(idx2,O_WAYPOINTSPEED);
	clock = ObjGet(idx2,O_WAYPOINTFLIP);

	radius = ObjGet(idx2,O_WAYPOINTRADIUS);
	rad = (float)radius;
	x2 = ObjGet(idx2,O_ X) ;
	y2 = ObjGet(idx2,O_Y);
	
	x = ObjGet(idx,O_ X) ;
	y = ObjGet(idx,O_Y);
	
	count = 0;
	label:
	if(speed - count==0)
	{
		ObjSet(idx,O_X,x);
		ObjSet(idx,O_Y,y);
		return;
	}
	else
	{
	if(clock==0){	if(y>y2){ xt = x - 1;}
			if(y<=y2){ xt = x + 1;}
			if(x>=x2){ yt = y + 1;}
			if(x<x2){ yt = y - 1;} }
	if(clock==1){	if(y>=y2){ xt = x + 1;}
			if(y<y2){ xt = x - 1;}
			if(x>x2){ yt = y - 1;}
			if(x<=x2){ yt = y + 1;} }
	
	dis1 = (float)(((xt - x2)*(xt - x2)) + ((y - y2)*(y -y2)));
	rad1 = gs_sqrt(dis1);
	dis2 = (float)(((x - x2)*(x - x2)) + ((yt - y2)*(yt -y2)));
	rad2 = gs_sqrt(dis2);
	
	if(gs_abs(rad1 - rad) < gs_abs(rad2 - rad))
	{x = xt;}
	if(gs_abs(rad1 - rad) > gs_abs(rad2 - rad))
	{y = yt;}
	count++;
	goto label;
	}
}	
So, please give it a go and let me know what you think. :)

User avatar
Noggin the Nog
Hard Boiled Egg
Posts: 412
Joined: Sun Jul 01, 2012 12:04 am

Post by Noggin the Nog » Fri Jul 12, 2013 6:10 pm

I've made a small improvement. :) The function still works the same way.

Code: Select all

func AIUpdateCircle2( idx )
{
	if(idx==-1) return;
	if(ObjGet(idx,O_DISABLE)) return;
	if(!IsUpdate(ObjGet(idx,O_DELAY))) return;
	if(ObjGet(idx,O_STATUS)!=1) return;
	id2 = ObjGet(idx,O_TARGET);
	if(id2==0) return;
	idx2 = ObjFind(id2);
	if(idx2==-1) return;

	speed = ObjGet(idx2,O_WAYPOINTSPEED);
	clock = ObjGet(idx2,O_WAYPOINTFLIP);
	radius = ObjGet(idx2,O_WAYPOINTRADIUS);
	rad = (float)radius;
	x2 = ObjGet(idx2,O_ X) ;
	y2 = ObjGet(idx2,O_Y);
	
	x = ObjGet(idx,O_ X) ;
	y = ObjGet(idx,O_Y);
	
	count = 0; xcount = 0; ycount = 0; extra = 0;
	label:
	if(speed + extra - count==0)
	{
		ObjSet(idx,O_X,x);
		ObjSet(idx,O_Y,y);
		return;
	}
	else
	{
	if(clock==0){	if(y>y2){ xt = x - 1;}
			if(y<=y2){ xt = x + 1;}
			if(x>=x2){ yt = y + 1;}
			if(x<x2){ yt = y - 1;} }
	if(clock==1){	if(y>=y2){ xt = x + 1;}
			if(y<y2){ xt = x - 1;}
			if(x>x2){ yt = y - 1;}
			if(x<=x2){ yt = y + 1;} }
	
	dis1 = (float)(((xt - x2)*(xt - x2)) + ((y - y2)*(y -y2)));
	rad1 = gs_sqrt(dis1);
	dis2 = (float)(((x - x2)*(x - x2)) + ((yt - y2)*(yt -y2)));
	rad2 = gs_sqrt(dis2);
	
	if(gs_abs(rad1 - rad) < gs_abs(rad2 - rad))
	{x = xt; if(xcount + ycount <= count) xcount++;}
	if(gs_abs(rad1 - rad) > gs_abs(rad2 - rad))
	{y = yt; if(xcount + ycount <= count) ycount++;}
	count++;
	
	if(xcount==0||ycount==0) {num = 0; if(num >= extra) extra = 0;}
	else
	{ if(xcount==ycount) {num = (int)((float)speed*0.4); if(num >= extra) extra = num;}
	  else {num = (int)((float)speed*0.3); if(num >= extra) extra = num;}
	}
	goto label;
	}
}	

AndyG
Hard Boiled Egg
Posts: 208
Joined: Thu May 22, 2014 1:54 pm
Location: UK
Contact:

Post by AndyG » Thu Jul 23, 2015 8:13 pm

Sorry I didn't comment on this sooner; I wanted to wait until I'd actually tried it out, and I was too obsessed with my own ideas for my first game! I just tried it out, and it shows a "parse error" around these two lines (I always forget if it's the one before!):

Code: Select all

if(x>=x2){ yt = y + 1;}
if(x=y2){ xt = x + 1;}
I can't work it out, as (to my untrained eye) they look fine. I did of course set the define. Do you think it's because DizzyAGE has been updated?

User avatar
Noggin the Nog
Hard Boiled Egg
Posts: 412
Joined: Sun Jul 01, 2012 12:04 am

Post by Noggin the Nog » Fri Jul 24, 2015 2:48 pm

Hi Andy,

I've had a good look at this and it turns out the forum's not displaying the code properly. The problem seems to be the "less than" (eg. x < y) and "greater than" (eg. x > y) symbols. The forum reads them as HTML brackets or something, and doesn't display anything between the two symbols. Anyway, to get round it I've put the problem <'s in brackets and coloured them red. When you copy the text into notepad, delete the brackets and the code should work fine.

Code: Select all

func AIUpdateCircle2( idx )
{
	if(idx==-1) return;
	if(ObjGet(idx,O_DISABLE)) return;
	if(!IsUpdate(ObjGet(idx,O_DELAY))) return;
	if(ObjGet(idx,O_STATUS)!=1) return;
	id2 = ObjGet(idx,O_TARGET);
	if(id2==0) return;
	idx2 = ObjFind(id2);
	if(idx2==-1) return;

	speed = ObjGet(idx2,O_WAYPOINTSPEED);
	clock = ObjGet(idx2,O_WAYPOINTFLIP);
	radius = ObjGet(idx2,O_WAYPOINTRADIUS);
	rad = (float)radius;
	x2 = ObjGet(idx2,O_ X) ;
	y2 = ObjGet(idx2,O_Y);
	
	x = ObjGet(idx,O_ X) ;
	y = ObjGet(idx,O_Y);
	
	count = 0; xcount = 0; ycount = 0; extra = 0;
	label:
	if(speed + extra - count==0)
	{
		ObjSet(idx,O_X,x);
		ObjSet(idx,O_Y,y);
		return;
	}
	else
	{
		if(clock==0)
		{
			if(y>y2){ xt = x - 1;}
			if(y<=y2){ xt = x + 1;}
			if(x>=x2){ yt = y + 1;}
			if(x[color="#FF0000"](<)[/color]x2){ yt = y - 1;}
		}
		if(clock==1)
		{	
			if(y>=y2){ xt = x + 1;}
			if(y[color="#FF0000"](<)[/color]y2){ xt = x - 1;}
			if(x>x2){ yt = y - 1;}
			if(x<=x2){ yt = y + 1;}
		}
	
		dis1 = (float)(((xt - x2)*(xt - x2)) + ((y - y2)*(y -y2)));
		rad1 = gs_sqrt(dis1);
		dis2 = (float)(((x - x2)*(x - x2)) + ((yt - y2)*(yt -y2)));
		rad2 = gs_sqrt(dis2);
	
		if(gs_abs(rad1 - rad) < gs_abs(rad2 - rad))
		{x = xt; if(xcount + ycount <= count) xcount++;}
		if(gs_abs(rad1 - rad) > gs_abs(rad2 - rad))
		{y = yt; if(xcount + ycount <= count) ycount++;}
		count++;
		
		if(xcount==0||ycount==0) {num = 0; if(num >= extra) extra = 0;}
		else
		{ if(xcount==ycount) {num = (int)((float)speed*0.4); if(num >= extra) extra = num;}
		  else {num = (int)((float)speed*0.3); if(num >= extra) extra = num;}
		}
		goto label;
	}
}

AndyG
Hard Boiled Egg
Posts: 208
Joined: Thu May 22, 2014 1:54 pm
Location: UK
Contact:

Post by AndyG » Fri Jul 24, 2015 4:02 pm

Excellent! That works perfectly :) . The reason I started looking is that I wanted to make a figure-8 movement, similar to the swordfish in Fantastic Dizzy. For some reason I find AI really hard and I can't get even the most basic movements to work. So with your complicated circular movement I was able to make a figure-8 with 2 waypoints (radius 30, speed 4) like this:

Code: Select all

func UpdateRoom_3_0()	
{
idx = ObjFind(3003);   // baddie
AIUpdateCircle2(idx);
ObjSet(idx,O_COUNTER,ObjGet(idx,O_COUNTER)+1);  // counter increment
if(ObjGet(idx,O_COUNTER)==150)
{
ObjSet(idx,O_TARGET,3005);  // new target
ObjSet(ObjFind(3005),O_WAYPOINTFLIP,1);  // anti-clockwise
}

if(ObjGet(idx,O_COUNTER)==300)
{
ObjSet(idx,O_TARGET,3004);
ObjSet(ObjFind(3005),O_WAYPOINTFLIP,0); // clockwise
ObjSet(idx,O_COUNTER,0);
}
}
Thanks a lot :)

User avatar
Noggin the Nog
Hard Boiled Egg
Posts: 412
Joined: Sun Jul 01, 2012 12:04 am

Post by Noggin the Nog » Fri Jul 24, 2015 6:15 pm

Glad to help mate. I'm a little disappointed you're the first person to use it actually. :(

The figure of eight thing's a really smart idea - the counter must have taken a fair bit of trial and error tho?

AndyG
Hard Boiled Egg
Posts: 208
Joined: Thu May 22, 2014 1:54 pm
Location: UK
Contact:

Post by AndyG » Fri Jul 24, 2015 9:16 pm

To be honest, I got lucky and got it exactly right on my second try! (My first try was 80.) I also plan to use circular motion for moving platforms

Grandad
Hard Boiled Egg
Posts: 1362
Joined: Sat Aug 08, 2009 10:47 am
Location: Balham - gateway to the south

Post by Grandad » Sat Jul 25, 2015 9:17 am

I've always used status checks to move objects around in a specific way - getting the O_X and O_Y coordinates and using the status check to move them a bit at a time either sideways, up or diagonally. Is this method any smoother?

AndyG
Hard Boiled Egg
Posts: 208
Joined: Thu May 22, 2014 1:54 pm
Location: UK
Contact:

Post by AndyG » Sat Jul 25, 2015 11:05 am

Have you been able to move something in a circle? I may have to pick your brains and some point because I'm OK working with the code here (which I don't really understand!), but certain much more simple movements I'm having trouble with.

Grandad
Hard Boiled Egg
Posts: 1362
Joined: Sat Aug 08, 2009 10:47 am
Location: Balham - gateway to the south

Post by Grandad » Sat Jul 25, 2015 3:09 pm

Personally I've never bothered with waypoints when using AI, it's a lot easier just to use targets as user #32 and #33 will work on the 'object' moving (regardless of what it says in the AI.gs file) and I always use the 'object' tile as the target tiles so that I can see exactly where the object if moving to.

What exactly is it that you want to move in a circle (or figure of eight) and if it's in one room how much of the room do you want it to occupy ...and is it a killing/hurting object or something like a block to jump onto? The reason I ask is that I've just finished my latest 'blockbuster' and may have some spare time to knock up a small template using the different methods to make it work.

In the meantime maybe I'll visit youtube as I can't remember a swordfish in fantastic dizzy.

Post Reply