Try setmetatable({}, {__index = Sword})
to remove module.new().new()
You should be doing self:Bind
instead of Sword:Bind
You could also do self:Equip
In your module, you need to call it on the sword instance, not the module.
Try setmetatable({}, {__index = Sword})
to remove module.new().new()
You should be doing self:Bind
instead of Sword:Bind
You could also do self:Equip
In your module, you need to call it on the sword instance, not the module.
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…
Where do you actually call Attack? I only see it in Bind but do you call that? Also, you don’t pass self to Attack in Bind.
ContextActionUtility:BindAction(ActionName,function()
self:Attack()
end,true,Input)
Here is how you do it
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:
ContextActionUtility:BindAction(ActionName, function(actionName, inputState)
self:Attack(inputState)
end, true, input)
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.
Huh, that makes sense. When I print self it does print the actionname. I’ll try this.
Here’s everything you need to know about contextactionutility: Easy Mobile Buttons - ContextActionUtility
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)
By the way, what do you mean by this?
local self = setmetatable({}, Sword)
is more memory efficient than
local self = setmetatable({}, {__index = Sword})
because you are creating a second table for every object. This is probably a negligible memory increase but it is one nonetheless
Oh,
I was told to replace Sword with that. Thanks
One table for the price of two is quite the bargain (on opposite day).
Is self nil only for the attack function or for everything?
For the attack function only. Everything else is accessible with self
Is settings accessible from other functions?
Yes, cody might have the solution though. I am still yet to test it (Im on mobile currently)
Doesn’t typeof()
return strings. I believe the module script won’t work properly because type Sword is a string.
Key word: Typeof
I don’t think my script uses typeof. it only uses type and type is for typechecking
it’s in line 32 of your original script
That’s for type annotations. An important reminder, type annotations in Luau are literally annotations; they do not and should not affect the compilation or runtime* (few edge cases) of the code. typeof
used in this context retrieves the type of a value. For example:
local a: typeof(workspace) = nil::any
--even though this variable is nil, the autocomplete feature will still treat it
--as if it's actually workspace itself because it has been assigned that type
Oh that’s just normal typechecking, it doesn’t really affect anything