An elegant way to make tables act like values ββwhen __indexed?
I got this problem with my homebrew OO design:
Entity = {}
function Entity:new(o)
o = o or {}
return setmetatable(o, {__index = Entity})
end
function Entity:init() end
function Entity:think() end
function Entity:spawn()
--put in entity pool and begin drawing/logic
self:init()
end
Block = Entity:new{
x = 0,
y = 0,
color = {255, 255, 255, 255},
}
function Block:getPos()
return self.x, self.y
end
--setPos, getColor, setColor etc
function Block:init()
self:setColor(math.random(255), math.random(255), math.random(255))
end
a = Block:new()
a:spawn() --a new block with a random color
--a few seconds later...
b = Block:new()
b:spawn() --all blocks change to new color
The table color
is shared by all prototypes and instances. How can I get this table to behave like a line:
a = {table}
b = a
print(b[1]) -->table
a[1] = "object"
print(a[1], b[1]) -->object, table
Unlike an object:
a = {table}
b = a
print(b[1]) -->table
a[1] = "object"
print(a[1], b[1]) -->object, object
TL; DR: I need to create a new datatype.
source to share
There are three ways to fix your problem:
- Initialize a table
Entity.color
during object initializationEntity
- place it in a functionEntity:new()
. - Replace the table
Entity.color
with four variables to represent its contents -Entity.colorred
,Entity.colorgreen
,Entity.colorblue
,Entity.coloralpha
. - Do
Entity:setColor()
create a new tableself.color
with new values ββinstead of directly changing the values.self.color = {red, green, blue, alpha}
instead ofself.color[1] = red; self.color[2] = green; self.color[3] = blue; self.color[4] = alpha
.
source to share
How can I get this table to behave like a line:
Your example uses Lua variable assignment to copy values, not references. Even if you can influence such a change in Lua (you cannot), it would be an unspeakably terrible idea.
The color table is shared by all prototypes and instances.
Try to put it in a prototype (like "class"), so it is equivalent to a static OOP member that is used by all instances. If you want this to be an instance variable, it must be part of the instance construction, not the class construction. You must do the same for x
and y
and for all instances Block
.
function Block:new()
local instance = { x = 0, y = 0 }
instance:setColor(math.random(255), math.random(255), math.random(255))
return setmetatable(instance, {__index = self})
end
Improvements can be added to the constructor, such as passing parameters (for example, for initialization x
, y
etc.), but the important part is that the instance carries its own state.
Having Entity:spawn
just call init on its own doesn't make sense. The example code you show indicates that it should in fact create new instances, but the implementation does not.
source to share