Hello, I’m trying to learn how metatables work. But, when trying to link Frame object to it, and change value of metatable, I understood that IDK how I can reflect that change to frame:
local Object = {}
Object.__index = Object
function Object.new(Size, Position, Rotation...)
local NewObject = {}
NewObject.Size = Size
NewObject.Position = Position
NewObject.Rotation = Rotation
Frame2D = Instance.new("Frame")
Frame2D.Size = Size
Frame2D.Position = Position
Frame2D.Rotation = Rotation
NewObject.Frame = Frame2D
return setmetatable(NewObject, Object)
end
...
local function changer(Object, newValue)
Object.Position = newValue
-- Object is METATABLE and not roblox instance.
-- I want change Frame2D position to changed metatable position.
end
How I can detect, when I try change smth in metatable, if that key already exists, without additional Object.Frame.Position = newValue
?
There is a metamethod named __newindex
which can be set to a function that fires whenever an index is changes to a particular value.
Object.__newindex = function(self, key, value)
if key == "Position" then
self.Frame.Position = value
end
end
- where
self
is the table (Object)
- where
key
is the index changed
- where
value
is the value set to key
This not working at all somewhy, even without if statement when trying to print any change.
Will __newindex fire if there’s already value existing?
local Object = {}
Object.__index = Object
function Object.new(Size, Position, Rotation, Anchored, Velocity, Shape, Color)
Rotation = Rotation or 0
Anchored = if Anchored == nil then true else Anchored
Velocity = Velocity or Vector2.new(0, 0)
Shape = Shape or "Block"
Color = Color or "Black"
local NewObject = {}
NewObject.Size = Size
NewObject.Position = Position
NewObject.Rotation = Rotation
NewObject.Anchored = Anchored
NewObject.Velocity = Velocity
NewObject.Shape = Shape
NewObject.Color = Color
local Frame2D
if Shape == "Block" then
Frame2D = Instance.new("Frame")
Frame2D.BackgroundColor3 = ObjectColors[Color]
elseif Shape == "Ball" then
Frame2D = Instance.new("Frame")
Frame2D.BackgroundColor3 = ObjectColors[Color]
local Corners = Instance.new("UICorner")
Corners.CornerRadius = UDim.new(1, 0)
Corners.Parent = Frame2D
elseif Shape == "Triangle" then
Frame2D = Instance.new("ImageLabel")
Frame2D.BackgroundTransparency = 1
Frame2D.Image = "http://www.roblox.com/asset/?id=14248930926"
Frame2D.ImageColor3 = ObjectColors[Color]
end
Frame2D.Size = UDim2.fromScale(Size.X, Size.Y)
Frame2D.Position = UDim2.fromScale(Position.X, Position.Y)
Frame2D.Rotation = Rotation
Frame2D.Parent = GameScreen.Map
NewObject.Object = Frame2D
return setmetatable(NewObject, Object)
end
function Object:Destroy()
self.Object:Destroy()
self = nil
end
function Object:Print()
print(self.Shape .. ":")
print("Size: " .. tostring(self.Size) .. "; Position: " .. tostring(self.Position) .. "; Rotation: " .. tostring(self.Rotation))
print("Color: " .. self.Color .. "; Anchored: " .. (if self.Anchored == true then "yes" else "no") .. "; Velocity: " .. tostring(self.Velocity))
end
Object.__newindex = function(table, key, value)
print("Changing?")
end
function ObjectHolder.Hearbeat(delta, Objects)
for i = 1, #Objects, 1 do
local Object = Objects[i]
if Object.Anchored == false then
Object.Position = Object.Position + Object.Velocity * delta
Object.Object.Position = UDim2.fromScale(Object.Position.X, Object.Position.Y)
end
end
for a = 1, #Objects, 1 do
local Object1 = Objects[a]
if Object1.Anchored == false then
for b = a + 1, #Objects, 1 do
local Object2 = Objects[b]
if Object2.Anchored == false then
ObjectHolder.DetectCollisions(Object1, Object2)
--Object.Object.Position = UDim2.fromScale(Object.Position.X, Object.Position.Y)
end
end
end
end
end
Heartbeat function calls every RenderStepped, and changes position of object if it’s Anchored property = false
So did a lil bit of digging and I realized that __newindex only fires when an index that is not present in the main table changes. Since, you set Position in NewObject
table and assign the __newindex
metamethod to that table, changes to Position
won’t be fired as it is an exisiting key in the table. An ugly work-around is to set the Position property after setting the metatable.
local obj = setmetatable(NewObject, Object)
obj.Position = Position
return obj