How to make an Fps viewmodel part 2! Anims and damage script

Before i start I would like to say that this is not the only way to make an fps viewmodel, this is just my way which I have been doing for months now so I hope you enjoy.
Last thing Part 3 will focus on reloads and sway.

Step 1 Damage
Create a script called Server and rename your local script to Local.
Inside of your local script type this,

local db = false
local Camera = game.Workspace.CurrentCamera
local Head = game.Players.LocalPlayer.Character.Head
local Player = game.Players.LocalPlayer
local Mouse = Player:GetMouse()
Mouse.Button1Down:Connect(function() -- if mouse down
	if db == false then -- If the debounce is dissabled (Debounce is a cooldown)
		if (Camera.CFrame.Position - Head.Position).Magnitude < 0.8 then -- If in first person
			db = true -- start cooldown
            print("hi")
			wait(0.5) -- time between cooldown
			db = false -- end cooldown
		end
	end
end)

This will make it so when you click it prints “hi”
Now inside of handle add a fire sound and name it Shoot.
Now replace print(“hi”) with script.Parent.Handle.Shoot:Play()
This will play the shoot sfx. Now create a remote event inside of Local, after script.Parent.Handle.Shoot:Play() do script.RemoteEvent:FireServer(Mouse.Hit.Position) This will fire the server and make it so you can connect a server script to this. Now open the script server and paste this:

script.Parent.Local.RemoteEvent.OnServerEvent:Connect(function(player,mousePos) -- gets player and mouse position
	local raycastParams = RaycastParams.new()
	raycastParams.FilterDescendantsInstances = {player.Character}
	raycastParams.FilterType = Enum.RaycastFilterType.Blacklist

	local raycastResult = workspace:Raycast(player.Character.HumanoidRootPart.Position,(mousePos - player.Character.HumanoidRootPart.Position)*1000,raycastParams) -- Were ray starts

	if raycastResult then
		local hitPart = raycastResult.Instance -- what the ray hits
		local model = hitPart:FindFirstAncestorOfClass("Model") -- if ray hits model

		if model then
			if model:FindFirstChild("Humanoid") then -- if hits model with humanoid
				model.Humanoid.Health -= 30 -- hurt player replace number with damage number
			end
		end
	end
end)

This will create a ray wich if a player gets hit 30 damage will be taken away from the players health, you can replace 30 with the amount of damage you want taken.

Last step for part 2 Animations!
First open the animation editor and create an Idle animation for your gun, now set looped to true,


now set the animation type to action.
Screen Shot 2022-06-20 at 1.19.51 PM
You can now export the animation and copy the id.
Now inside handle create an animation call this animation Idle and paste the id
Screen Shot 2022-06-20 at 1.20.32 PM
Now inside your local script at the top type: local idle = script.Parent:WaitForChild("AnimationController").Animator:LoadAnimation(script.Parent.Handle.Idle) now under RunService.RenderStepped:Connect(function(step) write idle:Play() Now your idle animation should work! The last step for today is to create the shoot animation, hop into the animator and create a shoot animation, do not loop the animation. Then set the animation type to action. Export and create a new animation in handle, call this animation ShootAnim and paste your id.
Screen Shot 2022-06-20 at 1.29.03 PM
Now inside of Local at the top paste local ShootAnim = script.Parent:WaitForChild("AnimationController").Animator:LoadAnimation(script.Parent.Handle.ShootAnim) and right after script.Parent.Handle.Shoot:Play() write ShootAnim:Play() The local script should look like this in the end,

local idle = script.Parent:WaitForChild("AnimationController").Animator:LoadAnimation(script.Parent.Handle.Idle)
local ShootAnim = script.Parent:WaitForChild("AnimationController").Animator:LoadAnimation(script.Parent.Handle.ShootAnim)
local RunService = game:GetService("RunService")
RunService.RenderStepped:Connect(function(step)
	idle:Play()
	script.Parent.PrimaryPart.CFrame = game.Workspace.CurrentCamera.CFrame
end)
RunService.RenderStepped:Connect(function(step)
	for index, instance in pairs(script.Parent:GetDescendants()) do 
		if instance:IsA("BasePart") then
			instance.LocalTransparencyModifier = 0
		end
	end
end)

local db = false
local Camera = game.Workspace.CurrentCamera
local Head = game.Players.LocalPlayer.Character.Head
local Player = game.Players.LocalPlayer
local Mouse = Player:GetMouse()
Mouse.Button1Down:Connect(function() -- if mouse down
	if db == false then -- If the debounce is dissabled (Debounce is a cooldown)
		if (Camera.CFrame.Position - Head.Position).Magnitude < 0.8 then -- If in first person
			db = true -- start cooldown
			script.RemoteEvent:FireServer(Mouse.Hit.Position) -- will fire a server that sets of a server script
			script.Parent.Handle.Shoot:Play()
			ShootAnim:Play()
			wait(0.5) -- time between cooldown
			db = false -- end cooldown
		end
	end
end)

That’s the end of part 2 like for part 3!

Part 3:

3 Likes

You shouldn’t do this. Set it to “Idle”. Have you tested this code with AnimationWeightBlendFix under Workspace properties set to “Enabled” or “Default”?

The shoot/reload animations should be Action because that makes the most sense, only one of them will be playing at once.

You should remove debugging prints from Tutorials.

1 Like

This was to show the player what happens in the code, I added that for the tutorial also for the first one it doesn’t really make a difference, I have play tested this alot and it works fine. Edit: I will check in the animator and see the difference in game.

1 Like