I’m currently trying to achieve an algorithm that utilises FastCast to make a sort of aimbot for NPC using a firearm, the algorithm would return a unit directional vector calculated from a constant magnitude for the projectile’s initial velocity, its starting point and its goal
for this, I was following Suphi’s projectile system tutorial and managed to apply his logic into the FastCast module however I’m struggling to figure out how I would alter his equations so that the resultant vector is a directional vector that still hits the target vector alongside the constant magnitude
here is what i got “working”:
local function Fire(Goal: Vector3, Origin: Vector3)
local O2GDirection = (Goal - Origin)
local dir: Vector3 = O2GDirection
+ Vector3.new(0, BULLETDROP * .5)
local magnitude = dir.Magnitude / BULLETVELOCITY
dir = O2GDirection / magnitude
+ Vector3.new(0, BULLETDROP * magnitude * .5)
Caster:Fire(Origin, dir.Unit, BULLETVELOCITY, CastBehaviour)
end
using his logic for constant projectile travel time I attempted to alter it for a constant velocity instead, but this algorithm is only really accurate at distances around 50-350 studs and has a bunch of other issues
tl;dr this code:
local function Fire(Goal: Vector3, Origin: Vector3)
local O2GDirection = (Goal - Origin)
local dir: Vector3 = O2GDirection / Duration
+ Vector3.new(0, BULLETDROP * Duration * .5)
Caster:Fire(Origin, dir.Unit, dir.Magnitude, CastBehaviour)
end
but instead of the projectile travel time “Duration” being constant, the projectile initial velocity should be constant instead like you would expect from a firearm
bumping, always forget how competitive it is to get a response in this channel, as usual if you want to respond but dont understand something in the original post please lmk because a confused reply is better than none
The reason it’s not getting replies is most likely because people don’t want to comment on something they don’t know well (like me). But ill try to reason with you, do you want the projectile to basically be directed at the target?
precisely! the second code snippet comes from a video i found from a creator named “Suphi”, and in his video he uses that equation to make a projectile always fly from the start point to finish. my issue is that his code works so that the ball will ALWAYS fly in the air for x amount of seconds before reaching the finish, whereas i want to change it so that it ALWAYS starts moving at the same speed, but ends up reaching the goal if possible.
you can imagine the difference like between a baseball pitcher who can throttle their throw so that it flies quickly or slowly past the batter, compared to a sniper which would always expect the bullet to leave the gun at the same speed and travel for however long before hitting their target.
I think you’re not getting much response for a few reasons, especially:
People are not sure what FastCast is, or what Caster:Fire expects, so it’s difficult to know if this change is valid.
Your explanation of the problem is vague:
i.e., it’s hard to know how to suggest a correction when the problem is stated as “has a bunch of issues”. We kinda need to know exactly how it’s broken
There are a lot of factors here. Are either the shooter or target (or both) moving? Is client-server sync possibly part of the issue? Are long range misses just because you’re not accounting for target/shooter relative velocity (shooter not leading the target). Details like that.
I mean I assumed FastCast was generally wellknown and/or my variable names were somewhat clear, but i guess both people were unsure of it so heres the API doc explanation; @ModernWarSciFite
I left the line of code for actually firing the projectile and seeing if the values were correct in the code snippet, but i guess i should’ve abstracted the function to just return the direction and magnitude instead
the first code snippet i gave, my code, is broken because the magnitude of “dir” is still inconsistent so although dir.Magnitude is what will cause the projectile to land correctly every time, using the “BULLETVELOCITY” constant will instead cause it to typically undershoot the Goal by exponentially greater lengths
currently both vectors/points are stationary and being ran on the server, so I can guarantee it is solely the algorithm miscalculating the vector direction and no other factors
i’ll test this solution when i return home but this seems similar to the solution i tried to write + when i asked ChatGPT to see if it understood the issue it seemed to make the same mistake as me so maybe all 3 of us are making a mistake somewhere
yeah… I just got home and it seems like you did the same thing as me and ChatGPT as all our algorithms seem to yield the same outcome every time i test them… i did notice though that i had to reimplement the * 0.5 within the vector accounting for gravity being added to “dir” as it was massively overshooting the goal before
You’re adding bullet drop that’s proportional to distance travelled, so the farther the target is from the shooter, the more the shot is going to fall short. That’s the expected result if your NPC is not aiming above the target to compensate for the drop (like a real sniper would have to), or if your compensation calculation is just wrong.
Do the shots all hit if you remove all of the bullet drop vectors?
im adding bullet drop to compensate for the bullet drop occurring on the projectile during its flight, BULLETDROP is just a constant for this acceleration. removing all vectors mentioning this constant would no longer account for bullet drop and so would cause the projectile to just immediately accelerate downwards
It looks like bullet drop is being used like a constant speed in your calculation, i.e. studs of drop per second or per stud of horizontal travel. But if this FastCast module is applying gravitational acceleration, then compensation that’s linear isn’t going to work, because the amount of actual drop is going to increase quadratically with distance to the target.
looking at the code for the FastCast module this honestly might be the case; im still not entirely sure what to change though… i multiplied “magnitude” to the power of 2, and although it changes the trajectory, it still misses the Goal
You could do some measurements, like make the shooter’s target a really tall block, remove any ground (baseplate, etc), and just record how far below the goal the shot lands at various shooter-to-target distances (by record I just mean print the Y-axis error to the output window). You’ll only need a small number of data points to see if it’s linear, quadratic, or something else.
Quantifying an error is almost always super insightful w.r.t. to figuring out what the source is.
Just modifying this cast function isn’t gonna help you. It looks like it’s just an API for launching a projectile. If you want it to be easier you would implement your guns with no bullet drop so it just travels in a straight line with and then you account for the the target’s velocity. It will still require a bit of trigonometry especially if you want the gun to shoot a non variable velocity.
If you want to implement the real projectile motion aimbot then that will require trigonometry and multivariable calculus of which I have a recommendation video: Vector Calculus Projectile
I was never going to modify the FastCast module, i was looking for an algorithm which could return a unit directional vector alongside an initial velocity constant to be plugged into FastCast’s “Fire” method
I obviously considered just entirely nuking the problem to a level i could solve if I never found the solution, but that really just defeats the purpose of troubleshooting and gaining experience from solving an issue
in the end, i managed to get into contact with the original creator who was able to offer the algorithm for solving this calculation, and after altering it to be compatible for my usecase, it finally works! here is the code that he offered me for the projectile calculation; (his Youtube handle is @ 5uphi)
local velocity = 70
local direction = Vector3.new(position2.X - position1.X, 0, position2.Z - position1.Z)
local height = position2.Y - position1.Y
local discriminant = velocity ^ 4 - game.Workspace.Gravity * (game.Workspace.Gravity * direction.Magnitude ^ 2 + 2 * height * velocity ^ 2)
if discriminant > 0 then
local rightVector = direction:Cross(Vector3.yAxis)
local angle1 = math.atan((velocity ^ 2 + math.sqrt(discriminant)) / (game.Workspace.Gravity * direction.Magnitude))
local cFrame = CFrame.fromMatrix(position1, rightVector, Vector3.yAxis) * CFrame.fromAxisAngle(Vector3.xAxis, angle1)
local clone = game.ReplicatedStorage.Projectile:Clone()
clone.CFrame = cFrame
clone.Parent = workspace
clone:ApplyImpulse(cFrame.LookVector * velocity * clone.AssemblyMass)
task.wait(1)
local angle2 = math.atan((velocity ^ 2 - math.sqrt(discriminant)) / (game.Workspace.Gravity * direction.Magnitude))
local cFrame = CFrame.fromMatrix(position1, rightVector, Vector3.yAxis) * CFrame.fromAxisAngle(Vector3.xAxis, angle2)
local clone = game.ReplicatedStorage.Projectile:Clone()
clone.CFrame = cFrame
clone.Parent = workspace
clone:ApplyImpulse(cFrame.LookVector * velocity * clone.AssemblyMass)
else
warn("Too far")
end
and here a Medal clip of the final system functioning;