@Vito_Curse,
I'm glad your issue got solved!
However, the solution you're using is inaccurate.
@flyingsaucerinvasion,
You don't know what you wrote, but it is very clear though.
Yet, your code makes the same mistake I addressed in the link I provided in my first post on this thread.
You're using calculations for a continuous model, whereas GameMaker isn't continuous, but works in discrete steps.
Your code makes the assumption X and Y (the positions of the projectile) in function of time can be described by:
X(t) = x + hspeed * t
Y(t) = y + vspeed * t + gravity / 2 * t²
That's already wrong.
The error of this model will become larger as the projectile continues its path.
You then go on to assume hspeed won't be 0, which is often a safe assumption, but can be fatal sometimes.
Using that assumption, you write the time and the Y coordinate of the projectile in function of the X coordinate.
t(X) = (X - x) / hspeed
Y(X) = y + (X - x) * vspeed / hspeed + gravity / 2 * (X - x)² / hspeed²
You now define a new variable d, which is the tangens of the direction the arow goes to.
Again, you assume hspeed won't be 0 here.
d = vspeed / hspeed
Using this, you rewrite the above formula as follows:
Y(X) = y + (X - x) * d + gravity / 2 * (X - x)² * (1 + d²) / speed²
= (gravity / 2 * (X - x)² / speed²) d² + (X - x) d + (y + gravity / 2 * (X - x)² / speed²)
<=> (gravity / 2 * (X - x)² / speed²) d² + (X - x) d + ((y - Y) + gravity / 2 * (X - x)² / speed²) = 0
=> (gravity / 2 * (X - x)) d² + (speed²) d + (speed² * (y - Y) / (X - x) + gravity / 2 * (X - x)) = 0
In case you don't know, the equation of pythagoras gives us:
hspeed² + vspeed² = speed²
=> hspeed² = speed² / (1 + d²)
Which is the reason the first step in rewriting the formula is valid.
You now want that when the projectile has the target's X coordinate, it will also have the target's Y coordinate.
So, you can fill this in in: (gravity / 2 * (X - x)) d² + (speed²) d + (speed² * (y - Y) / (X - x) + gravity / 2 * (X - x)) = 0
and you then get a quadratic equation in d, which you let your code solve in this part:
Code:
var _x = mouse_x - x;
var _y = y - mouse_y;
var _v = 15; //projectile speed
var _v2 = _v * _v;
var _g = 0.3; //gravitational acceleration (0.3 pixels per step per step)
//--------------------------------------------------------
var _a = _v2 * _v2 - _g * (_g * _x * _x + 2 * _y * _v2);
if (_a > 0) {
//target is within range if _a > 0
if (low_arc) { var _b = -(_v2 - sqrt(_a)) / (_g * _x); }
else { var _b = -(_v2 + sqrt(_a)) / (_g * _x); }
However, you clearly treat 2 cases wrongly there.
The if condition shouldn't be _a > 0, but rather _a >= 0, as the target is also in range if a = 0.
However, you need to make sure to perform this check with math_set_epsilon(0), as the default epsilon is too fuzzy and can lead to an error.
Of course, you'll also need to restore the math_set_epsilon to its previous value afterwards with the help of math_get_epsilon.
And the second case you treat wrongly, is again the case that hspeed = 0 or x = mouse_x,
which will also throw an error in your face.
Now that you have a value for d, you calculate hspeed and vspeed out of it using this formula again:
hspeed² = speed² / (1 + d²)
Here you also assume speed to be positive, so you can rewrite it to:
abs(hspeed) = speed / sqrt(1 + d²)
To decide the sign of hspeed, you just take the sign of mouse_x - x, so that the projectile will move towards the target.
Finally, you use the definition of d again to calculate the value of vspeed:
vspeed = hspeed * d
This all is what you do here:
Code:
var _c = 1 / _b;
var _m = sign(_x * _b) * _v / sqrt(1 + _c * _c);
var _hsp = _c * _m;
var _vsp = _m;
A couple of further notes:
Even though your method starts from a wrong model, if you just replace it at the start with the correct model:
X(t) = x + hspeed * t
Y(t) = y + (vspeed + gravity / 2) * t + gravity / 2 * t²
And you apply the changes in every other step in my explenation,
you will get a result that looks a lot like your code.
Also, as someone who had to here it so many times at university,
your code to solve the quadratic equation isn't always very precise with respect to the size of the mantissa of the number representation your device uses.
You can find more on how it can be done better here:
https://people.csail.mit.edu/bkph/articles/Quadratics.pdf
I'm also pretty sure the way you calculate _m can be done more precise when _b nears 0.
Having said all of this, I must admit that this approach does give code that is very likely to be a bit faster and quite a bit shorter than what my approach gives.
I suggest to the OP that he uses a corrected version of your suggestion.
@Vito_Curse,
I'm guessing you've read the above as well.
If you don't know how to apply the fixes I mentioned, feel free to ask for help.
If you still want me to explain my original approach in more depth, feel free to ask about that as well.