So I recently wanted to change the way I am managing playerData using OOP, buy lets say I have a rebirth system that should change a value for the player, how would I do that? Since I dont have self, I cant do self:Update(). Should I use bindable events? Or should I use a completely different way of managing playerdata?
You don’t have to abandon OOP or use bindable events for this
As If you’re using OOP for playerData, you should store the object class instance for each player, maybe in a dictionary like PlayerData[player]
and when your rebirth system triggers, just access the instance and call its method like
PlayerData[player]:UpdateRebirth()
or modify values directly
PlayerData[player].rebirths += 1
The key is to keep track of the player’s data object and I’d say there’s really no need for bindables
Ohhh so a seperate module for each player?
No, not a separate module, a separate instance of a class (from a module for each player) because the module defines the class and you create a new object from it per player
Ok could you give an example of how this would like because i am still kinda confused
Module:
local playerDataModule = {}
playerDataModule.__index = playerDataModule
function playerDataModule:initalize(player:Player)
local self = setmetatable({}, playerDataModule)
playerDataModule[player.UserId] = self
--
self.coins = 0
--
return self
end
function playerDataModule:update(value)
self[value] = self[value] + 1
end
return playerDataModule
Changer
local players = game:GetService("Players")
local replicatedStorage = game:GetService("ReplicatedStorage")
local modules = replicatedStorage:WaitForChild("modules")
local playerDataModule = require(modules:WaitForChild("playerDataModule"))
local part = script.Parent
local debounce = {}
part.Touched:Connect(function(otherPart)
local humanoid = otherPart.Parent:FindFirstChildOfClass("Humanoid")
if not humanoid then return end
local character = otherPart.Parent
local player = players:GetPlayerFromCharacter(character)
local self = playerDataModule[player.UserId]
self:update("coins")
print(playerDataModule)
end)
Like this?
No
You are turning self into a number…Why?
Why do yall begginers want to turn everything into a class anyway?
OOP in such cases makes code harder,more unoptimized and harder to manage.
All you need to do is having one table always alive per player and having backend system that saves it upon player leaving/autosaving.
Also you absolutelly never use self,there no any point of using methods here anyway
Also if you are creating a constructur please either name it new or separate it from main table.
like:
local module = {}
module.__index = module
local function module:Method():string
return self.Name
end
return function(name:string)
local class = {Name=name}
return setmetatable(class,module)
end
Anyway if you were to use OOP, i recomend you to either use C like OOP or closures/closure OOP:
Example of closure OOP:
type closureClass = {
Increase:(num:number)->();
Print:()->();
Destroy: ()->();
}
local function NewClosure():closureClass
local num:number = 0
local connection = Script.Destroying:Connect(function():()
print(num)
end)
return {
Increase = function():()
num+=1
end;
Print = function():()
print(`Closure scope: {num}`)
end;
Destroy = function(self:closureClass):()
connection:Disconnect()
table.clear(self::{[any]:any})
end;
}::closureClass
end
local closure = NewClosure()
local Increase,Print = closure.Increase,closure.Print
Increase()
Increase()
Increase()
Increase()
Increase()
Print()
task.wait(5)
closure:Destroy()
Agreed. There is so little instances where this would be practical.
No, it’s because you are overwriting the playerDataModule
table with some self instance for every player, losing previous player data and breaking the module’s functions
Ok I am sorry for being stupid, so from your response the conclusion is:
No OOP
From this response I conclude:
No OOP
From this response I conclude:
Still use OOP?
If everyone that replied here just please could tell me how they would do it without OOP, or send an example of a script with OOP, it would be very usefull
Sorry for being stupid, but I cant improve if I dont know how too, so please help me out if you can
You could do something pretty simple like this
local datas = {} :: {[Player] : {any}}
local function updateStat(player : Player, stat : string, value : any)
datas[player][stat] = value
end
game.Players.PlayerAdded:Connect(function(player)
datas[player] = {
Coins = 0
}
end)
updateStat(player, "Coins", 100)
print(datas[player].Coins) -- prints 100
Sorry I havent written out something properly, but I hope you get the jist of it.
And then to access it from other scripts you could put it in a ModuleScript and have it return a table with the updateStat function within it.
yes ok thats what I thought at first too
You could make a class that is created when a player joins, and saved and destroyed when they leave.
Anything related to changing a player’s data should be encapsulated inside the class as a method, like rebirthing.
-- Defining a type for the object to make it easier to read
export type PlayerData = {
Owner: Player,
Coins: Number,
Rebirths: Number,
Rebirth: (self: PlayerData) -> (),
Destroy: (self: PlayerData) -> (),
}
local PlayerData = {}
PlayerData.__index = PlayerData
function PlayerData.new(Owner: Player): PlayerData
local self = setmetatable({}, PlayerData)
self.Owner = Owner
self.Coins = 0 -- Could replace with a call to grab saved data, if any, so coins is assigned to the data
self.Rebirths = 0 -- Same here
return self
end
function PlayerData:Rebirth()
self.Coins = 0
-- Whatever other values need to be reset
self.Rebirths += 1
end
function PlayerData:Destroy()
table.clear(self)
end
return PlayerData
If you want to handle multiple players, you can create something called a singleton/handler (also a module):
local PlayerData = require(script.Parent) -- or whatever path PlayerData is in
local PlayerDataHandler = {}
local PlayerDatas: {[Player]: PlayerData.PlayerData} = {} -- Dictionary that holds all the players objects
-- Stores PlayerData objects in a dictionary, if a player doesn't have a PlayerData object yet it makes a new one
function PlayerDataHandler.Get(Owner: Player): PlayerData
local result = PlayerDatas[Owner]
if not result then
result = PlayerData.new(Owner)
PlayerDatas[Owner] = result
end
return result
end
return PlayerDataHandler
This is just a really basic template. In this case, you should only be requiring the PlayerDataHandler
in other scripts, and then calling functions from the value it returns, like:
local PlayerDataHandler = require(yourPath.PlayerData.PlayerDataHandler)
local PlrData = PlayerDataHandler.Get(player) -- Assuming you have a reference to a player
PlrData:Rebirth()
Let me know if this was helpful!