How to make a lazy fps shooter. Part 2

:warning: This tutorial is outdated, instead follow this one Making a simple fps framework. Part 1

Before I start I got some feedback which understandable.

You should explain some things. It’s bad for someone just to take code, and then later on not understand how to modify it and end up getting demotivated.

This is for people that knows cframes and raycasting

Now lets start!

Step 1 More animations!
Now the most of our animations are going to be CFrame animations.
“What is that?” You may be asking.

Well how I think it is its a cframe lerping.(I can’t get a working example)

So lets get going into our animations!

In the FPS module go to the RenderStepped function and now we are going to make a another idle animation that goes up and down.

But first we need to set the cframe.
So do this :

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RS = game:GetService("RunService")
local Viewmodels = ReplicatedStorage:WaitForChild("Viewmodels")
local viewModel : Model
local IdleCF = CFrame.new()

Later on we will be adding this to the :SetPrimaryPartCFrame function.

This is because just leaving the cframe will do nothing because the code will not know what IdleCF does.

Now set the IdleCF to a CFrame.new() in the EquipGun function just to make sure.

So now we are going to do this in the RenderStepped function:

IdleCF = CFrame.new(0 ,0.1 * math.sin(tick() * 6),0)

I have no idea how it works I just made this by accident when I was working on a fps game.

Now your code should look like this:

local module = {}

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RS = game:GetService("RunService")
local Viewmodels = ReplicatedStorage:WaitForChild("Viewmodels")
local viewModel : Model
local IdleCF = CFrame.new()

function module:animate(type)
	if type == "Idle" then
		if viewModel then
			viewModel.AnimationController:LoadAnimation(viewModel.AnimationController.Idle):Play()
		end
	end
end

function module:EquipGun(Name)
	viewModel = Viewmodels:WaitForChild(Name):Clone()
	viewModel.Parent = workspace.CurrentCamera
	IdleCF = CFrame.new(0,0,0)
	module:animate("Idle")
end



RS.RenderStepped:Connect(function()
	if viewModel then
		IdleCF = CFrame.new(0 ,0.1 * math.sin(tick() * 6),0)
		viewModel:SetPrimaryPartCFrame(workspace.CurrentCamera.CFrame * IdleCF)
	end
end)

return module

And you got a idle animation :

Now a shooting(recoil) animation

This is simple so won’t explain this.

Do the same thing as the we did for the idle animation but change the cframe to:

RecoilCF =  RecoilCF:Lerp(CFrame.new(0,0,0.5) * CFrame.Angles(math.rad(10),0,0),0.1)

Now your module should look like this:

local module = {}

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RS = game:GetService("RunService")
local Viewmodels = ReplicatedStorage:WaitForChild("Viewmodels")
local viewModel : Model
local IdleCF = CFrame.new()
local RecoilCF = CFrame.new()

function module:animate(type)
	if type == "Idle" then
		if viewModel then
			viewModel.AnimationController:LoadAnimation(viewModel.AnimationController.Idle):Play()
		end
	end
end

function module:EquipGun(Name)
	viewModel = Viewmodels:WaitForChild(Name):Clone()
	viewModel.Parent = workspace.CurrentCamera
	IdleCF = CFrame.new(0,0,0)
	RecoilCF = CFrame.new(0,0,0)
	module:animate("Idle")
end



RS.RenderStepped:Connect(function()
	if viewModel then
		IdleCF = CFrame.new(0 ,0.1 * math.sin(tick() * 6),0)
		RecoilCF =  RecoilCF:Lerp(CFrame.new(0,0,0.5) * CFrame.Angles(math.rad(10),0,0),0.1)
		viewModel:SetPrimaryPartCFrame(workspace.CurrentCamera.CFrame * IdleCF * RecoilCF)
	end
end)

return module

But its happing at the same time!

To fix this we need to make bools to check if its true we do the animation but if its false we don’t do the animation.

So your going to replace the module code with this:

local module = {}

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UIS = game:GetService("UserInputService")
local RS = game:GetService("RunService")
local Players = game:GetService("Players")
local Viewmodels = ReplicatedStorage:WaitForChild("Viewmodels")
local viewModel : Model
local IdleCF = CFrame.new()
local RecoilCF = CFrame.new()
local isRecoil = false
local isIdle = false
local localPlayer = Players.LocalPlayer
local Char = localPlayer.Character or localPlayer.CharacterAdded:Wait()

function module:animate(type)
	if type == "Idle" then
		if viewModel then
			viewModel.AnimationController:LoadAnimation(viewModel.AnimationController.Idle):Play()
		end
	end
end

function module:EquipGun(Name)
	viewModel = Viewmodels:WaitForChild(Name):Clone()
	viewModel.Parent = workspace.CurrentCamera
	IdleCF = CFrame.new(0,0,0)
	RecoilCF = CFrame.new(0,0,0)
	module:animate("Idle")
end



RS.RenderStepped:Connect(function()
	if viewModel then
		viewModel:SetPrimaryPartCFrame(workspace.CurrentCamera.CFrame * IdleCF * RecoilCF)
		if IdleCF then
			IdleCF = CFrame.new(0 ,0.1 * math.sin(tick() * 6),0)
		else
			IdleCF = CFrame.new(0,0,0)
		end
		if isRecoil then
			RecoilCF =  RecoilCF:Lerp(CFrame.new(0,0,0.5) * CFrame.Angles(math.rad(10),0,0),0.1)
		else
			RecoilCF =  RecoilCF:Lerp(CFrame.new(0,0,0) * CFrame.Angles(math.rad(10),0,0),0.1)
		end
	end
end)

UIS.InputBegan:Connect(function(inputKey)
	if inputKey.UserInputType == Enum.UserInputType.MouseButton1 then
		isRecoil = true
	end
end)

UIS.InputEnded:Connect(function(inputKey)
	if inputKey.UserInputType == Enum.UserInputType.MouseButton1 then
		isRecoil = false
	end
end)

Char:WaitForChild("Humanoid").Running:Connect(function(speed)
	if speed < 0.1 then
		isIdle = true
	else
		isIdle = false
		
	end
end)

return module

Now its fixed well kind of.
We will fix more of it in part 3.

Step 2 Raycasting
To make this a fps shooter we need the shooting.

So raycasting :slight_smile:

So create a script called Server in ServerScriptService.
And then create a RemoteEvent called Shoot in ReplicatedStorage.

In the Server script your going to type this in:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Shoot = ReplicatedStorage:WaitForChild("Shoot")

Then connect the RemoteEvent by doing this:

Shoot.OnServerEvent:Connect(function(plr, orgin, dir, distance)
	
end)

Then in the connection do this:

local rayCastTotal = workspace:Raycast(orgin, dir*distance)

if rayCastTotal.Instance then
	if rayCastTotal.Instance.Parent:FindFirstChild("Humanoid") then
		rayCastTotal.Instance.Parent:FindFirstChild("Humanoid"):TakeDamage(10)
	end
end

Okay now when we click we need to fire this RemoteEvent.

So in our FPS module go to InputBegan function and add this:

if viewModel then
   ReplicatedStorage:WaitForChild("Shoot"):FireServer(viewModel.Handle.Position, (Mouse.Hit.Position - viewModel.Handle.Position), 10)
end

Also add a dummy if you want.

And shooting is done!

End!

That is the end of this tutorial!

If you missed part 1 here it is: How to make a lazy fps shooter. Part 1

Tell me if you found this useful or anything!

6 Likes

Even though It’s says a lazy tutorial I will still take it as a real tutorial thanks

1 Like

Your welcome. Also the reason why I call it lazy is because is isn’t like a FE Gun kit.

2 Likes

You could alternatively use a number 0-360 inclusive for one whole cycle of possible values. That looks like unnecessary multiplication.

Edit:
This is an alternate, less expensive way to do what you’re doing (specially if you’re doing it on RenderStepped). Your code will still work obviously.

But it still works. The only reason I do that is because I can’t think of doing a another way and its shorter code for me.(Oh wait he changed it. Theres no point of saying this)

If you could take the time to read the first part of my post, you’ll see I suggested how you could do it:

I mean theres no code that how I can I code that I can think of.

You should look into using springs more often in your future tutorials. They are not too tricky to use and look really, really smooth. Most FPS games use springs for things such as sway when you move your camera or recoil for when you shoot your weapon.

I never used spring to be honest.