Why is this character follow mouse not working?

Currently I’m working on a weapon tool, when it’s being equipped, the arms will follow the mouse.

local followmouse = false

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

ShotgunTool.Equipped:Connect(function()
   ..
  followmouse = true
   ..
end)

ShotgunTool.Unequipped:Connect(function()
   ..
  followmouse = false
   ..
end)

game:GetService("RunService").RenderStepped:Connect(function()
if followmouse == true then
	char.Torso["Right Shoulder"].C0 = CFrame.new(1,0.5,0) * CFrame.Angles(-math.asin((mouse.Origin.p - mouse.Hit.p).unit.y),1.55,0)
	char.Torso["Left Shoulder"].C0 = CFrame.new(-1,0.5,0) * CFrame.Angles(-math.asin((mouse.Origin.p - mouse.Hit.p).unit.y),-1.55,0)
elseif followmouse == false then
	char.Torso["Right Shoulder"].C0 = RS
	char.Torso["Left Shoulder"].C0 = LS
	
    end
end)

However, this doesn’t work when there is 2 weapon in backpack, it only works for 1 tool, another one doesn’t work.
They both have the same LocalScript inside the tool:
https://gyazo.com/2518c1ab84c93d1beb50355801c54744

How do I resolve this? Thanks

1 Like

Have you tried removing the elseif statement? The problem is that when you have two tools with that script in your inventory, they’re both trying to do conflicting things with the arms. Tool 1 is trying to make the arms point towards the mouse, tool 2 is trying to keep the arms where they used to be.

Edit: I think I understand why you included the elseif statement, so that when you unequip the arms won’t stay where they were previously. If you wanted to do that, you could just add the contents of the elseif statement to the ShotgunTool.Unequipped connection.

Never thought of that, when I change RenderStepped into while wait() do, the arm gliches between where they used to be and the arms point toward the mouse.
I kinda resolve that by writing this in a separate script, it works but doesn’t seems efficient and I hope there’s a better solution:
local RS = char.Torso[“Right Shoulder”].C0
local LS = char.Torso[“Left Shoulder”].C0

game:GetService("RunService").RenderStepped:Connect(function()
	if char:FindFirstChildOfClass("Tool") then
		char.Torso["Right Shoulder"].C0 = CFrame.new(1,0.5,0) * CFrame.Angles(-math.asin((mouse.Origin.p - mouse.Hit.p).unit.y),1.55,0)
		char.Torso["Left Shoulder"].C0 = CFrame.new(-1,0.5,0) * CFrame.Angles(-math.asin((mouse.Origin.p - mouse.Hit.p).unit.y),-1.55,0)
	else
		char.Torso["Right Shoulder"].C0 = RS
		char.Torso["Left Shoulder"].C0 = LS
	end
end)

I hope there’s a better solution on this but thanks!

Did you see my edit? I think not having an else statement could help. The issue with the solution you posted is that it’s not compatible with any other tools. I think if you remove the else statement, and move the contents of it to the tool.Unequipped connection things will be working a lot smoother.

Try this so when you equip the tool it connects it and disconnects it on unequip.

That’s really not much better than what he’s currently doing, as he will still need to connect and disconnect the function on equip and unequip respectively, which is where his issues are rooted. Right now he simply has some code in the wrong spot.

He’s doing the equip stuff right, he never disconnects the renderstepped though so it’ll keep going so it’s just something to note.

@Headstackk what is

ShotgunTool

Where do you define this and how? Can we see the full script?

The problem isn’t that he’s not disconnecting the RenderStepped connection, the problem is that he’s constantly doing something in that connection that only needs to be done once (reset the shoulder C0s). The proper way to fix this would be to move the code inside the elseif statement to the tool.Unequipped connection. (In reference to the original post, not any subsequent posts.)

Edit: I do agree that it should be disconnected when not in use, but that isn’t where his issue is stemming from.

Edit: my brain stopped working @SebastianAurum is right, I for some reason was thinking you were doing something like FindFirstChild or WaitForChild. You need to remove your elseif and move the code into the unequipped function (the arm position inside the elseif). This is because you never disconnect your renderstepped meaning it runs and forces the arms into the same position.

So the method I posted up top works and so does a normal disconnect.

Here’s a fixed version of the code in the OP.

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

ShotgunTool.Equipped:Connect(function()
   ..
  followmouse = true
   ..
end)

ShotgunTool.Unequipped:Connect(function()
   ..
  followmouse = false
  char.Torso["Right Shoulder"].C0 = RS
  char.Torso["Left Shoulder"].C0 = LS
   ..
end)

game:GetService("RunService").RenderStepped:Connect(function()
  if followmouse then
    char.Torso["Right Shoulder"].C0 = CFrame.new(1,0.5,0) * CFrame.Angles(-math.asin((mouse.Origin.p - mouse.Hit.p).unit.y),1.55,0)
    char.Torso["Left Shoulder"].C0 = CFrame.new(-1,0.5,0) * CFrame.Angles(-math.asin((mouse.Origin.p - mouse.Hit.p).unit.y),-1.55,0)
  end
end)
1 Like

I’ve got a MUCH better solution. I reckoned I should share it.


-- Client
local Tool = script.Parent
local Player = game.Players.LocalPlayer
local Mouse = Player:GetMouse()

local TiltEvent = Tool:WaitForChild("TiltEvent")

local Character, Torso, RightShoulder, LeftShoulder
local RightShoulderCFrame = CFrame.new(1, 0.5, 0, 0, 0, 1, 0, 1, -0, -1, 0, 0)
local LeftShoulderCFrame = CFrame.new(-1, 0.5, 0, 0, 0, -1, 0, 1, 0, 1, 0, 0)

local FollowMouse = false

Tool.Equipped:Connect(function()
    FollowMouse = true
    while FollowMouse do
        wait(0.1)
        Character = Player.Character or Player.CharacterAdded:Wait()
        if Character and Character:FindFirstChild("Torso") then
            Torso = Character:FindFirstChild("Torso")
            if Torso:FindFirstChild("Right Shoulder") and Torso:FindFirstChild("Right Shoulder") then
                RightShoulder, LeftShoulder = Torso:FindFirstChild("Right Shoulder"), Torso:FindFirstChild("Right Shoulder")
                TiltEvent:FireServer(RightShoulder, CFrame.new(-1,0.5,0) * CFrame.Angles(-math.asin((mouse.Origin.p - mouse.Hit.p).unit.y), 1.55, 0))
                TiltEvent:FireServer(LeftShoulder, CFrame.new(-1,0.5,0) * CFrame.Angles(-math.asin((mouse.Origin.p - mouse.Hit.p).unit.y), -1.55, 0))
            end
        end
    end
end)

Tool.Unequipped:Connect(function()
    FollowMouse = false
    RightShoulder.C0 = RightShoulderCFrame
    LeftShoulder.C0 = LeftShoulderCFrame
end)

-- Server
local Tool = script.Parent
local TiltEvent = Tool:WaitForChild("TiltEvent")

local Tween1, Tween2

local function TweenFunction(Speed, Tween, Part, C0)
    pcall(function()
        Tween:Cancel()
    end)
    Tween = TS:Create(part, TweenInfo.new(Speed, Enum.EasingStyle.Linear, Enum.EasingDirection.Out), {C0 = C0})
    Tween:Play()
    return Tween
end

TiltEvent.OnServerEvent:Connect(function(_, Joint, JointCFrame)
    if Joint.Name == "Right Shoulder" then
        Tween1 = Tween(0.1, Tween1, Joint, JointCFrame)
    else
        Tween2 = Tween(0.1, Tween2, Joint, JointCFrame)
    end
end)

Hopefully we’re not getting into trouble by bumping this thread, but if you want some feedback I think your code could be improved in a few ways.

  • Right now, you’re not handling the movement on the client at all, and instead telling the server to update the joints every 0.1 seconds. The movement would be a lot more smooth to the player if you updated it on the client every frame, rather than on the server eveyr 0.1 seconds. If you handle it on the server, latency will meant that there will be a noticeable delay–input lag is something players hate. I would do this by connecting the client-side logic to RenderStepped.
game:GetService("RunService").RenderStepped:Connect(function()
	if FollowMouse then
		-- update arms
	end
end)
  • Now that you’re updating movement on the client every frame, you can send data to the server after every interval e.g. 0.1 seconds (sort of like you’re doing now) so that everything will be replicated.

  • Now we can optimise the network a little bit – you fire the TiltEvent twice, butwith the exact same data every time, except that the desired joint is different. This is unnecessary; you can optimize it by only sending the angle math.asin(...). The server can then construct the CFrame itself and adjust both joints appropriately.

  • Note that the client will “override” the server’s changes, but only from the local player, since we’re updating the joints locally every frame. This means that the server’s updating of the joints will not affect the client; only their joints from the perspective of other players, diminishing the appearance of latency.

local LastReplication = tick()
local ReplicationDebounce = 0.1


game:GetService("RunService").RenderStepped:Connect(function()
	if FollowMouse then
		local angle = math.asin((mouse.Origin.p - mouse.Hit.p).unit.y)
		-- update shoulders
		
		local timestamp = tick()
		if timestamp - LastReplication > ReplicationDebounce then
			-- 0.1 seconds has elapsed since last Remote fire; fire server 
			LastReplication = timestamp
			TiltEvent:FireServer(angle) -- way less data!!
		end
	end
end)
  • Secondly, you shuldn’t be assigning variables for the character, torso, and joints every time you want to update the arms. You can just do this once at the top of the script; this will both clean up your code and make it a little bit faster to run. Since the script is in a tool, you won’t have to worry about the character respawning.

The First Person Element Of A First Person Shooter is a great resource for handling viewmodels effectively

1 Like