Help with oop please

function BaseSword:PrimaryAction()

	print("why it doesnt works")
	self.LT = tick()
	for _,animation in ipairs(self.Player.Instance.Character.Humanoid:GetPlayingAnimationTracks()) do
		animation:Stop()
	end
	local attackAnim = self.Player.Instance.Character.Humanoid:LoadAnimation(self.AttackAnimation)
	local loopSignal
	loopSignal = attackAnim.DidLoop:Connect(function()
		attackAnim:Stop()
		self.Hold:Play()
		loopSignal:Disconnect()
	end)
	
	attackAnim:Play()
end

I have 2 modules.
One is for the tool handler, but, for some reason,this doesn’t works:

image
The code you see up, is the basesword module.
Handler is the tool base.
For some reason when (IN HANDLER) ‘PrimaryAction’ fires, it doesn’t fires on BaseSword

On handler:
image

Is the __index of Handler set as Handler?

Can you confirm your workflow is as follows?

local Tool = {}
Tool.__index = Tool

local BaseSword = setmetatable({}, Tool)
BaseSword.__index = BaseSword

function Tool:PrimaryAction()
    print("Primary action")
end

BaseSword:PrimaryAction()

I can’t really tell because your code is disjointed and you’ve provided them as images rather than code samples, which I’d really appreciate if you actually posted your code to the thread instead of as images so I can select the text.

What exactly do you mean with ‘Fires’? PrimaryAction seems to be a method, not an event. I’m not sure what you are trying to do here. Why do you have a PrimaryAction function in both the Tools class and the BaseSword class?

Sorry, this is code:

local Handler = require(game.ReplicatedStorage.CombatSystem.ToolHandler)
local BaseSword = {}
BaseSword.__index = Handler
setmetatable(BaseSword,Handler)

function BaseSword.new(Player,Model,ArmName,HoldAnimation,AttackAnimation,c0)
	local Base = Handler.new(Player,Model,ArmName,HoldAnimation,AttackAnimation,c0)
	return Base
end

function BaseSword:PrimaryAction()
print("this never runs")
end

function BaseSword:SecondaryAction()
	
end

return BaseSword

On the tool base

function Tools:PrimaryAction()
print("Fires!")
end


But, doesnt works on BaseSword

Found your problem. BaseSword class is useless in this scenario because you aren’t taking any of the methods from BaseSword. Handler doesn’t take from BaseSword, but vice versa is applicable.

When you’re creating a class that inherits from another, you don’t make a new object of the superclass. The methods are automatically pulled in because your class table has the superclass table as a metamethod. Make a new object from the class itself.

Proper inheritance needs to follow this workflow: you can replicate it to the best of your ability with what you have now. Here is what your superclass should look like, which it seems you already got that part down.

local Tool = {}
Tool.__index = Tool

function Tool.new()
    return setmetatable({}, Tool)
end

function Tool:PrimaryAction()
    print("Tool PrimaryAction")
end

Now for your BaseSword subclass, this is what you’re currently doing.

-- Take methods from Tool class as meta
local BaseSword = setmetatable({}, Tool)
-- Fall back to BaseSword if the object doesn't have the queried
-- index, or to BaseSword's metatable if an index
-- can't be found in the table either.
BaseSword.__index = BaseSword

function BaseSword.new()
    -- BaseSword is useless here, because you are
    -- not making a BaseSword object. The class
    -- becomes completely useless.
    return Tool.new()
end

function BaseSword:PrimaryAction()
    print("BaseSword PrimaryAction")
end)

Test it like this and Tool PrimaryAction will fire instead. You can fix this simply by changing your constructor function to make an object of the BaseSword class.

function BaseSword.new()
    return setmetatable({}, BaseSword)
end

Now BaseSword PrimaryAction will fire.

Why does this happen? The __index of your tool object becomes BaseSword, which due to inheritance has an __index of Tool. Therefore: if the index you query doesn’t exist in the Tool object, it looks in the meta index which is BaseSword. If it doesn’t exist in BaseSword, it looks at that meta index which is Tool.

Tried to explain it as simply as I could. Do you follow?

tl;dr your BaseSword constructor is currently just a wrapper for directly doing Tool.new. Tool does not have any BaseSword methods, only Tool methods. That is why Tool’s PrimaryAction fires but BaseSword’s does not.

1 Like

I tried this, and it doesn’t works


local Handler = require(game.ReplicatedStorage.CombatSystem.ToolHandler)
local BaseSword = {}
BaseSword.__index = Handler
setmetatable(BaseSword,Handler)


function BaseSword.new(Player,Model,ArmName,HoldAnimation,AttackAnimation,c0)
	local Base = Handler.new(Player,Model,ArmName,HoldAnimation,AttackAnimation,c0)
	return  Base
end

This is tool base:

local Handler = require(game.ReplicatedStorage.CombatSystem.ToolHandler)
local BaseSword = setmetatable({},Handler)
BaseSword.__index = Handler


function BaseSword.new(Player,Model,ArmName,HoldAnimation,AttackAnimation,c0)
	local Base = Handler.new(Player,Model,ArmName,HoldAnimation,AttackAnimation,c0)
	return  Base
end

function BaseSword:PrimaryAction()

	print("why it doesnt works")
	
end

function BaseSword:SecondaryAction()
	-- doesn't exixsts
end

return BaseSword

I tried literally what you sent and still doesnt works

Because you’re redefining the method in the tools class. If you want the original code either don’t create the method for that class or copy in paste it to the new method.

I don’t understand, ngl.
What do I do?

Under your class called tools you overwrote the function “PrimaryAction”, which now just prints “Fired” rather than actually functioning. It doesn’t include the original code when you overwrite a function in Lua.

tl;dr: Call the original method like this:

function Tools:PrimaryAction()
BaseSword.PrimaryAction(self)
print("Fires!")
end

Which lets you call the PrimaryAction from the BaseSword class while still overwriting the method.

Edit: I misunderstood how the classes were structured, the BaseSword is the class that you’re using.

No, I saw someone that made like me, and function fired for both, I have no clue what Im doing wrong

Isn’t __index a part of the metatable?

BaseSword.__index = Handler
setmetatable(BaseSword,Handler)

Is equivalent to

setmetatable(BaseSword,Handler)

Order does matter for this, right? :face_with_raised_eyebrow:
Maybe switch them.

@varjoy, I personally think that it should be done like this:

local BaseSword = setmetatable({}, Handler)
BaseSword.__index = BaseSword

It’s much more legible this way.

And then, for the constructor it should be:

...
local self = setmetatable(Handler.new(Player, Model, ArmName, HoldAnimation, AttackAnimation, c0), BaseSword)

I’d recommend looking at how @Quenty does it in his NevermoreEngine.

And @Pharyx_Styx, yeah it does. This method has worked the best for me and has very little inheritance bugs.

It should actually be:

function BaseSword.new(Player,Model,ArmName,HoldAnimation,AttackAnimation,c0)
local self = setmetatable(Handler.new(Player,Model,ArmName,HoldAnimation,AttackAnimation,c0), BaseSword)
return self
end