Bend the Torso relativ to the mouse Position

Basicly I saw this method to bend the uppertorso relativ to the lookvector of the camera and I was thinking on how you could bend and maybe even rotate based on the mouse position.

local c0 = game.Players.LocalPlayer.Character:WaitForChild("UpperTorso"):WaitForChild("Waist").C0
		
local function updatewaist()
	local cameralookvectorY = workspace.CurrentCamera.CFrame.lookVector.Y
	local radian = math.asin(cameralookvectorY)
	game.Players.LocalPlayer.Character.UpperTorso.Waist.C0 = c0*CFrame.fromEulerAnglesYXZ(radian,0,0)
end

I tried getting the mouse and mouse position but I couldn’t make it work with this function. Here is my try.

        local mouse = Players.LocalPlayer:GetMouse()
	local cameralookvectorY = mouse.Hit.Position
4 Likes

Mouse.Hit is a CFrame, so just index its LookVector property :+1:

local radian = math.asin(mouse.Hit.LookVector.Y)
2 Likes

Thanks! That did the trick :))
does it require alot more to change the bodyrotation aswell so your upperbody could turn right and left based on your mouse?

EDIT: Got it working myself
just make a second value and instead of the mouse.Hit.LookVector.Y take the X value of the LookVector and insert it into the fromEulerAnglesYXZ(radian, radian2, 0)

EDIT2: nevermind, it behaves weird. it doesnt reset when I turn and move around. So it’s not turning based on if I am aiming infront of my player which should make the body turn to normal again, This is not the case here hmm.

Any idea?

2 Likes

Ah, this is probably because Mouse.Hit uses the CurrentCamera to calculate the rotation of the hit, rather than the character’s head.

If you wanna mimic mouse.hit but with the head as the origin, it’s quite simple:

local plr = game.Players.LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()
local mouse = plr:GetMouse()

local function updatewaist()
    local direction = (mouse.Hit.Position - char.Head.Position).Unit
    local ray = Ray.new(char.Head.Position, direction*1000)
    local _, pos = workspace:FindPartOnRay(ray, char)
    local cf = CFrame.new(char.Head.Position, pos)*CFrame.new(0, 0, -(pos - char.Head.Position).Magnitude)

    -- do whatever with `cf'
end

I know the math seems a little daunting, but it’s fairly simple:

Math

step 1: get the change between the two vectors (using target - eye), then get the unit vector, which is simply the vector divided by its Magnitude; vec.Unit == vec/vec.Magnitude

step 2: create a Ray with the origin as the head’s position, facing the direction of our unit vector. We multiply by 1000 because that’s how long the ray will extend

step 3: use Workspace:FindPartOnRay to find the intersection between our ray and a physical object, making sure to ignore our character’s model in the process

step 4: use the CFrame.new(position, lookAt) constructor (I know it’s kinda deprecated but it’s useful!) to make our point of intersection face the direction of the ray

EDIT: cf was facing the wrong way

First of all, Thanks for this post, but what do I do know with the CFrame (cf) ?

cf.LookVector.Y like you were doing before

@ee0w, But it would be easier if you just use the CFrame.UpVector Propertie. @Paintertable, i hope that you use Remotes Events, else the others players dont will see that your Character bend his Torso. I tried to make a script:

[[LocalScript]]
local Player = game.Players.LocalPlayer
local UpperTorso = Player.Character:WaitForChild("UpperTorso")
local Head = Player.Character:WaitForChild("Head")
local RE = game.ReplicatedStorage.RemoteEvent
local CameraLookVector
local HeadLookVector

game:GetService("RunService").RenderStepped:Connect(function()
    CameraLookVector = workspace.CurrentCamera.CFrame.LookVector
    HeadLookVector = Head.CFrame.LookVector
    RE:FireServer(math.acos(Vector3:Dot(CameraLookVector, HeadLookVector)))
end

[[ServerScript]]

local neckC0 = CFrame.new(0, 0.8, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1);
local waistC0 = CFrame.new(0, 0.2, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1);

game.ReplicatedStorage.RemoteEvent.OnServerEvent:Connect(function(player, theta)
	local neck = player.Character.Head.Neck;
	local waist = player.Character.UpperTorso.Waist;
	neck.C0 = neckC0 * CFrame.fromEulerAnglesYXZ(theta*0.5, 0, 0);
	waist.C0 = waistC0 * CFrame.fromEulerAnglesYXZ(theta*0.5, 0, 0);
end)

Edit:

Here is the Updated script:

[[LocalScript]]
local InputService = game:GetService("UserInputService")
local Player = game.Players.LocalPlayer
local UpperTorso = Player.Character:WaitForChild("UpperTorso")
local Head = Player.Character:WaitForChild("Head")
local RE = game.ReplicatedStorage.RemoteEvent
local CameraLookVector
local HeadLookVector
local Aiming

spawn(function()
    InputService.InputBegan:Connect(function(key)
        if key == Enum.UserInputType.MouseButton2 then --You can change the Key/InputType with another Key/InputType of you choise
            Aiming = true
        end
    end)

    InputService.InputEnded:Connect(function(key)
        if key == Enum.UserInputType.MouseButton2 then --You can change the Key/InputType  with another Key/InputType of you choise
            Aiming = false
        end
    end)

    game:GetService("RunService").RenderStepped:Connect(function()
        CameraLookVector = workspace.CurrentCamera.CFrame.LookVector
        HeadLookVector = Head.CFrame.LookVector
        RE:FireServer(math.acos(CameraLookVector:Dot(HeadLookVector)), Aiming)
    end) 
end)
[[ServerScript]]

local neckC0 = CFrame.new(0, 0.8, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1);
local waistC0 = CFrame.new(0, 0.2, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1);

game.ReplicatedStorage.RemoteEvent.OnServerEvent:Connect(function(player, theta, aiming)
	local neck = player.Character.Head.Neck;
	local waist = player.Character.UpperTorso.Waist;
    if aiming then
	    neck.C0 = neckC0 * CFrame.fromEulerAnglesYXZ(theta*0.5, 0, 0);
	    waist.C0 = waistC0 * CFrame.fromEulerAnglesYXZ(theta*0.5, 0, 0);
    end
end)
1 Like

I’ll definitly try this one out! I didnt even think about the remoteevents, which was kind of dumb! :smiley:
Thanks so much for this post, it’ll help people definitly out!
I’ll let you know if I get it working!

1 Like

I self dont tested it: I am writing from a Mobile Device.

Jeah I’ve got an error.
Line 28 in localscript, "Attempt to call methode “Dot” ( a nil value)

1 Like

Wait a Bit, i will solve the error.

2 Likes

@Paintertable, Sorry, the error was so dumb: i forgot the Roblox LuA syntax and write Vector3:Dot(CameraLookVector, HeadLookVector), but i should write CameraLookVector:Dot(HeadLookVector). I have update the script.

1 Like

hmm, no errors now, which is good but nothing is happening.
It’s firing the event to the server but nothing happens.

EDIT: When are you available to come online? I think it’s easier to solve then :slight_smile: @Eternalove_fan32

2 Likes

I will let you know if i resolve it.

2 Likes

The dot product won’t work, for me typically I would use this:

local X = -math.asin((mouse.Origin.p - mouse.Hit.p).unit.y)
character.Torso.Neck.C0 = CFrame.new(character.Torso.Neck.C0.Position) * CFrame.Angles(X, 0, 0)
1 Like
[[LocalScript]]
local InputService = game:GetService("UserInputService")
local Player = game.Players.LocalPlayer
local UpperTorso = Player.Character:WaitForChild("UpperTorso")
local Head = Player.Character:WaitForChild("Head")
local RE = game.ReplicatedStorage.CameraUpdateEvent
local Mouse = Player:GetMouse()
local LastAngle = 0
local LookVector
local Opposite
local Angle
local HeadLookVector
local Aiming

spawn(function()
    InputService.InputBegan:Connect(function(key)
        if key == Enum.UserInputType.MouseButton2 then --You can change the Key/InputType with another Key/InputType of you choise
            Aiming = true
        end
    end)

    InputService.InputEnded:Connect(function(key)
        if key == Enum.UserInputType.MouseButton2 then --You can change the Key/InputType  with another Key/InputType of you choise
            Aiming = false
        end
    end)

    game:GetService("RunService").RenderStepped:Connect(function()
        local Camera = workspace.CurrentCamera
        local Torso = Player.Character.UpperTorso
		local lv = Camera.CFrame.LookVector
		local nv = Torso.CFrame.LookVector

		LookVector = Camera.CFrame.LookVector
		local Adjacent = math.sqrt((LookVector.X^2)+(LookVector.Z^2))
		Opposite = LookVector.Y
		Angle = math.atan2(Opposite, Adjacent)
		HeadLookVector = Head.CFrame.LookVector
        RE:FireServer(math.asin(LookVector.y), math.atan(LookVector.x, LookVector.z), Aiming)
    end) 
end)

[[ServerScript]]
local neckC0 = CFrame.new(0, 0.8, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1);
local waistC0 = CFrame.new(0, 0.2, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1);

game.ReplicatedStorage.CameraUpdateEvent.OnServerEvent:Connect(function(player, ytheta, xtheta, aiming)
	local neck = player.Character.Head.Neck;
	local waist = player.Character.UpperTorso.Waist;
	local Angle = -xtheta
	local LastAngle = xtheta
		spawn(function()
			if -xtheta > 89 then
				Angle = LastAngle
			else
				LastAngle = Angle
			end
			
		    neck.C0 = neckC0 * CFrame.fromEulerAnglesYXZ(ytheta*0.5, -xtheta, 0)
			waist.C0 = waistC0 * CFrame.fromEulerAnglesYXZ(ytheta*0.5, -xtheta, 0)

		end)
--	end
end)

It the script will bug if the Player play the IdleAnimation and then stop it bruscly by moving. it the best what i can make.

Have you update the head? Else it will look weird when you just update the torso. You also have to update the head so it doesn’t look so weird anymore. I tried to make a solution by myself, but it is bugged. Wait until tomorrow. Tomorrow I will improve it so that it also works, at the moment it does not work yet.

Thanks for your effort!
I really appreciate it

1 Like

Alright I got some good news. @EgoMoose made a character look at script already I’ve found online.
Its here: https://www.roblox.com/library/2274201850/Character-look-at

Instructions are givin in the model itselfs and I changed it a bit because with his method it uses the camera, I changed it to mouse position with mouse.hit.Lookvector instead of camera.CFrame.LookVector.

EDIT: Gonna mark this as solution so people can find it faster! :)) Thanks anyways @Eternalove_fan32 Eternallove_fan32

3 Likes