hello, so below I have my first completed version of an OOP system. It’s not completely OOP, i struggled with some of the aspects of a typical OOP because I wanted everything organized in folders and I wasn’t sure how to do a sort of table inside a table thing. So instead I went with folders in the replicated storage etc.
basically, Im looking at this code and thinking its very messy, and not very modular at all. the goal was for it to be object oriented like I said, But i wasn’t sure how else to do it. If someone could look through it and give me some pointers or something I should work on that would be great.
another thing is, as is explained in the code description, if the use of replicated storage was proper or not.
code description
I use a script to create a folder for every player that joins the game,
I have a folder with a folder of every location in the map, with three parts connected to touched events, all inside of the workspace
I use said folder in the workspace filled with every coin, and basically make a copy of that folder system in every players designated folder. I then use bool values to show if the player has touched the ‘coin’ or not.
--module script
local coin = {}
coin.__index = coin
local playerFolder = game.ReplicatedStorage:WaitForChild("playerFolder")
coin.New_Player = function(player)--create a table for every player upon joining
local newFolder = setmetatable({
folder = Instance.new("Folder",playerFolder)
},coin)
newFolder.folder.Name = "Player_"..tostring(player.UserId)
for i,v in pairs(game.Workspace.Locations:GetChildren()) do --create a folder for every location and puts it in player folder
newFolder["loc_"..tostring(v)] = Instance.new("Folder",newFolder.folder)
newFolder["loc_"..tostring(v)].Name = "loc_"..tostring(v)
for i = 1,3 do
local num = Instance.new("BoolValue")
num.Name = i
num.Value = false
num.Parent = newFolder["loc_"..tostring(v)]
end
end
return newFolder
end
coin.New_Coin = function(newCoinIn)
newCoinIn.Touched:Connect(function(part)
local player =game.Players:GetPlayerFromCharacter(part.Parent)
if game.ReplicatedStorage.playerFolder["Player_"..tostring(player.UserId)]["loc_"..tostring(newCoinIn.Parent.Name)][newCoinIn.Name] ~=true then
game.ReplicatedStorage.playerFolder["Player_"..tostring(player.UserId)]["loc_"..tostring(newCoinIn.Parent.Name)]:WaitForChild(tostring(newCoinIn.Name)).Value = true
end
end)
end
return coin
--script
local coin = require(script.ModuleScript)
game.Players.PlayerAdded:Connect(function(player)
local newPlayer = coin.New_Player(player)
end)
game.Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function()
print("character added")
end)
wait(2)
player:LoadCharacter()
end)
for i,v in pairs(game.Workspace.Locations:GetChildren()) do
for i,newCoin in pairs(v:GetChildren()) do
coin.New_Coin(newCoin)
end
end
The only thing I can see you improving is not relying on instances. I recommend making the modules not create folders and store these values in tables, which are dictionaries or arrays.
in this case it was helpful to have each location seperated, and for me I found it easiest to organize it via a folder system with values inside of them. If I wanted to do this I would have to do some sort of table inside of a table system, unless I’m wrong. How would I go about doing that?
You would do everything you do with folders, but this time organize them into global table variables. This means using playerListTable[playerInstance] = true, because indexing by instances will automatically free up memory when the instance is deleted.
i did not know I could index a table using an instance. Is it possible for you to explain how this works or what is going on?
playerListTable[playerInstance] = true
from what I’m understading what your saying is by making the playertable indexed via instances, when a player leaves it will just delete the player. I could also do this with the current system and just delete the folder with the player?
also, one last note, I have it all stored in folders so that both the server and and client can access the information, and I don’t know if sending a table back in forth is better or whatnot
Yes, this is correct, and you can do this with the current system.
I see. In fact, it is not better, you are correct. However, I think you can remove the folders entirely if you add attributes to the player, which will be faster. However, the more I think about the system you implemented, the better it seems.
The following prevents a coin from being collected more than once.
Just copy this into a modulescript named Coin, require it on the server, and tag your instances with Coin. It should print “Coin collected!” only once for each coin.
local Collection = game:GetService("CollectionService")
local Players = game:GetService("Players")
local Coin = {}
local collected = {}
local connection = {}
function Coin.new(self)
connection[self] = self.Touched:Connect(function (hit)
local plr = Players:GetPlayerFromCharacter(hit.Parent)
if not plr then return end
Coin.Collect(self, plr)
end)
end
function Coin:Destroy()
for _, plr in ipairs(Players:GetPlayers()) do
collected[plr][self] = nil
end
connection[self]:Disconnect()
connection[self] = nil
end
function Coin:Collect(plr)
if Coin.IsCollected(self, plr) then return end
collected[plr][self] = true
print("Coin collected!")
end
function Coin:IsCollected(plr)
return collected[plr][self] or false
end
Collection:GetInstanceAddedSignal("Coin"):Connect(Coin.new)
Collection:GetInstanceRemovedSignal("Coin"):Connect(Coin.Destroy)
for _, coin in ipairs(Collection:GetTagged("Coin")) do
Coin.new(coin)
end
local function playerAdded(plr)
collected[plr] = {}
end
Players.PlayerAdded:Connect(playerAdded)
Players.PlayerRemoving:Connect(function (plr)
collected[plr] = nil
end)
for _, plr in ipairs(Players:GetPlayers()) do
playerAdded(plr)
end
return Coin
You will need to create another module to handle client behavior. You can then use a RemoteEvent to communicate between the two.
I hope this at least provides some insight on how OOP can be used.
local data = {}
---
local playerDataTable = {leaderstats.Kills.Value, leaderstats.Deaths.Value}
--to get kills, do this:
--local kills = playerDataTable[1]
--put the table into another table!
data[player] = playerDataTable
--access it later:
local playerkills = data[player][1]
Is it possible to do this same method but if an individual player? I’m going to create a character selection script (hair color, skin shade, face) but store the data as a table and want to be able to reference it easily.
Ideally, you should encode the data into JSON format before saving it. Additionally, each player should have their own key. Yes, it should be stored in a table.