How to efficently save the Atrribute / Variable-Refernece inside a script Variable insteads of the actual Value

Good day, everyone!

I am currently making a weather simulation as a hobby project, with focus on the dynamic and smooth transition between different weather situations (f.e. clear sky slowly filling up with many clouds turning dark.)

For this I have attributes inside of my responsible WeatherTranistioner script for the desired weather conditions set by other scripts, like cloud density and cloud coverage. For the actual weather situation I read the values from the responsible weather objects directly (such as workspace.Terrain.Clouds.Cover).

A for-loop, executed constantly by a while-loop, then compares the values dynamically via tables and calls another method if the desired- and actual values do not match up.

The tables should look something like in this example:

Clouds = workspace.Terrain.Clouds

singularAttributeTable = {CloudDensity = {Clouds.Density, script:GetAttribute("DesiredCloudDensity")}, CloudCover = {Clouds.Cover, script:GetAttribute("DesiredCloudCover")}}

However, the problem I face with this is that the actual current value of the attributes is saved in the table, not the references to the values.

That’s why my current script looks far more ugly and uses a lot of [] brackets, such as value[1][value[2]] as I save the location name of the object and the key name of the value. A working version of this can be cloned here: Weather Demo - Roblox (version 5/20/2022, note that I didn’t know about Attributes at that point and instead used global variables hehe.)

So, is there any effective way to save the value reference, so I can dynamically read and change it? Or should I instead just save strings that the script then resolves to the value?

Many thanks in advance!

No, you cannot really save a reference to a property in lua.

The version you linked to is probably the easiest way. Make convenience functions if the syntax for using it bothers you:

attributeTable = {CloudDensity = {Clouds, "Density", "DesiredCloudDensity", 0.1}, CloudCover = {Clouds, "Cover", "DesiredCloudCover", 0.1}}

local function GetProperty(entry) return entry[1][entry[2]] end
local function SetProperty(entry, value) entry[1][entry[2]] = value end
local function GetTarget(entry) return script:GetAttribute(entry[3]) end
local function GetModifier(entry) return entry[4] end

What I recommend, though, is wrapping these details in a custom object to make things even easier to use. In fact, you could move Advance in there as well.

For example, if you stuck this in a module script called “WeatherAttribute” as a child of WeatherTransitioner:

image

local WeatherAttribute = {}
WeatherAttribute.__index = WeatherAttribute

function WeatherAttribute.new(obj: Instance, property: string, attribute: string, modifier: number)
	return setmetatable({
		_obj = obj,
		_property = property,
		_attribute = attribute,
		_modifier = modifier
	}, WeatherAttribute)
end

function WeatherAttribute:Advance()
	local val = self._obj[self._property]
	local target = script:GetAttribute(self._attribute)
	local modifier = self._modifier
	
	if val == target then return end

	if val < target then
		if (val + _G.MaximumDesireSpeed * modifier) < target then
			val = val + _G.MaximumDesireSpeed * modifier
		else
			val = target
		end
	else
		if (val - _G.MaximumDesireSpeed * modifier) > target then
			val = val - _G.MaximumDesireSpeed * modifier
		else
			val = target
		end
	end
end

type WeatherAttribute = typeof(WeatherAttribute.new())

return WeatherAttribute

Now you nave a nice, easy-to-use attribute object for the parent script to use:

local WeatherAttribute = require(script.WeatherAttribute)

local attributeTable: {WeatherAttribute} = {
	CloudDensity = WeatherAttribute.new(Clouds, "Density", "DesiredCloudDensity", 0.1),
	CloudCover = WeatherAttribute.new(Clouds, "Cover", "DesiredCloudCover", 0.1),
}

while(true) do
	for key, attr in pairs(attributeTable) do
		attr:Advance()
	end
	
	wait(0.1)
end

If you find the parent script needing more info exposed than just the Advance() method, you can add that to your WeatherAttribute class:

function WeatherAttribute:GetProperty() return self._obj[self._property] end
function WeatherAttribute:SetProperty(val) self.obj[self._property] = val end
function WeatherAttribute:GetTarget() return script:GetAttribute(self._attribute) end
function WeatherAttribute:GetModifier() return self._modifier end
2 Likes

Awesome, lots of thanks for your instructions!
I’m not experienced in LUA yet, so there’s a lot of stuff I haven’t seen before in your answer (which I only used in other languages so far), but I’ll definitely research it the next time I’m working on the game!

Again, lots and lots of thanks, it’s not only helpful but very interesting and educational to me, you’re awesome!

1 Like