I am making a sword class and I am having issues trying to get self._settings and using it inside a method.
Here’s the entire class:
--!strict
local Sword = {}
Sword.__index = Sword
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Source = ReplicatedStorage.Source
local RaycastHitbox = require(Source.RaycastHitboxV4)
local Trove = require(Source.Packages.Trove)
local ContextActionUtility = require(Source.ContextActionUtility)
local LocalPlayer = Players.LocalPlayer
local ATTACK_IMG = "rbxassetid://5743593320"
type tab = {
_damage: number,
_yield: number,
_attacktime: number,
}
type self = {
_sword: Tool,
_animations: Folder,
_settings: tab,
_connections: Trove.ClassType,
_hitbox: RaycastHitbox.ClassType,
_loadedAnimations: any,
_loadedSounds: any
}
export type Sword = typeof(
setmetatable({}, {__index = Sword})
)
function Sword.new(sword: Tool, setting: tab): Sword
local self = setmetatable({} :: self, Sword})
local Animator = LocalPlayer.Character.Humanoid.Animator
self._sword = sword
self._animations = sword:FindFirstChild("Animations"):: Folder
self._settings = setting
self._connections = Trove.new()
self._hitbox = RaycastHitbox.new(self._sword:FindFirstChild("Handle"))
self._loadedAnimations = {}
self._loadedSounds = {}
self._loadedAnimations.Equip = Animator:LoadAnimation(self._sword
:FindFirstChild("Animations")
:FindFirstChild("Equip"))
self._loadedAnimations.Idle = Animator:LoadAnimation(self._sword
:FindFirstChild("Animations")
:FindFirstChild("Idle"))
self._loadedSounds.Equip = self._sword:FindFirstChild("Handle"):FindFirstChild("Equip"):: Sound
self._connections:Connect(self._sword.Equipped, function(mouse: Mouse)
self:Equip()
self:Bind(self._sword.Name, Enum.UserInputType.MouseButton1)
end)
self._connections:Connect(self._sword.Unequipped, function(mouse: Mouse)
self:Unequip()
self:Unbind(self._sword.Name)
end)
return self
end
-- methods
function Sword:Equip()
self._loadedSounds.Equip:Play()
self._loadedAnimations.Equip:Play()
self._loadedAnimations.Idle:Play()
print("Equipped", self._sword.Name)
end
function Sword:Unequip()
print("Unequipped",self._sword.Name)
if self._loadedAnimations.Idle.IsPlaying then
self._loadedAnimations.Idle:Stop()
end
if self._loadedAnimations.Equip.IsPlaying then
self._loadedAnimations.Equip:Stop()
end
end
function Sword:Attack(InputState)
if InputState ~= Enum.UserInputState.Begin then
return
end
print(self._settings) -- prints nil, I need to get the self table
print("Attack")
end
function Sword:Bind(ActionName: string, Input)
ContextActionUtility:BindAction(ActionName,self.Attack,true,Input)
ContextActionUtility:SetImage(ActionName,ATTACK_IMG)
end
function Sword:Unbind(ActionName: string)
ContextActionUtility:UnbindAction(ActionName)
end
function Sword:Destroy()
self._connections:Destroy()
end
return Sword
For me it works. I hope you use Attack on an already created sword via .new and not via a module. Example:
local module = require(...)
local sword = module.new(Tool, { _damage=5,_yield=4,_attacktime=2})
--must be
sword:Attack(Enum.UserInputState.Begin)
--must not be
module:Attack(Enum.UserInputState.Begin)
The thing is my sword class is supposed to make it easy for me to create swords on the go.
-- not meant to be neat / for testing purps
local Sword = require(game:GetService("ReplicatedStorage").Source.Classes.Sword)
local Tool = game:GetService("ReplicatedStorage").Instances.Weapons["Overlord Scythe"]
local Settings = { -- sword params
30, -- damage
1, -- yield
1, -- attacktime
}
Sword.new(Tool,Settings)
-- I don't really need to use Sword.new(Tool,Settings):Attack()
-- because the sword class should do it automatically for me.
Tool.Parent = game.Players.LocalPlayer.Backpack
Your solution didn’t really do anything but optimize my class a little more (unless I did it wrong)
Here’s the new class:
--!strict
local Sword = {}
Sword.__index = Sword
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Source = ReplicatedStorage.Source
local RaycastHitbox = require(Source.RaycastHitboxV4)
local Trove = require(Source.Packages.Trove)
local ContextActionUtility = require(Source.ContextActionUtility)
local LocalPlayer = Players.LocalPlayer
local ATTACK_IMG = "rbxassetid://5743593320"
type tab = {
_damage: number,
_yield: number,
_attacktime: number,
}
type self = {
_sword: Tool,
_animations: Folder,
_settings: tab,
_connections: Trove.ClassType,
_hitbox: RaycastHitbox.ClassType,
_loadedAnimations: any,
_loadedSounds: any
}
export type Sword = typeof(
setmetatable({}, {__index = Sword})
)
function Sword.new(sword: Tool, setting: tab): Sword
local self = setmetatable({}, {__index = Sword})
local Animator = LocalPlayer.Character.Humanoid.Animator
self._sword = sword
self._animations = sword:FindFirstChild("Animations"):: Folder
self._settings = setting
self._connections = Trove.new()
self._hitbox = RaycastHitbox.new(self._sword:FindFirstChild("Handle"))
self._loadedAnimations = {}
self._loadedSounds = {}
self._loadedAnimations.Equip = Animator:LoadAnimation(self._sword
:FindFirstChild("Animations")
:FindFirstChild("Equip"))
self._loadedAnimations.Idle = Animator:LoadAnimation(self._sword
:FindFirstChild("Animations")
:FindFirstChild("Idle"))
self._loadedSounds.Equip = self._sword:FindFirstChild("Handle"):FindFirstChild("Equip"):: Sound
self._connections:Connect(self._sword.Equipped, function(mouse: Mouse)
self:Equip()
self:Bind(self._sword.Name, Enum.UserInputType.MouseButton1)
end)
self._connections:Connect(self._sword.Unequipped, function(mouse: Mouse)
self:Unequip()
self:Unbind(self._sword.Name)
end)
return self
end
-- methods
function Sword:Equip()
self._loadedSounds.Equip:Play()
self._loadedAnimations.Equip:Play()
self._loadedAnimations.Idle:Play()
print("Equipped", self._sword.Name)
end
function Sword:Unequip()
print("Unequipped",self._sword.Name)
if self._loadedAnimations.Idle.IsPlaying then
self._loadedAnimations.Idle:Stop()
end
if self._loadedAnimations.Equip.IsPlaying then
self._loadedAnimations.Equip:Stop()
end
end
function Sword:Attack(InputState)
if InputState ~= Enum.UserInputState.Begin then
return
end
print(self._settings) -- prints nil, I need to get the self table
print("Attack")
end
function Sword:Bind(ActionName: string, Input)
ContextActionUtility:BindAction(ActionName,self.Attack,true,Input)
ContextActionUtility:SetImage(ActionName,ATTACK_IMG)
end
function Sword:Unbind(ActionName: string)
ContextActionUtility:UnbindAction(ActionName)
end
function Sword:Destroy()
self._connections:Destroy()
end
return Sword
I figured out ContextActionUtility might be the issue because when I use tool.Activated it works as normal. I’m not sure how to fix this though…
When I use ContextActionUtility:Bind, it binds self.Attack from the module itself. Basically like ContextActionService. I’ve already tried your method of calling it but it doesn’t print out anything for some reason.
self.Attack = function to bind to
self.Attack is already a function, so I don’t need to nest it inside a function
Creating a new table here inside of your constructor for the metatable is actually inefficient for memory just so you know.
If you can, you could try making ContextActionUtility:Bind a vararg function and pass self as an argument for the vararg, then pass the vararg to the bound action.
If that isn’t an option, or if you want an easier method, I think the best course of action would be to create an anonymous function inside of your ContextActionUtility:BindAction call like so:
While I can’t be for certain since I don’t know what ContextActionUtility contains, I would suspect that if you were to print self in sword:Attack, you would get whatever ActionName is equal to. The reason you don’t get an error here is because if you try to index a string with anything (that isn’t a member of the string library), you will get nil because indexing a string is in essence the same as indexing the string library.
Ah okay looking at that module it already takes a variadic argument for input types and keycodes so I’d stick with the second method (creating a function then calling self:Attack(inputState) in said function)