Author Topic: Ano's Code Documentation  (Read 3218 times)

Ano's Code Documentation
« on: January 25, 2018, 03:23:32 PM »
Ano's Code Documentation

i'm recording the process/logic behind any of my endeavors with Danmakufu ph3 should they succeed. pay this no mind... or do. whatever, if something comes up that you're interested in then by all means read away.

EDIT: it occurs to me that if I'm going to keep updating this its probably best to have a table of contents so I and other people don't have to scroll down through walls of text and multiple replies to find what they're looking for... i suppose that without a table of contents people wouldn't have any clue if what they were looking for was in here... lets rectify that shall we?

Table of Contents
will be updated as more entries are added

Documentation of the process of homing player shots
Homing shot, Strong homing:
shots that accuratly home towards enemies, if the homing is strong enough or the bullet is traveling slow enough then it becomes impossible to doge
Link: N/A scroll down.
Homing shot, wavering homing
shot's that incorporate over-steering as a feature. swerves left and right as it travels towards the target.
Link: https://www.shrinemaiden.org/forum/index.php/topic,21285.msg1380137.html#msg1380137

Documentation of the process of homing player shots

Figured out how to make homing shots. Typing out the process/logic behind the coding both for self-documentation and because if anyone else wants to make homing shots they can read through and understand the logic rather than have to figure it out by themselves like I had to.

Homing shot: strong homing
Shots that strongly home in on targets. If the homing is strong enough or the bullet is traveling slow enough then it becomes impossible to dodge

Global variables/constants:
   SHOT_HOMING = how strong the homing on the shots should be
   SHOT_MAX_HOMING_DIST = the shot will home in on enemies within this distance
   //make this a constant at the top of your script so that if you want to adjust the characteristics of the bullet then you can just change this number rather than go through and edit every instance of this value
   //you may want to do the same for stuff like how fast you want the shot to travel, the shot?s acceleration, the shot?s max speed etc? those values aren?t getting put here because those aren?t integral to the basic homing mechanism.


?Plain English? code
//don't worry if you don't understand all of this, there are further explanations in the respective sections

A: While the bullet exists
   1: check if there are enemies on screen and create a matrix of the ID?s of all enemies with hitboxes (henceforth referred to as enemyMatrix)
   2: create a variable to check if the shot has found a target (henceforth referred to as homingBool)
   3: if there is at least one enemy on screen
   //see section ?finding the closest enemy?
      3.1: create a variable that will store the distance of the nearest enemy (henceforth referred to as targetDist) set it to MAX_HOMING_DIST
      3.2: create a variable that will store the ID of the closest enemy (henceforth referred to as targetID) this should initially be set to 0
      3.3: for as many times as there are enemy ID?s in enemyMatrix
         3.3.1: if the distance from the shot to the Nth enemy is less than targetDist
            3.3.1.1: set targetDistance to the distance of the Nth enemy
            3.3.1.2: set targetID to the ID of the Nth enemy
            3.3.1.3: set homingBool to true
      3.4 if homingBool is true (the ascent loop found an enemy in range)
         3.4.1: find the angle that the shot is traveling (henceforth referred to as ?shotAngle?)
         //see section ?angleTo?
            3.4.1.1: convert shotAngle to 0-359 value
            //see section ?Working with 0-359 angle values?
         3.4.2: find the angle to the target (henceforth referred to as ?targetAngle?)
            3.4.2.1: convert targetAngle to 0-359 value
         3.4.3: find the negative of the targetAngle (henceforth referred to as ?targetAngleN?)
            3.4.3.1: convert targetAngleN to 0-359 value
            //see section ?Homing conditions?
            //see section ?Oversteering?

         3.4.4: if the targetAngle is more than 180 (target is above the shot, and targetAngle is greater than targetAngleN)
            3.4.4.1: if the angle is less than (targetAngle ? SHOT_HOMING) and more than targetAngleN
               3.4.4.1.1: increase angle by SHOT_HOMING (turn the bullet clockwise)
            3.4.4.2: if the angle is more than (targetAngle + SHOT_HOMING) or is less than targetAngleN
               3.4.4.2.1: decrease angle by SHOT_HOMING (turn the bullet anticlockwise)
            3.4.4.3: if the angle is >= (targetAngle ? SHOT_HOMING) and <= (targetAngle + SHOT_HOMING)
               3.4.4.3.1: set angle to targetAngle
         3.4.5: if the targetAngle is less than 180 (target is below the shot, and targetAngle is less than targetAngleN)
            3.4.5.1: if the angle is greater than targetAngleN and less than (targetAngle + SHOT_HOMING)
               3.4.5.1.1: increase angle by SHOT_HOMING (turn the bullet clockwise)
            3.4.5.2: if the angle is less than targetAngleN or more than (targetAngle ? SHOT_HOMING)
               3.4.5.2.1: decrease angle by SHOT_HOMING (turn the bullet anticlockwise)
            3.4.5.3: if the angle is >= (targetAngle ? SHOT_HOMING) and <= (targetAngle + SHOT_HOMING)
               3.4.5.3.1: set angle to targetAngle
   4: yield while loop

Finding the closest enemy
The ?GetIntersectionRegistedEnemyID? function finds all enemies with a hitbox on screen and returns all their ID?s in a matrix, so if there are three enemies on screen then it will return ?[1st enemyID, 2nd enemyID, 3rd enemyID]?. The problem is that it orders them based on the order they were created with the ID at matrix[0] being the oldest object spawned. To find the closest enemy we have to go through all of the enemies on screen, calculate the distance from the shot to the enemy, then figure out which is the closest. Here we will go over each of the lines of the plain English code individually

   3.1: create a variable that will store the distance of the nearest enemy (henceforth referred to as targetDist) set it to MAX_HOMING_DIST
   //the number you initially set this variable has the side effect of being the maximum homing distance, for reasons that will become clear as we continue. Basically, if all the distance to all enemies is above this number then the shot wont home in on anything. You can set this number to 591 which is the diagonal of the standard playing field or 801 which is the diagonal of the full screen. Technically with some finangling you could set this variable to something like -1, then do some more finangling with the if conditions within the ascent loop to make sure that the first enemy iterated through always sets the distance. However, this is not only easier but has an added benefit. If you set the initial value of this number to something like ?50? then the shot will only home in on the closest enemy in a circle with a radius of 50. Ahem? anyway

   3.2: create a variable that will store the ID of the closest enemy (henceforth referred to as targetID
   //I don?t know enough about the mechanics of the ?GetIntersectionRegistedEnemyID? function to explain why this works. Just understand that the ID is a number(?) and that if you set this variable to 0 you can then re-assign it to the enemyID in future.

   3.3: for as many times as there are enemy ID?s in enemyMatrix
   //if you don?t know how to use ascent loops its ?ascent (i in 0..length(enemyMatrix))?. I can?t be bothered to explain in detail so if you don?t know what that means, look up Sparen?s danmakufu tutorials, he has both a video tutorial on ascent loops and a written tutorial that covers it as well.

      3.3.1: if the distance from the shot to the Nth enemy is less than targetDist
            3.3.1.1: set targetDist to the distance of the Nth enemy
            3.3.1.2 set targetID to the ID of the Nth enemy
            3.3.1.3: set homingBool to true

      //for example, if the loop is on the first enemy. We check if the distance to the enemy is less than the targetDist (since this is the first enemy the target distance will be MAX_HOMING_DIST) then if it is, we
      1. set the targetDist to this new distance
      2. set the targetID to this enemy?s ID
      3. set homingBool to true (we?ve found at least one enemy within MAX_HOMING_DIST)
Then the loop will move onto the second enemy, if the distance to the second enemy is less than the distance to the first enemy (remember we set targetDist to the distance of the first enemy) then its distance will become the new targetDist and its ID will become the new targetID.
   //this loop will run through once for each enemy with the Nth changing to 1st, 2nd, 3rd?etc? each time. In other words, this process of checking if each enemy is closer than the last will occur for all enemies (with hitboxes)

   3.4 if homingBool is true (the ascent loop found an enemy in range)
      ?(rest of code)

   //on the other hand, if we?ve gone through all the enemies and none of them have been within the MAX_HOMING_RANGE, then homingBool will never have been changed to true and the rest of the code is skipped. In other words, the bullet will continue along its merry way.

angleTo
the angleTo function is pretty simple to get and use even if I don?t entirely understand the math behind it? well whatever

Code: [Select]
function angleTo(obj,dest) {
let dir = atan2(ObjMove_GetY(dest)-ObjMove_GetY(obj),ObjMove_GetX(dest)-ObjMove_GetX(obj));
return dir;
}

//copy and paste this into your code. Now whenever you need to find the angle between two objects you just type ?angleTo(first object, second object)? for the purposes of creating homing shots we use this to find the angle from the shot to the target ?angleTo(shotObj,targetObj)?

Working with 0-359 angle values
One of the main issues I had with creating a system that could handle homing shots was the fact that every angle has an infinite possible number of values. For example 90 is the same as 450, 810, 1170? etc? and the same as -270, -630, -990? etc? when you add or subtract 360 from an angle you get the same angle. This causes problems like bullets looping multiple times before actually beginning to home, or bullets looping in circles endlessly. To get over this, we ensure that angles are always a number between 0 and 359. This way if one of the angle values is reduced to a negative number or increased past 359. We will return it to its equivalent 0-359 value.

Code: [Select]
while (angle >= 360) {
angle -= 360;
}
while (angle < 0) {
angle += 360;
}

//using this code we can ensure that even if the angle becomes something absurd like 1170. It will be reduced down to 90. Its important to note when and where this code is placed. We place it at the very beginning of the ?shotCommands? code and immediately after each piece of angle data is pulled and stored in a variable. Technically we don?t need this for 3.4.1.1 since I think that value will always be a 0-359 value but if somehow that value exceeds boundaries, that code is there.

//also take note of the ?>=? and the ?<? symbols. If that ?>=? was just a ?>? then 360 degrees won?t be reduced to 0 degrees. Its not too important in the grand scheme of things but its good practice to smooth out these overlaps.

Homing conditions
How does homing actually work? Well first off let?s familiarise ourselves with the danmakufu co-ordinate system. Directly right is 0 degrees, then progressing clockwise the four cardinal directions are 0 = E, 90 = S, 180 = W, 270 = N, and then back to 360 = E which would then be reduced back down to 0 if we?re working in 0-359 angles
 


To facilitate homing we need three values, the direction the shot is traveling, the direction to the target, and the direction directly opposite that (shotAngle, targetAngle, and targetAngleN respectively). Using these three values we need to determine if the bullet needs to turn clockwise (we increase the shotAngle) or anticlockwise (we decrease the shotAngle).

So let?s start off easy. Let?s assume that the targetAngle is 180. Which would make targetAngleN 0
 


In this situation if the shotAngle is less than 180 it needs to rotate clockwise (the pink sector of angles) and if its more than 180 it needs to rotate anticlockwise (the blue sector). In other words, this can be written as these conditions

If shotAngle is less than targetAngle
   Increase shotAngle (rotate CW)
If shotAngle is more than targetAngle
   Decrease shotAngle (rotate ACW)

However, if it was this easy to make a homing shot then I wouldn?t need to be typing this all up. The truth is that the targetAngle is not always going to be 180 so let?s check out some other situations.
 


Here the targetAngle is 270 if we apply the previous conditions we have an issue. Let?s take the previous conditions and replace targetAngle with its value in this scenario

   1: If shotAngle is less than 270
      1.1: Increase shotAngle
   2: If shotAngle is more than 270
      2.1: Decrease shotAngle

If the shotAngle is 90 to 270. It works, and if the shotAngle is from 270 to 0 (remember 360 = 0) then everything is fine. However, when the shotAngle is from 0 to 90 then the bullet will rotate clockwise instead of anticlockwise like it?s supposed to. This is because anything from 0 to 90 still counts as being under 270 and therefor triggers the first condition rather than the second. We fix this by modifying our conditions.

   1: If shotAngle is less than targetAngle AND more than targetAngleN
      1.1: Increase shotAngle (rotate CW)
   2: If shotAngle is more than targetAngle OR less than targetAngleN
      2.1: Decrease shotAngle (rotate ACW)

   //take special note of, ?less than? which becomes "<", ?more than? which becomes ">", and whether to use ?AND? or ?OR?. These are important to the logic of homing and your bullet will likely loop in circles if you mess them up

This is why we need targetAngleN, because it?s the opposite of targetAngle, it counts as the point where the difference between the shotAngle and the targetAngle is great enough that the bullet should turn the other way.
//as a side note understand that targetAngleN is (targetAngle ? 180) NOT ?(targetAngle). Also, because the -180 is will kick the value of targetAngleN into the negatives if targetAngle is less than 180 its important you ensure targetAngleN is a 0-359 value.

With this we should have a proper homing bullet? or is it? Let?s try one last scenario, just to be sure.
 


In this situation the targetAngle is 90 and targetAngleN is 270. Like before let?s try the previous conditions with these values plugged in.

   1: If shotAngle is less than 90 AND more than 270
      1.1: Increase shotAngle (rotate CW)
   2: If shotAngle is more than 90 OR less than 270
      2.1: Decrease shotAngle (rotate ACW)

Oh dear? this is bad. The first condition will never trigger because there?s no way a number can be more than 270 and less than 90 at the same time. And the second condition will always trigger because every value from 0 to 359 is either more than 90 or less than 270. In other words. In this situation the bullets will keep turning anticlockwise. the reason this happens is because targetAngleN has become more than targetAngle. In fact, as long as targetAngle is less than 180, targetAngleN will be more than targetAngle.

but there?s some good news, this means that this particular set of conditions works as long as targetAngle is more than 180, because targetAngleN will always be less than targetAngle in that situation.

With those two factors in mind we can create a proper homing bullet. We already know that our current conditions work if the targetAngle is more than 180 so let?s include another layer of checks.

   1: If targetAngle is more than 180
      1.1: If shotAngle is less than targetAngle AND more than targetAngleN
         1.1.1: Increase shotAngle (rotate CW)
      1.2: If shotAngle is more than targetAngle OR less than targetAngleN
         1.2.1: Decrease shotAngle (rotate ACW)

Now we just need conditions for when targetAngle is less than 180. Let?s again assume that targetAngle is 90 and targetAngleN is 270. In this situation the conditions are instead. here's the picture again if you need it



   1: if shotAngle is more than 270 OR less than 90
      1.1: Increase shotAngle(rotate CW)
   2: if shotAngle is less than 270 AND more than 90
      2.1: Decrease shotAngle (rotate ACW)

Then we swap out the numbers for targetAngle (90) and targetAngleN (270)

   1: if shotAngle is more than targetAngleN OR less than targetAngle
      1.1: Increase shotAngle(rotate CW)
   2: if shotAngle is less than targetAngleN AND more than targetAngle
      2.1: Decrease shotAngle (rotate ACW)

   //again, take special note of ?more than?, ?less than?, ?AND?, ?OR?, whether you?re increasing the shot angle or decreasing it, and lastly whether you?re comparing the shot angle to targetAngle or targetAngleN. If any of these are incorrect then you?ll likely have a looping bullet

And finally, we just need to put this set of conditions into another level with the first set of conditions.   

   1: If targetAngle is more than 180
      1.1: If shotAngle is less than targetAngle AND more than targetAngleN
         1.1.1: Increase shotAngle (rotate CW)
      1.2: If shotAngle is more than targetAngle OR less than targetAngleN
         1.2.1: Decrease shotAngle (rotate ACW)
   2: if targetAngle is less than 180
      2.1: if shotAngle is more than targetAngleN OR less than targetAngle
         2.1.1: Increase shotAngle(rotate CW)
      2.2: if shotAngle is less than targetAngleN AND more than targetAngle
         2.2.1: Decrease shotAngle (rotate ACW)

   //as long as the bullet goes through this process on every frame (at least every frame that it should be homing) then the bullet will always turn towards the target.

Oversteering
There?s one last issue you should look out for. Let?s assume that the SHOT_HOMING value is set to a large number like? 30. That way the shot will turn 30 degrees towards the target per frame. However, what if the difference between the shotAngle and the targetAngle is only something like 5 degrees. In this situation the bullet will turn 30 degrees towards the target, and overshoot it by 15 degrees. Then on the next frame it will turn 30 degrees again (in the opposite direction this time) and overshoot it by 5, leaving you back where you started. The result is that the bullet ?jitters? as it travels towards the target. with small values of SHOT_HOMING its barely noticeable however with large values it becomes quite noticeable. Let?s make some adjustments to the homing conditions.

   1: If targetAngle is more than 180
      1.1: If shotAngle is less than targetAngle AND more than targetAngleN
         1.1.1: Increase shotAngle (rotate CW)
      1.2: If shotAngle is more than targetAngle OR less than targetAngleN
         1.2.1: Decrease shotAngle (rotate ACW)
   2: if targetAngle is less than 180
      2.1: if shotAngle is more than targetAngleN OR less than targetAngle
         2.1.1: Increase shotAngle(rotate CW)
      2.2: if shotAngle is less than targetAngleN AND more than targetAngle
         2.2.1: Decrease shotAngle (rotate ACW)

What we want to do is create a third option for each series of conditions. This third condition will be when the difference between the shotAngle and the targetAngle is less than the angle of SHOT_HOMING. We also need to adjust the previous conditions so that they don?t overlap with this new condition. Imagine that we are taking a ?wedge? SHOT_HOMING to the left and right of targetAngle.
 


//basically, we want to insert that orange wedge into the formula, its left boundary is targetAngle - SHOT_HOMING, and its right boundary is targetAngle + SHOT_HOMING if the shotAngle enters that wedge, then instead of turning it by SHOT_HOMING, we just make shotAngle = targetAngle

I?m going to save you the trouble of working out whether you have to + or ? SHOT_HOMING to targetAngle and just note down things here

   1: If targetAngle is more than 180
      1.1: If shotAngle is less than (targetAngle ? SHOT_HOMING) AND more than targetAngleN
         1.1.1: Increase shotAngle (rotate CW)
      1.2: If shotAngle is more than (targetAngle + SHOT_HOMING) OR less than targetAngleN
         1.2.1: Decrease shotAngle (rotate ACW)
      1.3: if shotAngle >= (targetAngle ? SHOT_HOMING) AND shotAngle <= (targetAngle + SHOT_HOMING)
         1.3.1: set shotAngle to targetAngle
   2: if targetAngle is less than 180
      2.1: if shotAngle is more than targetAngleN OR less than (targetAngle + SHOT_HOMING)
         2.1.1: Increase shotAngle(rotate CW)
      2.2: if shotAngle is less than targetAngleN AND more than (targetAngle ? SHOT_HOMING)
         2.2.1: Decrease shotAngle (rotate ACW)
      2.3: if shotAngle >= (targetAngle ? SHOT_HOMING) AND  shotAngle <= (targetAngle + SHOT_HOMING)
         2.3.1: set shotAngle to targetAngle

      //since fulfilling that third condition means that the shotAngle is within the (targetAngle +- SHOT_HOMING) if you set the shotAngle to the targetAngle the change in angle will never be more than SHOT_HOMING. So don?t worry about the bullet suddenly turning a great deal more than it should.

   //also, do you see ?>=? and ?<=? that?s been used in the third conditions. If they were simply ?>? and ?<? we?d have ?liminal value?. If shotAngle exactly equalled (targetAngle ? SHOT_HOMING) or (targetAngle + SHOT_HOMING) then it wouldn?t fulfil any of the three conditions and therefore homing wouldn?t occur. Its not too big of a deal since the shot will be moving so the angle will change, however its still good practice to close these gaps. There?s actually another liminal value. If shotAngle = targetAngleN or in plain speak, if the shot is travelling directly away from the target, then it won?t turn in either direction, you can close up this gap as well if you want. But I didn?t because I?m a goddamn weirdo and closing that gap means that the conditions become asymmetrical. If somehow a shot manages to travel in the exact opposite direction of the target it can fly off for all I care, it deserves freedom.

Alright that takes care of that.

Final Code Form
Ok so if you?ve read through all the above you should have enough information to create homing shots assuming you also have some prior knowledge of object bullets. So I whole heartedly recommend that you read through the plain English code line by line and just convert that to actual ph3 code, It shouldn?t be too hard and you can make adjustments yourself. However if you really need to then here the code to help you check. This is under the assumption that you?re making a player shot but you can repurpose it to be used for enemy bullets

Pastebin link:
https://pastebin.com/nAJRJ95K

If you want to look up a specific step from the plain english code, then just press ctrl + F and type in its ?step code? e.g. ?3.3.1.1:? will highlight line 29 and just below it is the code for step 3.3.1.1: which is ?targetDist = GetObjectDistance(obj,enemy);?
« Last Edit: January 27, 2018, 10:24:41 AM by ReaperZX7 »

Re: Ano's Code Documentation
« Reply #1 on: January 27, 2018, 10:07:01 AM »
Homing shot: wavering homing
Rather than lock onto enemies this bullet swerves towards them much like a racecar turning, or like the bullet is on ice. We facilitate this by engineering oversteering into the code rather than try and eliminate it like we did with the strong homing.

Global variables/constants
   SHOT_HOMING_ACCEL = this is how quickly the bullets can "steer" as opposed to turn in the previous bullet
   SHOT_HOMING_LIMIT = this is the maximum angle the bullets can turn
   SHOT_MAX_HOMING_DIST = same as before

?Plain English? code
//the code is mostly the same as the strong homing shot bullet, so I?ll bold the bits that have changed and that you need to be aware of.

A: create a variable to store the current angular velocity of the bullet, set its initial value to 0 (henceforth referred to as angularVelocity)
B: while the bullet exists
   1: check if there are enemies on screen and create a matrix of the ID?s of all enemies with hitboxes (henceforth referred to as enemyMatrix)
   2: create a variable to check if the shot has found a target (henceforth referred to as homingBool)
   3: if there is at least one enemy on screen
      3.1: create a variable that will store the distance of the nearest enemy (henceforth referred to as targetDist) set it to MAX_HOMING_DIST
      3.2: create a variable that will store the ID of the closest enemy (henceforth referred to as targetID) this should initially be set to 0
      3.3: for as many times as there are enemy ID?s in enemyMatrix
         3.3.1: if the distance from the shot to the Nth enemy is less than targetDist
            3.3.1.1: set targetDistance to the distance of the Nth enemy
            3.3.1.2: set targetID to the ID of the Nth enemy
            3.3.1.3: set homingBool to true
      3.4 if homingBool is true (the ascent loop found an enemy in range)
         3.4.1: find the angle that the shot is traveling (henceforth referred to as ?shotAngle?)
            3.4.1.1: convert shotAngle to 0-359 value
         3.4.2: find the angle to the target (henceforth referred to as ?targetAngle?)
            3.4.2.1: convert targetAngle to 0-359 value
         3.4.3: find the negative of the targetAngle (henceforth referred to as ?targetAngleN?)
            3.4.3.1: convert targetAngleN to 0-359 value
         //see section ?Fun with Oversteering!?
         3.4.4: if the targetAngle is more than 180 (target is above the shot, and targetAngle is greater than targetAngleN)
            3.4.4.1: if the shotAngle is less than targetAngle and more than targetAngleN
               3.4.4.1.1: if angularVelocity is not more than SHOT_HOMING_LIMIT
                  3.4.4.1.1.1: increase angularVelocity by SHOT_HOMING_ACCEL

            3.4.4.2: if the shotAngle is more than targetAngle or is less than targetAngleN
               3.4.4.2.1: if the angularVelocity is not less than -SHOT_HOMING_LIMIT
                  3.4.4.2.1.1: decrease angularVelocity by SHOT_HOMING_ACCEL

         3.4.5: if the targetAngle is less than 180 (target is below the shot, and targetAngle is less than targetAngleN)
            3.4.5.1: if the shotAngle is greater than targetAngleN and less than targetAngle
               3.4.5.1.1: if  angularVelocity is not more than SHOT_HOMING_LIMIT
                  3.4.5.1.1.1: increase angularVelocity by SHOT_HOMING_ACCEL

            3.4.5.2: if the shotAngle is less than targetAngleN or more than targetAngle
               3.4.5.2.1: if angularVelocity is not less than -SHOT_HOMING_LIMIT
                  3.4.5.2.1.1: decrease angularVelocity by SHOT_HOMING_ACCEL

         3.4.6: change shotAngle by angularVelocity
   4: yield while loop

Fun with Oversteering!
With the strong homing shot, oversteering was an issue that we wanted to get rid of. However, with a little bit of effort we can incorporate oversteering into the shot?s homing capability and get a shot that swerves left and right as it travels to the target. there are basically four differences between this code and the code for strong homing shots.

Firstly, at the very beginning of the code we create a local variable to store the current angular velocity of the shot.

   A: create a variable to store the current angular velocity of the bullet, set its initial value to 0 (henceforth referred to as angularVelocity)
   //by placing this line at the very beginning of the code outside of the while loop the variable is declared and set to the initial value of 0 only when the bullet is created. If this line was inside the while loop then the variable would be reset to 0 each frame which defeats the purpose.

Secondly, we remove the third condition from our homing conditions that checks if the shotAngle is within targetAngle +- SHOT_HOMING. We also remove SHOT_HOMING from the first two conditions (basically taking out that ?orange wedge? we inserted with the strong homing shot?.

   3.4.4: if the targetAngle is more than 180 (target is above the shot, and targetAngle is greater than targetAngleN)
      3.4.4.1: if the shotAngle is less than targetAngle and more than targetAngleN
         ?rest of code
      3.4.4.2: if the shotAngle is more than targetAngle or is less than targetAngleN
         ?rest of code
   3.4.5: if the targetAngle is less than 180 (target is below the shot, and targetAngle is less than targetAngleN)
      3.4.5.1: if the shotAngle is greater than targetAngleN and less than targetAngle
         ?rest of code
      3.4.5.2: if the shotAngle is less than targetAngleN or more than targetAngle
         ?rest of code

   //because we?re incorporating oversteering into the bullet?s characteristics and the purpose of those features were to remove oversteering, we get rid of them.

Thirdly, we change the actual effect of our homing conditions. Before we would simply increase the bullets angle by SHOT_HOMING however now instead we use this code for clockwise movement:

   3.4.4.1.1: if angularVelocity is not more than SHOT_HOMING_LIMIT
      3.4.4.1.1.1: increase angularVelocity by SHOT_HOMING_ACCEL


And this code for anticlockwise movement:

   3.4.4.2.1: if the angularVelocity is not less than -SHOT_HOMING_LIMIT
      3.4.4.2.1.1: decrease angularVelocity by SHOT_HOMING_ACCEL

   //these two sets of code mean that the bullet?s angular velocity will always be ?accelerating? towards the target however the actual angularVelocity might overshoot the target. it?s a bit hard to explain in simple terms without going into detail and busting out more diagrams? but if you understand what the relationship between time, velocity, and acceleration is (from your high school physics or math class) then you should understand what this code is doing numerically.

Lastly, we have one final line outside of the homing conditions that actually updates the bullet?s angle

   3.4.6: change shotAngle by angularVelocity
   //things have been engineered so that angular velocity can be positive or negative value. So this one line can handle steering in both directions and we don?t actually need one of these lines inside each homing condition.

Final Code Form
once again I recommend going through the plain English code and converting that to ph3 code. But once again, i have provided proper code that you can use to compare.

https://pastebin.com/pgXxJmUn