https://developer.roblox.com/en-us/api-reference/property/Camera/FieldOfView
The offset is because since i made the local transprency modifier of the body 0 regarding accessories the top of the Upper torso is visible if you look straight down. So i added an offset to make it look down from upper torso to lower torso
I think I understand what they’re trying to do: make the limbs visible, but make it so you can’t glitch through the limbs and all that, realistically “offsetting” it
Im trying to make a camera like the one in JUDY or any other horror game thats relaistic
Never played JUDY but I think I have an idea on what you’re looking for.
This requires a decent understanding of CFrames.
…
Let me explain my thought process:
First for this custom camera, to make the player able to look around, we need to use their mouse position somehow.
We can use UserInputService:GetMouseDelta()
to detect changes in the mouse position, and add that to a stored variable (even if the change is negative, 5 + (-5) = 0, just like 5-5 = 0, so all we need to do is add)
From there we can create angles using those positions relative to the screen, by using some sort of multiplier like 0.15 on Delta.X here. It won’t matter how large their screen is, because we’re using GetMouseDelta, so as long as they keep moving their mouse positive or negative, the value will be adjusted accordingly.
Using those angles we can then multiply that from the character’s root part, and use an offset to get their head position. We don’t want to use the head itself because that could look weird while moving, although you can change the code for your own needs.
…
local Player = game.Players.LocalPlayer
local Char = Player.Character or Player.CharacterAdded:Wait()
local UIS = game:GetService("UserInputService")
local X, Y, AngleX, AngleY = 0,0, CFrame.Angles(0,0,0), CFrame.Angles(0,0,0) -- Base values
local Camera = workspace.CurrentCamera
local Offset = CFrame.new(0, 2, -1) -- You might want to change this to suit your game better
function Update()
UIS.MouseBehavior = Enum.MouseBehavior.LockCenter
Camera.CameraType = Enum.CameraType.Scriptable
local Delta = UIS:GetMouseDelta() -- Get change in mouse position
X = X + (Delta.X*0.15) -- Set X value accordingly (mouse left/right)
Y = math.clamp(Y + (Delta.Y*0.15),-89.99,89.99) -- Set value Y value accordingly (mouse up/down, clamped to prevent glitch where camera rotates at 90)
AngleX = CFrame.Angles(0, math.rad(-X), 0) -- Create angles using X on Y
AngleY = CFrame.Angles(math.rad(-Y),0,0) -- Create angles using Y on X
Camera.CFrame = CFrame.new((Char.HumanoidRootPart.CFrame).p)* AngleX * Offset * AngleY
end
game:GetService("RunService"):BindToRenderStep("Update",Enum.RenderPriority.Camera.Value, Update) -- Use BindToRenderStep so it updates compared to Roblox's default camera
And here is the end result:
So remember to plan.
If it doesn’t work or you have any questions please let me know!
Wow! It works all i had to change is a few variables and the humanoidRootPart to head because of what i wanted initially; but when i turn the body doesn’t turn with it. Anyway to fix that?
The thing about Roblox math and me is that i know a lot of math! Unfortunately i don’t know how to put it all together, like how i should use this or where i should put that.
Sure, we can simply add some code to make the player turn towards the direction of the camera. To make a part look at another part we simply do CFrame.new(Origin, LookAt)
, but here we need to limit the rotation to the Y axis only, because we want the player’s body to rotate side to side only, not rotate all over the place!
So first we set a variable GoalRotate
to equal CFrame.new(Origin, LookAt)
, in this case the origin being the HumanoidRootPart’s position, and the LookAt to the Camera’s position. Now to get the Y orientation value of the GoalRotate, we use GoalRotate:ToOrientation()
on it.
The reason we do local _, RotY, _ = GoalRotate:ToOrientation()
is because the function returns the X,Y, and Z values, and we only want the Y orientation value.
With this Y orientation value, we can then use CFrame.fromOrientation()
to construct a new CFrame with just that Y orientation value while setting the X and Z to 0. Sorry if I’m bad at explaining this.
The code would look like this:
local Position = Char.HumanoidRootPart.CFrame.p
local GoalRotate = CFrame.new(Position, Camera.CFrame.Position)
local _, RotY, _= GoalRotate:ToOrientation()
Char.HumanoidRootPart.CFrame = CFrame.new(Position) * CFrame.fromOrientation(0, RotY, 0)
And this would be ran after setting the Camera.CFrame
…
So for example in my script I made earlier it would be like this:
local Player = game.Players.LocalPlayer
local Char = Player.Character or Player.CharacterAdded:Wait()
local UIS = game:GetService("UserInputService")
local X, Y, AngleX, AngleY = 0,0, CFrame.Angles(0,0,0), CFrame.Angles(0,0,0) -- Base values
local Camera = workspace.CurrentCamera
local Offset = CFrame.new(0, 2, -1) -- You might want to change this to suit your game better
function Update()
UIS.MouseBehavior = Enum.MouseBehavior.LockCenter
Camera.CameraType = Enum.CameraType.Scriptable
local Delta = UIS:GetMouseDelta() -- Get change in mouse position
X = X + (Delta.X*0.15) -- Set X value accordingly (mouse left/right)
Y = math.clamp(Y + (Delta.Y*0.15),-89.99,89.99) -- Set value Y value accordingly (mouse up/down, clamped to prevent glitch where camera rotates at 90)
AngleX = CFrame.Angles(0, math.rad(-X), 0) -- Create angles using X on Y
AngleY = CFrame.Angles(math.rad(-Y),0,0) -- Create angles using Y on X
Camera.CFrame = CFrame.new((Char.HumanoidRootPart.CFrame).p)* AngleX * Offset * AngleY
local Position = Char.HumanoidRootPart.CFrame.p -- Set to the root part's position
local GoalRotate = CFrame.new(Position, Camera.CFrame.Position) -- Faces the camera from the root part's position
local _, RotY, _= GoalRotate:ToOrientation() -- Stores the Y orientation value, which we will then use in CFrame.fromOrientation to set the X and Z to 0, limiting it to Y (rotating side to side)
Char.HumanoidRootPart.CFrame = CFrame.new(Position) * CFrame.fromOrientation(0, RotY, 0)
end
game:GetService("RunService"):BindToRenderStep("Update",Enum.RenderPriority.Camera.Value, Update) -- Use BindToRenderStep so it updates compared to Roblox's default camera
Hopefully this helps!
for the RotY variable why did you put ,RotY, ?
It works! but when my cartoony animation plays one of the idle animations it glitched but then fixes back why does that happen? Sorry if its taking too much of your time
Ah yeah I understand that looks confusing so I explained it here
The reason we do
local _, RotY, _ = GoalRotate:ToOrientation()
is because the function returns the X,Y, and Z values, and we only want the Y orientation value.
Basically you can try this on your own function as well
local function ReturnThreeValues()
return 1,2,3
end
local One, Two, Three = ReturnThreeValues()
print(One) -- 1
print(Two) -- 2
print(Three) -- 3
So if we only wanted Three (3), we could do
local _, _, Three = ReturnThreeValues()
print(Three) -- 3
Or if we only wanted One (1), we could do
local One, _, _ = ReturnThreeValues()
print(One) -- 1
“_” is basically a placeholder that replaces variables you won’t use, which is thought to be more organized as you’re only storing variables you need, and could be 0.0001% better for performance
I’m not sure, I would have to see the animation and things like that. Can you send a video?
Ohhhhh so it returns 3 values and you need only 1 just making a random character as placeholders?
Yeah pretty much, helps to stay organized in my opinion, but if you wanted to you could do
local RotX, RotY, RotZ = GoalRotate:ToOrientation()
even if you’re just using RotY, and that’s totally fine as well.
I have an idea: because the origin of the camera system uses the HumanoidRootPart, and animations never move it. So if your animation moves the character’s limbs around a lot it could cause lots of clipping, or if you move the LowerTorso it would cause the player to move away from the camera, etc.
There are a few ways to prevent this but unfortunately I am running out of time right now. If you still haven’t marked a solution later, maybe tomorrow, if I have the time I could help. What I am thinking of is either using the head as the origin and limiting the axis with :ToOrientation()
and .fromOrientation()
, or changing the character offset based on animations (limb transformations).
Glad I could help you fix most of your camera issues though, good luck
Yes i will try to find a way to limit the rotation on Y so they wont look directly down, thank for your help! Still a few things i don’t understand but if i don’t find a solution until tomorrow ill @ you.
Turns out that i was mistaken, it glitches when I look up and down but I want the players to be able to look directly up
@Luacrative When i swam in the water it didnt look right so i tried fixing it using this:
humanoid.StateChanged:Connect(function(old, new)
local x, y, z = camera.CFrame:ToEulerAnglesXYZ()
if new == Enum.HumanoidStateType.Swimming then
character.HumanoidRootPart.CFrame = camera.CFrame:ToWorldSpace() * CFrame.Angles(0, math.deg(y) * math.rad(45), 0)
end
end)
but it doesnt work