Reputation: 23
Sprite = {x = 0, y = 0, pos = {z=0}}
function Sprite:new()
o = {}
setmetatable(o,self)
self.__index = self
return o
end
s1 = Sprite:new()
s2 = Sprite:new()
s1.x = 10
s1.pos.z = 5
print("s1.x", s1.x, "s2.x", s2.x, "s1.z",s1.pos.z, "s2.z", s2.pos.z )
s2.x = 20
s2.pos.z = 50
print("s1.x", s1.x, "s2.x", s2.x, "s1.z",s1.pos.z, "s2.z", s2.pos.z )
In the above code snippet, I define a class Sprite
which has x(int),y(int),pos(table)
3 attributes, but when I init two object s1,s2
. I found that they shared the pos
attribute.
If you run the code, it will print:
s1.x 10 s2.x 0 s1.z 5 s2.z 5
s1.x 10 s2.x 20 s1.z 50 s2.z 50
s1
and s2
has their own x,y
attribute, but share pos
attribute, if s1.pos.z
is changed, so as the s2.pos.z
.
How can I fix this?
Upvotes: 2
Views: 150
Reputation: 29463
Sprite represents the class, hence you can think of Sprite table as the "class wide" entries: they will be shared by all "instances". Instance specific entries should be in the o table:
Sprite = {classX = 0, classY = 0} -- class; vars shared by all instances
function Sprite:new()
o = {pos = {z=0}}
setmetatable(o,self)
self.__index = self
return o
end
Note that "shared" really does mean shared at the reference level, so all instances will see the same values and any changes made by one instance will be seen by all others. OTOH data you put in o table is per instance. Putting this in Sprite.new() ensures that all instances have the same fields, but their own data; changes by one instance will not affect any other instance.
That said, your Sprite:new() does not define self.__newindex. So Sprite.classX = 5 will be seen by all instances, as expected, but s1.classX = 6 will only be seen by s1: it will create a new field, thus hiding that of Sprite. From then on, changes to Sprite.classX will no longer be seen by s1 (but will be by all other instances that have not overridden Sprite.classX). To get around that, you could do this:
function Sprite:new()
o = {pos = {z=0}}
setmetatable(o,self)
self.__index = self
self.__newindex = self
return o
end
In Lua console you would see this if you played around with this:
> s1=Sprite:new()
> s2=Sprite:new()
> print(s1.classX, s2.classX)
0 0
> Sprite.classX=1
> print(s1.classX, s2.classX)
1 1
> s1.classX=3
> print(s1.classX, s2.classX)
3 3
Without that change, that last output will show "3 1" and changes to Sprite.classX would not be visible in s1.
Upvotes: 0
Reputation: 72312
In Sprite:new
, the variable self
always has Sprite
as its value. So, self.pos
refers to Sprite.pos
. Try changing to o.pos={}
. Also, consider making o
a local.
Upvotes: 3
Reputation: 13859
Lua shares tables(keeps them as reference), and copy variables. Use metatables for methods, and keep fields copying them in your object table.
Sprite = {
instanceData = { x = 0, y = 0, pos = {z = 0} },
method = function(self) print("do smth with "..self) end
}
function Sprite:new()
local o = deepCopy(self.instanceData)
setmetatable(o,self)
self.__index = self
return o
end
deep copy implementation can be found wiki/CopyTable
Upvotes: -1