Hi everyone,
I’m currently working on using FastCast to create projectives that move along a (quadratic) bezier curve. Potentially helping me out here does require some knowledge of the FastCast module, but the main the thing is that you work under the limitation that you can only modify a projectile’s trajectory by changing the acceleration.
Well, first things first:
The quadratic bezier curve calculation:
local function CalculateQuadraticBezierCurve(startPos, controlPos, endPos, t)
local u = 1 - t
local tt = t * t
local uu = u * u
local p = uu * startPos
local q = 2 * u * t * controlPos
local r = tt * endPos
local tangent = 2 * u * (controlPos - startPos) + 2 * t * (endPos - controlPos)
return p + q + r, tangent
end
And also the calculation for the approximate total length of the curve:
local function CalculateQuadraticBezierCurveLength(startPos, controlPos, endPos, numSegments)
local length = 0
local previousPoint = startPos
for i = 1, numSegments do
local t1 = (i - 1) / numSegments
local t2 = i / numSegments
local point1, tangent1 = CalculateQuadraticBezierCurve(startPos, controlPos, endPos, t1)
local point2, tangent2 = CalculateQuadraticBezierCurve(startPos, controlPos, endPos, t2)
length = length + (point2 - previousPoint).magnitude
previousPoint = point2
end
return length
end
These functions are used in the FastCast handler where you activate the tool:
local startingCFrame = CFrame.new(FirePointObject.WorldPosition, TargetPos)
p1[i] = (startingCFrame + (direction * (ClientRange/1.5)) + (startingCFrame:ToWorldSpace(CFrame.Angles(0, 0, math.rad(120 * i + 90))).RightVector * 4)).Position -- The third point on the curve, the control position, is different for each projectile.
local distance = CalculateQuadraticBezierCurveLength(FirePointObject.WorldPosition, p1[i], TargetPos, 100)
totalTime = distance / BULLET_SPEED -- So here we approximate the duration (which turns out to not be correct because of the velocity speeding up beyond the specified BULLET_SPEED)
startingTime[i] = tick()
local passedTime = tick() - startingTime[i]
local alpha = passedTime / totalTime
local _, tan = CalculateQuadraticBezierCurve(FirePointObject.WorldPosition, p1[i], TargetPos, alpha) -- This calculates the tangent
CastBehavior.Acceleration = tan
CastBehavior.Count = i -- As I fire 3 projectiles at once, you want to keep track of which is which
And finally the acceleration gets updated on every ray update:
local passedTime = tick() - startingTime[cast.RayInfo.Count]
local alpha = passedTime / totalTime
local _, tan = CalculateQuadraticBezierCurve(FirePointObject.WorldPosition, p1[cast.RayInfo.Count], TargetPos, alpha)
cast.StateInfo.Trajectories[1].Acceleration = tan
So, this implementation unfortunately speeds up the projectile far beyond the intended total speed, and because of that also screws up the curve:
I tried a couple solutions, but since maths is a bit hard on me generally, most were fruitless anyway. I think that my best idea was to get the 2D planes on which these curves actually move
local line = Instance.new("Part")
line.Anchored = true
line.CanCollide = false
line.CanQuery = false
local v = (FirePointObject.WorldPosition - TargetPos)
line.Size = Vector3.new(0.1, 0.1, v.Magnitude)
line.CFrame = CFrame.new(TargetPos + 0.5 * v, FirePointObject.WorldPosition) * CFrame.fromOrientation(0, 0, math.rad(120 * i + 90))
line.Color = Color3.fromRGB(i * 80, 0, 0)
line.Parent = workspace
local line2 = Instance.new("Part")
line2.Anchored = true
line2.CanCollide = false
line2.CanQuery = false
line2.Size = Vector3.new(0.1, 3, 3)
line2.Position = line.Position
line2.CFrame = line.CFrame * CFrame.Angles(0, 0, math.rad(90))
line2.Color = Color3.fromRGB(i * 80, 0, 0)
line2.Parent = workspace
mod[i] = Vector3.new(math.abs(line2.CFrame.UpVector.X), math.abs(line2.CFrame.UpVector.Y), math.abs(line2.CFrame.UpVector.Z))
And then:
local passedTime = tick() - startingTime[cast.RayInfo.Count]
local alpha = passedTime / totalTime
local _, tan = CalculateQuadraticBezierCurve(FirePointObject.WorldPosition, p1[cast.RayInfo.Count], TargetPos, alpha)
cast.StateInfo.Trajectories[1].Acceleration = tan * mod[cast.RayInfo.Count]
This changes the trajectories the projectiles follow depending on the axes it is launched and only slightly decreases the speed increase; so not a solution. Maybe my implementation is way too shabby though, so I haven’t quite given up on the idea.
I hope someone can delve into this challenge and help me out. Conceptually helpig would be great as well. By now it’s just quite frustrating hahaha. Not using FastCast makes the whole thing pretty much trivial, see this example I made:
Quadratic Bezier Curve.rbxm (6.2 KB)
So that example is the result I want using FastCast. Thanks in advance!