I’ve been having trouble for a week and some days and no one has been able to solve the issue with how I am setting up my base classes.
My problem is that the variables aren’t being shared + the more subclasses that use the base class means the more times it iterates itself…
MAIN CODE:
Subclass Example
--!strict
--[[
Test sub-class
--]]
--// roblox services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
--// Dependencies
local BaseMovement = require(script.Parent.BaseMovement)
--// class
local Test = {}
Test.__index = Test
export type ClassType = typeof( setmetatable({} :: {
} , Test) ) & BaseMovement.ClassType
--// constructor
function Test.new(): ClassType
local self = setmetatable(BaseMovement.new() :: any, Test)
return self
end
function Test.Bind(self: ClassType, actionName, inputState, _inputObject): ()
if not self.character then
return
end
local Character = self.character
local Humanoid = Character:FindFirstChild("Humanoid") :: Humanoid
if inputState == Enum.UserInputState.Begin then
print("Test start")
end
if inputState == Enum.UserInputState.End then
print("Test end")
end
end
function Test.GetParameters()
return {
actionName = "Test", -- mandatory
createTouchButton = false, -- optional, will always be false on default
inputs = { -- mandatory
Enum.KeyCode.X,
}
}
end
return Test.new()
BaseMovement
--!strict
--[[
The base class for 'movement' // superclass
--]]
--// roblox services
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
--// dependencies
local Trove = require(ReplicatedStorage.Packages._Index["sleitnick_trove@1.1.0"]["trove"])
--// class
local BaseMovement = {}
BaseMovement.__index = BaseMovement
export type ClassType = typeof(setmetatable({} :: {
BaseConnections: Trove.ClassType;
character: Model?;
isMoving: boolean;
isSprinting: boolean;
}, BaseMovement))
--// constructor
function BaseMovement.new() : ClassType
local self = {
BaseConnections = Trove.new(),
character = nil,
isMoving = false,
isSprinting = false,
}
setmetatable(self, BaseMovement)
self:_init()
return self
end
function BaseMovement._init(self: ClassType): ()
self.BaseConnections:Connect(Players.LocalPlayer.CharacterAdded, function(character: Model)
if not self.character then
self.character = character
end
end)
if Players.LocalPlayer.Character then
self.character = Players.LocalPlayer.Character
end
end
function BaseMovement.GetCharacter(self: ClassType): Model?
return self.character
end
function BaseMovement.Destroy(self: ClassType): ()
self.BaseConnections:Destroy()
end
return BaseMovement
CONTEXT:
The movement module requires and binds all the subclasses (Test and Test2) that have the bind function
if type(requiredModule.Bind) ~= "function" or type(requiredModule.GetParameters) ~= "function" then
continue
end
then, the subclasses use BaseMovement as the Base Class, which gets the character and the state variables which should be shared.
Here’s an example, you’re gonna have to extract what you need from it.
My base class
local Players = game:GetService("Players")
local Types = script.Parent
local CameraModule = Types.Parent
local Settings = require(CameraModule.Settings)
local Signal = require(CameraModule.Signal)
local Maid = require(script:WaitForChild("Maid"))
local Base = {}
Base.__index = Base
function Base.Start(Data: {})
local NewType = {}
NewType._running = true
NewType._player = Players.LocalPlayer
NewType._camera = workspace.CurrentCamera
NewType._oldRot = NewType._camera.CFrame.Rotation
NewType._maid = Maid.new()
NewType.Stopped = Signal.new()
if Data then
NewType._oldRot = Data.OldRot or NewType._oldRot
end
NewType._maid:GiveTask(function()
NewType.Stopped:Fire()
NewType.Stopped:DisconnectAll()
end)
return NewType
end
function Base:Stop(Keep)
self._running = false
self._maid:Destroy()
if not Keep then
self._camera.CameraType = Enum.CameraType.Custom
self._player.CameraMode = Settings.CameraMode
self._camera.CFrame = CFrame.new(self._camera.CFrame.Position) * self._oldRot
end
return self._oldRot
end
return Base
My inheriting class
local RunService = game:GetService("RunService")
local Types = script.Parent
local CameraModule = Types.Parent
local Base = require(Types.Base)
local Enums = require(CameraModule.Enums)
local Attach = {
Enum = Enums.Attach
}
Attach.__index = setmetatable(Attach, Base)
function Attach.Start(Data: {})
local NewType = setmetatable(Base.Start(Data), Attach)
NewType._camera.CameraType = Enum.CameraType.Scriptable
NewType.Delta = 0.0005
if Data then
NewType.Attached = Data.Attached or nil
NewType.Delta = Data.Delta or NewType.Delta
end
NewType._maid:GiveTask(RunService.RenderStepped:Connect(function(dt)
local Attached = NewType.Attached
if not Attached then return end
local AttachedType = typeof(Attached)
local AttachCFrame
if AttachedType == "Instance" and Attached:IsA("BasePart") then
AttachCFrame = Attached.CFrame
elseif AttachedType == "Attachment" then
AttachCFrame = Attached.WorldCFrame
elseif AttachedType == "CFrame" then
AttachCFrame = Attached
else
warn(`Incorrect attached type: {AttachedType}`)
return
end
NewType._camera.CFrame = NewType._camera.CFrame:Lerp(AttachCFrame, 1 - NewType.Delta ^ dt)
end))
return NewType
end
return Attach
local debuggingEnabled = true
local instanceId = math.random()
local BaseCharacterController = {}
BaseCharacterController.__index = BaseCharacterController
function BaseCharacterController.new()
local self = setmetatable({}, BaseCharacterController)
self.enabled = false
self.moveVector = ZERO_VECTOR3
self.moveVectorIsCameraRelative = true
self.isJumping = false
task.spawn(function()
while debuggingEnabled and task.wait(5) do
print("Instance:", instanceId, "isJumping:", self.isJumping)
end
end)
return self
end
I have this base class that works how I want it to work. It shares isJumping and moveVector. When I run the debug, it only prints one true or false depending on if I’m jumping, and multiple subclasses are accessing the isJumping shared property.
Yeah, that’s not what inheritance is for. You probably shouldn’t be using OOP for a movement system anyways, it’d be better to have one main module with the data and some submodules or a state machine.