Hey, and thanks for reading in advance.
One of the classes in the Fat Princess clone I’m making has the ability to fire a bow. Ordinarily, the firing point that the trajectory simulation uses is calculated based on your mouse’s screen position, but since people can move relatively quickly, I’m attempting to create a sort of pseudo-aim-assist that hijacks your sent position if your mouse was hovering over a targetable entity by automatically firing at their root.
Problem there is, the arrow’s simulated trajectory arcs downwards. The solution seemed simple enough - simply adjust the targeted position of the arrow upwards based on the distance between yourself and the target. I’m having trouble finding the exact math, though - I assume I’m likely going to need some complicated ballistics formula, but I’m not sure just yet.
Clientside snippet:
Client = function(Character, Animator, InputObject)
local shootAnim = LoadAnim(Character, Animator, 2991996122, "ShootA")
local fakeArrow = Character:FindFirstChild("Arrow")
local castLength = 500
local hitCon
local targetParams = RaycastParams.new()
targetParams.FilterDescendantsInstances = {Character, workspace.CurrentCamera}
targetParams.FilterType = Enum.RaycastFilterType.Blacklist
targetParams.IgnoreWater = true
hitCon = shootAnim:GetMarkerReachedSignal("Fire"):Connect(function()
local arrowKey = Core:GenerateKey(9)
local screenRay, fireTo
if InputObject.UserInputType.Name:find("Gamepad") then
screenRay = workspace.CurrentCamera:ScreenPointToRay(
workspace.CurrentCamera.ViewportSize.X/2,
(workspace.CurrentCamera.ViewportSize.Y - 32) * .3,
1
)
else
screenRay = workspace.CurrentCamera:ScreenPointToRay(InputObject.Position.X, InputObject.Position.Y, 1)
end
screenParams.FilterDescendantsInstances = {Character, workspace.CurrentCamera}
fireTo = workspace:Raycast(screenRay.Origin, screenRay.Direction * castLength, screenParams)
if fireTo then
local livingTarget = Core:FetchFromPart(fireTo.Instance)
if livingTarget and livingTarget:FindFirstChild("HumanoidRootPart") then
-- This is where I'd be doing the adjustments
fireTo = livingTarget.HumanoidRootPart.Position
else
fireTo = fireTo.Position
end
else
fireTo = screenRay.Origin + screenRay.Direction * castLength
end
if fakeArrow then
fakeArrow.Transparency = 1
end
local attackCF = CFrame.new(
Character.HumanoidRootPart.Position + (fireTo - Character.HumanoidRootPart.Position).Unit * 4,
fireTo
)
local simulatedPos = attackCF.Position
local shotVelocity = attackCF.LookVector * Classes.Ranger.Primary.SHOT_SPEED
local g = Vector3.new(0, -game.Workspace.Gravity, 0)
local t = Classes.Ranger.Primary.SHOT_LIFETIME
local lastPos = simulatedPos - shotVelocity.Unit
local lastDelta = 1/30
local nt = 0
--
Effect("Arrow", {
cf = attackCF, speed = Classes.Ranger.Primary.SHOT_SPEED,
lt = Classes.Ranger.Primary.SHOT_LIFETIME,
col = game.Players.LocalPlayer.TeamColor.Color,
ignite = Core:HasStatus(Character, "Ignite"),
ID = arrowKey
})
Effect("GameAudio", {
sound = RS.GameAudio.Attacks.BowFire,
pos = Character:FindFirstChild("HumanoidRootPart")
})
task.spawn(function()
while (nt < t * 2) and workspace.CurrentCamera:FindFirstChild(arrowKey) do
local hitQuery, skewAngle, thisDelta
simulatedPos = .25 * g * nt * nt + shotVelocity * nt + attackCF.Position
skewAngle = (simulatedPos - lastPos).Unit
lastPos = simulatedPos
hitQuery = workspace:Raycast(simulatedPos,
skewAngle * ((Classes.Ranger.Primary.SHOT_SPEED * lastDelta) + Classes.Ranger.Primary.SHOT_LENGTH),
targetParams
)
if hitQuery then
local dataPacket = {Instance = hitQuery.Instance, Position = hitQuery.Position, Direction = skewAngle}
RS.Remotes.ProjectileHit:FireServer("Primary", dataPacket, arrowKey)
end
thisDelta = RUN.Heartbeat:Wait()
nt = nt + thisDelta; lastDelta = thisDelta
end
end)
RS.Remotes.SendAction:FireServer("Primary", {ID = arrowKey, CF = attackCF, ShotVelocity = shotVelocity})
Character.Humanoid.AutoRotate = false
Character.HumanoidRootPart.CFrame = CFrame.new(
Character.HumanoidRootPart.Position,
Vector3.new(fireTo.X, Character.HumanoidRootPart.Position.Y, fireTo.Z)
)
hitCon:Disconnect()
end)
Effect("GameAudio", {
sound = RS.GameAudio.Misc.BowString,
pos = Character:FindFirstChild("HumanoidRootPart")
})
shootAnim:Play()
while shootAnim.IsPlaying and Core:CanAct(Character) do
RUN.Heartbeat:Wait()
end
hitCon:Disconnect()
Character.Humanoid.AutoRotate = true
screenParams.FilterDescendantsInstances = {}
if fakeArrow then
fakeArrow.Transparency = 0
end
end,
I’m not following an exact gravitational constant, but I assume that can be accounted for.
Any help or advice is appreciated!