Post by BeasTie on Dec 16, 2012 21:58:20 GMT -5
True Targetted Jumpattacks by Bloodbane
Like promised, this is the explanation for true targetted jumpattack. Let's start from definition,
About True Targetted Jumpattacks
Let's review 3D attack definition 1st: 3D attack is attack which can hit heroes standing in different z coordinate. True Targetted Jumpattack is another example of 3D attack. In this attack, enemy jumps and lands right at targetted hero's location.
Examples:
Tyrog (Cadillacs & Dinosaurs) & Guardroid (Punisher)
Aside from that, there's targetted tossing who works the same way except that it's projectile who is 'jumpattacking' hero instead.
Examples: Morgan & Hogg (Cadillacs & Dinosaurs), Doc & Jennifer (Battle Circuit) & Dr Crayborn (Undercover Cops)
These 2 attacks use same target function called 'targetL'.
I'm not going to explain how to set offset, attackbox, range and rangez including how to use animationscript. Learn those yourselves if you haven't.
Targetting
Like said before, these attacks are targetted which means we need to target 1st before performing them. To find the target we use a function named 'findtarget()'.
'findtarget(self)' means find another entity whom this 'self' entity is hostile to. Since this is for enemies, the target is player. If there are 2 or more player, the closest one will be chosen. If there are none, 'target' will be empty.
What are we going to do with the targetted player assuming it's not empty? See next.
Moving Philosophy
After target is attained, the next thing to do is to move the enemy toward player. How does enemy move? there are 2 ways to do it, one is with 'move' command and 2nd is with 'velocity setting'. The 1st method is not preferred cause it's cumbersome. It requires multiple frames for moving and using script to replicate 'move' brings problem with walls and platforms. It's solvable though but it's best to avoid this method and use 2nd method instead.
2nd method moves entity smoothly with velocity setting and it moves just like using 'jumpframe'. It also require less frame since one frame is enough. If more frames are used, it's usually for graphical effect.
Since the enemy is jumping, we use 'tossentity' like this:
2 is y velocity, 4 is x velocity while 2 is z velocity. With 3 velocities set at same time, entity will jump diagonally downward right.
Before going further, there's important subject to discuss related to jumping.
Jumping Philosophy
Unlike previous 3D attacks, true targetted jumpattack requires the enemy to land exactly at hero instead of continue moving. In other word, land exactly at certain spot.
Also since this is jumping, enemy will stop right after landing. This means to land exactly at certain spot, timing and position must be exact.
In order to get precise timing, we need to know how much required time for complete jump. A complete jump is comprised of rising and falling. From my measurements, both process take same time regardless of y velocity. Still, how much required time is affected by y velocity. From my measurements, it's:
Time = Required time for complete jump in centiseconds
Vy = y velocity
This formula isn't affected if entity is moving in x and/or z or not.
Speaking of moving in x and/or z, another fact to know is that entity can move in x and z while jumping and neither x , z or y velocity affect each other.
After we know that useful fact, we can continue previous subject.
Moving Philosophy (continued)
Since x, z and y velocity don't affect each other, we could define value for them seperately. However, we need to ensure precise moving which is by the time enemy lands, enemy has moved to hero's location. In order to do this, we need to get distance between hero and enemy first.
Note the 'if' above. We need to check if player is available or not cause we can't get any info from it if it's empty.
After we attain Disx and Disz, we could calculate proper speed. Let's name x velocity with Vx and z velocity with Vz.
The idea here is enemy moves with Vx in x axis to move Disx pixels while at same time enemy moves with Vz in z axis to move Disz pixels. Do you get it? by moving like that, enemy will eventually reach player's position cause the former moves Disx pixels in x axis and Disz in z axis. Both distance must be covered at same time otherwise enemy will miss targetted hero.
So in math formula we could write them like this:
t = required time for enemy to reach player
Unlike previous 3D attack, this time 't' is important so we don't remove it like before. Since we need enemy to reach hero at end of jump, time for complete jump is same with time to reach player so we can combine this formula with previous formula into:
Getting Velocity
Three velocities in formula above is unknown while both Disx and Disz is known. This means we can either set Vx and Vz freely (which then defines Vy) or set Vy (which then defines Vx and Vz). The former has worse consequences than the latter so let's choose the latter.
So the above formula becomes:
With these, both values of Vx and Vz are attained.
Code Implementation
Now that we have the formula, last thing to do is to implement it with code. However we should incorporate some factors 1st:
1. What if there are no players to target at all?
The answer is simple, let's set 0 for Vx and Vz which means enemy is not moving at all while jumping.
2. Other enemy using same function ended having same target or even worse altering target. This usually happen if there are 2 same enemies attacking with same attack at almost same time.
I don't get why this could happen but this issue can be fixed by using local value with unique identifier like this:
...
3. Although velocity is adjusted, enemy won't turn back if player is standing behind while targetting.
To solve this, simply flip facing direction to where player is like this:
Last, this target function is meant to support other function. That means the function who perform the actual move is not this function. This function only calculate proper velocity values. To transfer these values, we use local variables. And the whole function becomes like this:
The input of this function is Vy which is the y velocity or jumping velocity.
The output of this function is local variable named '"x"+self' which contains x velocity and '"z"+self' which contains z velocity.
Velocity Usage
Need aspirin? just kidding
Are you sure? OK let's get on.
There are 2 functions which can use the outputs above i.e:
1. leap(float Vely) for true targetted jump attack
2. toss2(void Bomb, float dx, float dy, float dz, float Vy) for targetted tossing
Each functions affect enemy differently.
Since they use outputs from 'targetL' function, they must be declared AFTER that function.
True Targetted Jumpattack
In Cadillacs & Dinosaurs, Tyrog will jump and land ontop of hero if it's standing far from hero. That is one example of this type of targetted attack. The function here toss enemy with certain speed toward player. Aside from moving in x and z, it also toss enemy upwards. It doesn't matter what actually they are doing, they could be jumpcrushing, jumpkicking or elbow strike.
Here's the function:
Yes, this function is the same function as in previous 3D attack. Read my 1st post for info about this function.
Targetted Tossing
In Cadillacs & Dinosaurs, Hogg and Morgan can toss grenades which landed right at hero's position. That's an example of this type of attack. This function toss a bomb then toss it with targetted speed toward player. It doesn't matter how the bomb looks like, it could be grenade, bomb, rock or energy bolt.
Here's the function:
The function differs alot with previous one cause this function toss bomb and alters its speed. 'Projectile' function tosses entity named Shot which is inputted. This projectile function also requires starting position for tossed bomb which is procurred by attaining x, z and a coordinate above. Position adjustment is inputted to allow scripter to give position shift to the tossed bomb.
vShot gets the tossed bomb. After that, Vx and Vz is attained like before. Due to fact that tossed bombs move twice faster than normal entities for same speed, we divide both velocity with 2. Then toss the bomb with tossentity to move it toward target.
However since projectile's flying speed is based on its speed instead of velocity, speed change is required. Since speed isn't relative, we need to get enemy's facing direction 1st before changing the speed with Vx. Negative speed(-Vx) for moving left or positive speed(Vx) for right.
Review
Like previous 3D attack, seperating targetting function and action function also enables intelligence control. That's important aspect to remember.
Still, there are 2 more subjects to explain more related to this.
1. Don't you wonder why I said "The former has worse consequences than the latter so let's choose the latter" above?
Let's review the formula again:
Former refers to "set Vx and Vz freely (which then defines Vy)". Let's change the formula for this.
There are 2 consequence of this formula:
a. since Vy is same in both formula, we can't set both Vx or Vz freely. One can only be set freely while the other will be defined.
b. Vy is jumping velocity which also affects how high enemy jumps and how long enemy would take to make complete jump. Since Disx and Disz could be in any value (depending on distance), Vy could be very small or very large. That also means, enemy could jump very short or very high. If we try to synch this jumping speed with animation, it would cumbersome cause we can't tell how long it would take to finish jumping. Sure, there is landframe but the animation skip isn't always good to see IMO. This is what I meant with worse consequences.
2. So does that mean latter method has no consequence at all? no not really.
Let's review the formula again:
Disx and Disz could be in any value (depending on distance) which means Vx and Vz could be very small or very large. These aren't big deal since both only moves enemy in x and z axis.
The real consequence is this:
Since Vy is defined by modder, Time (required time for complete jump) will be defined too. This mean we can tell how long it would take for enemy to finish jumping or to hit hero from start of jumpattack. This is good news cause we can set good animation for the jumpattack.
Another thing to remember is since Time is defined, enemy will always require same time to hit hero no matter where hero is IOW whether hero is close or very far, enemy can hit them both with same time.
Other Usage
As you can see, the targetting philosophy above is used to find proper speed to hit target. Actually, same philosophy can be used for other purpose which is jumping to certain location. Unlike jumpattack, this kind of jumping only makes entity jumps to certain location without targetting at all. It doesn't matter what they do while jumping or after landing.
'TargetL' function above can be modified for that purpose like this:
There's y velocity input like 'targetL' but there are also Tx and Tz for leaping destination. Tx is relative to leftmost edge of level so it might require adjustments.
The assumptions are the same except that there's no targetting here. And just like 'targetL', this function is compatible with 'leap' and 'toss2'.
Also, just like mentioned in Review, entity will reach the destination in same time with same y velocity no matter how far the destination is.
Conclusion
I hope you all can understand all above explanation. Just like previous one, no need to hurry, reread if you need to. Take all time you need to grasp it.
There are alot more 3D attacks than explained above. I'll explain some of them after I can generalize them. Or you could ask me here about certain 3D attack, maybe I could help.
Like promised, this is the explanation for true targetted jumpattack. Let's start from definition,
About True Targetted Jumpattacks
Let's review 3D attack definition 1st: 3D attack is attack which can hit heroes standing in different z coordinate. True Targetted Jumpattack is another example of 3D attack. In this attack, enemy jumps and lands right at targetted hero's location.
Examples:
Tyrog (Cadillacs & Dinosaurs) & Guardroid (Punisher)
Aside from that, there's targetted tossing who works the same way except that it's projectile who is 'jumpattacking' hero instead.
Examples: Morgan & Hogg (Cadillacs & Dinosaurs), Doc & Jennifer (Battle Circuit) & Dr Crayborn (Undercover Cops)
These 2 attacks use same target function called 'targetL'.
I'm not going to explain how to set offset, attackbox, range and rangez including how to use animationscript. Learn those yourselves if you haven't.
Targetting
Like said before, these attacks are targetted which means we need to target 1st before performing them. To find the target we use a function named 'findtarget()'.
void self = getlocalvar("self");
void target = findtarget(self);
'findtarget(self)' means find another entity whom this 'self' entity is hostile to. Since this is for enemies, the target is player. If there are 2 or more player, the closest one will be chosen. If there are none, 'target' will be empty.
What are we going to do with the targetted player assuming it's not empty? See next.
Moving Philosophy
After target is attained, the next thing to do is to move the enemy toward player. How does enemy move? there are 2 ways to do it, one is with 'move' command and 2nd is with 'velocity setting'. The 1st method is not preferred cause it's cumbersome. It requires multiple frames for moving and using script to replicate 'move' brings problem with walls and platforms. It's solvable though but it's best to avoid this method and use 2nd method instead.
2nd method moves entity smoothly with velocity setting and it moves just like using 'jumpframe'. It also require less frame since one frame is enough. If more frames are used, it's usually for graphical effect.
Since the enemy is jumping, we use 'tossentity' like this:
void self = getlocalvar("self");
tossentity(self, 2, 4, 2);
2 is y velocity, 4 is x velocity while 2 is z velocity. With 3 velocities set at same time, entity will jump diagonally downward right.
Before going further, there's important subject to discuss related to jumping.
Jumping Philosophy
Unlike previous 3D attacks, true targetted jumpattack requires the enemy to land exactly at hero instead of continue moving. In other word, land exactly at certain spot.
Also since this is jumping, enemy will stop right after landing. This means to land exactly at certain spot, timing and position must be exact.
In order to get precise timing, we need to know how much required time for complete jump. A complete jump is comprised of rising and falling. From my measurements, both process take same time regardless of y velocity. Still, how much required time is affected by y velocity. From my measurements, it's:
time = Vy * 20
Time = Required time for complete jump in centiseconds
Vy = y velocity
This formula isn't affected if entity is moving in x and/or z or not.
Speaking of moving in x and/or z, another fact to know is that entity can move in x and z while jumping and neither x , z or y velocity affect each other.
After we know that useful fact, we can continue previous subject.
Moving Philosophy (continued)
Since x, z and y velocity don't affect each other, we could define value for them seperately. However, we need to ensure precise moving which is by the time enemy lands, enemy has moved to hero's location. In order to do this, we need to get distance between hero and enemy first.
void self = getlocalvar("self");
float x = getentityproperty(self, "x"); // Get enemy's x coordinate
float z = getentityproperty(self, "z"); // Get enemy's z coordinate
void target = findtarget(self); // Find target
if( target != NULL()){ // Is there a target?
float Tx = getentityproperty(target, "x"); // Get target's x coordinate
float Tz = getentityproperty(target, "z"); // Get target's z coordinate
float Disx = Tx - x; // Get x distance
float Disz = Tz - z; // Get z distance
}
Note the 'if' above. We need to check if player is available or not cause we can't get any info from it if it's empty.
After we attain Disx and Disz, we could calculate proper speed. Let's name x velocity with Vx and z velocity with Vz.
The idea here is enemy moves with Vx in x axis to move Disx pixels while at same time enemy moves with Vz in z axis to move Disz pixels. Do you get it? by moving like that, enemy will eventually reach player's position cause the former moves Disx pixels in x axis and Disz in z axis. Both distance must be covered at same time otherwise enemy will miss targetted hero.
So in math formula we could write them like this:
Disx = Vx * t
Disz = Vz * t
t = required time for enemy to reach player
Unlike previous 3D attack, this time 't' is important so we don't remove it like before. Since we need enemy to reach hero at end of jump, time for complete jump is same with time to reach player so we can combine this formula with previous formula into:
Disx = Vx * Vy * 20
Disz = Vz * Vy * 20
Getting Velocity
Three velocities in formula above is unknown while both Disx and Disz is known. This means we can either set Vx and Vz freely (which then defines Vy) or set Vy (which then defines Vx and Vz). The former has worse consequences than the latter so let's choose the latter.
So the above formula becomes:
Vx = Disx / (Vy * 20)
Vz = Disz / (Vy * 20)
With these, both values of Vx and Vz are attained.
Code Implementation
Now that we have the formula, last thing to do is to implement it with code. However we should incorporate some factors 1st:
1. What if there are no players to target at all?
The answer is simple, let's set 0 for Vx and Vz which means enemy is not moving at all while jumping.
void self = getlocalvar("self");
void target = findtarget(self); // Find target
if( target != NULL()){ // Is there a target?
...
} else { // No target at all!
Vz = 0; // 0 z velocity
Vx = 0; // 0 x velocity
}
}
2. Other enemy using same function ended having same target or even worse altering target. This usually happen if there are 2 same enemies attacking with same attack at almost same time.
I don't get why this could happen but this issue can be fixed by using local value with unique identifier like this:
void self = getlocalvar("self");
setlocalvar("T"+self, findtarget(self)); // Find target and put it in local variable
if( getlocalvar("T"+self) != NULL()){ // Is there a target?
...
3. Although velocity is adjusted, enemy won't turn back if player is standing behind while targetting.
To solve this, simply flip facing direction to where player is like this:
if(Tx < x){
changeentityproperty(self, "direction", 0); // Face left
} else {
changeentityproperty(self, "direction", 1); // Face right
}
Last, this target function is meant to support other function. That means the function who perform the actual move is not this function. This function only calculate proper velocity values. To transfer these values, we use local variables. And the whole function becomes like this:
void targetL(float Vy)
{// Targetting opponent before performing targetted leap attack
void self = getlocalvar("self");
float x = getentityproperty(self, "x"); // Get enemy's x coordinate
float z = getentityproperty(self, "z"); // Get enemy's z coordinate
setlocalvar("T"+self, findtarget(self)); // Find target and put it in local variable
if( getlocalvar("T"+self) != NULL()){ // Is there a target?
void target = getlocalvar("T"+self);
float Tx = getentityproperty(target, "x"); // Get target's x coordinate
float Tz = getentityproperty(target, "z"); // Get target's z coordinate
if(Tx < x){
changeentityproperty(self, "direction", 0); // Face left
} else {
changeentityproperty(self, "direction", 1); // Face right
}
setlocalvar("x"+self, (Tx-x)/(20*Vy)); // Calculate Vx then store value in local variable
setlocalvar("z"+self, (Tz-z)/(20*Vy)); // Calculate Vz then store value in local variable
} else { // No target at all!
setlocalvar("z"+self, 0); // 0 z velocity
setlocalvar("x"+self, 0); // 0 x velocity
}
}
The input of this function is Vy which is the y velocity or jumping velocity.
The output of this function is local variable named '"x"+self' which contains x velocity and '"z"+self' which contains z velocity.
Velocity Usage
Need aspirin? just kidding
Are you sure? OK let's get on.
There are 2 functions which can use the outputs above i.e:
1. leap(float Vely) for true targetted jump attack
2. toss2(void Bomb, float dx, float dy, float dz, float Vy) for targetted tossing
Each functions affect enemy differently.
Since they use outputs from 'targetL' function, they must be declared AFTER that function.
True Targetted Jumpattack
In Cadillacs & Dinosaurs, Tyrog will jump and land ontop of hero if it's standing far from hero. That is one example of this type of targetted attack. The function here toss enemy with certain speed toward player. Aside from moving in x and z, it also toss enemy upwards. It doesn't matter what actually they are doing, they could be jumpcrushing, jumpkicking or elbow strike.
Here's the function:
void leap(float Vely)
{// Leap with previously attained speed!
void self = getlocalvar("self");
float Vx = getlocalvar("x"+self); // Attain x velocity
float Vz = getlocalvar("z"+self); // Attain z velocity
if( Vx!=NULL() && Vz!=NULL() ){ // Are both velocity available?
tossentity(self, Vely, Vx, Vz); //Leap towards target!
}
}
Yes, this function is the same function as in previous 3D attack. Read my 1st post for info about this function.
Targetted Tossing
In Cadillacs & Dinosaurs, Hogg and Morgan can toss grenades which landed right at hero's position. That's an example of this type of attack. This function toss a bomb then toss it with targetted speed toward player. It doesn't matter how the bomb looks like, it could be grenade, bomb, rock or energy bolt.
Here's the function:
void toss2(void Bomb, float dx, float dy, float dz, float Vy)
{ // Tossing targetted bomb
void self = getlocalvar("self");
int Direction = getentityproperty(self, "direction"); // Get enemy's facing direction
int x = getentityproperty(self, "x"); // Get enemy's x coordinate
int y = getentityproperty(self, "a"); // Get enemy's y coordinate
int z = getentityproperty(self, "z"); // Get enemy's z coordinate
float Vx = getlocalvar("x"+self)/2; // Attain x velocity
float Vz = getlocalvar("z"+self)/2; // Attain z velocity
void vShot; // Bomb entity
if (Direction == 0){ //Is entity facing left?
dx = -dx; //Reverse X direction to match facing
}
vShot = projectile(Bomb, x+dx, z+dz, y+dy, Direction, 0, 1, 0); // Toss the bomb!
if( Vx!=NULL() && Vz!=NULL() ){ // Are both velocity available?
tossentity(vShot, Vy, Vx, Vz); //Toss bomb towards target!
if (Direction == 0){ //Is entity facing left?
changeentityproperty(vShot, "speed", -Vx); // Change speed so it moves left
} else {changeentityproperty(vShot, "speed", Vx);} // Change speed so it moves right
}
}
The function differs alot with previous one cause this function toss bomb and alters its speed. 'Projectile' function tosses entity named Shot which is inputted. This projectile function also requires starting position for tossed bomb which is procurred by attaining x, z and a coordinate above. Position adjustment is inputted to allow scripter to give position shift to the tossed bomb.
vShot gets the tossed bomb. After that, Vx and Vz is attained like before. Due to fact that tossed bombs move twice faster than normal entities for same speed, we divide both velocity with 2. Then toss the bomb with tossentity to move it toward target.
However since projectile's flying speed is based on its speed instead of velocity, speed change is required. Since speed isn't relative, we need to get enemy's facing direction 1st before changing the speed with Vx. Negative speed(-Vx) for moving left or positive speed(Vx) for right.
Review
Like previous 3D attack, seperating targetting function and action function also enables intelligence control. That's important aspect to remember.
Still, there are 2 more subjects to explain more related to this.
1. Don't you wonder why I said "The former has worse consequences than the latter so let's choose the latter" above?
Let's review the formula again:
Disx = Vx * Vy * 20
Disz = Vz * Vy * 20
Former refers to "set Vx and Vz freely (which then defines Vy)". Let's change the formula for this.
Vy = Disx / (Vx * 20)
Vy = Disz / (Vz * 20)
There are 2 consequence of this formula:
a. since Vy is same in both formula, we can't set both Vx or Vz freely. One can only be set freely while the other will be defined.
b. Vy is jumping velocity which also affects how high enemy jumps and how long enemy would take to make complete jump. Since Disx and Disz could be in any value (depending on distance), Vy could be very small or very large. That also means, enemy could jump very short or very high. If we try to synch this jumping speed with animation, it would cumbersome cause we can't tell how long it would take to finish jumping. Sure, there is landframe but the animation skip isn't always good to see IMO. This is what I meant with worse consequences.
2. So does that mean latter method has no consequence at all? no not really.
Let's review the formula again:
Vx = Disx / (Vy * 20)
Vz = Disz / (Vy * 20)
Disx and Disz could be in any value (depending on distance) which means Vx and Vz could be very small or very large. These aren't big deal since both only moves enemy in x and z axis.
The real consequence is this:
time = Vy * 20
Since Vy is defined by modder, Time (required time for complete jump) will be defined too. This mean we can tell how long it would take for enemy to finish jumping or to hit hero from start of jumpattack. This is good news cause we can set good animation for the jumpattack.
Another thing to remember is since Time is defined, enemy will always require same time to hit hero no matter where hero is IOW whether hero is close or very far, enemy can hit them both with same time.
Other Usage
As you can see, the targetting philosophy above is used to find proper speed to hit target. Actually, same philosophy can be used for other purpose which is jumping to certain location. Unlike jumpattack, this kind of jumping only makes entity jumps to certain location without targetting at all. It doesn't matter what they do while jumping or after landing.
'TargetL' function above can be modified for that purpose like this:
void targetPos(float Vy, int Tx, int Tz)
{// Targetting certain position before leaping there
// Vy : Leaping speed
// Tx : Leaping destination x coordinate
// Tz : Leaping destination z coordinate
// Used with 'leap' or 'toss2'
void self = getlocalvar("self");
float x = getentityproperty(self, "x"); // Get entity's x coordinate
float z = getentityproperty(self, "z"); // Get entity's z coordinate
if(Tx < x){
changeentityproperty(self, "direction", 0); // Face left
} else {
changeentityproperty(self, "direction", 1); // Face right
}
setlocalvar("x"+self, (Tx-x)/(20*Vy)); // Calculate Vx then store value in local variable
setlocalvar("z"+self, (Tz-z)/(20*Vy)); // Calculate Vz then store value in local variable
}
There's y velocity input like 'targetL' but there are also Tx and Tz for leaping destination. Tx is relative to leftmost edge of level so it might require adjustments.
The assumptions are the same except that there's no targetting here. And just like 'targetL', this function is compatible with 'leap' and 'toss2'.
Also, just like mentioned in Review, entity will reach the destination in same time with same y velocity no matter how far the destination is.
Conclusion
I hope you all can understand all above explanation. Just like previous one, no need to hurry, reread if you need to. Take all time you need to grasp it.
There are alot more 3D attacks than explained above. I'll explain some of them after I can generalize them. Or you could ask me here about certain 3D attack, maybe I could help.