Designing an FPS Framework: Beginner’s guide [PART 2]

so i create a new module and put that inside?

You’d probably have to replace your current spring with that one, or you can use both. If you’re going to replace it make sure you replace all of the old springs with the new one.

image
ok what have i done

wait nevermind i jsut changed replicated storage name lol

well its still the same error image

1 Like

This amazing guide helped me out so much. Tho I’m not quite sure how to make ammo.

UPDATE: Added section 7: Reload. enjoy!

3 Likes

Hello, i am having some trouble with the casting part
Here is the error

https://gyazo.com/7f93d350b8071210efd9b1dc812cd9c0

function module.cast(gun, endposition, velocity, damage, ViewModel)
	local Origin = gun.GunComponents.Barrel
	
	local CastParams = RaycastParams.new()
	CastParams.IgnoreWater = true
	CastParams.FilterType = Enum.RaycastFilterType.Blacklist
	CastParams.FilterDescendantsInstances = {ViewModel, game.Players.LocalPlayer.Character}

	local MouseLocation = game:GetService("UserInputService"):GetMouseLocation()
	local UnitRay = game:GetService("Workspace").Camera:ViewportPointToRay(MouseLocation.x, MouseLocation.y)

	local origin = UnitRay.Origin
	local endp = UnitRay.Direction * 1000
	local Hit = game:GetService("Workspace"):Raycast(origin, endp, CastParams)
	
	local Bullet = Instance.new("Part")
	Bullet.Size = Vector3.new(0.1,0.1,5)
	Bullet.CanCollide = false
	Bullet.BrickColor = BrickColor.new("Bright yellow")
	Bullet.Material = Enum.Material.Neon
	Bullet.Anchored = true
	Bullet.Parent = workspace
	

	
	if Hit then
		Bullet.CFrame = CFrame.new(Origin.Position, Hit.Position)
	else
		Bullet.CFrame = CFrame.new(Origin.Position, UnitRay.Origin + UnitRay.Direction * 1000)
	end
	
	local Loop
	
	Loop = game:GetService("RunService").RenderStepped:Connect(function(dt)
		
		local Hit = workspace:Raycast(Bullet.Position, Bullet.CFrame.LookVector * velocity * 1.5)

		if Hit then
			if Hit.Instance.Parent:FindFirstChild("Humanoid") and damage ~= nil then

				damage:FireServer(Hit.Instance.Parent, 10)

			else 

				Loop:Disconnect()
				Bullet:Destroy()

			end
		end
		
		Bullet.CFrame *= CFrame.new(0, 0, -velocity * (dt * 60))
	end)
end

Edit: i edited the cast, because i had the same problem i suppose its comming from the Arguements

Edit2: NVM I FOUND THE Solution to it! its actually because at Fire OnClientEvent in the LocalHandler, the “client” is actually the origin’s position, so to do that i must also Replicate the Player on the FireAllClients arguements, Anyway, Good Tutorial you got there

Few things I would like to know: How do I implement running into it and how do I make the gun semi auto?

For running you want to detect an input from the player and increase the walkspeed accordingly, if you also want the gun to have an animation just apply one when player speed reaches above normal.

Making it semi is just detecting the gun’s firemode and if it’s semi you just have to make another variable and check if the variable is false, once the mouse lifts up you turn on the variable

local isSemi = true
if isSemi and canShootSemi == true then
    canShootSemi = false
end

mousebutton1up:connect(function()
    canShootSemi = true
end)

But don’t you have to define what canShootSemi is? so It will know what to do? I also would like to know how would you make classes like for example you click a textbutton you would spawn with that framework

Hey yo, I am quoting this so a friend of mine can see.
Pls no blame, I was trying to talk to him about how to make the gun sway

Im stuck on this part because all it does is just go straight up not bounce around also i have no idea where to put this at all like do u put it in a Runservice? Or just by itself? This is what i have so far in both my scripts

LocalHandler:

 local gunmodel = game.ReplicatedStorage:WaitForChild("MiniGun")
 local AnimationsFolder = game.ReplicatedStorage:WaitForChild("MiniGunAnimations")
 local viewportmodel = game.ReplicatedStorage:WaitForChild("Viewmodel")
 local ts = game:GetService("TweenService")
 local firing = viewportmodel.AnimationController:LoadAnimation(AnimationsFolder.Firing)
 local springmodule = require(game.ReplicatedStorage.SpringModule)
 local recoilspring = springmodule.new()


-- mainmodule idk

local mainmodule = require(game.ReplicatedStorage.GunSystemMainModule)

viewportmodel.Parent = game.Workspace.Camera

--position viewport model

game:GetService("RunService").RenderStepped:Connect(function(dt)
mainmodule.update(viewportmodel,dt, recoilspring)
end)

--calls the weldgun thing
mainmodule.weldgun(gunmodel)
--equip thing
mainmodule.equip(viewportmodel,gunmodel, AnimationsFolder.Hold)
local IsPlayerHoldingMouse
local CanFire = true
local Delay_ = 0.1

game:GetService("RunService").Heartbeat:Connect(function(dt)
if IsPlayerHoldingMouse then
	if CanFire then
		CanFire = false
		
		recoilspring:shove(Vector3.new(1,0,0))
		mainmodule.cast(gunmodel, game.Players.LocalPlayer:GetMouse().Hit.Position,60)
		wait(Delay_)
		CanFire = true
	end
end
end)

recoilspring:shove(Vector3.new(3,math.random(-2,2),10))

coroutine.wrap(function()
wait(0.2)
recoilspring:shove(Vector3.new(-2.8,math.random(-1,1),-10))
end)()

game:GetService("UserInputService").InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
	IsPlayerHoldingMouse = true
	firing:Play()
end
end)
game:GetService("UserInputService").InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
	IsPlayerHoldingMouse = false
	firing:Stop()
end
end)

MainModule:

local module = {}



function module.update(viewmodel, dt, recoilspring)
viewmodel.HumanoidRootPart.CFrame = game.Workspace.Camera.CFrame

local updatedrecoilspring = recoilspring:update(dt)

viewmodel.HumanoidRootPart.CFrame *= CFrame.Angles(math.rad(updatedrecoilspring.X) * 
2,0,0)
game.Workspace.Camera.CFrame *= CFrame.Angles(math.rad(updatedrecoilspring.X),math.rad(updatedrecoilspring.Y),math.rad(updatedre 
coilspring.Z))
end
--Weld gun or something

function module.weldgun(gun)
local main = gun.Components.Handle
for i, v in pairs(gun:GetDescendants()) do
	if v:IsA("BasePart") and v ~= main then
		local newmotor = Instance.new("Motor6D")
		newmotor.Name = v.Name
		newmotor.Part0 = main
		newmotor.Part1 = v
		newmotor.C0 = newmotor.Part0.CFrame:Inverse() * newmotor.Part1.CFrame
		newmotor.Parent = main
	end
end
end

function module.equip(viewmodel,gun, hold)
local gunhandle = gun.Components.Handle
local HRP_Motor6D = viewmodel:WaitForChild("HumanoidRootPart").Handle

gun.Parent = viewmodel
HRP_Motor6D.Part1 = gunhandle

local Hold = viewmodel.AnimationController:LoadAnimation(hold)
Hold:Play()
end
function module.cast(gun, endposition, velocity)
local gunbarrel = gun.Components.Barrel
local bullet = Instance.new("Part")
bullet.Size = Vector3.new(1,1,5)
bullet.Anchored = true
bullet.CanCollide = false
bullet.Color = Color3.new(1, 1, 0)
bullet.Material = Enum.Material.Neon
bullet.Parent = game.Workspace

bullet.CFrame = CFrame.new(gunbarrel.Position, endposition)
local loop
loop = game:GetService("RunService").RenderStepped:Connect(function(dt)
	bullet.CFrame *= CFrame.new(0,0,-velocity * (dt * 60))
	
	if (bullet.Position - gunbarrel.Position).magnitude > 5000 then
		bullet:Destroy()
		loop:Disconnect()
	end
end)

end




return module

Edit:I fixed it!

2 Likes

@EXM_0 I have a question about the particle emitter on this it doesnt say to change anything other then lock to part and disable i did both of those and it doesnt look like how it does in the video.
Heres the result i got: (Sorry for the low quality i had to take a roblox video recording and screenshot that)


Heres a video if you want more:
robloxapp-20211123-0031534.wmv (1.6 MB)

Edit: i was carrying on with the tutorial until you responded to this until i ran into this error with the swaying
image
And it goes to this line in the spring module:

	local scaledDeltaTime = dt * self.Speed / ITERATIONS

Here are my scripts:

MainModule
local module = {}

local function GetBobbing(addition)
return math.sin(tick() * addition * 1.3) * 0.5
end

function module.update(viewmodel, dt, recoilspring, bobbleswaying, swayingspring)
viewmodel.HumanoidRootPart.CFrame = game.Workspace.Camera.CFrame

local bobble = Vector3.new(GetBobbing(10), GetBobbing(5),GetBobbing(5))
local mousedelta = game:GetService("UserInputService"):GetMouseDelta()

local character = game.Players.LocalPlayer.Character or game.Players.LocalPlayer.CharacterAdded:Wait()

bobbleswaying:shove(bobble / 10 * (character.HumanoidRootPart.Velocity.Magnitude) / 10)
swayingspring:shove(Vector3.new(-mousedelta.X / 500, mousedelta.Y / 200, 0))

local updatedrecoilspring = recoilspring.update(dt)
local updatedbobblespring = bobbleswaying.update(dt)
local updatedswayingspring = swayingspring.update(dt)

viewmodel.HumanoidRootPart.CFrame = viewmodel.HumanoidRootPart.CFrame:ToWorldSpace(CFrame.new(updatedbobblespring.Y,updatedb obblespring.X,0))
viewmodel.HumanoidRootPart.CFrame *= CFrame.new(updatedswayingspring.X,updatedswayingspring.Y,0)

viewmodel.HumanoidRootPart.CFrame *= CFrame.Angles(math.rad(updatedrecoilspring.X) * 2,0,0)
game.Workspace.Camera.CFrame *= CFrame.Angles(math.rad(updatedrecoilspring.X),math.rad(updatedrecoilspring.Y),math.rad(updatedrecoilspring.Z))
 end
 --Weld gun or something

 function module.weldgun(gun)
local main = gun.Components.Handle
for i, v in pairs(gun:GetDescendants()) do
	if v:IsA("BasePart") and v ~= main then
		local newmotor = Instance.new("Motor6D")
		newmotor.Name = v.Name
		newmotor.Part0 = main
		newmotor.Part1 = v
		newmotor.C0 = newmotor.Part0.CFrame:Inverse() * newmotor.Part1.CFrame
		newmotor.Parent = main
	end
end
end

function module.equip(viewmodel,gun, hold)
local gunhandle = gun.Components.Handle
local HRP_Motor6D = viewmodel:WaitForChild("HumanoidRootPart").Handle

gun.Parent = viewmodel
HRP_Motor6D.Part1 = gunhandle

local Hold = viewmodel.AnimationController:LoadAnimation(hold)
Hold:Play()
end
function module.cast(gun, endposition, velocity)
local gunbarrel = gun.Components.Barrel
local bullet = Instance.new("Part")
bullet.Size = Vector3.new(1,1,5)
bullet.Anchored = true
bullet.CanCollide = false
bullet.Color = Color3.new(1, 1, 0)
bullet.Material = Enum.Material.Neon
bullet.Parent = game.Workspace

bullet.CFrame = CFrame.new(gunbarrel.Position, endposition)
local loop
loop = game:GetService("RunService").RenderStepped:Connect(function(dt)
	bullet.CFrame *= CFrame.new(0,0,-velocity * (dt * 60))
	
	
	if (bullet.Position - gunbarrel.Position).magnitude > 5000 then
		bullet:Destroy()
		loop:Disconnect()
	end
end)

end




return module
LocalHandler
local gunmodel = game.ReplicatedStorage:WaitForChild("MiniGun")
local AnimationsFolder = game.ReplicatedStorage:WaitForChild("MiniGunAnimations")
local viewportmodel = game.ReplicatedStorage:WaitForChild("Viewmodel")
local ts = game:GetService("TweenService")
local firing = viewportmodel.AnimationController:LoadAnimation(AnimationsFolder.Firing)
local springmodule = require(game.ReplicatedStorage.SpringModule)
local recoilspring = springmodule.new()
local bobbleswaying = springmodule.new()
local swayspring = springmodule.new()


-- mainmodule idk

 local mainmodule = require(game.ReplicatedStorage.GunSystemMainModule)

viewportmodel.Parent = game.Workspace.Camera

--position viewport model

game:GetService("RunService").RenderStepped:Connect(function(dt)
mainmodule.update(viewportmodel,dt, recoilspring, bobbleswaying, swayspring)
end)

--calls the weldgun thing
mainmodule.weldgun(gunmodel)
--equip thing
mainmodule.equip(viewportmodel,gunmodel, AnimationsFolder.Hold)
local IsPlayerHoldingMouse
local CanFire = true
local Delay_ = 0.1

game:GetService("RunService").Heartbeat:Connect(function(dt)
if IsPlayerHoldingMouse then
	if CanFire then
		CanFire = false
		recoilspring:shove(Vector3.new(2,math.random(-2,2),10))
		
		coroutine.wrap(function()
			for i, v in pairs(gunmodel.Components.Barrel:GetChildren()) do
				if v:IsA("ParticleEmitter") then
					v:Emit()
				end
			end
			
			local firesound = gunmodel.Components.Sounds.MiniGunFiring:Clone()

			firesound.Parent = game.Workspace
			firesound.Parent = nil
			firesound:Destroy()
		end)()


		coroutine.wrap(function()
			wait(0.2)
			recoilspring:shove(Vector3.new(-2.8,math.random(-1,1),-10))
		end)()
		recoilspring:shove(Vector3.new(1,0,0))
		mainmodule.cast(gunmodel, game.Players.LocalPlayer:GetMouse().Hit.Position,60)
		wait(Delay_)
		CanFire = true
	end
end
end)



game:GetService("UserInputService").InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
	IsPlayerHoldingMouse = true
	firing:Play()
end
end)
game:GetService("UserInputService").InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
	IsPlayerHoldingMouse = false
	firing:Stop()
end
end)
2 Likes

HI regarding the error, it should be :update(dt) not .update(dt). About the particle emitter, you should just try adjusting the setting of the particle emitter. My current emitter looks something like this.

image

1 Like

How did i not notice that i put .update instead of :update well thanks!
Also the particles still do things a bit weird but ill play with the speed and stuff.
One more thing i updated the code and now i get this error

06:09:15.920  HumanoidRootPart is not a valid member of Model "Workspace.spydercam500"  -  
Client 
GunSystemMainModule:15

This is the line it goes to:

bobbleswaying:shove(bobble / 10 * (character.HumanoidRootPart.Velocity.Magnitude) / 10)

Already mentioned about this error here.

1 Like

Oh ok thanks!

I didnt know where to put the :WaitForChild() so i just used a repeat wait() until game.Loaded at the start of the script and it worked perfectly!

Ah well that’s good and just to mention a better method to that is

if not game:IsLoaded() then
    game.Loaded:Wait()
end

(fyi you put the waitforchild on the humanoirdrootpart)

1 Like

Ive ran into a issue with 0 errors (sorry for asking for help 3 diffrent times lol) basically ive gotten to the damage part and i cant seem to make it work im pretty sure that i did everything right unless its just another spelling mistake.

Heres all the scripts:

MainModule
local module = {}

if not game.Loaded then
game.Loaded:Wait()
end

local function GetBobbing(addition)
return math.sin(tick() * addition * 1.3) * 0.5
end

function module.update(viewmodel, dt, recoilspring, bobbleswaying, swayingspring)
viewmodel.HumanoidRootPart.CFrame = game.Workspace.Camera.CFrame

local bobble = Vector3.new(GetBobbing(10), GetBobbing(5),GetBobbing(5))
local mousedelta = game:GetService("UserInputService"):GetMouseDelta()

local character = game.Players.LocalPlayer.Character or game.Players.LocalPlayer.CharacterAdded:Wait()

bobbleswaying:shove(bobble / 10 * (character:WaitForChild("HumanoidRootPart").Velocity.Magnitude) / 10)
swayingspring:shove(Vector3.new(-mousedelta.X / 500, mousedelta.Y / 200, 0))

local updatedrecoilspring = recoilspring:update(dt)
local updatedbobblespring = bobbleswaying:update(dt)
local updatedswayingspring = swayingspring:update(dt)

viewmodel.HumanoidRootPart.CFrame = viewmodel.HumanoidRootPart.CFrame:ToWorldSpace(CFrame.new(updatedbobblespring.Y,updatedbobblespring.X,0))
viewmodel.HumanoidRootPart.CFrame *= CFrame.new(updatedswayingspring.X,updatedswayingspring.Y,0)

viewmodel.HumanoidRootPart.CFrame *= CFrame.Angles(math.rad(updatedrecoilspring.X) * 2,0,0)
game.Workspace.Camera.CFrame *= CFrame.Angles(math.rad(updatedrecoilspring.X),math.rad(updatedrecoilspring.Y),math.rad(updatedrecoilspring.Z))
end
--Weld gun or something

function module.weldgun(gun)
local main = gun.Components.Handle
for i, v in pairs(gun:GetDescendants()) do
	if v:IsA("BasePart") and v ~= main then
		local newmotor = Instance.new("Motor6D")
		newmotor.Name = v.Name
		newmotor.Part0 = main
		newmotor.Part1 = v
		newmotor.C0 = newmotor.Part0.CFrame:Inverse() * newmotor.Part1.CFrame
		newmotor.Parent = main
	end
end
end

function module.equip(viewmodel,gun, hold)
local gunhandle = gun.Components.Handle
local HRP_Motor6D = viewmodel:WaitForChild("HumanoidRootPart").Handle

gun.Parent = viewmodel
HRP_Motor6D.Part1 = gunhandle

local Hold = viewmodel.AnimationController:LoadAnimation(hold)
Hold:Play()
end
function module.cast(gun, endposition, velocity, damage)
local gunbarrel = gun.Components.Barrel
local bullet = Instance.new("Part")

bullet.Size = Vector3.new(0.523,0.1,0.1	)
bullet.Anchored = true
bullet.CanCollide = false
bullet.Color = Color3.new(1, 1, 0)
bullet.Material = Enum.Material.Neon
bullet.Parent = game.Workspace

bullet.CFrame = CFrame.new(gunbarrel.Position, endposition)
local loop


loop = game:GetService("RunService").RenderStepped:Connect(function(dt)
	bullet.CFrame *= CFrame.new(0,0,-velocity * (dt * 60))
	
	local hit = workspace:Raycast(bullet.Position, bullet.CFrame.LookVector * velocity * 1.5)
	if hit then
		if hit.Instance.Parent:FindFirstChild("Humanoid") then
			
			damage:FireServer(hit.Instance.Parent,10)

		else

			--WALL

		end
	end

	if (bullet.Position - gunbarrel.Position).magnitude > 5000 then
		bullet:Destroy()
		loop:Disconnect()
	end
end)

end




return module
LocalHandler
local gunmodel = game.ReplicatedStorage:WaitForChild("MiniGun")
local AnimationsFolder = game.ReplicatedStorage:WaitForChild("MiniGunAnimations")
local viewportmodel = game.ReplicatedStorage:WaitForChild("Viewmodel")
local ts = game:GetService("TweenService")
local firing = viewportmodel.AnimationController:LoadAnimation(AnimationsFolder.Firing)
local springmodule = require(game.ReplicatedStorage.SpringModule)
local recoilspring = springmodule.new()
local bobbleswaying = springmodule.new()
local swayspring = springmodule.new()
local Damage = game.ReplicatedStorage.ToolEvents:WaitForChild("MiniGunDamage")
-- mainmodule idk

local mainmodule = require(game.ReplicatedStorage.GunSystemMainModule)

viewportmodel.Parent = game.Workspace.Camera

--position viewport model

game:GetService("RunService").RenderStepped:Connect(function(dt)
mainmodule.update(viewportmodel,dt, recoilspring, bobbleswaying, swayspring)
end)

--calls the weldgun thing
mainmodule.weldgun(gunmodel)
--equip thing
mainmodule.equip(viewportmodel,gunmodel, AnimationsFolder.Hold)
local IsPlayerHoldingMouse
local CanFire = true
local Delay_ = 0.1

game:GetService("RunService").Heartbeat:Connect(function(dt)
if IsPlayerHoldingMouse then
	if CanFire then
		CanFire = false
		recoilspring:shove(Vector3.new(2,math.random(-2,2),10))
		
		coroutine.wrap(function()
			for i, v in pairs(gunmodel.Components.Barrel:GetChildren()) do
				if v:IsA("ParticleEmitter") then
					v:Emit()
				end
			end
			
			local firesound = gunmodel.Components.Sounds.MiniGunFiring:Clone()

			firesound.Parent = game.Workspace
			firesound.Parent = nil
			firesound:Destroy()
		end)()


		coroutine.wrap(function()
			wait(0.2)
			recoilspring:shove(Vector3.new(-2.8,math.random(-1,1),-10))
		end)()
		
		 
  mainmodule.cast(gunmodel,game.Players.LocalPlayer:GetMouse().Hit.Position,5,Damage)
		recoilspring:shove(Vector3.new(1,0,0))
		mainmodule.cast(gunmodel, game.Players.LocalPlayer:GetMouse().Hit.Position,60)
		wait(Delay_)
		CanFire = true
	end
end

end)

game:GetService("UserInputService").InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
	IsPlayerHoldingMouse = true
	firing:Play()
end
end)
game:GetService("UserInputService").InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
	IsPlayerHoldingMouse = false
	firing:Stop()
end
  end)
DamageScript
local damage = game.ReplicatedStorage.ToolEvents:WaitForChild("MiniGunDamage")

damage.OnServerEvent:Connect(function(client,player,damage)
if player then
	player:FindFirstChild("Humanoid"):TakeDamage(damage)
end
end)

(Again sorry for asking for help again im not that great at scripting lol)