Help with class System (Also I don't want to use other methods like metatables)

So I made this class system and I need feedback/debugging for it. For example, it prints 4x rather than once, and I’m not sure if the while loop is needed or if it’s just slowing it down and causing said bug. So here is the code:

gunClass

local gunClass = {}
gunClass.name = "gun"

function gunClass.shoot()
	print("Shot")
end

return gunClass

swordClass

local swordClass = {}
swordClass.name = "sword"

function swordClass.swing()
	print("Slashed")
end

return swordClass

PlayerScript

local player = game.Players.LocalPlayer
local guns = {"gun"}
local swords = {"sword"}

while wait(0.1) do
	local character = player.Character
	local tool = character and character:FindFirstChildOfClass("Tool")

	if tool then
		local toolName = tool.Name

		if table.find(guns, toolName) then
			local gunClass = require(game.ReplicatedStorage.gunClass)
			tool.Activated:Connect(gunClass.shoot)
		elseif table.find(swords, toolName) then
			local swordClass = require(game.ReplicatedStorage.swordClass)
			tool.Activated:Connect(swordClass.swing)
		end
	end
end

The reason why it prints 4x rather than just 1x is because it’s nested in a while loop. Try removing the while loop and just using the Activated event of the tool, like so:

PlayerScript:

local Players = game:GetService('Players')
local ReplicatedStorage = game:GetService('ReplicatedStorage')

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

local Guns = { 'gun' }
local Swords = { 'sword' }

local ToolsInBackpack = Player:WaitForChild('Backpack'):GetChildren()

for _, Tool in ipairs(ToolsInBackpack) do
    if (Tool:IsA('Tool')) then
        if (table.find(Guns, Tool.Name)) then
            Tool.Activated:Connect(require(ReplicatedStorage:WaitForChild('gunClass')).shoot)
        else if (table.find(Swords, Tool.Name)) then
            Tool.Activated:Connect(require(ReplicatedStorage:WaitForChild('swordClass')).swing)
        end
    end
end

The ToolsInBackpack variable is defined, assuming the tools are in the Backpack. If not, change “Player:WaitForChild(‘Backpack’)” to where the tools are located. (And the tools are only located under the player’s character if they’re active.)

Hope that helps!

1 Like

This fixes the problem but is it really necessary to do all of that “stuff”? Not sure how else to put it…

Give me examples of “stuff,” please.

:WaitForChild()

This function haults the thread - just like using task.wait() - until the Instance is loaded. This is especially useful if you aren’t quite sure if something will be fully loaded in when the game starts.

As for the Loop, this just goes through every tool in the backpack (defined by the ToolsInBackpack variable.) The if statement checks if it’s a tool using Type Checking, and if it’s the correct type, it continues.

And finally, the variables at the top may looks a little confusing, but I promise, they aren’t. It’s generally good coding practices to use :GetService() whenever getting any service; including workspace. It just prevents the hassle if your services get renamed or any other error caused by service-getting other ways.

One final note; this line:

local Character = Player.Character or Player.CharacterAdded:Wait()

that defines your character. If the character isn’t loaded when the script runs, it will yield the thread until it is loaded in, to prevent errors from trying to access a nonexistent character.

Hope that cleared some things up!

2 Likes

Yes! This explains it all thanks.

1 Like

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