Everyone knows how ugly is it to have a global state in your scripts.
Using stringValue and numberValue and put them in a workspace to keep a game state is roughly equivalent of using _G table but not super horrid first of all as long as module scripts do not have side effects and only assignments to datavalues are done in scripts it should be managable/maintainable and less of a mess.
Still this is more prone to errors due to datavalues can modified from anywhere.
There are other alternatives such as create a table in the main script and pass it around modules.
Or use a functional approach and simply update the state based on changes in a loop and pass the new state around there (though this seems “beautiful” it has risk of stack overflow if isn’t properly done and hard to get it though there are libraries like rodux made by Roblox itself but those are more geared towards UI rather than actual game state.
What is your approach to keep game state?
Any better way than that?
Has :GetPropertyChangedSignal event for value observation
Arguably better than _G and module scripts
Replicates to the Client
Cons:
Maybe memory intensive and or increase loading times if too many instances are used
Overall I’d say yes. But if you want more control/customizability I’d say create custom …Value objects using module scripts because they allow you to code custom behavior.
If you don’t access those states many many times within a frame, then it should be fine. It does take up more performance to use Values (and not just more memory), compared to using modules scripts or a main table
That is only true because ModuleScripts are loaded only once. If they make it so that you have to load the ModuleScript to access it’s value every time, it will be a lot worse than a …Value object.
Updating the properties of objects or even reading the properties of objects is slow overall (if you do hundreds or thousands of read/writes), probably because it has to break the C/lua boundary or something, while with a module script, the code execution remains in the same thread, which is much better for performance
Well it is the best choice in this case since ModuleScripts aren’t that much faster.
Also, the value objects are parsed into actual code objects in the memory when the game loads I believe
This is doing some number addition 10 000 times. Module scripts are that much faster, however, the question is, does it really matter? Values might very well be a good option, since you need thousands of writes for it to have a significant impact on performance. I just think it’s good to be aware of this, as this also applies to like, the CFrame property, but much worse
Code I used
local NumberValue = Instance.new("NumberValue")
NumberValue.Value = 0
local Module = require(script.ModuleScript)
Module.Value = 0
task.wait(3)
--[[
while true do
debug.profilebegin("NumberValue")
for i = 1, 10000 do
NumberValue.Value += i
end
debug.profileend()
warn(NumberValue.Value)
NumberValue.Value = 0
task.wait()
end
]]
while true do
debug.profilebegin("ModuleScript")
for i = 1, 10000 do
Module.Value += i
end
debug.profileend()
warn(Module.Value)
Module.Value = 0
task.wait()
end
Nvm I thought the value objects were referenced separately in the memory for optimization but ig not since it takes 2.6ms which is really significant. But again, this test shows that ModuleScripts are faster because they are loaded once unlike value objects which need to be indexed using the instance pointer each time which makes sense why it is so slow. Otherwise it would be worse.
I usually use one script for my entire game, so I just used global or local variables depending on the performance context. I don’t use _G because how ugly it looks and how much people dislike it.
Otherwise, I keep game states with game:SetAttribute() and game:GetAttribute() because I was informed they’re hashed. Tables that aren’t accessed frequently are JSON encoded and stored as a string attribute. Probably less performant than modulescripts and such, but significantly easier.
Reading over this I don’t know why nobody brought up Attributes… they’re literally perfect for state replication both server and client if you put the attributes on something the client can access, and so long as the value is within the allowed types for Attributes.
Otherwise, just use BindableEvents/BindableFunctions or Remotes for more complex data types.