Need help with OOP

I’m quite new to the whole object oriented programming thing, so I was wondering, is there a way I would be able to make a custom class in one script, and reference it in another? Something like this:

--ModuleScript
local CustomPlayer = {}
function CustomPlayer:Create(Player_Instance)
    local Player = {}
    Player.Instance = Player_Instance
    Player.Character = Player.Instance.Character or Player.Instance.CharacterAdded:Wait()
    Player.ID = Player_Instance.UserId
    setmetatable(Player, CustomPlayer)
    return Player
end

function CustomPlayer:GetPlayer(Player)
    --Oooooh magic magic code here
    return PlayerInstanceThing
end

--Script One:
local CustomPlayer = require(script.Parent:WaitForChild("CustomPlayer")
game.Players.PlayerAdded:Connect(function(player)
    CustomPlayer:Create(player)
end)

--Script Two
local CustomPlayer = require(script.Parent:WaitForChild("CustomPlayer")
local Event = game.ReplicatedStorage:WaitForChild("SomeRandomEvent")

Event.OnServerEvent:Connection(function(player)
    local Player = CustomPlayer:GetPlayer(player)
    print(Player.ID)
end)

Yes, this is the entire basis of OOP. Let’s take your script and make a few minor edits so that it is functional:

Module Script:

local CustomPlayer = {}
CustomPlayer.__index = CustomPlayer -- Let calls of object's know to search the CustomPlayer table

function CustomPlayer.new(playerInstance) -- Let's create an object!
	local self = setmetatable({
		instance = playerInstance;
		character = playerInstance.Character; -- Waiting for character should be done prior in this example
		id = playerInstance.UserId
	},CustomPlayer)
	
	return self
end

function CustomPlayer:GetId() -- Create a function for this object
	return self.id
end

return CustomPlayer -- return this table for module script calls

Server (or client) Script:

local CustomPlayer = require(game.ServerScriptService.ModuleScript) -- Obtain the module information
local Player = CustomPlayer.new(game.Players.Imp_erator) -- Set up the custom player object

print(Player:GetId()) -- Use our function from before to print the Player's UserId
1 Like

Welcome to OOP! I want to address something real quickly before getting into the answer to your question, which is the difference between classes and objects; I noticed you mentioned making a custom class in your original post, and wanted to clear this up just in-case you were confused about this.

Classes should be thought of as synonymous to Roblox classes, and Objects–that is, each instance of your class–should be thought of in the same sense as how you think about instances created with Instance.new. The Class in your code would be CustomPlayer, and the Objects would be the individual Player tables that you’re returning in the CustomPlayer:Create(Player) constructor method sorry if this was all stuff you knew i just like talking about oop.

With that out of the way: It’s of course possible to reference your custom class in another script–you’re doing it already in the line local CustomPlayer = require(script.Parent:WaitForChild("CustomPlayer"). I’m gonna assume you’re talking about referencing the objects that are created from your custom class, which is possible as well.

To accomplish this, you need to create a table that stores your objects and a method to retrieve them from said table. The most obvious way to make this method accessible is via a BindableFunction. In this situation, it makes the most sense (to me) to handle this in Script One. It could look something like this:

--Script One:
local CustomPlayerTable = {}
local CustomPlayer = require(script.Parent:WaitForChild("CustomPlayer")

-- Handle players joining; create objects and add them to the table
game.Players.PlayerAdded:Connect(function(player)
    local newCustomPlayer = CustomPlayer:Create(player)
    CustomPlayerTable[player.UserId] = newCustomPlayer -- add the new CustomPlayer object to the CustomPlayerTable here, with the key being the player's UserId
end)

-- Handle players leaving; remove the object from the table.
game.Players.PlayerRemoving:Connect(function(player)
    CustomPlayerTable[player.UserId] = nil
end)

-- Create a BindableFunction, which when invoked and given a UserId argument, will return the CustomPlayer object.
local GetPlayerBindableFunction = Instance.new("BindableFunction")
GetPlayerBindableFunction .Name = "GetCustomPlayer"
GetPlayerBindableFunction .Parent = game:GetService("ServerStorage")

-- Attach a get method to the BindableFunction
GetPlayerBindableFunction.OnInvoke = function(UserId)
    return CustomPlayerTable[UserId] -- This will return the custom player object, or nil if one does not exist for some reason.
end

You could then get a player’s custom player object from Script Two, or any other server-script that can access game.ServerStorage:

--Script Two
local Event = game.ReplicatedStorage:WaitForChild("SomeRandomEvent")
local GetCustomPlayer = game.ServerStorage:WaitForChild("GetCustomPlayer")

Event.OnServerEvent:Connection(function(player)
    local Player = GetCustomPlayer:Invoke(player.UserId)
    if Player == nil then return end -- Ensures that the BindableFunction didn't return nil
    print(Player.ID)
end)

Ah, I see. Thanks for your help! OOP is awesome… :flushed: