Making an FPS system, thoughts on the movement of the viewmodel?

I’m working on an FPS system as the title says. It took me a good while but I’m happy with the end result!
Just two problems I’ve had

  • When Tapping any direction, the viewmodel instantly snaps to the SwayCFrame
  • Idk how to put in movement when you jump :frowning:

That aside, take a look and give me your thoguhts!

1 Like

I’ll even put in the code, if anyone wants to see.

-- Service
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local CollectionService = game:GetService("CollectionService")

-- Var
local Camera = workspace.CurrentCamera
local Plr = Players.LocalPlayer

local Tag = "Test_ViewModel"

-- Wait For load
local Character = Plr.Character or Plr.CharacterAppearanceLoaded:Wait()
local Humanoid = Character:FindFirstChildOfClass("Humanoid")

repeat task.wait() until CollectionService:GetTagged(Tag)[1] ~= nil

local Viewmodel : Model = CollectionService:GetTagged(Tag)[1]; print(Viewmodel)

-- Setup Viewmodel
local vm_colors = Viewmodel:FindFirstChildOfClass("BodyColors")
local bodycolors = Character:FindFirstChildOfClass("BodyColors")

if Character:FindFirstChildOfClass("Shirt") then
	Viewmodel:FindFirstChildOfClass("Shirt").ShirtTemplate = Character:FindFirstChildOfClass("Shirt").ShirtTemplate
end
vm_colors.LeftArmColor3 = bodycolors.LeftArmColor3
vm_colors.RightArmColor3 = bodycolors.RightArmColor3

Viewmodel.Parent = workspace.VM_store

--////////////////////////////////
-- Calibration Variables
local LastCameraCFrame = CFrame.new()

local SwayAmount = 0.55
local SwayCFrame = CFrame.new()

local LeftTiltMax = CFrame.Angles(0, 0, math.rad(-5))
local RightTiltMax = CFrame.Angles(0, 0, math.rad(5))
local TiltCFrame = CFrame.new()
local LastTiltCFrame = CFrame.new()

local BobOffset
--////////////////////////////////

-- Func
local function CalibrateViewModel(Delta)
	local evilalpha = 1 - 0.005 ^ Delta; local testalpa = 0.07
	--Sway
	local Rot = Camera.CFrame:ToObjectSpace(LastCameraCFrame)
	local x, y, z = Rot:ToOrientation()
	SwayCFrame = SwayCFrame:Lerp(CFrame.Angles(math.sin(x) * SwayAmount, math.sin(y) * SwayAmount, 0), 0.15)
	LastCameraCFrame = Camera.CFrame
	
	--Tilt
	local RawTilt = Humanoid.MoveDirection:Dot(Camera.CFrame.RightVector)
	local Tilt = math.round(RawTilt / 0.01) * 0.01
	
	if Tilt == 0 then
		TiltCFrame = LastTiltCFrame:Lerp(CFrame.Angles(0, 0, 0), 0.075)
	elseif Tilt > 0.7 then
		TiltCFrame = LastTiltCFrame:Lerp(LeftTiltMax, testalpa)
	elseif Tilt < 0.7 then
		TiltCFrame = LastTiltCFrame:Lerp(RightTiltMax, testalpa)
	end
	
	LastTiltCFrame = TiltCFrame
	
	--Bobbing
	if Humanoid.MoveDirection.Magnitude > 0 then
		BobOffset = CFrame.new(math.cos(tick() * 5) * 0.25, math.sin(tick() * 10) * 0.125, -Humanoid.CameraOffset.Z/3)
	else
		BobOffset = CFrame.new(0, -Humanoid.CameraOffset.Y/3, 0)
	end
	
	Viewmodel:PivotTo(
		Camera.CFrame * TiltCFrame * SwayCFrame * BobOffset-- Service
		local ReplicatedStorage = game:GetService("ReplicatedStorage")
		local RunService = game:GetService("RunService")
		local Players = game:GetService("Players")
		local CollectionService = game:GetService("CollectionService")

		-- Var
		local Camera = workspace.CurrentCamera
		local Plr = Players.LocalPlayer

		local Tag = "Test_ViewModel"

		-- Wait For load
		local Character = Plr.Character or Plr.CharacterAppearanceLoaded:Wait()
		local Humanoid = Character:FindFirstChildOfClass("Humanoid")

		repeat task.wait() until CollectionService:GetTagged(Tag)[1] ~= nil

		local Viewmodel : Model = CollectionService:GetTagged(Tag)[1]

		-- Setup Viewmodel
		local vm_colors = Viewmodel:FindFirstChildOfClass("BodyColors")
		local bodycolors = Character:FindFirstChildOfClass("BodyColors")

		if Character:FindFirstChildOfClass("Shirt") then
			Viewmodel:FindFirstChildOfClass("Shirt").ShirtTemplate = Character:FindFirstChildOfClass("Shirt").ShirtTemplate
		end
		vm_colors.LeftArmColor3 = bodycolors.LeftArmColor3
		vm_colors.RightArmColor3 = bodycolors.RightArmColor3

		Viewmodel.Parent = workspace.VM_store

		--////////////////////////////////
		-- Calibration Variables
		local LastCameraCFrame = CFrame.new()

		local SwayAmount = 0.55
		local SwayCFrame = CFrame.new()

		local LeftTiltMax = CFrame.Angles(0, 0, math.rad(-5))
		local RightTiltMax = CFrame.Angles(0, 0, math.rad(5))
		local TiltCFrame = CFrame.new()
		local LastTiltCFrame = CFrame.new()

		local BobOffset
		--////////////////////////////////

		-- Func
		local function CalibrateViewModel(Delta)
			
			--Sway
			local Rot = Camera.CFrame:ToObjectSpace(LastCameraCFrame)
			local x, y, z = Rot:ToOrientation()
			SwayCFrame = SwayCFrame:Lerp(CFrame.Angles(math.sin(x) * SwayAmount, math.sin(y) * SwayAmount, 0), 0.15)
			LastCameraCFrame = Camera.CFrame

			--Tilt
			local RawTilt = Humanoid.MoveDirection:Dot(Camera.CFrame.RightVector)
			local Tilt = math.round(RawTilt / 0.01) * 0.01

			if Tilt == 0 then
				TiltCFrame = LastTiltCFrame:Lerp(CFrame.Angles(0, 0, 0), 0.075)
			elseif Tilt > 0.7 then
				TiltCFrame = LastTiltCFrame:Lerp(LeftTiltMax, 0.07)
			elseif Tilt < 0.7 then
				TiltCFrame = LastTiltCFrame:Lerp(RightTiltMax, 0.07)
			end

			LastTiltCFrame = TiltCFrame

			--Bobbing
			if Humanoid.MoveDirection.Magnitude > 0 then
				BobOffset = CFrame.new(math.cos(tick() * 5) * 0.25, math.sin(tick() * 10) * 0.125, -Humanoid.CameraOffset.Z/3)
			else
				BobOffset = CFrame.new(0, -Humanoid.CameraOffset.Y/3, 0)
			end

			Viewmodel:PivotTo(
				Camera.CFrame * TiltCFrame * SwayCFrame * BobOffset
			)

		end

		-- Start
		RunService:BindToRenderStep("Test_ViewModelCalibrate", 301, CalibrateViewModel)
	)
	
end

-- Start
RunService:BindToRenderStep("Test_ViewModelCalibrate", 301, CalibrateViewModel)

Well, looks pretty smooth with the shaking effect when you’re moving, so good job on making this :grinning:

2 Likes

2 suggestions

  1. is to make an option for players to shrink or “minimize” the view model (if you don’t have already) because some players (like me) hate having their vision obstructed by a view model (no matter how cool it is)

  2. is to make it a tad closer to the player, and angle a bit in as this is more realistic

For your first suggestion, I’ll definitely keep that in mind, thank you for that!
For your second suggestion, I’ll do some research and experiment, as well as get others opinions>
Thanks!

1 Like

no problem, happy developing!

Small quick reply, did some testing with a friend real quick and I like this look much better!
I’ll experiment with settings like you proposed much later down the line
Thats all for now, have a good one

1 Like

This FPS system and movement look VERY good! Great job on it! How long did it take you to create all of this? It’s very cool!

I’ve been working on this on and off for about a month and a half I’d say
Took some tutorials, some of my own knowledge, and a lot of tweaking to get the values used in this.
I plan to make this easy to use and maybe even in a module script and distribute it for everyone to use.