The approach is kind of subjective. The best way is your most comfortable way in my opinion.
I think that In OOP, you should be keeping your code as coupled as possible. In other words, have your code closely related: code for weapons and movement are unrelated so have them setup in different modules.
You can handle what you described by passing in the class as a constructor to another class with either a function to construct your class OR the __call metamethod. Here’s something I wrote up and how I would approach something like what you’re describing from what I understand:
the Player Module, which could be responsible for custom “properties” like isRunning
local player = game.Players.LocalPlayer`
local self = {}
local function init(character) --humanoid listener(s) need to be updated
local humanoid = character:WaitForChild("Humanoid") --our new humanoid
self.isRunning = humanoid.Running:Wait() >= 1
humanoid.Running:Connect(function(speed)
self.isRunning = speed >= 1
end)
end
local init_connection = player.CharacterAdded:Connect(function(character)
init(character)
end)
return self
the Weapon Module, which could be responsible for handling the player’s weapon. This will be our ‘class’ with a constructor because I want to implement the Player class to use isRunning from it.
local function construct(PlayerClass) --construct these methods with the implementation of the PlayerClass class.
local self = {}
self.swing = function()
local success = PlayerClass.isRunning
if not(success) then
return
end
-- code to swing ...
return true
end
return self
end
return setmetatable({}, {
__call = function(self, PlayerClass) --the constructor
return construct(PlayerClass)
end
})
The script that requires these ‘classes’, and some usage:
local PlayerClass = require(script:WaitForChild("Player"))
local WeaponClass = require(script:WaitForChild("Weapon"))(PlayerClass)
--example usage: try to swing the sword every second
while true do
print(
WeaponClass.swing() and
"Swinged sword" or
"Cannot swing sword" --because the player is not running
)
wait(1)
end
Also, you might be wondering why I didn’t just require Player class inside of Weapon class. It’s because we might want to change something in the table ourselves, which would effect everything else that will construct the classes with. Everything we change in PlayerClass inside our initializing script will also change for our Weapon’s because they’re using the same pointer.
This works well and I do this it is a good approach, however, a lot of things are good approaches. Like said above, imo, just do whatever works and what you’re most comfortable with. Good luck!