User Tag List

Results 1 to 4 of 4

Thread: "Helmstar-style" Tail Whip Code

  1. #1
    Wizrobe C-Dawg's Avatar
    Join Date
    Jan 2002
    Posts
    4,205
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    6,611
    Level
    24
    vBActivity - Bars
    Lv. Percent
    99.85%

    "Helmstar-style" Tail Whip Code

    Hey,

    I've coded up this script, which should mimic the behavior of Helmstar's tail from LttP. But it doesn't work. At runtime, the tail end stays where it was placed, one of the segments moves a little bit, and then nothing else happens. I can't tell whether this is a continuing bug where there are multiple FFCs on the screen, or a runtime error. Maybe someone else can take a look at it.

    I tried to avoid problems by putting all the code in ONE FFC. So FFC 7, the spikey end of the tail, has all the code; the rest of the FFCs run no script whatsoever.

    Code:
    import "std.zh"
    
    int distancesq(int x1, int x2, int y1, int y2)
    {
    	return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
    }
    
    // ===============================================
    // TAIL_WHIP : This ffc will move slowly back and forth horizontally
    // over four tiles, centered on it's original location.  After a set amount
    // of time, it will lash out towards link' s location at a high speed.  It
    // will pause breifly after reaching link's old location, and then return
    // to it's starting point to continue wagging.  Will use FFCs 1,2, 3, 4, and 5
    // as tail segments, and FFC 6 as the base of the tail.  Accordingly,
    // the Tail_Whip FFC should be FFC 7.
    // ===============================================
    
    ffc script tail_whip{
    
    	// CONSTANTS
    
    	int wait = 60;			// How long the tail waits 
    	float pi = 3.14;		// It's pi!
    	int delay = 10;			// How much warning Link gets before
    						// the tail strikes
    
    	// VARIABLES
    
    	int i = 0;			// Counter
    
    	int x_origin = 0;
    	int y_origin = 0;	
    
    	int x_target = 0;
    	int y_target = 0;
    
    	int x;				// working variables
    	int y;
    
    	int dist;
    
    	int state = 0;			// The state of the tail_whip.
    					//  0 = wagging right
    					//  1 = wagging left
    					//  2 = pulling back to strike
    					//  3 = striking at link
    					//  4 = pausing after striking
    					//  5 = returning to wagging mode
    
    
    	// RUN FUNCTION
    	void run(){
    
    		// POINTERS 
    
    		ffc segment_1 = Screen->LoadFFC(1);
    		ffc segment_2 = Screen->LoadFFC(2);
    		ffc segment_3 = Screen->LoadFFC(3);
    		ffc segment_4 = Screen->LoadFFC(4);
    		ffc segment_5 = Screen->LoadFFC(5);
    		ffc base = Screen->LoadFFC(6);
    
    		x_origin = this->X;	
    		y_origin = this->Y;
    
    		while (true){
    
    			// Wagging right
    
    			if (state ==0){
    				
    				if (this->X >= x_origin + 32){ state = 1; }
    				else{					
    					this->Vx = Sin( ( 2 * pi) / 32) * (this->X - x_origin);
    				}
    
    				if (i >= wait) { i = 0; state = 2;}
    				else{ i = i + 1;}
    			}
    
    			// Wagging left
    			
    			if (state ==1){
    				
    				if (this->X >= x_origin - 32){ state = 0; }
    				else{					
    					this->Vx = -Sin( ( 2 * pi) / 32) * (this->X - x_origin);
    				}
    
    				if (i >= wait) { i = 0; state = 2;}
    				else{ i = i + 1;}
    			}
    			
    			// Targeting and pulling back to strike
    
    			if (state ==2){
    				
    				x_target = Link->X;
    				y_target = Link->Y;
    				if ( i >= delay ){ i = 0; state = 3; }
    				else {
    					this -> Vx = 0;
    					this->Vy = -0.1;
    				}				
    			}
    
    			if (state == 3){
    
    				if ( (this->X >= x_target - 16) && (this->X <= x_target + 16) && 
    					(this->Y >= y_target - 16) && (this->Y <= y_target + 16) ){
    					
    					state = 4;
    				}
    				else{
    
    					dist = distancesq(x_target, this->X, y_target, this->Y);
    					x = this->X;
    					y = this->Y;
    					this->Vx = 2* ((x_target - x)*Abs((x_target - x))/dist);
    					this->Vy = 2 * ((y_target - y)*Abs((y_target - y))/dist);
    				}
    
    			}
    
    			if (state == 4){
    
    				if ( i >= delay/2 ) { i = 0; state = 5;}
    				else{ i = i++; }
    
    			}
    
    			if (state == 5){
    
    				if ( (this->X >= x_origin - 16) && (this->X <= x_origin + 16) && (this->Y >= y_origin - 16) && (this->Y <= y_origin + 16) ){
    					
    					state = 0;
    				}
    				else{
    
    					dist = distancesq(x_origin, this->X, y_origin, this->Y);
    					x = this->X;
    					y = this->Y;
    					this->Vx = ((x_origin - x)*Abs((x_origin - x))/dist);
    					this->Vy = ((x_origin - y)*Abs((x_origin - y))/dist);
    				}
    			}
    
    			// After moving the tail end, next the tail segments are moved into position.
    			// First, put the third segment at the midpoint.
    
    			segment_3->X = ( (this->X - base->X) / 2);
    			segment_3->Y= ( (this->Y - base->Y) / 2);
    
    			// Next, place the other segments by finding the midpoint between 3 and the
    			// base, and between 3 and the tail whip, and placing two segments
    			// around it.
    
    			x = ( (segment_3->X - base->X) / 2);
    			y = ( (segment_3->Y - base->Y) / 2);
    			
    			segment_1->X = ( ( x - base->X) / 2);
    			segment_1->Y = ( ( y - base->Y) / 2);
    
    			segment_2->X = ( ( x - segment_3->X) / 2);
    			segment_2->Y = ( ( y - segment_3->Y) / 2);
    
    			x = ( (segment_3->X - this->X) / 2);
    			y = ( (segment_3->Y - this->Y) / 2);
    
    			segment_4->X = ( ( x - segment_3->X) / 2);
    			segment_4->Y = ( ( y - segment_3->Y) / 2);
    
    			segment_5->X = ( ( x - this->X) / 2);
    			segment_5->Y = ( ( y - this->Y) / 2);
    		
    			Waitframe();
    
    		} // end of while loop
    	} // end of void run()
    } // end of ffc script

  2. #2
    Is this the end?
    ZC Developer
    Saffith's Avatar
    Join Date
    Jan 2001
    Age
    41
    Posts
    3,389
    Mentioned
    178 Post(s)
    Tagged
    6 Thread(s)
    vBActivity - Stats
    Points
    6,432
    Level
    24
    vBActivity - Bars
    Lv. Percent
    70.02%

    Re: "Helmstar-style" Tail Whip Code

    I'm afraid I don't completely understand how parts of it are supposed to work, but I fixed a couple of problems.

    Code:
    			if (state ==0){
    				
    				if (this->X >= x_origin + 32){ state = 1; }
    				else{					
    					this->Vx = Sin( ( 2 * pi) / 32) * (this->X - x_origin);
    				}
    
    				if (i >= wait) { i = 0; state = 2;}
    				else{ i = i + 1;}
    			}
    x_origin is initialized to this->X, so you're multplying that sine by 0.
    I think you may want to skip the velocity and modify the position directly, something like this->X = x_origin + 32 * Sin(i). That should also eliminate the need for separate left and right motion states. But that's the part of the script where I'm least certain of your intent, so that might not be quite what you want.

    If not...
    Code:
    				if (this->X >= x_origin - 32){ state = 0; }
    Make sure, at least, to change that to this->X <= x_origin - 32.

    Code:
    			if (state ==2){
    				
    				x_target = Link->X;
    				y_target = Link->Y;
    				if ( i >= delay ){ i = 0; state = 3; }
    				else {
    					this -> Vx = 0;
    					this->Vy = -0.1;
    				}				
    			}
    Don't forget to increment i.

    Code:
    			if (state == 3){
    
    				if ( (this->X >= x_target - 16) && (this->X <= x_target + 16) && 
    					(this->Y >= y_target - 16) && (this->Y <= y_target + 16) ){
    					
    					state = 4;
    				}
    				else{
    
    					dist = distancesq(x_target, this->X, y_target, this->Y);
    					x = this->X;
    					y = this->Y;
    					this->Vx = 2* ((x_target - x)*Abs((x_target - x))/dist);
    					this->Vy = 2 * ((y_target - y)*Abs((y_target - y))/dist);
    				}
    
    			}
    Do you mean to be using both target-16 and target+16? The target was set to Link's top-left corner, so the end area defined in the if statement is a 2x2 tile square with Link's original position in the bottom-right.
    Remember to set the velocity back to 0 after it hits.
    Also, though you don't really have to set i to 0, since it was already 0 and wasn't changed, it would just make a bit more sense to set it here than at the end of state 2.

    Code:
    			if (state == 4){
    
    				if ( i >= delay/2 ) { i = 0; state = 5;}
    				else{ i = i++; }
    
    			}
    Not sure if you don't know or if you just mistyped it, but i = i++ is redundant. It's just i++ instead.
    I doubt that would cause any problems, but it's not inconceivable.

    Code:
    			if (state == 5){
    
    				if ( (this->X >= x_origin - 16) && (this->X <= x_origin + 16) && (this->Y >= y_origin - 16) && (this->Y <= y_origin + 16) ){
    					
    					state = 0;
    				}
    				else{
    
    					dist = distancesq(x_origin, this->X, y_origin, this->Y);
    					x = this->X;
    					y = this->Y;
    					this->Vx = ((x_origin - x)*Abs((x_origin - x))/dist);
    					this->Vy = ((x_origin - y)*Abs((x_origin - y))/dist);
    				}
    			}
    Again, remember to reset i and the velocities to 0.



    Gah, it's after four in the morning. It doesn't seem to be right yet, but I can't keep working on it now. Hopefully I didn't screw anything up too badly, at least.

    Here's the script with all the above changes, whether you wanted them or not...
    Code:
    import "std.zh"
    
    int distancesq(int x1, int x2, int y1, int y2)
    {
    	return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
    }
    
    // ===============================================
    // TAIL_WHIP : This ffc will move slowly back and forth horizontally
    // over four tiles, centered on it's original location.  After a set amount
    // of time, it will lash out towards link' s location at a high speed.  It
    // will pause breifly after reaching link's old location, and then return
    // to it's starting point to continue wagging.  Will use FFCs 1,2, 3, 4, and 5
    // as tail segments, and FFC 6 as the base of the tail.  Accordingly,
    // the Tail_Whip FFC should be FFC 7.
    // ===============================================
    
    ffc script tail_whip{
    
    	// CONSTANTS
    
    	int wait = 60;			// How long the tail waits 
    	float pi = 3.14;		// It's pi!
    	int delay = 10;			// How much warning Link gets before
    						// the tail strikes
    
    	// VARIABLES
    
    	int i = 0;			// Counter
    
    	int x_origin = 0;
    	int y_origin = 0;	
    
    	int x_target = 0;
    	int y_target = 0;
    
    	int x;				// working variables
    	int y;
    
    	int dist;
    
    	int state = 0;			// The state of the tail_whip.
    					//  0 = wagging right
    					//  1 = wagging left
    					//  2 = pulling back to strike
    					//  3 = striking at link
    					//  4 = pausing after striking
    					//  5 = returning to wagging mode
    
    
    	// RUN FUNCTION
    	void run(){
    
    		// POINTERS 
    
    		ffc segment_1 = Screen->LoadFFC(1);
    		ffc segment_2 = Screen->LoadFFC(2);
    		ffc segment_3 = Screen->LoadFFC(3);
    		ffc segment_4 = Screen->LoadFFC(4);
    		ffc segment_5 = Screen->LoadFFC(5);
    		ffc base = Screen->LoadFFC(6);
    
    		x_origin = this->X;	
    		y_origin = this->Y;
    
    		while (true){
    
    			// Wagging
    
    			if (state ==0){
    
    				this->X = x_origin + 32 * Sin(i);
    
    				if (i >= wait) { i = 0; state = 2;}
    				else{ i++;}
    			}
    
    			// State 1 no longer used
    
    			// Targeting and pulling back to strike
    
    			if (state ==2){
    				
    				x_target = Link->X;
    				y_target = Link->Y;
    				if ( i >= delay ){ state = 3; }
    				else {
    					this -> Vx = 0;
    					this->Vy = -0.1;
    					i++;
    				}				
    			}
    
    			if (state == 3){
    
    				if ( (this->X >= x_target) && (this->X <= x_target + 16) && 
    					(this->Y >= y_target) && (this->Y <= y_target + 16) ){
    
    					this->Vx = 0;
    					this->Vy = 0;
    					state = 4;
    					i = 0;
    				}
    				else{
    
    					dist = distancesq(x_target, this->X, y_target, this->Y);
    					x = this->X;
    					y = this->Y;
    					this->Vx = 2* ((x_target - x)*Abs((x_target - x))/dist);
    					this->Vy = 2 * ((y_target - y)*Abs((y_target - y))/dist);
    				}
    
    			}
    
    			if (state == 4){
    
    				if ( i >= delay/2 ) { i = 0; state = 5;}
    				else{ i++; }
    
    			}
    
    			if (state == 5){
    
    				if ( (this->X >= x_origin - 16) && (this->X <= x_origin + 16) && (this->Y >= y_origin - 16) && (this->Y <= y_origin + 16) ){
    
    					this->Vx = 0;
    					this->Vy = 0;
    					i = 0;
    					state = 0;
    				}
    				else{
    
    					dist = distancesq(x_origin, this->X, y_origin, this->Y);
    					x = this->X;
    					y = this->Y;
    					this->Vx = ((x_origin - x)*Abs((x_origin - x))/dist);
    					this->Vy = ((x_origin - y)*Abs((x_origin - y))/dist);
    				}
    			}
    
    			// After moving the tail end, next the tail segments are moved into position.
    			// First, put the third segment at the midpoint.
    
    			segment_3->X = ( (this->X - base->X) / 2);
    			segment_3->Y= ( (this->Y - base->Y) / 2);
    
    			// Next, place the other segments by finding the midpoint between 3 and the
    			// base, and between 3 and the tail whip, and placing two segments
    			// around it.
    
    			x = ( (segment_3->X - base->X) / 2);
    			y = ( (segment_3->Y - base->Y) / 2);
    			
    			segment_1->X = ( ( x - base->X) / 2);
    			segment_1->Y = ( ( y - base->Y) / 2);
    
    			segment_2->X = ( ( x - segment_3->X) / 2);
    			segment_2->Y = ( ( y - segment_3->Y) / 2);
    
    			x = ( (segment_3->X - this->X) / 2);
    			y = ( (segment_3->Y - this->Y) / 2);
    
    			segment_4->X = ( ( x - segment_3->X) / 2);
    			segment_4->Y = ( ( y - segment_3->Y) / 2);
    
    			segment_5->X = ( ( x - this->X) / 2);
    			segment_5->Y = ( ( y - this->Y) / 2);
    		
    			Waitframe();
    
    		} // end of while loop
    	} // end of void run()
    } // end of ffc script


    One interesting thing I noticed... If I change the script thusly:
    Code:
    		ffc segment_1 = Screen->LoadFFC(2);
    		ffc segment_2 = Screen->LoadFFC(3);
    		ffc segment_3 = Screen->LoadFFC(4);
    		ffc segment_4 = Screen->LoadFFC(5);
    		ffc segment_5 = Screen->LoadFFC(6);
    		ffc base = Screen->LoadFFC(7);
    ... And attach it to FFC #1, it works quite differently, even aside from the pieces being shifted. It's closed to how it's meant to work, I think. Perhaps I'm mistaken, but I don't think it should make any difference. I believe it might indeed be a problem in the compiler or the game itself.

  3. #3
    Wizrobe C-Dawg's Avatar
    Join Date
    Jan 2002
    Posts
    4,205
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    6,611
    Level
    24
    vBActivity - Bars
    Lv. Percent
    99.85%

    Re: "Helmstar-style" Tail Whip Code

    Saffith - Thanks man, you're an asset to the community. I'll check out your edits when I get back from the gym today.

    And yea, I've noticed that ffc scripts tend to interact unpredictably, but changing the number of the FFC changes the behavior. Bizarre.

  4. #4
    Wizrobe C-Dawg's Avatar
    Join Date
    Jan 2002
    Posts
    4,205
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    6,611
    Level
    24
    vBActivity - Bars
    Lv. Percent
    99.85%

    Re: "Helmstar-style" Tail Whip Code

    Quote Originally Posted by Saffith View Post
    That should also eliminate the need for separate left and right motion states. But that's the part of the script where I'm least certain of your intent, so that might not be quite what you want.
    The behavior I'm looking for is a smoothly wagging behavior, where the tail moves left, then right, and accellerates and decellerates during it's wag. As opposed to sharply moving left and right like it would using ATT_CHG FFCs. Your script's behavior is right on the money, even if I don't understand the mathematics behind it. What I was trying to do was use the equation for a sin wave, with amplitude 1 and period of 64, to calculate a smoothly increasing and decreasing velocity. Guess it didn't work like I'd planned.


    Quote Originally Posted by Saffith View Post
    Do you mean to be using both target-16 and target+16? The target was set to Link's top-left corner, so the end area defined in the if statement is a 2x2 tile square with Link's original position in the bottom-right.
    I made the target range wide because I was concerned about the possibility of the moving FFC "overshooting" the target and never returning to the wagging behavior. Of course, the issue with such a wide range is that it won't actually hit Link if he just stands still.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
About us
Armageddon Games is a game development group founded in 1997. We are extremely passionate about our work and our inspirations are mostly drawn from games of the 8-bit and 16-bit era.
Social