What I did wrong here? [Metatables]

Hello guys. I’m trying to rescript Roblox controls modules, and add part swimming system. But I run into one problem:
.Initialize creates self, with some values, and that values aren’t visible to diffirent parts of script:
Example:
I .initialize module, and then I try to swim. AlignOrientation/self.DirectionalForce are created, but can’t be found with :GetDirectionalForce function.

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

local Folder = workspace.WaterFolder

local WaterDetector = {}
WaterDetector.__index = WaterDetector

local WaterDetectionParams = OverlapParams.new()
WaterDetectionParams.FilterType = Enum.RaycastFilterType.Include
WaterDetectionParams.BruteForceAllSlow = true


function WaterDetector.Initialize()
	local InitialInfo = {
		CurrentCharacter = nil,
		CurrentHumanoid = nil,
		InsideWater = false,
		AntiGravForce = nil,
		DirectionalForce = nil,
		WaterDetectionFunction = nil,
		WaterParts = {},
	}
	local self = setmetatable(InitialInfo, WaterDetector)
	
	Players.LocalPlayer.CharacterAdded:Connect(function(Character) self:OnCharacterAdded(Character) end)
	Players.LocalPlayer.CharacterRemoving:Connect(function(Character) self:OnCharacterRemoving() end)
	if Players.LocalPlayer.Character then
		self:OnCharacterAdded(Players.LocalPlayer.Character)
	end
	
	local HumRoot = self.CurrentCharacter and self.CurrentCharacter.HumanoidRootPart or nil
	
	local WaterParts = Folder:GetChildren()
	
	for i = 1, #WaterParts, 1 do
		--Here, I unsert every water part into self.WaterParts
	end
	
	self.WaterDetectionFunction = RunService.RenderStepped:Connect(function(Delta)
		if self.CurrentHumanoid then
			local HumRoot = self.CurrentCharacter.HumanoidRootPart
			local InsideWater = false
			for WaterPart, Params in pairs(self.WaterParts) do
				--My "Is in water" detection method
			end
			local HumValue = self.CurrentHumanoid.MovementState
			if InsideWater then
				if HumValue.Value ~= "Swim" then
					self.CurrentHumanoid:Move(Vector3.zero, false)
					self:ChangeHumanoidState(false, Enum.HumanoidStateType.Swimming)
					local AntiGravity = Instance.new("VectorForce")
					--Configuring this constraint with initial values.
					AntiGravity.Parent = HumRoot
					self.AntiGravForce = AntiGravity
					local Rotator = Instance.new("AlignOrientation")
					--Configuring this constraint with initial values.
					Rotator.Parent = HumRoot
					self.DirectionalForce = Rotator
					warn(self.DirectionalForce) --HERE "AlighOrientation" exists
					self.CurrentHumanoid.MovementState.Value = "Swim"
				end
			else
				if HumValue.Value ~= "Walk" then
					self:ChangeHumanoidState(true, Enum.HumanoidStateType.Running)
					self.AntiGravForce:Destroy()
					self.AntiGravForce = nil
					self.DirectionalForce:Destroy()
					self.DirectionalForce = nil
					self.CurrentHumanoid.MovementState.Value = "Walk"
				end
			end
		end
	end)

	return self
end

function WaterDetector:OnCharacterAdded(Character)
	--Character adding
end

function WaterDetector:OnCharacterRemoving()
	--Character removing
end

function WaterDetector:ChangeHumanoidState(Activate, ToSet)
	self.CurrentHumanoid:SetStateEnabled(Enum.HumanoidStateType.Running, Activate)
	self.CurrentHumanoid:SetStateEnabled(Enum.HumanoidStateType.RunningNoPhysics, Activate)
	self.CurrentHumanoid:SetStateEnabled(Enum.HumanoidStateType.GettingUp, Activate)
	self.CurrentHumanoid:SetStateEnabled(Enum.HumanoidStateType.Jumping, Activate)
	self.CurrentHumanoid:SetStateEnabled(Enum.HumanoidStateType.Freefall, Activate)
	self.CurrentHumanoid:SetStateEnabled(Enum.HumanoidStateType.FallingDown, Activate)

	self.CurrentHumanoid:ChangeState(ToSet)
end

function WaterDetector:GetDirectionalForce()
	print("Returning dirforce") -- prints
	print(self.DirectionalForce) -- nil
	return self.DirectionalForce -- nil
end

return WaterDetector
--requiring module
local module = WaterDetector.Initialize()
local Orientator = module:GetDirectionalForce() --nil, expected AlignOrientation
local Orientator2 = module.DirectionalForce -- nil again

Can someone tell me, why I’m running in this problem, and how I can fix it?

1 Like

You’re not calling your initialize function.

local module = require(path.to.WaterDetector)
local object = module.initialize()

local Orientator = object:GetDirectionalForce()
local Orientator2 = object.DirectionalForce
1 Like

Oof, I did that mistake on dev forum. In script there’s .initialize()

1 Like

Is the Initializing script a server script?

1 Like

you are using self incorrectly

Instead you should change your Initialize function

so instead of doing this:

function module.Initialize()
local InitialInfo = {
		CurrentCharacter = nil,
		CurrentHumanoid = nil,
		InsideWater = false,
		AntiGravForce = nil,
		DirectionalForce = nil,
		WaterDetectionFunction = nil,
		WaterParts = {},
	}
	local self = setmetatable(InitialInfo, WaterDetector)
end

do this:

function module:Initialize()
      --DO NOT OVERWRITE self
end

just like I commented DO NOT OVERWRITE self because then it wont replicate to other functions like GetDirectionalForce

and then

require(module):Initialize()
2 Likes

Surely you cannot be expecting the AlignPosition/AlignOrientation right when you create the object? Because your RenderStepped connection will only run execute till the NEXT pre-render frame, this might be why it’s not giving it to you immediately. Otherwise, your “InsideWater” detection method is messing up, causing your Aligners to be deleted every other frame. Personally I wouldn’t create & destroy these aligners as you might need them again (Which is why you create them, again.), so it’s easier to just turn their Enable state to false.

Also @Bakonowychlopak123 that’s not exactly correct, while self is syntax sugar, there’s not a ‘correct’ way of using it. The way they’re using it is extremely common and doesn’t interfere with the methods.

1 Like

No, hes using it incorrectly.

Example of how to use self correctly:

local main={}
function main:Init()
	self.Thing="yes"
end
function main:print()
	print(self.Thing)
	return self.Thing
end
return main

server script:

local real=require(script.ModuleScript)
real:Init()
real:print()

Here is what OP is using:

local main={}
main.__index=main
function main.indexInit()
	local self=setmetatable({
		Thing="hello world!"
	},main)
	
	return self
end
function main:printIndex()
	print(self.Thing)
end
return main

then if you can notice

require(module).indexInit()

and then

require(module):printIndex()

will print “nil” instead of printing “hello world”

unless you do something like this (fixes nil issue)

local main=require(module).indexInit()
main:printIndex()
1 Like

Correct, I was assuming this module is a class and initialize creates an Object of that class. So you’re not wrong either.

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.