C-Dawg
01-07-2007, 11:18 PM
Here's a slightly more complicated movement pattern. In practice, the enemy seems to jump around in a quasi-random way. What it's really doing is following an ideal (x,y) in orbit around the player, dodging away from player attacks, and swiping in for an attack periodically.
Shout goes out to Jman who debugged this one. I changed his resulting script a little bit, based on the following observation:
You need to guard against your custom boss movement scripts going off the edge of the screen. If they go off to far, the FFC will dissapear. It turns out to be easier to keep things on the screen if you only modify velocity, not actual position. Where I can't do that here, I've tried to guard against going off the screen anyway.
NOTE: This code is not written with this_ffc, but with this->. So wherever you stick it, it will currently affect the first ffc.
// ========================================
// orbit_diver - This FFC script makes the FFC behave as an
// orbit diver. At rest, the FFC will orbit the player at a certain
// distance. If the player attacks, the FFC distance of the
// orbit will double for a short period of time, then it will
// immediately counterattck. At regular
// intervals, the FFC will dive towards the player and then return
// to it's circular path.
//
// D0 - Speed of the orbit diver's normal behavior. Must be
// between 0 and about 6.28 for proper behavior.
// D1 - Speed of the orbit diver's attack
// D2 - Radius of the orbit diver's normal behavior
// D3 - Delay between orbit diver's diving attack. Make it longer
// than 30, because that's how long the attack will last.
// D4 - The time the orbit diver spends in a larger orbit after an attack
// =======================================
ffc script orbit_diver{
void run(int orbit_speed, int diving_speed, int radius, int delay, int dodge_time) {
int state = 0; // 0 = At rest, not dodging
// 1 = Dodging away from player attack
// 2 = Diving towards player
int i = 0; // Used to keep track of the
int orbit_x; // orbit of the ffc.
int orbit_y;
int orig_radius = radius;
int delay_counter = delay; // Countdown to attack
int dodge_counter = dodge_time; // Countdown to dodging
int dive_counter = 30; // Duration of attack
bool ontrack = true;
// We need to scale
while(true) {
// First, calculate the idea orbit of this ffc and put it into orbit_x, orbit_y
orbit_x = ((Sin(i)*radius) + Link->X+8)-(this->EffectWidth/2);
orbit_y = ((Cos(i)*radius) + Link->Y+8)-(this->EffectWidth/2);
// Next, increase the value of i for the next loop.
i = i + orbit_speed;
// ============= State 0 Behavior ==============
if (state == 0) {
// The FFC should get close to the ideal orbit (kept track of
// by orbit_x, orbit_y) if it is not already.
if(!ontrack)
{
if ( ((this->X - orbit_x) > diving_speed) || ((this->X - orbit_x) < -diving_speed) ||
((this->Y - orbit_y) > diving_speed) || ((this->Y - orbit_y) < -diving_speed) )
{
if (this->X >= orbit_x)
{
this->Vx = -diving_speed;
}
else
{
this->Vx = diving_speed;
}
if (this->Y >= orbit_y)
{
this->Vy = -diving_speed;
}
else
{
this->Vy = diving_speed;
}
}
else
{
ontrack=true;
}
}
// If the FFC is already close to the ideal orbit, just follow it around.
else{
if(orbit_x > 248) { this->X = 248; }
else{
if(orbit_x < 0) { this->X = 0; }
else {this->X = orbit_x;}
}
if(orbit_y > 168) { this->Y = 168; }
else{
if(orbit_y < 0) { this->Y = 0; }
else {this->Y = orbit_y;}
}
}
// Countdown to diving attack
if (delay_counter <= 0){
state = 2;
dive_counter = 30;
delay_counter = delay;
}
else{
delay_counter--;
}
// Detect whether the player is attacking or using an item
if ( (Link->InputB) || (Link->InputA)){
state = 1;
}
} // end of state 0
// ============= State 1 Behavior ==============
if ( state == 1 ) {
// Increase the radius incrementally until it reaches double the radius;
if(radius >= orig_radius*2) { radius = orig_radius*2; }
else { radius += 1; }
// The FFC should get close to the ideal orbit (kept track of
// by orbit_x2, orbit_y2) if it is not already.
if(!ontrack)
{
if ( ((this->X - orbit_x) > orbit_speed) || ((this->X - orbit_x) < -orbit_speed) ||
((this->Y - orbit_y) > orbit_speed) || ((this->Y - orbit_y) < -orbit_speed) ){
if (this->X >= orbit_x) { this->X -= diving_speed; }
else { this->X += diving_speed; }
if (this->Y >= orbit_y) { this->Y -= diving_speed; }
else { this->Y += diving_speed; }
}
else
{
ontrack=true;
}
}
// If the FFC is already close to the ideal orbit, just follow it around.
else{
this->X = orbit_x;
this->Y = orbit_y;
}
// Countdown to diving attack
if (delay_counter <= 0){
state = 2;
dive_counter = 30;
delay_counter = delay;
}
else{
delay_counter--;
}
// Countdown to counterattack
if (dodge_counter <= 0){
state = 2;
dive_counter = 30;
dodge_counter = dodge_time;
}
else{
dodge_counter--;
}
} // end of state 1
// ============= State 2 Behavior ==============
if (state == 2) {
if (this->X <= Link->X){
this->Vx = this->Vx + (diving_speed/10);
if ( this->Vx > diving_speed ) { this->Vx = diving_speed; }
}
else{
this->Vx = this->Vx - (diving_speed/10);
if ( this->Vx < -diving_speed ) { this->Vx = -diving_speed; }
}
if (this->Y <= Link->Y){
this->Vy = this->Vy + (diving_speed/10);
if ( this->Vy > diving_speed ) { this->Vy = diving_speed; }
}
else{
this->Vy = this->Vy - (diving_speed/10);
if ( this->Vy < -diving_speed ) { this->Vy = -diving_speed; }
}
// Duration of attack
if (dive_counter <= 0){
state = 0;
this->Vx = 0;
this->Vy = 0;
ontrack = false;
delay_counter = delay;
dodge_counter = dodge_time;
radius = orig_radius;
}
else{
dive_counter--;
}
} //end of state 2
// Edgeguard function
if(this->X > 248) { this->Vx = -1; }
if(this->X < 0) { this->Vx = 1; }
if(this->Y > 168) { this->Vy = -1; }
if(this->Y < 0) { this->Vy = 1; }
Waitframe();
} // end of while loop
} // end of void run
} // end of ffc script
Shout goes out to Jman who debugged this one. I changed his resulting script a little bit, based on the following observation:
You need to guard against your custom boss movement scripts going off the edge of the screen. If they go off to far, the FFC will dissapear. It turns out to be easier to keep things on the screen if you only modify velocity, not actual position. Where I can't do that here, I've tried to guard against going off the screen anyway.
NOTE: This code is not written with this_ffc, but with this->. So wherever you stick it, it will currently affect the first ffc.
// ========================================
// orbit_diver - This FFC script makes the FFC behave as an
// orbit diver. At rest, the FFC will orbit the player at a certain
// distance. If the player attacks, the FFC distance of the
// orbit will double for a short period of time, then it will
// immediately counterattck. At regular
// intervals, the FFC will dive towards the player and then return
// to it's circular path.
//
// D0 - Speed of the orbit diver's normal behavior. Must be
// between 0 and about 6.28 for proper behavior.
// D1 - Speed of the orbit diver's attack
// D2 - Radius of the orbit diver's normal behavior
// D3 - Delay between orbit diver's diving attack. Make it longer
// than 30, because that's how long the attack will last.
// D4 - The time the orbit diver spends in a larger orbit after an attack
// =======================================
ffc script orbit_diver{
void run(int orbit_speed, int diving_speed, int radius, int delay, int dodge_time) {
int state = 0; // 0 = At rest, not dodging
// 1 = Dodging away from player attack
// 2 = Diving towards player
int i = 0; // Used to keep track of the
int orbit_x; // orbit of the ffc.
int orbit_y;
int orig_radius = radius;
int delay_counter = delay; // Countdown to attack
int dodge_counter = dodge_time; // Countdown to dodging
int dive_counter = 30; // Duration of attack
bool ontrack = true;
// We need to scale
while(true) {
// First, calculate the idea orbit of this ffc and put it into orbit_x, orbit_y
orbit_x = ((Sin(i)*radius) + Link->X+8)-(this->EffectWidth/2);
orbit_y = ((Cos(i)*radius) + Link->Y+8)-(this->EffectWidth/2);
// Next, increase the value of i for the next loop.
i = i + orbit_speed;
// ============= State 0 Behavior ==============
if (state == 0) {
// The FFC should get close to the ideal orbit (kept track of
// by orbit_x, orbit_y) if it is not already.
if(!ontrack)
{
if ( ((this->X - orbit_x) > diving_speed) || ((this->X - orbit_x) < -diving_speed) ||
((this->Y - orbit_y) > diving_speed) || ((this->Y - orbit_y) < -diving_speed) )
{
if (this->X >= orbit_x)
{
this->Vx = -diving_speed;
}
else
{
this->Vx = diving_speed;
}
if (this->Y >= orbit_y)
{
this->Vy = -diving_speed;
}
else
{
this->Vy = diving_speed;
}
}
else
{
ontrack=true;
}
}
// If the FFC is already close to the ideal orbit, just follow it around.
else{
if(orbit_x > 248) { this->X = 248; }
else{
if(orbit_x < 0) { this->X = 0; }
else {this->X = orbit_x;}
}
if(orbit_y > 168) { this->Y = 168; }
else{
if(orbit_y < 0) { this->Y = 0; }
else {this->Y = orbit_y;}
}
}
// Countdown to diving attack
if (delay_counter <= 0){
state = 2;
dive_counter = 30;
delay_counter = delay;
}
else{
delay_counter--;
}
// Detect whether the player is attacking or using an item
if ( (Link->InputB) || (Link->InputA)){
state = 1;
}
} // end of state 0
// ============= State 1 Behavior ==============
if ( state == 1 ) {
// Increase the radius incrementally until it reaches double the radius;
if(radius >= orig_radius*2) { radius = orig_radius*2; }
else { radius += 1; }
// The FFC should get close to the ideal orbit (kept track of
// by orbit_x2, orbit_y2) if it is not already.
if(!ontrack)
{
if ( ((this->X - orbit_x) > orbit_speed) || ((this->X - orbit_x) < -orbit_speed) ||
((this->Y - orbit_y) > orbit_speed) || ((this->Y - orbit_y) < -orbit_speed) ){
if (this->X >= orbit_x) { this->X -= diving_speed; }
else { this->X += diving_speed; }
if (this->Y >= orbit_y) { this->Y -= diving_speed; }
else { this->Y += diving_speed; }
}
else
{
ontrack=true;
}
}
// If the FFC is already close to the ideal orbit, just follow it around.
else{
this->X = orbit_x;
this->Y = orbit_y;
}
// Countdown to diving attack
if (delay_counter <= 0){
state = 2;
dive_counter = 30;
delay_counter = delay;
}
else{
delay_counter--;
}
// Countdown to counterattack
if (dodge_counter <= 0){
state = 2;
dive_counter = 30;
dodge_counter = dodge_time;
}
else{
dodge_counter--;
}
} // end of state 1
// ============= State 2 Behavior ==============
if (state == 2) {
if (this->X <= Link->X){
this->Vx = this->Vx + (diving_speed/10);
if ( this->Vx > diving_speed ) { this->Vx = diving_speed; }
}
else{
this->Vx = this->Vx - (diving_speed/10);
if ( this->Vx < -diving_speed ) { this->Vx = -diving_speed; }
}
if (this->Y <= Link->Y){
this->Vy = this->Vy + (diving_speed/10);
if ( this->Vy > diving_speed ) { this->Vy = diving_speed; }
}
else{
this->Vy = this->Vy - (diving_speed/10);
if ( this->Vy < -diving_speed ) { this->Vy = -diving_speed; }
}
// Duration of attack
if (dive_counter <= 0){
state = 0;
this->Vx = 0;
this->Vy = 0;
ontrack = false;
delay_counter = delay;
dodge_counter = dodge_time;
radius = orig_radius;
}
else{
dive_counter--;
}
} //end of state 2
// Edgeguard function
if(this->X > 248) { this->Vx = -1; }
if(this->X < 0) { this->Vx = 1; }
if(this->Y > 168) { this->Vy = -1; }
if(this->Y < 0) { this->Vy = 1; }
Waitframe();
} // end of while loop
} // end of void run
} // end of ffc script