Why is my OOP class object forgetting self variables defined in .new()?

So basically I am new to using OOP and I am running into an issue where the self variables I’m defining in my constructor function are being forgotten in other methods.

This is my first time writing my own OOP class, however I have used classes made by other developers in the past and I just don’t know where I’m going wrong. I’ve compared my class to others but I can’t figure out why mine is forgetting variables.

The variable I’m specifically having a problem with right now is the self.Type variable, however this is an issue with every single self variable I try to define in the constructor. self.Type stores the name of the type of gun being used. It is supposed to use that to find the config settings for that specific gun in another module I’m using to store config data.

Here is some snippets of my code (this isn’t the whole script just what is necessary to see):

local Gun = {}
Gun.__index = Gun

function Gun.new(player, gunType)
	local self = setmetatable({}, Gun)
	self.Owner = player
	self.Type = gunType
	
    print(self.Type) -- correctly prints what it's supposed to here which is "AK-47"

	self.CurrentMode = 1
	
	return self
end
function Gun:Fire(player, mousePos, tool)
	local origin = tool.Handle.FirePoint.WorldPosition
	local dir = (mousePos - origin).Unit

    print(self.Type, GunConfig[self.Type]) -- prints "nil, nil" here
	self.Caster:Fire(origin, dir, GunConfig[self.Type].BulletVelocity, self.CastBehavior)
end

The line where I’m getting the error is the last one and specifically where it says:

GunConfig[self.Type].BulletVelocity

This is the error I get:

Btw, the “self.Caster” was also originally defined in the constructor function and it didn’t recognize it but when I moved it to the :Init() function it started working. Hopefully that maybe helps anyone trying to figure out my problem.

Maybe I’m missing something very obvious but like I said I am still new to this so any help would be greatly appreciated!
(also I hope I used my OOP terminology in the correct context lol, feel free to correct any terminology mistakes)

Edit: Since it will probably help I’ll just put the entire module here at the bottom

--//Services
local rep = game:GetService("ReplicatedStorage")
local debris = game:GetService("Debris")

--//References
local modules = rep.Modules
local dataModules = modules.Data
local mainModules = modules.Main

local remotes = rep.Remotes

--//Modules
local GunConfig = require(dataModules.GunConfig)
local FastCast = require(mainModules.FastCastRedux)

--//Remotes
local fireRE = remotes.Weapons.Fire

FastCast.VisualizeCasts = false

--//Class
local Gun = {}
Gun.__index = Gun

local function CreateBulletsFolder()
	local bulletsFolder = workspace:FindFirstChild("BulletFolder") 
		or Instance.new("Folder", workspace)
	bulletsFolder.Name = "BulletFolder"
	return bulletsFolder
end

function Gun.new(player, gunType)
	local self = setmetatable({}, Gun)
	self.Owner = player
	self.Type = gunType
	
	print(self.Type)
	
	self.CurrentMode = 1
	
	return self
end

function Gun:Init()
	self.Caster = FastCast.new()
	self.BulletFolder = CreateBulletsFolder()
	self.CosmeticBullet = self:CreateBulletTemplate()
	self.CastParams = self:CreateCastParams()
	self.CastBehavior = self:CreateCastBehavior()
	self:MakeConnections()
end

function Gun:CreateBulletTemplate()
	local bulletTemplate = Instance.new("Part")
	bulletTemplate.Anchored = true
	bulletTemplate.CanCollide = false
	bulletTemplate.Shape = "Ball"
	bulletTemplate.Size = Vector3.new(1, 1, 1)
	bulletTemplate.Material = Enum.Material.SmoothPlastic
	return bulletTemplate
end

function Gun:CreateCastParams()
	local castParams = RaycastParams.new()
	castParams.FilterType = Enum.RaycastFilterType.Blacklist
	castParams.IgnoreWater = true
	return castParams
end

function Gun:CreateCastBehavior()
	local castBehavior = FastCast.newBehavior()
	castBehavior.RaycastParams = self.CastParams
	castBehavior.Acceleration = Vector3.new(0, -workspace.Gravity, 0)
	castBehavior.AutoIgnoreContainer = false
	castBehavior.CosmeticBulletContainer = self.BulletFolder
	castBehavior.CosmeticBulletTemplate = self.CosmeticBullet
	return castBehavior
end

function Gun:ToggleFireMode()
	local modes = GunConfig[self.Type].FireMode
	self.CurrentMode += 1
	if self.CurrentMode > #modes then
		self.CurrentMode = 1
	end
	return modes[self.CurrentMode]
end

function Gun:SimulateProjectile(cast, lastPoint, dir, length, velocity, bullet)
	if bullet then
		local bulletLength = bullet.Size.Z/2
		local offset = CFrame.new(0, 0, -(length - bulletLength))
		bullet.CFrame = CFrame.lookAt(lastPoint, lastPoint + dir):ToWorldSpace(offset)
	end
end

function Gun:OnHit(cast, result, velocity, bullet)
	local hit = result.Instance

	local character = hit:FindFirstAncestorWhichIsA("Model")
	if character and character:FindFirstChild("Humanoid") then
		character.Humanoid:TakeDamage(10)
	end

	debris:AddItem(bullet, 2)
end

function Gun:Fire(player, mousePos, tool)
	local origin = tool.Handle.FirePoint.WorldPosition
	local dir = (mousePos - origin).Unit
	
	print(self.Type, GunConfig[self.Type])
	self.Caster:Fire(origin, dir, GunConfig[self.Type].BulletVelocity, self.CastBehavior)
end

function Gun:FilterInstances(tool)
	self.CastParams.FilterDescendantsInstances = {tool.Parent, self.BulletFolder}
end

function Gun:MakeConnections()
	fireRE.OnServerEvent:Connect(function(player, mousePos, tool)
		self:Fire(player, mousePos, tool)
	end)
	self.Caster.LengthChanged:Connect(function(cast, lastPoint, dir, length, velocity, bullet)
		self:SimulateProjectile(cast, lastPoint, dir, length, velocity, bullet)
	end)
	self.Caster.RayHit:Connect(function(cast, result, velocity, bullet)
		self:OnHit(cast, result, velocity, bullet)
	end)
end

return Gun
1 Like

Have you tried putting a print statement before that line to see the values? Maybe:

print(self.Type, GunConfig[self.Type])

Should give you an idea of what is failing.

Where are you declaring GunConfig? the error you are getting is from the GunConfig table not having an element with the key self.Type

It returns them both as “nil” but when I do the print in the constructor it outputs the correct thing

I don’t think that is the problem because the GunConfig works in another method, but if u want to know, GunConfig is declared outside the class at the top of the script

local GunConfig = require(dataModules.GunConfig)

Edit: that other method i was talking about, apparently it doesn’t work there now either

and u are right about the error but that is because it thinks self.Type is “nil” and I don’t know why

Can you show the code where you set up and call Fire?

function Gun:MakeConnections()
	fireRE.OnServerEvent:Connect(function(player, mousePos, tool)
		self:Fire(player, mousePos, tool)
	end)
    -- You can ignore the connections below this
	self.Caster.LengthChanged:Connect(function(cast, lastPoint, dir, length, velocity, bullet)
		self:SimulateProjectile(cast, lastPoint, dir, length, velocity, bullet)
	end)
	self.Caster.RayHit:Connect(function(cast, result, velocity, bullet)
		self:OnHit(cast, result, velocity, bullet)
	end)
end

MakeConnections() is called in Gun:Init() btw

The class is fine. The problem must be where it is being used.
Maybe you made this error,

-- some place
local gun = Gun.new(...)

-- another place
Gun:Fire(...)

which would explain why the value of self.Type is nil.

2 Likes

this is the only place the gun class is used. this is in a server script inside the tool btw

Gun.new(player, "AK-47")

tool.Equipped:Connect(function()
	Gun:FilterInstances(tool)
end)

Gun:Init()

The return of the Gun.new is the instance and you aren’t using it. You need to do something like this:

local myGun = Gun.new(player, "AK-47")
myGun:Init()
3 Likes

I would just take a guess that you did something like this

local Gun = require() -- Class

local gun = Gun.new() -- Imagine the parameters are here ✨
Gun:Fire() -- Imagine the parameters are here ✨

What I mean is, you called Fire from the constructor and not the class. This is a complete random guess but it makes sense to be true.

2 Likes

omg I can’t believe I missed that. such a simple mistake lol. Thanks for catching that!

that was exactly the problem, thanks!

1 Like

after seeing the other replies I understand what you’re saying now, thanks for catching my stupid mistake lol

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.