Viewmodel.lua || Viewmodel handler for FPS frameworks

Devvit Community Weapons System

Part 1: Viewmodel.lua

This module is part of an upcoming weapons framework that will be free for everybody to use.


What this does

This handles viewmodels, their animations, and frame update. Essentially, it:

  • Pre-loads the viewmodels and animation events before any viewmodel is made
  • Handles viewmodels as a class, not just as a model
  • Contains methods to Equip, Unequip, Update, Play/Stop animation
  • Culls models, not spawns and destroys them

Why you should use it

There are some reasons this module should be considered. These are pointed out below.

Viewmodel culling

This does not call :Destroy() on viewmodels to remove them, nor does it call :Clone(). When a viewmodel is not being used, it instead teleports to the position 0, 10e5, 0, and when it is used, it stays on the screen. This is more optimized as you are not constructing and deconstructing instances.

Flexibility

This is an object-oriented module.

As a class, you can preload the viewmodels and events through Module.Load(), as well as contruct a new viewmodel with Module.New().

You can use this however you would like, and modify each method to your liking as well.

Optimization

This is an extremely lightweight module. Using this will be superior to what most developers use for viewmodel handling.


How to use it

You need to do the following in order:

  • Require the module in the appropriate script
  • Call the Load class method, inputting the Viewmodel folder and the events binded to the animations
  • For every viewmodel, call module.New() ONE TIME AND ONE TIME ONLY

Everything else is up to you.


Source code

local Viewmodel = {}
Viewmodel.__index = Viewmodel

local ViewmodelFolder, EventBinds
local CullCFrame = CFrame.new(0,10e5,0)
local Camera = workspace.CurrentCamera

local SearchBinds = {
	Animation = {"Animations", function(self, Child)
		return self.Animator:LoadAnimation(Child)
	end};
	
	Sound = {"Sounds", function(self, Child)
		return Child
	end};
}


function Viewmodel.New(ViewmodelName)
	local self = {}
	
	self.Name = ViewmodelName
	self.Equipped = false
	
	self.Model = ViewmodelFolder:FindFirstChild(ViewmodelName)
	self.Animator = self.Model:FindFirstChildOfClass("AnimationController"):WaitForChild("Animator")
	
	for _, Child in pairs(self.Model:GetChildren()) do
		local MappedDataSet = SearchBinds[Child.ClassName]
		
		if MappedDataSet then
			if not self[MappedDataSet[1]] then
				self[MappedDataSet[1]] = {}
			end
			
			self[MappedDataSet[1]][Child.Name] = MappedDataSet[2](self, Child)
		end
	end
	
	for _, Animation in pairs(self.Animations) do
		for BindName, BindFunction in pairs(EventBinds) do
			Animation:GetMarkerReachedSignal(BindName):Connect(BindFunction)
		end
	end
	
	return setmetatable(self, Viewmodel)
end

function Viewmodel.Load(_ViewmodelFolder, _EventBinds)
	ViewmodelFolder = _ViewmodelFolder
	EventBinds = _EventBinds or {}
	
	ViewmodelFolder.Parent = workspace
	
	for _, Model in pairs(ViewmodelFolder:GetChildren()) do
		Model:SetPrimaryPartCFrame(CullCFrame)
	end
end

----------------------------------------------------------------------
----------------------------------------------------------------------
----------------------------------------------------------------------

function Viewmodel:Equip()
	if not self.Equipped then
		self.Equipped = true
		self.Animations.Idle:Play()
		self.Animations.Equip:Play()
		
		self:Update()
	end
end

function Viewmodel:Unequip()
	if self.Equipped then
		self.Equipped = false
		
		for _, Animation in pairs(self.Animations) do
			Animation:Stop()
		end
		
		self.Model:SetPrimaryPartCFrame(CullCFrame)
	end
end

function Viewmodel:Update() -- Change this to your liking!
	if self.Equipped then
		local CameraCF = Camera.CFrame
		self.Model:SetPrimaryPartCFrame(CameraCF)
	end
end

function Viewmodel:PlayAnimation(Name)
	self.Animations[Name]:Play()
end

function Viewmodel:StopAnimation(Name)
	self.Animations[Name]:Stop()
end

return Viewmodel

Footer

This is likely to update due to feedback and internal needs. This is not a final module.
Any feedback is listened to and considered.

Thanks so much for reading!

43 Likes

This would be useful, but don’t view models ignore lighting and ambient effects?

It’s probably really cool, but I’m still confused about the Module.new() part?

Is this only for guns? or it can be used with tools and everything we want?

It’s a constructor method, I suggest that you read this post about OOP: All about Object Oriented Programming

1 Like

No. Viewmodels are a descendant of workspace.

Module just means the module script itself. New is a function of it ^-^

As Viss mentioned, it is Object-Oriented Programming

Can expand beyond guns, yes. It’s generally just for viewmodels.

Oh, that’s very helpful. Thanks.

1 Like

Have the Open Source Weapons Framework out yet?

2 Likes

Hello @iGottic !

Where do i put the script? In a LocalScript inside StarterPlayerScripts?

1 Like

Can somebody guide me? Im not a scripter type of guy.

The script shown in this is a ModuleScript so to use it you should use a local script then add a variable such as

local ViewmodelModule = require(game:GetService("ReplicatedStorage"):WaitForChild("Module script name here")
1 Like

to be honest this makes no sense, how do you even do this.
nothing i do is working.
any help please?

can we get a better explanation on how to use this

2 Likes