Is there an way to, when the goblin’s health get below an certain point, it fires a signal? Maybe something like this:
goblin.onLowHealth = Signal.new()
observer.observe(goblin.health, function(health) -- fired when
local lowHealth = health < 30 -- value changes
if not lowHealth then return end
goblin.onLowHealth:Fire()
end)
You can either write your own connection module to mimic connections or connect to a bindable event then fire that bindable event everytime you write to the health value within the goblin table given in the example.
The simplest way would be to just use a method that updates the health, and does the check you want. Only interact with the health through that method.
If you really wanted you can do this with metatables, though:
local goblin
do
local internal = {
Health = 100
}
goblin = setmetatable({}, {
-- getters
__index = internal,
-- setters
__newindex = function(t, k, v)
if t[k] then
print(k, "changed to", v)
rawset(t, k, v)
else
error("cannot add new keys!")
end
end,
})
end
print(goblin.Health) --> 100
goblin.Health = 50 --> "Health changed to 50"
print(goblin.Health) --> 50
goblin.health = 75 --> error: "cannot add new keys!"
Thanks for the response, I found an OOP solution some minutes ago, but your solution is good too. Just for who will stumble upon this question in the future, here is the code:
function TableWrapper:wrap(tabl: table, callback)
self.onTableChange = Signal.new()
local proxy = newproxy(true)
local metatable = getmetatable(proxy)
metatable.__index = tabl
metatable.__newindex = function(_, index, value)
if tabl[index] == value then return end
tabl[index] = value
self.onTableChange:Fire(index, value)
callback(index, value)
end
return proxy
end
It wraps the table, so you will set the values like this:
local goblin = {health = 100}
local wrapper = TableWrapper:wrap(goblin, function(i, v)
print(("%s changed to %s"):format(i,v))
end)
wrapper.health = 40 --> "health changed to 40"
local Goblin = require(script.Goblin)
local goblin = Goblin.new(500)
goblin:GetPropertyChangedSignal("Health"):Connect(function()
print("custom event handler: health changed to", goblin.Health)
end)
print(goblin.Health) --> 500
goblin.Health = 50 --> "custom event handler: health changed to 50"
print(goblin.Health) --> 50
goblin.health = 75 --> error: "cannot add new properties"
Goblin ModuleScript:
local Goblin = {}
function Goblin.new(health: number?)
local properties = {
Health = health or 100
}
local events = {}
local meta = {
__index = function(t, k)
local curr = properties[k]
if curr then return curr end
return Goblin[k]
end,
__newindex = function(t, k, v)
local curr = properties[k]
if curr then
local event = events[k]
if event then event:Fire() end
rawset(t, k, v)
else
error("cannot add new properties")
end
end
}
return setmetatable({_properties = properties, _events = events}, meta)
end
function Goblin:GetPropertyChangedSignal(property: string): RBXScriptSignal
if not self._properties[property] then
error("invalid property name")
end
local bindable = self._events[property]
if bindable then return bindable.Event end
bindable = Instance.new("BindableEvent")
self._events[property] = bindable
return bindable.Event
end
return Goblin