OOP / Self in Tables?

Forgive me for lack of examples, I’m currently away from studio.

I’m looking to utilise Tables & Self to create a simple framework in which functions can communicate.
Now the issue is I have managed to achieve this by using self & other tables.

i.e.

local self = {}
self.__index = self

self.Camera = {}
function self.Camera:Enable() end
function self.Camera:Disable() end
function self.Camera:Indoor() end

self.Background = {}
function self.Background:Indoor() end

Now my issue with this is that both Camera:Indoor() and Background:Indoor() over-ride eachother - I understand they have the same function call, however they’re in two seperate tables?

Aswell as being found within their allocated table i.e. self.Background ; self.Camera both functions are also found within the initial self table and that seems to be where the overwriting is taking place?

Does anyone have any suggestions on how I can better this?

1 Like

I don’t fully understand what you’re describing here. Could you explain it a bit differently?

2 Likes

Because both camera and background tables have the same :Indoor() function, they are being overwritten when you access them through self because it’s the same table

Why not use two different modules for Camera and Background and put them under the framework module? I think that would solve it.

2 Likes

solution ^

Sorry!

So I have one initial Module script: Util that requires others and allows them to communicate with each other - They’re stored within the same ‘self’ so it’s simple to call another function.

Heirarchy as:

Util

Camera
Background
Teleport
Transition

The Util requires the modules below and creates a table for them within a self.
So say like self.Camera = {} then within the Camera module is self.Camera:Enable()

There shouldn’t be any conflicts unless the functions were all stored in the same table

They are two different modules :confused: That’s the issue.
They both have the same function name as :Indoor() - However one is:
self.Camera:Indoor() and the other is self.Background:Indoor() however they both seem to overwrite eachother despite being two different tables.

This is a pretty good tutorial that explains inheritance (what you’re trying to do)

They’re not doing inheritance though, they’re all separate

Because you’re indexing both tables into self, and they become the same table

Hold on just booted my PC.

So this is the main util:

	local Core = { ... }
	local Server, Script = game, script
	
	self = {}
	self.__index = self
	
	self.Player = Server:GetService('Players').LocalPlayer
	self.Character = self.Player.Character or self.Player.CharacterAdded:Wait(2)
	self.Player.CharacterAdded:Connect(function(Character, ...)
		self.Character = Character
	end)
	
	for __,Module in (Script:GetChildren(...)) do
		if Module:IsA('ModuleScript') then
			self[Module.Name] = setmetatable(self, {})
			require(Module):init(self, ...)
		end
	end
	
	self.Camera:Enable(...)
	self.Chunk:Load("Ol' Oak Village", ...)
	
	return Core

and for an example this is the Camera (Doesn’t include the indoor function on this version.)

	local Core = { ... }
	local Server, Script = game, script
	
	function Core:init(__index, ...)
		self = __index
		
		local Camera = Server:GetService('Workspace'):WaitForChild('Camera')
		
		local Connection = nil
		local Offset = Vector3.new(0, 20, -15)
		local Shake = Vector2.new(0, 0)
		
		function self.Camera:Enable(...)
			Camera.CameraType = Enum.CameraType.Scriptable
			Connection = Server:GetService('RunService').PreRender:Connect(function(...)
				local HumanoidRootPart = self.Character:FindFirstChild('HumanoidRootPart')
				if HumanoidRootPart then
					Camera.CFrame = CFrame.lookAt((HumanoidRootPart.Position + Offset) + Vector3.new(Shake.X, Shake.Y, 0), HumanoidRootPart.Position + Vector3.new(Shake.X, Shake.Y, 0))
				end
			end)
		end
		
		function self.Camera:Disable(...)
			pcall(function(...)
				Connection:Disconnect(...)
				Camera.CameraType = Enum.CameraType.Custom
				Offset = Vector3.new(0, 20, -15)
				Shake = Vector2.new(0, 0)
			end)
		end
		
		function self.Camera:Shake(int, Time, ...)
			for i = 1, Time do
				task.wait(...)
				Shake = Vector2.new(math.random(-int, int)/10, math.random(-int, int)/10)
			end
			Shake = Vector2.new(0, 0, 0)
		end
		
		self.Player.Chatted:Connect(function(Msg, ...)
			if Msg == '/shake' then
				self.Camera:Shake(10, 100, ...)
			end
		end)
	end
	
	return Core

They are though, it’s what they’re trying to achieve with the structure they explained

The issue is that the : symbol means that the argument self is passed in(the one you define at the top), and both functions have that so they use the same copy of self, this is definitely one of the reasons this override occurs. Basically self.Camera:Indoor() and self.Background:Indoor() don’t use self.Camera and self.Background respectively, they use self.

2 Likes

Why are you setting the metatable to the util module?

2 Likes

That was the only way I could make the ‘self’ work with the others - Without the metatable it returned nil.

Shouldn’t this just be a simple loop or are you like creating a new object from the util module

1 Like

I mean different actual modules(not tables within a module), with different self and different self.__index each. Basically different objects that have a relationship with the framework(they get required by it).

1 Like

Are you trying to do something like this? Where for example, toolHandler is the “main” module and then crossbow is a tool you can use. And you can make more tools while using the same :activated() function for example set in the crossbow module?

–Main module

local ToolHandler = {}
ToolHandler.__index = ToolHandler

local Players = game:GetService("Players")
local localPlayer = Players.LocalPlayer

local dependencyModules = {
	Crossbow = script.Crossbow,
	Sword = script.Sword,
}

ToolHandler.new = function(tool : string)
    local self = setmetatable({}, ToolHandler)

	self.name = tool
    self.particleEmitters = {}
    self.character = localPlayer.Character
    self.humanoid = localPlayer.Character.Humanoid

	self:start()
	return self
end

function ToolHandler:start()
	print("load stuff like activated, unequip and equip connections")
end

function ToolHandler:usedTool(amount : number)
	print("tool used")
end

ToolHandler.init = function()
	for _, instance in dependencyModules do
		if instance:IsA("ModuleScript") then
			dependencyModules[instance.Name] = require(instance)
			dependencyModules[instance.Name].init()
		end
	end
end

return ToolHandler

Tool example using crossbow

local Crossbow = {}
Crossbow.__index = Crossbow

local ToolHandler = require(script.Parent)

Crossbow.new = function(tool)
	local self = ToolHandler.new(tool)
	setmetatable(self, Crossbow)
	self.timeout = 3

	return self
end

function Crossbow:activated()
	print("activated")
end

function Crossbow:equip()
	print("equip")
end

function Crossbow:unequip()
	print("unequip")
end

function Crossbow.init()
	setmetatable(Crossbow, ToolHandler)
end

return Crossbow
1 Like

I think I’ve fixed it by adjusting the Function from self.Camera:Indoor() to self.Camera.Indoor = function()?