Gun aiming system for using in a game with a "time slow" mechanic is inaccurate due to torso movement/ animtion

Gun aiming system for using in a game with a “time slow” mechanic is inaccurate. -posting on behalf of @poeyrex (or eg)

The Problem

I’m using the c0 frame of the rightshoulder, relative to the torso, to calculate and position the muzzle of my gun to point exactly to where my mouse is. I need the muzzle to line up perfectly as when a character’s time is slowed their aiming will be too and the bullet is fired from the direction of the muzzle, not to where im clicking like most games.

It works perfectly fine when stationary (minimal movement and animation interference):

But, when walking or running it becomes innacurate due to the movement of the torso (i believe):

I need to have control over the accuracy or else the aiming mechanic will basically just be down to luck.

Some solutions i’ve tried so far:

  • Creating a seperate motor6d that isnt effected by animations and then animating relative to the humrp,
    this works to an extend but as it’s relative to the humrp the arm does not move with the torso at all and looks detached and unnatural:
a seperate motor6d

  • Tried manipulating the c1 instead of c0, c1 is still effected by animation offset.

  • Tried using an R6IK module but didnt help with the issue im facing , also made it look even worse and screwed the aiming up. ( Roblox IKControl doesn’t support R6 )

Honestly I don’t know if this is even possible but I feel like it should be, if anyone has any ideas on how to make this work or if you need any extra information/explanation please let me know.


Example of the timeslow effect i’m trying to have which is the reason for this specific way of aiming:

vid

Script

local c0 = CFrame.new(1, 0.5, 0, 0, 0, 1, 0, 1, -0, -1, 0, 0)

local pistolAim = {}

function pistolAim:Call(args)
	local player = game.Players.LocalPlayer
	local char = player.Character or player.CharacterAdded:Wait()
	local humRP = char:WaitForChild("HumanoidRootPart")
	local torso = char:WaitForChild("Torso")
	local rightShoulder = torso:FindFirstChild("Right Shoulder")
	local mouse = player:GetMouse()

	local uis = game:GetService("UserInputService")

	local workspace = game:GetService("Workspace")

	local yawMin, yawMax = math.rad(-100), math.rad(60)
	local pitchMin, pitchMax = math.rad(-75), math.rad(75)
	local raycastParams = RaycastParams.new()
	raycastParams.FilterDescendantsInstances = { char }
	raycastParams.FilterType = Enum.RaycastFilterType.Exclude

	local playerShiftLockModule = require(player.PlayerScripts.CustomShiftLock.SmoothShiftLock)

	local connection

	connection = game:GetService("RunService").RenderStepped:Connect(function(dt)
		local muzzleWorldCFrame = char.GunModel.Muzzle.Attachment.WorldCFrame
		local mousePos = mouse.Hit.Position
		local torsoCframe = torso.CFrame

		local rayOrigin = muzzleWorldCFrame.Position
		local rayDirection = (mousePos - muzzleWorldCFrame.Position).Unit
		if playerShiftLockModule:IsShiftlocked() then --if in shiftlock, offset by the shiftlock offset (due to custom shiftlock module causing issues with aiming offset)
			rayDirection = (mousePos - (muzzleWorldCFrame * CFrame.new(Vector3.new(1.75, -0.25, 0))).Position).Unit
		end

		local aimPosition = rayOrigin + rayDirection * 1000
		local rightShoulderWorldPos = torsoCframe * c0
		local rightLookWorld = CFrame.new(rightShoulderWorldPos.Position, aimPosition)
		local rightLookLocal = torsoCframe:ToObjectSpace(rightLookWorld)
		local rx, ry, _ = rightLookLocal:ToOrientation()

		local clampedYaw = math.clamp(ry, yawMin, yawMax) --clamping horizontal
		local clampedPitch = math.clamp(rx, pitchMin, pitchMax) --clamping vertical

		rightShoulder.C0 = rightShoulder.C0:Lerp(
			c0 * CFrame.Angles(0, clampedYaw, clampedPitch + math.rad(90)),
			dt * args.aimSpeed * char.TimeFlow.Value
		)
		game.ReplicatedStorage.Remotes.AimUpdate:FireServer(
			c0 * CFrame.Angles(0, clampedYaw, clampedPitch + math.rad(90)),
			dt * args.aimSpeed
		) --sends to server for replication
	end)

	task.spawn(function()
		while char:FindFirstChild("Aiming") do
			task.wait()
		end
		connection:Disconnect()
	end)
end

return pistolAim