Hey you all. I’m currently trying to get a first person script to work while the player can see their own character (With the right camera placement), but when I sprint, the camera goes behind the player for some reason, making it turn into 3rd person. Even when I’m idle, the camera is placed slightly behind the character, which makes it look weird.
After I turn on transparency modifiers for the character, I noticed that this was happening with the camera, because I could actually see the character of course.
I’m asking here because this was a resource that I applied to my game.
I tried modifying the different CFrames, by modifying this value: (x, y, Here) where negative values were the only way to put the camera in place, which did place the camera a bit better, but for some reason the player’s character would constantly look backwards.
Also, when looking directly down, the character looks backward and forward constantly (Similar to how the negative values made the character look backwards), which is another issue.
Here’s an image of how the player’s view looks like:
While Idle:
While Running:
The credits to the scripts made by others are comments in the scripts.
So with that out of the way, here is the code:
The First Person System (Local Script)
Located in StarterCharacterScripts
--!strict
--[[
Move script to:
StarterCharacterScripts
Made by:
@isPauI
YT: @Paul1Rb
Updated: 10.07.2023 - 10:35 CET
Log:
- Changed the Sway effect to work on CameraOffset because it caused the player to rotate on Y axis since they were in first person.
- Changed line 65 [Cam.CameraType = Enum.CameraType.Scriptable] to .Custom
]]
local Settings : SettingsType = require(script:WaitForChild("Settings"))
type SettingsType = {
BaseRot : number,
SetRot : number,
BaseFreq : number,
SetFreq : number,
BaseMult : number,
BaseNumLerp: number,
SwayStrenght : number,
BaseSway : number,
SetSway : number,
CustomSwayZVal : number,
DriftMin : number,
DriftMax : number,
Rate : number,
MaxBlur : number,
BlurMult : number,
}
local sway : CFrame
local MouseDelta : Vector2
local Vel,t,x,y : number
local sin = math.sin
local cos = math.cos
local rad = math.rad
local abs = math.abs
local sqrt = math.sqrt
local clamp = math.clamp
local round = math.round
local clock = os.clock
local CurrentVel = 0
local Drift = 0
local Limiter = 0
local RunServ = game:GetService("RunService")
local UIS = game:GetService("UserInputService")
local PlrServ = game:GetService("Players")
local Workspace = game:GetService("Workspace")
local LightingServ = game:GetService("Lighting")
local LocalPlr : Player = PlrServ.LocalPlayer
local Cam : Camera = Workspace.CurrentCamera
--local BaseFov = Cam.FieldOfView
Cam.CameraType = Enum.CameraType.Custom
LocalPlr.CameraMode = Enum.CameraMode.LockFirstPerson
local char : Model = LocalPlr.Character or LocalPlr.CharacterAdded:Wait()
local hum = char:WaitForChild("Humanoid") :: Humanoid
local HRP = char:WaitForChild("HumanoidRootPart") :: BasePart
function NumLerp(num1: number, num2: number, rate: number) : number
return num1 + (num2-num1)*rate
end
function CalculateCurve(Base : number, Set : number) : number
return sin(clock() * Base) * Set
end
function GetVelMag() : number
return round(Vector3.new(HRP.AssemblyLinearVelocity.X, HRP.AssemblyLinearVelocity.Y, HRP.AssemblyLinearVelocity.Z).Magnitude)
end
function GetMouseDrift(Drift : number, MouseDelta : Vector2, dt : number) : number
return NumLerp(Drift, clamp(MouseDelta.X, Settings.DriftMin, Settings.DriftMax), (Settings.BaseMult * dt))
end
function GetSwayVal(x:number, y:number) : CFrame
return CFrame.new(Vector3.new(x, y, 0), Vector3.new(x*.95, y*.95, Settings.CustomSwayZVal)) + Cam.CFrame.Position
end
local function setBlur() : BlurEffect
local MotionBlur : BlurEffect = LightingServ:FindFirstChild("MotionBlur")
if not MotionBlur then
local newMotionBlur = Instance.new("BlurEffect")
newMotionBlur.Size = 0
newMotionBlur.Name = 'MotionBlur'
newMotionBlur.Enabled = true
newMotionBlur.Parent = LightingServ
MotionBlur = newMotionBlur
end
return MotionBlur
end
local MotionBlur = setBlur()
function ConvCFrameToOrientation(_CFrame: CFrame)
local setX, setY, setZ = _CFrame:ToOrientation()
return Vector3.new(math.deg(setX), math.deg(setY), math.deg(setZ))
end
local function CameraUpdt(dt)
Limiter += dt
if Limiter >= 1/Settings.Rate then
t = clock()
MouseDelta = UIS:GetMouseDelta()
Vel = NumLerp(CurrentVel, GetVelMag(), Settings.BaseNumLerp)
x = cos(t * Settings.BaseSway) * Settings.SetSway
y = sin(t * Settings.BaseSway) * Settings.SetSway
sway = GetSwayVal(x,y)
Drift = GetMouseDrift(Drift, MouseDelta, dt)
--Cam.FieldOfView = BaseFov + sqrt(Vel)
MotionBlur.Size = clamp(abs(Drift*Settings.BlurMult) --[[ & Vel with lower mult]], 0, Settings.MaxBlur)
CurrentVel = Vel
Cam.CFrame = Cam.CFrame--:Lerp(sway * Cam.CFrame.Rotation, Settings.SwayStrenght)
* CFrame.new(0, CalculateCurve(Settings.BaseFreq, Settings.SetFreq) * Vel / Settings.BaseMult, 0)
* CFrame.Angles(0, 0, rad(CalculateCurve(Settings.BaseRot, Settings.SetRot) * Vel / Settings.BaseMult) + rad(Drift))
hum.CameraOffset = ConvCFrameToOrientation(sway)
Limiter -= 1/Settings.Rate
end
end
RunServ:BindToRenderStep("CamEffect", Enum.RenderPriority.Camera.Value, CameraUpdt)
local function reset() : ()
LocalPlr.CameraMode = Enum.CameraMode.Classic
--Cam.CameraType = Enum.CameraType.Custom
end
--hum.Died:Once(reset)
Here is the settings module related to this script:
return{
--static
BaseRot = 2.5, -- rotation speed
SetRot = .4, -- rotation strenght
BaseFreq = 15, -- view bobbing frequency (Was 15)
SetFreq = 0.12, -- view bobbing strenght (Was .16)
BaseMult = 12, -- base multiplier: less -> stronger effects
BaseNumLerp = 0.25, -- lerp time value
--sway settings
SwayStrenght = .2, -- effect strenght (Was .2)
BaseSway = 2.3, -- axis strenght
SetSway = 0.7, -- axis multiplier (Was .5)
CustomSwayZVal = -10, -- vector z value (Was -10)
--drift min/max
DriftMin = -3, --(Was -3)
DriftMax = 1, --(Was 1)
--fps
Rate = 60,
--blur
MaxBlur = 3, -- max blur value
BlurMult = 3, -- blur multiplier
}
Sprint System
Module Script in Replicated Storage
--[[
========================================
By: luisgamercooI231fan,
Time: tue march 29 21:15:00 2022,
Description: sprint,
========================================
]]--
local module = {}
local data = {}
local player = game:GetService("Players").LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local UIS = game:GetService("UserInputService")
local TS = game:GetService("TweenService")
local CAS = game:GetService("ContextActionService")
local Anim = Instance.new('Animation')
Anim.AnimationId = "rbxassetid://16754777947" ----------animation id here
PlayAnim = character.Humanoid:LoadAnimation(Anim)
local function scale_button(CurrentCamera, name:string)
local MinAxis = math.min(CurrentCamera.ViewportSize.X, CurrentCamera.ViewportSize.Y)
local IsSmallScreen = MinAxis <= 500
local ActionButtonSize = IsSmallScreen and 70 or 120
local function RescaleActionButton(Name)
local ActionButton = CAS:GetButton(Name)
if ActionButton then
local ActionTitle = ActionButton:WaitForChild("ActionTitle")
if not IsSmallScreen then
ActionTitle.TextSize = 36
else
ActionTitle.TextSize = 18
end
ActionButton.Size = UDim2.fromOffset(ActionButtonSize, ActionButtonSize)
end
end
RescaleActionButton(name)
end
function module.new()
if game:GetService("RunService"):IsClient() then
local plr = game:GetService("Players").LocalPlayer
local self = setmetatable({}, {})
local start_time = nil
self.phone_button_offset = 45 -- the offset of the default mobile button on phones
self.tablet_button_offset = 2.45 -- the offset of the default mobile button on tablets
self.mobile_button_icon = "rbxassetid://1921587812" -- the icon for the default mobile button
local sprinted = Instance.new("BindableEvent")
local unsprinted = Instance.new("BindableEvent")
self.camera = workspace.CurrentCamera
self.mobile_button_title = nil -- the mobile button title
self.run_animation = "rbxassetid://16754777947" -- I just started scripting and idk how to use this. ,Mr_baconhair839
self.default_FOV = 90
self.FOV_tween_speed = 0.5 -- how long it takes for the fov to tween
self.FOV_tween_style = Enum.EasingStyle.Quad -- the easing style of which the tween is tweened at
self.FOV_tween_direction = Enum.EasingDirection.Out -- the easing direction of which the tween is tweened at.
self.FOV_tween_info = TweenInfo.new(self.FOV_tween_speed, self.FOV_tween_style, self.FOV_tween_direction, 0, false, 0)
self.default_speed = 21 --game:GetService("StarterPlayer").CharacterWalkSpeed -- the default speed for when you stop sprinting
self.run_speed = 32 --self.default_speed * 1.7-- the speed of which the player sprints at
self.uses_default_ui = true -- if the mobile ui uses the default mobile ui
self.sprint_ui = nil -- if the mobile ui is set to false, you can set this to add a custom ui(image button or text button).
self.Sprinted = sprinted.Event
self.Unsprinted = unsprinted.Event
self.use_run_FOV = true -- if the player's fov changes when sprinting
self.running_FOV = 130 -- the FOV for the player when they run
local goals = {
FieldOfView = self.running_FOV
}
local stop_goals = {
FieldOfView = self.default_FOV
}
local FOV_tween = TS:Create(self.camera, self.FOV_tween_info, goals)
local FOV_stop_tween = TS:Create(self.camera,self.FOV_tween_info, stop_goals)
self.valid_keys = { -- the keys that can be used to start sprinting
--[PC]--
Enum.KeyCode.LeftShift,
Enum.KeyCode.RightShift,
--[Xbox]--
Enum.KeyCode.ButtonX -- the X button on controller
}
local function sprint(name, state)
if state == Enum.UserInputState.Begin then
start_time = tick()
sprinted:Fire(start_time)
else
if start_time then
unsprinted:Fire(tick(),tick() - start_time)
else
unsprinted:Fire(tick(),0)
end
start_time = nil
end
end
self.Sprint = function(state:Enum.UserInputState)
sprint(nil, state)
end
self.Sprinted:Connect(function(start_time)
local char = plr.Character
if char then
local hum = char:FindFirstChildWhichIsA("Humanoid")
if hum then
hum.WalkSpeed = self.run_speed
if hum.WalkSpeed > 30 then --Was 15 instead of 20
PlayAnim:Play()
end
if self.use_run_FOV then
FOV_tween:Play()
end
end
end
end)
self.Unsprinted:Connect(function(end_time, activation_time)
local char = plr.Character
if char then
local hum = char:FindFirstChildWhichIsA("Humanoid")
if hum then
hum.WalkSpeed = self.default_speed
PlayAnim:Stop()
FOV_stop_tween:Play()
end
end
end)
function self:Init(id:string)
table.insert(data, self)
local CurrentCamera = self.camera
if self.uses_default_ui == true and self.sprint_ui == nil then
local MinAxis = math.min(CurrentCamera.ViewportSize.X, CurrentCamera.ViewportSize.Y)
local IsSmallScreen = MinAxis <= 500
local ActionButtonSize = IsSmallScreen and 70 or 120
CAS:BindActionAtPriority(id, sprint, true, 10000, unpack(self.valid_keys))
CAS:SetPosition(id, IsSmallScreen and UDim2.new(1, -(ActionButtonSize * 2.52), 1, -ActionButtonSize - self.phone_button_offset) or
UDim2.new(1, -(ActionButtonSize * 2.52 - 10), 1, -ActionButtonSize * self.tablet_button_offset))
scale_button(CurrentCamera, id)
if self.mobile_button_title then
CAS:SetTitle(id, self.mobile_button_title)
else
CAS:SetImage(id, self.mobile_button_icon)
end
elseif self.uses_default_ui == false and self.sprint_ui ~= nil then
local ui:TextButton | ImageButton = self.sprint_ui
if ui:IsA("TextButton") or ui:IsA("ImageButton") then
CAS:BindActionAtPriority("sprint-action", sprint, false, 10000, unpack(self.valid_keys))
if not UIS.KeyboardEnabled then
ui.Visible = true
ui.InputBegan:Connect(function(input)
sprint(nil, input.UserInputState)
end)
ui.InputEnded:Connect(function(input)
sprint(nil, input.UserInputState)
end)
else --user has keyboard
ui.Visible = false
end
end
end
end
return self
else
error('please run sprinting module on client; exit code 1')
end
end
function module:Get(id:string)
for _, sprint_data in ipairs(data) do
if sprint_data.id == id then
return sprint_data
end
end
end
return module
Local Script in StarterPlayerScripts
local module = require(game.ReplicatedStorage:WaitForChild("SprintModule"))
local sprint_data = module.new() -- creates our sprinting data
sprint_data:Init("sprint") -- initialize for it to start being used, sprint is the id of the sprint data, this is required.
The First Person Visible Character Script (Just if you need it)
for i, v in script.Parent:GetChildren() do
if not v:IsA("BasePart") then
continue
end
v:GetPropertyChangedSignal("LocalTransparencyModifier"):Connect(function()
v.LocalTransparencyModifier = 0
end)
v.LocalTransparencyModifier = 0
end
script.Parent.ChildAdded:Connect(function(v)
if not v:IsA("BasePart") then
return
end
v:GetPropertyChangedSignal("LocalTransparencyModifier"):Connect(function()
v.LocalTransparencyModifier = 0
end)
v.LocalTransparencyModifier = 0
end)
Thank You All