Writing an FPS framework (2020)

set the anchor on the rootpart to false

1 Like

can anyone tell me how to get the current ammo count

  13:53:09.111  ReplicatedStorage.modules.fps:242: 'Value' is not a member of NumberSequence  -  Client - fps:242
  13:53:09.112  Stack Begin  -  Studio
  13:53:09.112  Script 'ReplicatedStorage.modules.fps', Line 242 - function fire  -  Studio - fps:242
  13:53:09.113  Script 'ReplicatedStorage.modules.fps', Line 272 - function fire  -  Studio - fps:272
  13:53:09.113  Script 'Workspace.DRIFT_NINJA06.InputController', Line 104  -  Studio - InputController:104
  13:53:09.113  Script 'ReplicatedStorage.modules.Velocity.Services.InputService', Line 16 - function on  -  Studio - InputService:16

That is the error I get whenever I click the LMB.
Someone pls help me out here

All good now,
Just a spelling problem.

Hey There! I am in the middle of your tutorial (End of part 7, to be exact) and am having trouble getting to have the gun ā€˜implanted straight in my faceā€™. When I play, the gun spawns on the ground where I was configuring it, as well as the viewmodel. Why?

I have no way to know without your code. If it is not moving, you can safely assume the CFrame of the rootPart is not getting set, which means either the :update() function isnā€™t running, or an if statement doesnā€™t pass

edit: (that, or the equip function fails somewhere)

Alright I have checked everything but it still seems that it is not working. I believe it is an issue with my rigging but I am not sure. Here is everything

Gun:
https://www.roblox.com/library/7056278933/gun

Viewmodel:
https://www.roblox.com/library/7056291724/viewmodel

FPS ModuleScript:

-- This is game.replicatedstorage.fps 

-- Coolio module stuff
local handler = {}
local fpsMT = {__index = handler}	

local replicatedStorage = game:GetService("ReplicatedStorage")
local spring = require(replicatedStorage.Modules.spring)

-- Functions i like using and you will probably too.

-- Bobbing!
local function getBobbing(addition,speed,modifier)
	return math.sin(tick()*addition*speed)*modifier
end

-- Cool for lerping numbers (useful literally everywhere)
local function lerpNumber(a, b, t)
	return a + (b - a) * t
end

function handler.new(weapons)
	local self = {}


	return setmetatable(self,fpsMT)
end

function handler:equip(wepName)

	-- Explained how this works earlier. we can store variables too!
	-- if the weapon is disabled, or equipped, remove it instead.
	if self.disabled then return end
	if self.equipped then self:remove() end
	print("removed old gun")

	-- get weapon from storage
	local weapon = replicatedStorage.Weapons:FindFirstChild(wepName) -- do not cloen 
	if not weapon then return end -- if the weapon exists, clone it, else, stop
	weapon = weapon:Clone()
	print("weapon has been cloned")

       --[[
	
	 	Make a viewmodel (easily accessible with weapon.viewmodel too!) 
		and throw everything in the weapon straight inside of it. This makes animation hierarchy work.
		
	--]]
	self.viewmodel = replicatedStorage.viewmodel:Clone()
	print("viewmodel has been cloned")
	for i,v in pairs(weapon:GetChildren()) do
		v.Parent = self.viewmodel
		if v:IsA("BasePart") then
			v.CanCollide = false
			v.CastShadow = false
		end
	end		

	-- Time for automatic rigging and some basic properties
	self.camera = workspace.CurrentCamera
	self.character = game.Players.LocalPlayer.Character

	-- Throw the viewmodel under the map. It will go back to the camera the next render frame once we get to moving it.
	self.viewmodel.rootPart.CFrame = CFrame.new(0,-100,0)
	print("set viewmodel rootpart cframe")
	-- We're making the gun bound to the viewmodel's rootpart, and making the arms move along with the viewmodel using hierarchy.
	self.viewmodel.rootPart.weapon.Part1 = self.viewmodel.WeaponRootPart
	self.viewmodel.left.leftHand.Part0 = self.viewmodel.WeaponRootPart
	self.viewmodel.right.rightHand.Part0 = self.viewmodel.WeaponRootPart
	print("set all part motor6d stuff")
	-- I legit forgot to do this in the first code revision.
	self.viewmodel.Parent = workspace.Camera
	print("viewmodels parent is the workspaces' camera")

	--[[
		Real life example:
		
		self.loadedAnimations.idle = self.viewmodel.AnimationController:LoadAnimation(self.settings.anims.viewmodel.idle)
		self.loadedAnimations.idle:Play()
	
		self.tweenLerp("equip","In")
		self.playSound("draw")
		
	--]]

	self.equipped = true -- Yay! our gun is ready.
end

function handler:remove()

	-- Not much to see here yet. even the real life function for removing a weapon takes like 30 lines ***on the client***.
	self.viewmodel:Destroy()
	
	self.viewmodel = nil
	self.equipped = false -- Nay! your gun is gone.

end

function handler:aim(toaim)

	-- we'll be using this soon

end

function handler:update(deltaTime)

	-- IF we have a gun right now. We're checking the viewmodel instead for "reasons".
	if self.viewmodel then
		print("There is a viewmodel")
		self.viewmodel.rootPart.CFrame = self.camera.CFrame
		print("The viewmodel's rootpart's cframe is the camera's cframe")
	end
end

--[[
	Used in my real game for framerate counting. I kept it in for fun.
	(decomissioned since like 3 months ago, don't use this)

	spawn(function()
		
		local fps = 0
		game:GetService("RunService").RenderStepped:Connect(function()
			fps = fps + 1
		end)
		
		while wait(1) do
			local gui = game.Players.LocalPlayer.PlayerGui:FindFirstChild("wepGui")
			if gui then
				gui.FPScount.Text = string.format("FPS: %s",fps)
			end
			fps = 0
		end
		
	end)
--]]
return handler

InputController:

-- input controller

-- The fps module we're about to add
local weaponHandler = require(game.ReplicatedStorage.Modules.fps)
print("got the wep handler")

--Custom input service. Do this how you want, i just couldn't ever remember how to use other services consistently.
local velocity = require(game.ReplicatedStorage.Modules.Velocity):Init(true)
print("got velocity and have inited")
local inputs = velocity:GetService("InputService")
print("got inputservice")

--Current weapon and translating binds from integer to enum. You don't need to understand that.
local curWeapon = nil
print("set var curWeapon")
local enumBinds = {
	[1] = "One";
	[2] = "Two";
	[3] = "Three";
}
print("set var enumBinds")

-- Server security. We don't need this right now, so i'll just comment it.
-- local weps,primaryAmmo,secondaryAmmo = game.ReplicatedStorage.weaponRemotes.New:InvokeServer()

--[[

	This means if you add a second weapon it'll automatically go under the bind 2,3, etc. 
	This is a bad thing, at least for later stages. The above commented line shows that we 
	should get the weapons from the server on-spawned. Here's how it looks in my game:
	
	local defaultWeapons = {
		[1] = "UMP45";
	--	[2] = "JESUS"; lol railgun
	}
--]]
local weps = game.ReplicatedStorage.Weapons:GetChildren() 
print("got weps")
local weapon = weaponHandler.new(weps)
print("got the weapon")
print(weapon)

-- clearing viewmodels we could have kept in the camera because of script errors and stuff
local viewmodels = workspace.Camera:GetChildren()
print("got viewmodels from workspace camera")
print(viewmodels)
for i,v in pairs(viewmodels) do
	if v.Name == "viewmodel" then
		v:Destroy()
		print("destroyed old viewmodel")
	end
end


-- equip code
for i,v in pairs(weps) do

	-- cooldown for spammy bois
	local working

	-- we will bind this per-weapon
	local function equip()

		-- if cooldown active, then don't execute the function. for less experienced scripters, this is just the equivalent of:
		 --[[
			
			local function brug()
				
				if working == false then
					
					-- do stuff
					
				end
				
			end
		
		 --]]

		if working then return end 

		working = true

		-- if the current equipped weapon is different from the one we want right now (also applies to the weapon being nil)
		if curWeapon ~= v then

			if weapon.equipped then
				weapon:remove()
			end
			weapon:equip(v.Name)
			print("equipped weapon")
	
			curWeapon = v
			print("curWeapon is: "..tostring(curWeapon))

		else
			-- if it's the same, just remove it

			spawn(function()
				weapon:remove()
			end)
			curWeapon = nil

		end

		working = false
	end

	-- This means you can have 3 different weapons at once.
	inputs.BindOnBegan(nil,enumBinds[i],equip,"Equip : "..i)
	print("on input began")
end

local function update(dt)
	weapon:update(dt)
end


-- marking the gun as unequippable
game.Players.LocalPlayer.Character:WaitForChild("Humanoid").Died:Connect(function() weapon:remove() weapon.disabled = true end)
game:GetService("RunService").RenderStepped:Connect(update)
print("updated")

Still, no errors.
If you need anything else let me know.

EDIT: All my folders and scripts are PascalCase, so ignore that.

Hi! (not sure if this thread is active but might as well try)
Im currently at the part about making it aim, and im having a bit of an issue, I have the function aim running through some print statements, and its finishing them, but not weening the correct values, im not sure why
and yes I did go in the game and edit the values with the command bar

function handler:aim(toaim)
	if self.disabled then return end
	if not self.equipped then return end

	self.aiming = toaim
	game:GetService("UserInputService").MouseIconEnabled = not toaim 

	if toaim then
		local tweeningInformation = TweenInfo.new(1, Enum.EasingStyle.Quart,Enum.EasingDirection.Out)
		tweenService:Create(self.lerpValues.aim, tweeningInformation, { Value = 1 }):Play()			
	else

		local tweeningInformation = TweenInfo.new(0.5, Enum.EasingStyle.Quart,Enum.EasingDirection.Out)
		tweenService:Create(self.lerpValues.aim, tweeningInformation, { Value = 0 }):Play()			
	end
end

weaponRootPart is not a valid member of Model ā€œviewmodelā€ Not sure what I did wrong

screw this. this stuff doesnā€™t even work, and thereā€™s some steps that arenā€™t specified on. Spent all day trying to fix my gun, and checked everything.

Donā€™t blame the tutorial for user mistake.

It works perfectly for me, pay attention to the tutorial and youā€™ll eventually find out what you did wrong.

1 Like

thereā€™s stuff thatā€™s not specified on, Iā€™m new to working with motor 6ds and guns, so itā€™s not really helpful if you say you pulled a gun model instead of directly providing the model itself.

Do you really expect a tutorial to baby you through everything? Shibe provides an open-source place so you can get your model from there. Additionally, they provide an image to show you the structure of the gun model so you wouldnā€™t have to use the same weapon model.

1 Like

I kinda agree with @Hyules, I genuinely feel like Shibes skipped past a lot of important details in setting up the viewmodels etc.

By step 5 I was completely lost and was wondering why Shibes pictures has 3 WeldConstraints in his right arm model but only one in his left arm model. There are also some unspecified children to their AnimationController which Iā€™m not sure about.

At one point I ended up abandoning the tutorial and basically copying and pasting from the place link included.

2 Likes

Like what @DaDude_89 said, thereā€™s some things that arenā€™t specific enough. The tutorial seems more of a shell, than everything as a whole. I followed another tutorial which gave me satisfying results, and everything was shown step by step, and he seemed to care more. I would rather create my own viewmodel and learn how to do it, so I donā€™t have to go in this dudeā€™s place and copy it.

1 Like

Would you mind linking it? I think this tutorial does a fair job explaining most things but there are a few things that I wouldnā€™t mind seeing more detail in

1 Like

Never use SetPrimaryPartCFrame inside of ViewModel
loops. It actually has an insanely small inaccuracy and the rig will wander around very slowly.

1 Like

the muzzle flash isnt working, anyway i can fix this?

I designed the post to be a reference to the finished framework and commented every single line i had written.

The particle emitter had transparency set to 1, i fixed it