GameMaker Path prediction for projectiles

I've been trying to find a way to get the angle that a supposed turret will need to aim at taking into consideration projectile speed, distance and the current position an enemy is in to where they WILL be when a projectile could hit its mark

This is what i have at the moment, this only aims directly at the enemy and mostly misses because the projectile is too slow and too far to hit the enemy, any idea how to make this happen?

Code:
/// @arg instance instance we are to manipulate
/// @arg target target to point toward

var objToTurn = argument0, target = argument1;
var x1 = objToTurn.x, y1 = objToTurn.y, x2 = target.x, y2 = target.y;

var targetDir = point_direction(x1, y1, x2, y2); //Direction to face target

// -------------
//Supposed Prediction Code Here
// -------------

objToTurn.direction = targetDir; //Turn to target
I know there's way to predict where an object with speed will be if the momentum is both constant and linear, since paths are not linear there's no easy answer i feel, any help please?
 
It's not too difficult to hit an object moving at a constant speed and direction

Code:
    var _vx = _target.hspeed;
    var _vy = _target.vspeed;
    var _x = _target.x - x;  //presuming here (x,y) is position of turret
    var _y = _target.y - y;
    var _p = 15; //projectile speed
    var _a = _vx*_vx + _vy*_vy - _p*_p
    var _b = 2*(_x*_vx + _y*_vy);
    var _c = _x*_x + _y*_y;
    var _disc = _b*_b - 4*_a*_c;
    if (_disc > 0) {
        var _t = (-_b - sqrt(_disc)) / (2*_a);
        if (_t > 0) {
            var _aim_x = _x + _vx * _t;  //aim point relative to (x,y)
            var _aim_y = _y + _vy * _t;
            var _angle = point_direction(0,0,_aim_x,_aim_y);  //shoot in this direction
        }
    }

    //in event that barrel length is really long, substitute, _a,_b,_c with the following.  "_l" is barrel length
    var _a = _vx*_vx + _vy*_vy - _p*_p;
    var _b = 2 * (_x*_vx + _y*_vy - _p*_l);
    var _c = _x*_x + _y*_y - _l*_l;
[/code[
 
Last edited:
Z

Zachary_tzy

Guest
I think first you would need to get the length in pixels of your path using path_get_length().

Then in your enemy object you might need to have a variable to record how far you are along the path in pixels

and from that get a variable that converts it to how far along between 0 and 1, with 0 the beginning and 1 the end
so maybe like in your step event:
Code:
faralong_ += pathspeed_ // Lets assume pathspeed_ = 3
faralongin0and1_ = faralong_ / lengthofpath_ // Lets assume lengthofpath_ = 30
When your cannon is preparing to fire, it will now know how far along the target enemy is along his path using enemy.faralongin0and1_.

Assuming your cannon projectile has a speed of 5, and your enemy has a speed of 3 along the path.

You now have to know if your cannon can ever have a chance of hitting your enemy with the speed of the projectile before the enemy completes the path.

Get the point_distance(cannon_x, cannon_y, enemy_x, enemy_y) = e.g. 10 pixels away.

From the code above lets assume that the enemy is 6/30 pixels along the path meaning faralong0and1_ = 0.2, with a speed of 3, it will complete the path in 8 steps.

Assuming your cannon does not know the path of your enemy it will have to guess whether it can reach or not.

10 pixels means that your projectile would be 2 steps away from where the enemy was when the cannon is preparing.

Assuming the worst case scenario path where your enemy is moving away from your projectile, it will take 5 steps to catch up to and hit the enemy in the worst case scenario, meaning in any case it will be possible to hit the enemy since the enemy will complete the path in 8 steps.

For maximum accuracy of your cannon, you might only want to aim for points in time after the worst case so anywhere after 5 steps along the path. In 5 steps the enemy would have now gone 21/30 pixels along the path, meaning >0.7. Lets use 0.8 for this example.

Since we have decided to hit the enemy at 0.8 along his path, we get the coords of that using the path_get_x(path_, 0.8) and the same for y.

We know the enemy will reach that point from 6/30 to 24/30 (which is 0.8) in 6 steps.

Calculate the distance from the cannon to that point point_distance(cannon_x, cannon_y, path_get_x(path_, 0.8), path_gety(path_, 0.8)).

Your cannon projectile can definitely cover that distance within 6 steps, now your cannon just needs to fire at the right amount of steps delayed.

point_distance / projectile_speed (which is 5) = steps needed to reach, 6 - steps needed to reach = steps needed to wait.

Wait that amount of steps after preparation and create projectile with direction point_direction(x, y, path_get_x(path_, 0.8), path_gety(path_, 0.8)) AND FIRE!!

DISCLAIMER: I haven't slept in the last 24 hours and I just randomly theory crafted this with no testing and totally 0 assurance it will work or make sense. But regardless, I hope you may find something that might push you in the right path to predict and fire at a point on a non linear path. Hope it helps!
 
Last edited by a moderator:
I think first you would need to get the length in pixels of your path using path_get_length().
So this is wqhat i've crafter after what you said, I'm not sure if this is what you exactly said, but this KINDA works, its just still aiming just short of the enemy if the weapon speed is too slow and the turret is too far, any tweaks you'd recommend?
Code:
/// @arg instance
/// @arg target
/// @arg weapon-speed

var objToTurn = argument0, target = argument1, wpSpd = argument2;
var x1 = objToTurn.x, y1 = objToTurn.y, x2 = target.x, y2 = target.y;

var traveltime = point_distance(x1, y1, x2, y2) / wpSpd; //Travel time from current enemy x/y
var path = target.path_index; //Path index
var pathlen = path_get_length(path); //Path length
var pathpro = target.path_position; //Path progress
var pathdis = pathlen * pathpro; //Path traveled amount
var pathdisfut = pathdis + (target.path_speed * traveltime); //Path distance future
var pathprofut = pathdisfut / pathlen; //Path progress future

x2 = path_get_x(path, pathprofut); //Future enemy x
y2 = path_get_y(path, pathprofut); //Future enemy y

var targetDir = point_direction(x1, y1, x2, y2); //Direction to point

objToTurn.direction = targetDir;
 
Last edited:
Z

Zachary_tzy

Guest
So this is wqhat i've crafter after what you said, I'm not sure if this is what you exactly said, but this KINDA works, its just still aiming just short of the enemy if the weapon speed is too slow and the turret is too far, any tweaks you'd recommend?
Code:
/// @arg instance
/// @arg target
/// @arg turnspeed
/// @arg weapon-speed

var objToTurn = argument0, target = argument1, turnSpeed = argument2, wpSpd = argument3;
var x1 = objToTurn.x, y1 = objToTurn.y, x2 = target.x, y2 = target.y;

/
var traveltime = point_distance(x1, y1, x2, y2) / wpSpd; //Travel time from current enemy x/y
var path = target.path_index; //Path index
var pathlen = path_get_length(path); //Path length
var pathpro = target.path_position; //Path progress
var pathdis = pathlen * pathpro; //Path traveled amount
var pathdisfut = pathdis + (target.path_speed * traveltime); //Path distance future
var pathprofut = pathdisfut / pathlen; //Path progress future

x2 = path_get_x(path, pathprofut); //Future enemy x
y2 = path_get_y(path, pathprofut); //Future enemy y

var targetDir = point_direction(x1, y1, x2, y2); //Direction to point

objToTurn.direction = targetDir;
From the looks of it you are on the right track with some of the right variables, but I don't see the boolean check to fire or not to fire which is important. Thats why your projectiles are firing even if they are too slow or if its too far. Like a spaceship firing at another spaceship, if you know it is impossible to even hit, would you fire? Because it is a non linear path, your turret can only guess with a certain benchmark accuracy and decide whether it wants to fire based on that.

A script event would look something like this. When I wrote this I wrote it with 100% accuracy check in mind, but I commented the parts where you can change if you want to lower the accuracy for more efficiency, meaning the turret might hit the enemy earlier, but might also miss.
Code:
var _faralong = argument0
var _dist = argument1
var _timeenemycompletion = argument2
var _wcs = argument3
var _possible = false
var _xx = 0
var _yy = 0
var _bulletspeed = 12 // You don't want this to be a local variable if you want to pass it into your alarm event
if keyboard_check_pressed(vk_space)
{
    _faralong = obj_enemy.faralongin0and1_
    _dist = point_distance(x, y, obj_enemy.x, obj_enemy.y)
 
    _timeenemycompletion = ((1-_faralong)*obj_enemy.lengthofpath_)/obj_enemy.pathspeed_
 
    _wcs = _dist / (_bulletspeed - obj_enemy.pathspeed_)

  // This below is the part you are missing I think :D

    if _wcs < _timeenemycompletion // Here is where you might want an accuracy check. e.g. if _timeenemycompletion - _wcs > ACCURACY
    {
        _possible = true
    }
    else
    {
        _possible = false
    }
 
    if _possible
    {
// The point you have decided to fire to, 100% accuracy because of absolute check above
         var _pointafterwcs = (_faralong * obj_enemy.lengthofpath_
        + _wcs * obj_enemy.pathspeed_)/obj_enemy.lengthofpath_ + 0.1

// The distance in pixels the enemy is from reaching that point
         var _pointpathdist = (_pointafterwcs - _faralong) * obj_enemy.lengthofpath_
// The distance in steps the enemy is from reaching that point
         var _enemystepstoreach = _pointpathdist / obj_enemy.pathspeed_
 
        _xx = path_get_x(path_random, _pointafterwcs)
        _yy = path_get_y(path_random, _pointafterwcs)
        instance_create_layer(_xx, _yy, "Instances", obj_point_check)
 
        _bullettraveldist = point_distance(x, y, _xx, _yy)
        _delay = _enemystepstoreach - _bullettraveldist/12
        alarm[0] = _delay
    }
}
alarm[0] would be something like
Code:
var inst = instance_create_layer(x, y, "Instances", obj_bullet)
// inst.speed = _bulletspeed <-- only if you want to pass in your bullet speed
inst.direction = point_direction(x, y, _xx, _yy)
You might want to pass in the obj_enemy variables as arguments if you are using a script. I tested yesterday after what I said, but I did it in the step event of my obj_cannon object.

You will also need a obj_enemy which would be simpler and look something like this
Create Event:
Code:
pathspeed_ = 3 // Speed on path
path_start(path_random, pathspeed_, path_action_stop, true) // Start path, here I used a path I created randomly, but any path is fine
lengthofpath_ = path_get_length(path_random)
faralong_ = 0
faralongin0and1_ = 0
Step Event:
Code:
faralong_ += pathspeed_
faralongin0and1_ = faralong_ / lengthofpath_
If you are not passing in bullet speed, your bullet will have a set speed on create
Bullet Create Event:
Code:
speed = 12
It's a rough sketch of how it roughly works, and can probably be optimized, but I tested it yesterday and it works! The only downside is that right now because it always test for the "worst case scenario" if your projectile is too slow or the distance is too far, and it cannot meet the worst case scenario, it will not fire, but you can toggle that with an accuracy variable that allows it to be not so strict on the firing. As of now it will only fire if it 100% knows it can hit!

Sorry if I over explained but this is just what I wrote converting from my pseudocode, not sure if this is exactly what you are looking for but I hope it helps!
 
Last edited by a moderator:
From the looks of it you are on the right track with some of the right variables, but I don't see the boolean check to fire or not to fire which is important. Thats why your projectiles are firing even if they are too slow or if its too far. Like a spaceship firing at another spaceship, if you know it is impossible to even hit, would you fire? Because it is a non linear path, your turret can only guess with a certain benchmark accuracy and decide whether it wants to fire based on that.
Alright, so the reason im not firing a bullet here is because my bullet code simply shoots when an enemy is close, so in my turret code it, it executes my script and then it attempts to shoot a bullet, mostly want this code to be universal, so im not hardcoding it the turret.

Also, what is "wcs_" do if you're just setting in the code after it takes an argument value? I'm not sure I understand this quite well
 
Z

Zachary_tzy

Guest
Alright, so the reason im not firing a bullet here is because my bullet code simply shoots when an enemy is close, so in my turret code it, it executes my script and then it attempts to shoot a bullet, mostly want this code to be universal, so im not hardcoding it the turret.

Also, what is "wcs_" do if you're just setting in the code after it takes an argument value? I'm not sure I understand this quite well
You can place the check into the script with an accuracy argument to make it universal! With 0 being 100% accuracy and anything above reducing the accuracy. This will make the turret shoot only if the enemy is close enough for the turret to hit it. If you don't have an accuracy argument, it will work, and it will just shoot only if it can 100% hit the worst case scenario from when it executes the script. I assume you also have a separate distance check to execute the script? It should still work fine, just remember that you will have a delay before firing the projectile.

A workaround is that you incorporate the delay into the projectile, so before the delay, its speed will be 0 and maybe image_alpha 0, after the delay, it will get its speed and make it visible, this way you won't have to use an alarm and you can create as many shots as you want simultaneously. I can't see where you create the bullet in your original code, probably in the turret, but wherever or however you do, make sure to give it that delay before it fires!

Oops just ignore that argument declaration! I was converting my step event to a script form and messed up. You're right, just declare it when you set it :D

edit: oh I just reread and realized you said your bullet code shoots, does that mean your bullet is the one deciding whether it will fire or not? I think I understand maybe, so what you will have to do is, have your bullet code hold a _delay argument. When you execute your script in your turret code, your script will pass the delay value it got to the bullet it just created. Then have the bullet only move after the delay.
 
Last edited by a moderator:
Z

Zachary_tzy

Guest
This is what my code does
Is this the effect you are trying to achieve? In the video, I press space, and after a short delay, the cannon fires a projectile. Sorry if I'm misunderstanding your question.
 
This is what my code does
Is this the effect you are trying to achieve? In the video, I press space, and after a short delay, the cannon fires a projectile. Sorry if I'm misunderstanding your question.
Yeah actually thats the effect i want, but i want it to just AIM at the x/y value of the enemy when the bullet will hit it, nothing to do with if we shjould decide to shoot or not,mi just want it to AIM at those x and y values, is that what you tried to explain on the code above?
 
This is what my code does
Is this the effect you are trying to achieve? In the video, I press space, and after a short delay, the cannon fires a projectile. Sorry if I'm misunderstanding your question.
Okay, so i tried to implement ur code into a script, but i just keeps aiming at the end of path, this is what it looks like
Code:
/// @arg instance
/// @arg target
/// @arg weapon-speed
var objToMove = argument0, target = argument1, wpSpd = argument2;
var path = target.path_index;
var pathlen = path_get_length(path);
var _faralong = target.path_position
var _dist = point_distance(objToMove.x, objToMove.y, target.x, target.y)
   
var _timeenemycompletion = ((1 - _faralong) * pathlen) / target.path_speed;
   
var _wcs = _dist / (wpSpd - target.path_speed)
   
var _possible = _wcs < _timeenemycompletion;
   
if (_possible) {
    var _pointafterwcs = (_faralong * pathlen + _wcs * pathlen) / pathlen + 0.1
       
    var _pointpathdist = (_pointafterwcs - _faralong) * pathlen
    var _enemystepstoreach = _pointpathdist / target.path_speed
       
    var _xx = path_get_x(path, _pointafterwcs)
    var _yy = path_get_y(path, _pointafterwcs)
   
    objToMove.direction = point_direction(objToMove.x, objToMove.y, _xx, _yy);
}
I just strictly want to aim in the direction, not fire anything else, just aim there, my weapon script will handle the firing and stuff, cause theres a bunch of different weapons ima be making and i cant hardcode them, not even this script will be used all the time, this is mostly for an aimbot turret
 
Z

Zachary_tzy

Guest
Okay, so i tried to implement ur code into a script, but i just keeps aiming at the end of path, this is what it looks like
Code:
/// @arg instance
/// @arg target
/// @arg weapon-speed
var objToMove = argument0, target = argument1, wpSpd = argument2;
var path = target.path_index;
var pathlen = path_get_length(path);
var _faralong = target.path_position
var _dist = point_distance(objToMove.x, objToMove.y, target.x, target.y)
 
var _timeenemycompletion = ((1 - _faralong) * pathlen) / target.path_speed;
 
var _wcs = _dist / (wpSpd - target.path_speed)
 
var _possible = _wcs < _timeenemycompletion;
 
if (_possible) {
    var _pointafterwcs = (_faralong * pathlen + _wcs * pathlen) / pathlen + 0.1
    
    var _pointpathdist = (_pointafterwcs - _faralong) * pathlen
    var _enemystepstoreach = _pointpathdist / target.path_speed
    
    var _xx = path_get_x(path, _pointafterwcs)
    var _yy = path_get_y(path, _pointafterwcs)
 
    objToMove.direction = point_direction(objToMove.x, objToMove.y, _xx, _yy);
}
I just strictly want to aim in the direction, not fire anything else, just aim there, my weapon script will handle the firing and stuff, cause theres a bunch of different weapons ima be making and i cant hardcode them, not even this script will be used all the time, this is mostly for an aimbot turret
May I see the example of your weapon code when it is firing?
 
May I see the example of your weapon code when it is firing?
i mean, it just fires in a straight line, nothing really to it, theres just too many scripts to actually show it, i just simply need to aim to where the bullet will hit the enemy already knowing the bullets speed, which is the variable i give to the script above
 
Z

Zachary_tzy

Guest
i mean, it just fires in a straight line, nothing really to it, theres just too many scripts to actually show it, i just simply need to aim to where the bullet will hit the enemy already knowing the bullets speed, which is the variable i give to the script above
I assume objToMove is your bullet? Where do you instance create it? The issue is probably you are creating it immediately after running the script, besides passing the direction, you will also need to factor in the delay. The way the method I suggested works is that the direction and delay work hand in hand :)

Without the delay you will notice that your projectile always falls just a little short of the target.
Code:
if _possible
   {
// The point you have decided to fire to, 100% accuracy because of absolute check above
        var _pointafterwcs = (_faralong * obj_enemy.lengthofpath_
       + _wcs * obj_enemy.pathspeed_)/obj_enemy.lengthofpath_ + 0.1

// The distance in pixels the enemy is from reaching that point
        var _pointpathdist = (_pointafterwcs - _faralong) * obj_enemy.lengthofpath_
// The distance in steps the enemy is from reaching that point
        var _enemystepstoreach = _pointpathdist / obj_enemy.pathspeed_

       _xx = path_get_x(path_random, _pointafterwcs)
       _yy = path_get_y(path_random, _pointafterwcs) <--- YOUR CODE YOU STOPPED HERE

       _bullettraveldist = point_distance(x, y, _xx, _yy)
       _delay = _enemystepstoreach - _bullettraveldist/12 // <---- BUT YOU ALSO NEED THIS VARIABLE
   }
Therefore in your objToMove I suggest creating it with speed = 0, and adding an alarm[0] event that sets the speed, in the script pass in objToMove.alarm[0] = _delay.

Your objToMove Create Event will look like
Code:
speed = 0
image_alpha = 0 // makes it invisible before it moves
alarm[0] = -1
Your objToMove Alarm[0] Event will look like
Code:
speed = 12
image_alpha = 1 // make it visible
Your script will look like
Code:
/// @arg instance
/// @arg target
/// @arg weapon-speed
var objToMove = argument0, target = argument1, wpSpd = argument2;
var path = target.path_index;
var pathlen = path_get_length(path);
var _faralong = target.path_position
var _dist = point_distance(objToMove.x, objToMove.y, target.x, target.y)
  
var _timeenemycompletion = ((1 - _faralong) * pathlen) / target.path_speed;
  
var _wcs = _dist / (wpSpd - target.path_speed)
  
var _possible = _wcs < _timeenemycompletion;
  
if (_possible) {
   var _pointafterwcs = (_faralong * pathlen + _wcs * pathlen) / pathlen + 0.1
    
   var _pointpathdist = (_pointafterwcs - _faralong) * pathlen
   var _enemystepstoreach = _pointpathdist / target.path_speed
    
   var _xx = path_get_x(path, _pointafterwcs)
   var _yy = path_get_y(path, _pointafterwcs)

   _bullettraveldist = point_distance(x, y, _xx, _yy)
   _delay = _enemystepstoreach - _bullettraveldist/12 // <---- BUT YOU ALSO NEED THIS
  
   objToMove.direction = point_direction(objToMove.x, objToMove.y, _xx, _yy);
   objToMove.alarm[0] = _delay
}
 
Last edited by a moderator:
I assume objToMove is your bullet? Where do you instance create it? The issue is probably you are creating it immediately after running the script, besides passing the direction, you will also need to factor in the delay. The way the method I suggested works is that the direction and delay work hand in hand :)
Okay, so i see where you are coming from, the "objToMove" is actually the turret, its just supposed to AIM at the enemy where it wont miss, the bullet is handled separately, but it is fired after we aim, i want to keep them 100% seperated, as the bullet does not know what it will be hitting cause there will be different turret modes. I also am not a fan of Alarms, u could probably tell that i just need a script that aims at the enemy, kinda like we do when we are shooting projectiles in games, but this takes it an extra step cause it will know where the enemy will be related to its path.
Also just to clarify "target" is the enemy we have targeted from previous code, and the "wpSpd" is the speed of the bullet the turret will fire
I hope this clarifies a bit of what im talking about?

Also, what is this "wcs_" variable? And why do we just randomly add "0.1" to our path length?
 
J

Jordan Robinson

Guest
In case you are interested, or for other people reading this thread in the future. I made a script that handles exactly this with a lot of customisability. It's free to download from the GameMaker Marketplace here. Just a simple script, very easy to add to your project.
 
Z

Zachary_tzy

Guest
Okay, so i see where you are coming from, the "objToMove" is actually the turret, its just supposed to AIM at the enemy where it wont miss, the bullet is handled separately, but it is fired after we aim, i want to keep them 100% seperated, as the bullet does not know what it will be hitting cause there will be different turret modes. I also am not a fan of Alarms, u could probably tell that i just need a script that aims at the enemy, kinda like we do when we are shooting projectiles in games, but this takes it an extra step cause it will know where the enemy will be related to its path.
Also just to clarify "target" is the enemy we have targeted from previous code, and the "wpSpd" is the speed of the bullet the turret will fire
I hope this clarifies a bit of what im talking about?

Also, what is this "wcs_" variable? And why do we just randomly add "0.1" to our path length?
edit:
I'm dumb, I just needed convert the delay to dist and factor it into the script, you may find it a little more in accurate like maybe by a tiny bit because
Code:
  // This below is the part you are missing I think :D

    if _wcs < _timeenemycompletion // Here is where you might want an accuracy check. e.g. if _timeenemycompletion - _wcs > ACCURACY
    {
        _possible = true
    }
    else
    {
        _possible = false
    }

    if _possible
    {
// The point you have decided to fire to, 100% accuracy because of absolute check above
         var _pointafterwcs = (_faralong * obj_enemy.lengthofpath_
        + _wcs * obj_enemy.pathspeed_)/obj_enemy.lengthofpath_ + 0.1

// The distance in pixels the enemy is from reaching that point
         var _pointpathdist = (_pointafterwcs - _faralong) * obj_enemy.lengthofpath_
// The distance in steps the enemy is from reaching that point
         var _enemystepstoreach = _pointpathdist / obj_enemy.pathspeed_


_bullettraveldist = point_distance(x, y, _xx, _yy) // SHIFT THESE TWO UP
        _delay = _enemystepstoreach - _bullettraveldist/12

    var additionaldist = _delay * obj_enemy.pathspeed_ / obj_enemy.lengthofpath // ADD THESE TWO LINES IN
    _pointafterwcs -= additionaldist

        _xx = path_get_x(path_random, _pointafterwcs)
        _yy = path_get_y(path_random, _pointafterwcs)

 
 
    }
}
Now there's no delay. Might sometimes be a fraction of a pixel inaccurate because I suspect the calculation is not optimize enough in that it takes away too many decimal values from the rounding too many times? Maybe :)
Just ignore everything below about the time needed if you don't want to know how the calculation is done. Now the script has factored in the time as distance too.

------
before edit:

Hmm at least to my knowledge, it is impossible to take aim at an enemy on a random non linear path where it WON'T miss if you don't want to know where the enemy will be relatative to its path. If you don't want to miss, that step is necessary. If you don't want to miss, you need to know the path, because the enemy can move any direction at any point in time for a non linear path.

Imagine your turret is an officer on a spaceship, he is in charge of aiming the spaceship at the enemy. What he needs to do it, tell the spaceship where to aim (angle) AND tell the spaceship when to shoot. But now you want it separate, so you need another officer, officer2, to tell your spaceship when to shoot. Your script is officer1 which tells it where to aim, but you don't have officer2 to tell it when to shoot? All you need to do is to either make your bullet officer2 to tell itself when to shoot, or create another object to be officer2 to shoot all the bullets. All this is NEEDED if you don't want to miss hitting a target on a random non linear path, at least to my knowledge.

Your original script is correct in taking aim at the enemy. But you noticed it always falls a little short of the enemy, because officer2 is missing. If you just want you turret to AIM at the enemy, it is already doing so.

wcs_ means "worst case scenario", which means for a non linear path, what is the worst possible amount of time it would take to hit the enemy at a point along the path, and that worst possible scenario is if the enemy is travelling directly away from the projectile.
IF the projectile is able to hit the enemy at the worst case scenario, it will be able to hit the enemy at a point on path anywhere after the worst case scenario point. It is the logic behind getting 100% accuracy to hit a random non linear moving enemy.
The 0.1 I added is just an example. If my wcs_ point is 0.7, you will have to fire at any point after 0.7 that is why I added 0.1, you could also do 0.7 + 0.01 or 0.7 + 0.3 and it will also work. As long as it is above 0.7.
However, you COULD technically use 0.7 but the rounding of numbers made by gamemaker might affect the true value and hence why it is better to use >0.7.
IF you use anywhere below 0.7, for example 0.65, it MIGHT still hit, assuming the enemy did not make a worse case scenario maneuver which is travelling directly away from the projectile. The lower you go from 0.7 the higher the chance to miss. With 0 being a complete miss unless the enemy is travelling directly towards your projectile.

This wcs step is for optimization, you can technically search through every point till you find apossible point like a O(n) search however for VERY long paths it might get too tedious. With the wcs, you can get the desired point in 1 step an O(1) which is very fast even for long paths.

All these calculations are to HIT an enemy on a RANDOM NON linear path. To my knowledge, you need BOTH Direction AND Time to achieve. I do not think you can calculate a 100% hit on an object with random angular velocity (random non linear path) with just direction alone.

However, if you just want to aim and fire at a location relative to the velocity the enemy was moving at at that point in time? If that is the case then it is predicting a LINEAR PATH and firing at a linear velocity, and @Jordan Robinson's script will fit your requirements perfectly.

Sorry I might have misunderstood your original question incorrectly, I assumed you wanted to HIT an enemy moving on a non linear path, but it seems like you just wanted to fire at an enemy relative to his current linear velocity at that given time. That would technically still be a linear path calculation that was why I got confused. :(

If you still want to use the code I provided and just want to JUST AIM and fire without the time calculation, increase the 0.1 value, that way it will know to shoot further ahead. This may be what you want instead. BUT it is not a guaranteed hit.

And alarms are the simplest way to execute code after a certain amount of time in game. Unless you want to manually count the steps yourself which would be like an alarm but just manually.
 
Last edited by a moderator:
edit:
I'm dumb, I just needed convert the delay to dist and factor it into the script, you may find it a little more in accurate like maybe by a tiny bit because
Alright, maybe i'm just not explaining my self well enough here, I simply just need to aim at a target, taking into account the turrets weapon speed, and thats it, I dont want the script to shoot at the target. The turret will be executing this script when the turret has an enemy in sight, nothing more, the script that @Jordan Robinson described is kinda simple to do if you want that functionality, but it doesn't handle any paths so it wont work when an enemy is turning a corner, so yeah useful but not the effect im looking for.

The script I have has these inputs "instance" the instance to change the direction of. "target" the target we are aiming at that is on a path. and last "weapon speed" the speed of the bullet the tower will fire, thats it. i dont get why we need to fire it in the aiming code.

Also, what does this do in the example u gave above?
Code:
_bullettraveldist = point_distance(x, y, _xx, _yy) // SHIFT THESE TWO UP
_delay = _enemystepstoreach - _bullettraveldist/12
why are you calculating the last position we are shooting at, also, i think im lost on the whole _delay variable, is it how much we should delay from firing the bullet or what? cause ur variables arent really descriptive here.

P.S: Sorry if i dont understand all this, I just want one script that doesnt save any variables, i just simply want it to point to the direction it will hit its target and nothing more. Basically plug and play script. Thats how most of my code is done, very clean and very dynamic

This is my current code, could we work off of this? So we can be on the same page :) (Could we also comment on what everything does too)
Code:
/// @arg instance
/// @arg target
/// @arg weapon-speed
var objToMove = argument0, target = argument1, wpSpd = argument2;
var path = target.path_index;
var pathlen = path_get_length(path);
var _faralong = target.path_position
var _dist = point_distance(objToMove.x, objToMove.y, target.x, target.y)
   
var _timeenemycompletion = ((1 - _faralong) * pathlen) / target.path_speed;
   
var _wcs = _dist / (wpSpd - target.path_speed)
   
var _possible = _wcs < _timeenemycompletion;
   
if (_possible) {
    var _pointafterwcs = (_faralong * pathlen + _wcs * pathlen) / pathlen + 0.1
       
    //var _pointpathdist = (_pointafterwcs - _faralong) * pathlen
    //var _enemystepstoreach = _pointpathdist / target.path_speed
       
    var _xx = path_get_x(path, _pointafterwcs)
    var _yy = path_get_y(path, _pointafterwcs)
   
    objToMove.direction = point_direction(objToMove.x, objToMove.y, _xx, _yy);
       
    //var _bullettraveldist = point_distance(x, y, _xx, _yy)
    //_delay = _enemystepstoreach - _bullettraveldist / wpSpd
}
 
Z

Zachary_tzy

Guest
Alright, maybe i'm just not explaining my self well enough here, I simply just need to aim at a target, taking into account the turrets weapon speed, and thats it, I dont want the script to shoot at the target. The turret will be executing this script when the turret has an enemy in sight, nothing more, the script that @Jordan Robinson described is kinda simple to do if you want that functionality, but it doesn't handle any paths so it wont work when an enemy is turning a corner, so yeah useful but not the effect im looking for.

The script I have has these inputs "instance" the instance to change the direction of. "target" the target we are aiming at that is on a path. and last "weapon speed" the speed of the bullet the tower will fire, thats it. i dont get why we need to fire it in the aiming code.

Also, what does this do in the example u gave above?
Code:
_bullettraveldist = point_distance(x, y, _xx, _yy) // SHIFT THESE TWO UP
_delay = _enemystepstoreach - _bullettraveldist/12
why are you calculating the last position we are shooting at, also, i think im lost on the whole _delay variable, is it how much we should delay from firing the bullet or what? cause ur variables arent really descriptive here.

P.S: Sorry if i dont understand all this, I just want one script that doesnt save any variables, i just simply want it to point to the direction it will hit its target and nothing more. Basically plug and play script. Thats how most of my code is done, very clean and very dynamic

This is my current code, could we work off of this? So we can be on the same page :) (Could we also comment on what everything does too)
Code:
/// @arg instance
/// @arg target
/// @arg weapon-speed
var objToMove = argument0, target = argument1, wpSpd = argument2;
var path = target.path_index;
var pathlen = path_get_length(path);
var _faralong = target.path_position
var _dist = point_distance(objToMove.x, objToMove.y, target.x, target.y)
 
var _timeenemycompletion = ((1 - _faralong) * pathlen) / target.path_speed;
 
var _wcs = _dist / (wpSpd - target.path_speed)
 
var _possible = _wcs < _timeenemycompletion;
 
if (_possible) {
    var _pointafterwcs = (_faralong * pathlen + _wcs * pathlen) / pathlen + 0.1
 
    //var _pointpathdist = (_pointafterwcs - _faralong) * pathlen
    //var _enemystepstoreach = _pointpathdist / target.path_speed
 
    var _xx = path_get_x(path, _pointafterwcs)
    var _yy = path_get_y(path, _pointafterwcs)
 
    objToMove.direction = point_direction(objToMove.x, objToMove.y, _xx, _yy);
 
    //var _bullettraveldist = point_distance(x, y, _xx, _yy)
    //_delay = _enemystepstoreach - _bullettraveldist / wpSpd
}
Haha it's ok, I am quite happy to help as it is pretty interesting to me as well.
_delay is the step difference between the enemy reaching the point, and the projectile reaching the point. Because the enemy and projectile both travels at different speeds!
Hmm I now know what you want but there is a problem, because I calculate the delay after I calculate the point, give me awhile to think.

First of all when I refer to points I mean the percentage along the path in 0 - 1. For example a target at point of 0.2 would mean the target is 20% along the distance of the path in pixels.
Code:
//var _pointpathdist = (_pointafterwcs - _faralong) * pathlen // This subtracts the initial point from the safe point we have calculated above to get the distance in points needed to travel
   //var _enemystepstoreach = _pointpathdist / target.path_speed // This converts the points into steps relative to the target's speed
    
   var _xx = path_get_x(path, _pointafterwcs)
   var _yy = path_get_y(path, _pointafterwcs)
  
   objToMove.direction = point_direction(objToMove.x, objToMove.y, _xx, _yy);
    
   //var _bullettraveldist = point_distance(x, y, _xx, _yy) // This get distance in pixels the projectile needs to travel to reach the planned coords
   //_delay = _enemystepstoreach - _bullettraveldist / wpSpd // This is the step different between when the target will reach and when the bullet will reach
Basically we are working with 3 different types of values, points, pixels, and steps, and we manipulate them to get what we want.
 
Last edited by a moderator:
Haha it's ok, I am quite happy to help as it is pretty interesting to me as well.
_delay is the step difference between the enemy reaching the point, and the projectile reaching the point. Because the enemy and projectile both travels at different speeds!
You are very close to achieving what you want.
This should be your script, just call it in a step event and your turret will be continuously pointing in the right direction! Please let me know if it works!
This I knew it would error out, is it important to know the previous _xx and _yy? Because here:
Code:
var _bullettraveldist = point_distance(x, y, _xx, _yy)
"_xx" and "_yy" are not declared until after we calculate the delay and add to "_pointafterwcs"
Is it possible to declare "_bullettraveldist" after the fact? or can we just take the current enemies x and y values?
 
B

blandanablandana

Guest
This I knew it would error out, is it important to know the previous _xx and _yy? Because here:
Code:
var _bullettraveldist = point_distance(x, y, _xx, _yy)
"_xx" and "_yy" are not declared until after we calculate the delay and add to "_pointafterwcs"
Is it possible to declare "_bullettraveldist" after the fact? or can we just take the current enemies x and y values?
you could possibly add an invisible sprite in front of or behind your enemies that is parented (or receives x and y data + or - a certain amount front the enemy sprite) to them and randomly focus on those instead of the enemies (that way if you're worried about aiming in front of the enemy, you can make two sprites on either side and focus on either one depending on the enemy's direction. I found this works as a solution for this sort of scenario. I'm just a beginner but I tend to think a bit differently. If this idea doesn't help don't worry about it, but I thought I'd just throw it out there in case you implement it and it actually works better than just math. (even though I've taken calculus 3, there are some times where just a "stupid" idea sort of works better sometimes lol.

I figure if you do this the missiles or projectiles can still collide with your enemy sprite even if they are focusing on a target that is in front of it.
 
Last edited by a moderator:
Z

Zachary_tzy

Guest
This I knew it would error out, is it important to know the previous _xx and _yy? Because here:
Code:
var _bullettraveldist = point_distance(x, y, _xx, _yy)
"_xx" and "_yy" are not declared until after we calculate the delay and add to "_pointafterwcs"
Is it possible to declare "_bullettraveldist" after the fact? or can we just take the current enemies x and y values?
Edit:
I got it! Just call this script, done and done!
Code:
var target = argument0 // Target to aim at
var weaponSpeed = argument1 // Projectile speed

if instance_exists(target)
{
    // How far in percentage the target is along the path, between 0 - 1
    var _faralong = target.faralongin0and1_
 
    // How far the calling instance is from the target in pixels
    var _dist = point_distance(x, y, target.x, target.y)
 
    // How long in steps will the enemy take to complete the path
    var _timeenemycompletion = ((1-_faralong)*target.lengthofpath_)/target.pathspeed_
 
    // The longest possible time in steps the projectile might take to hit the target
    var _wcs = _dist / (weaponSpeed - target.pathspeed_)
 
    // The check to see if the projectile can hit the target with a 100% chance
    if _wcs < _timeenemycompletion
    {
        var _possible = true // If possible to hit it with a 100% chance
    }
    else
    {
        _possible = false // If not possible to hit it with a 100% chance
    }
    
    if _possible
    {
        // The point you have decided to fire to, 100% accuracy because of absolute check above
        // Point is the percentage along the path between 0 - 1. E.g. 0.4
        var _pointafterwcs = (_faralong * target.lengthofpath_
               + _wcs * target.pathspeed_)/target.lengthofpath_ + 0.1
    
        // The distance in pixels the enemy is from reaching that point
        var _pointpathdist = (_pointafterwcs - _faralong) * target.lengthofpath_
    
        // The distance in steps the enemy is from reaching that point
        var _enemystepstoreach = _pointpathdist / target.pathspeed_
    
        // The distance in pixels the projectile is from reaching the point
        if variable_instance_exists(id,"_xx") && variable_instance_exists(id,"_yy")
        {
            var _bullettraveldist = point_distance(x, y, _xx, _yy)
        }
        else
        {
            variable_instance_set(id,"_xx",0)
            variable_instance_set(id,"_yy",0)
            var _bullettraveldist = point_distance(x, y, _xx, _yy)
        }    
    
        // The time in steps between the enemy reaching the point and the projectile reaching the point
        var _delay = _enemystepstoreach - _bullettraveldist/12
    
        // Getting the new point after offsetting the time
        _pointafterwcs -= _delay * obj_enemy.pathspeed_ / obj_enemy.lengthofpath_
    
        // Getting coordinates to aim at
        _xx = path_get_x(path_random, _pointafterwcs)
        _yy = path_get_y(path_random, _pointafterwcs)
    
        // Getting angle to aim at
        direction = point_direction(x, y, _xx, _yy)
    }
}
Something cool ~
------
Before Edit:

Yes, after much thought I for now can't think of a solution without storing a persistent _xx and _yy. Maybe you could compromise and initiate _xx = 0 and _yy = 0 in the create event of objects that you want to run the script in? If so, the completed script will look like this:
Code:
var target = argument0 // Target to aim at
var weaponSpeed = argument1 // Projectile speed

if instance_exists(target)
{
    // How far in percentage the target is along the path, between 0 - 1
    var _faralong = target.faralongin0and1_
 
    // How far the calling instance is from the target in pixels
    var _dist = point_distance(x, y, target.x, target.y)
 
    // How long in steps will the enemy take to complete the path
    var _timeenemycompletion = ((1-_faralong)*target.lengthofpath_)/target.pathspeed_
 
    // The longest possible time in steps the projectile might take to hit the target
    var _wcs = _dist / (weaponSpeed - target.pathspeed_)
 
    // The check to see if the projectile can hit the target with a 100% chance
    if _wcs < _timeenemycompletion
    {
        var _possible = true // If possible to hit it with a 100% chance
    }
    else
    {
        _possible = false // If not possible to hit it with a 100% chance
    }
 
    if _possible
    {
        // The point you have decided to fire to, 100% accuracy because of absolute check above
        // Point is the percentage along the path between 0 - 1. E.g. 0.4
        var _pointafterwcs = (_faralong * target.lengthofpath_
               + _wcs * target.pathspeed_)/target.lengthofpath_ + 0.1
 
        // The distance in pixels the enemy is from reaching that point
        var _pointpathdist = (_pointafterwcs - _faralong) * target.lengthofpath_
 
        // The distance in steps the enemy is from reaching that point
        var _enemystepstoreach = _pointpathdist / target.pathspeed_
 
        // The distance in pixels the projectile is from reaching the point
        var _bullettraveldist = point_distance(x, y, _xx, _yy)
 
        // The time in steps between the enemy reaching the point and the projectile reaching the point
        var _delay = _enemystepstoreach - _bullettraveldist/12
 
        // Getting the new point after offsetting the time
        _pointafterwcs -= _delay * obj_enemy.pathspeed_ / obj_enemy.lengthofpath_
 
        // Getting coordinates to aim at
        _xx = path_get_x(path_random, _pointafterwcs)
        _yy = path_get_y(path_random, _pointafterwcs)
 
        // Getting angle to aim at
        direction = point_direction(x, y, _xx, _yy)
    }
}
Initiate _xx = 0 and _yy = 0 in your create event. Call the script in your step event. And its done, it will look something like:
You could have any object that wants to call the script be a parent of an object with _xx and _yy initiated, that would be very clean, neat and dynamic.

Because tracking a random non linear path is a little more complicated, for now I can't think of a better solution. I thought it would be possible if scripts could somehow instantiate the calling instance variable, but I did a quick google search and could not find any answers. Maybe in gms only the instance can instantiate its own variables.

Sorry if I couldn't find you a better solution :(
 
Last edited by a moderator:
J

Jordan Robinson

Guest
What about this: in theory it should work but it might be a little slow.

In the script, have a loop which temporarily moves the target instance forward through the path by the distance moved in 1 step and keep a track of how many steps it has moved. Each time this while loop executes, divide the distance between the new position and the spawn location of the bullet by the bullet speed to see if the game steps for the bullet to hit the target is the same as the steps for the target to get to that position on the path. If it is the same then return the direction to that target position.


This code works, but it is very rushed so you can probably improve it a lot. It follows the logic of my theory above. Have a play with it.


Code:
///angle_to_intercept_path()

/*
    This script will return the angle in order to hit a target moving along a given path
*/

//get arguments
var target          = argument0;
var bullet_speed    = argument1;

//return angle
angle = -1; //-1 by default for error checking

//calculate required information
var path = target.path_index;

var path_step_pos = target.path_speed / path_get_length(path); //percentage of path travelled per step. 1 = 100%

//this is the starting position of the target instance on the path at the time the script is called
var path_pos = target.path_position;
var xx = path_get_x(path, path_pos);
var yy = path_get_y(path, path_pos);

var n = 1; //start step 1

while(n < 240) //number of steps allowed to check for
{
    path_pos += path_step_pos; //move one step into the future
    xx = path_get_x(path, path_pos);
    yy = path_get_y(path, path_pos);
  
    //check if the time for the bullet to reach this position is the same as for the target to reach it
    var bullet_dist = point_distance(x, y, xx, yy);
    var bullet_time = bullet_dist / bullet_speed; //in steps
  
    if(bullet_time > n - 1 && bullet_time < n + 1) //needs some wiggle room because it's unlikely that it will match exactly
    {
        angle = point_direction(x, y, xx, yy);
        break; //break out of loop early
    }
  
    n++; //increase the current step
}

return angle;
 
Last edited by a moderator:
Z

Zachary_tzy

Guest
What about this: in theory it should work but it might be a little slow.

In the script, have a loop which temporarily moves the target instance forward through the path by the distance moved in 1 step and keep a track of how many steps it has moved. Each time this while loop executes, divide the distance between the new position and the spawn location of the bullet by the bullet speed to see if the game steps for the bullet to hit the target is the same as the steps for the target to get to that position on the path. If it is the same then return the direction to that target position.


This code works, but it is very rushed so you can probably improve it a lot. It follows the logic of my theory above. Have a play with it.


Code:
///angle_to_intercept_path()

/*
    This script will return the angle in order to hit a target moving along a given path
*/

//get arguments
var target          = argument0;
var bullet_speed    = argument1;

//return angle
angle = -1; //-1 by default for error checking

//calculate required information
var path = target.path_index;

var path_step_pos = target.path_speed / path_get_length(path); //percentage of path travelled per step. 1 = 100%

//this is the starting position of the target instance on the path at the time the script is called
var path_pos = target.path_position;
var xx = path_get_x(path, path_pos);
var yy = path_get_y(path, path_pos);

var n = 1; //start step 1

while(n < 240) //number of steps allowed to check for
{
    path_pos += path_step_pos; //move one step into the future
    xx = path_get_x(path, path_pos);
    yy = path_get_y(path, path_pos);
 
    //check if the time for the bullet to reach this position is the same as for the target to reach it
    var bullet_dist = point_distance(x, y, xx, yy);
    var bullet_time = bullet_dist / bullet_speed; //in steps
 
    if(bullet_time > n - 1 && bullet_time < n + 1) //needs some wiggle room because it's unlikely that it will match exactly
    {
        angle = point_direction(x, y, xx, yy);
        break; //break out of loop early
    }
 
    n++; //increase the current step
}

return angle;
That is actually a decent idea! When I first read your question at a cafe, I had my cousin with me. He is not a programmer, so I gave him the variables that were available and asked him how he would solve it. The first answer he gave to me was to search through every point in the path till a point was found that would satisfy the turret being able to hit it and have the turret fire. It is kind of similar to the solution you have provided!

It is by no means a bad solution, but if I am reading the code right, your script will be calling the path_get_x and y functions approx 240 times to predict 240 steps in advance! 240 in the grandscale of things is not a very large number to check for, but! When building algorithms, there is something called a big o notation. It just means that as your data goes to infinity, in this case I think it would be is the distance between the turret and the target goes to infinity and the speed of your projectile drops to near 0, your number 240 would have to increased proportionately for a longer path check to take into consideration the longer distance the projectile has to fire. You solution would be as O(n), a sequential search, which is why you might notice it to be a little taxing on processing as you add more turrets! Now that I think about it searching for a satisfactory point in a path is kind of like search for data through a data structure.

There are pros and cons of course! While your solution is an O(n) search, it can potentially be way more accurate then the solution I provided in the sense that it does not have to guess a point using a worst case scenario kind of thing. While my solution on the other being an O(1) it uses the worst case scenario to immediately pin point 1 point every time the script is executed, but in turn is missing out on all the possibilities that it could've fired in advance, think of it like my code being a pessimist while your code is a realist.

Whichever script you choose to use, it really depends on the kind of game you are going for! How long is your path? How far is your target? and what is your turret's inherent behavior? Pin point firing times sacrificing efficiency vs guessing efficiently while sacrificing pin point firing times. Both are workable solutions, they just do different things! Regardless, I'm glad you have also found a solution on your own! :D

ps: in case you missed it, I have edited my previous comment with the completed script! Just one script a one a done deal!
 
J

Jordan Robinson

Guest
That is actually a decent idea! When I first read your question at a cafe, I had my cousin with me. He is not a programmer, so I gave him the variables that were available and asked him how he would solve it. The first answer he gave to me was to search through every point in the path till a point was found that would satisfy the turret being able to hit it and have the turret fire. It is kind of similar to the solution you have provided!

It is by no means a bad solution, but if I am reading the code right, your script will be calling the path_get_x and y functions approx 240 times to predict 240 steps in advance! 240 in the grandscale of things is not a very large number to check for, but! When building algorithms, there is something called a big o notation. It just means that as your data goes to infinity, in this case I think it would be is the distance between the turret and the target goes to infinity and the speed of your projectile drops to near 0, your number 240 would have to increased proportionately for a longer path check to take into consideration the longer distance the projectile has to fire. You solution would be as O(n), a sequential search, which is why you might notice it to be a little taxing on processing as you add more turrets! Now that I think about it searching for a satisfactory point in a path is kind of like search for data through a data structure.

There are pros and cons of course! While your solution is an O(n) search, it can potentially be way more accurate then the solution I provided in the sense that it does not have to guess a point using a worst case scenario kind of thing. While my solution on the other being an O(1) it uses the worst case scenario to immediately pin point 1 point every time the script is executed, but in turn is missing out on all the possibilities that it could've fired in advance, think of it like my code being a pessimist while your code is a realist.

Whichever script you choose to use, it really depends on the kind of game you are going for! How long is your path? How far is your target? and what is your turret's inherent behavior? Pin point firing times sacrificing efficiency vs guessing efficiently while sacrificing pin point firing times. Both are workable solutions, they just do different things! Regardless, I'm glad you have also found a solution on your own! :D

ps: in case you missed it, I have edited my previous comment with the completed script! Just one script a one a done deal!
I concur. The script I provided has more than a few parts that could be heavily optimised and what you pointed out is definitely one of those. The script will break the loop once it finds the correct angle so potentially it may never reach 240. The other issue is that comparing the time for the target to reach a given position is difficult to match to the bullet given that it’s moving in steps and not a continuous timeline. All things to consider. I suppose it really comes down to what situation you’re trying to resolve. Hopefully we have given the OP enough of an idea of how to solve this in the most efficient way.

EDIT:
In fact you could further optimise my script by making an estimate of how long it would take the bullet to get there and cut out possibly a lot of the first iterations of the loop. For example if we know it is about 30 steps for the bullet to reach the target, you could start at 30 steps in the future and then resume the original code
 
Z

Zachary_tzy

Guest
I concur. The script I provided has more than a few parts that could be heavily optimised and what you pointed out is definitely one of those. The script will break the loop once it finds the correct angle so potentially it may never reach 240. The other issue is that comparing the time for the target to reach a given position is difficult to match to the bullet given that it’s moving in steps and not a continuous timeline. All things to consider. I suppose it really comes down to what situation you’re trying to resolve. Hopefully we have given the OP enough of an idea of how to solve this in the most efficient way.

EDIT:
In fact you could further optimise my script by making an estimate of how long it would take the bullet to get there and cut out possibly a lot of the first iterations of the loop. For example if we know it is about 30 steps for the bullet to reach the target, you could start at 30 steps in the future and then resume the original code
I honestly replied to your previous comment mistaking you for the op haha. Indeed! Hopefully OP has a general idea of the possibilities open to him. I love questions like these where there can be many different answers, and learning from others! Thanks for participating in this thread and sharing your insight too :D, I learnt quite a lot from this thread, hopefully now it can be solved!
 
Top