Love2D / LUA Problem with object not keeping values it was created with [duplicate] - oop

I need a table variable in a Lua class, which is unique for each instance of the class.
In the example listed below the variable self.element seems to be a static variable, that is used by all class instances.
How do I have to change the testClass to get a non static self.element table variable?
Example:
local testClass ={dataSize=0, elementSize=0, element = {} }
function testClass:new (data)
local o = {}
setmetatable(o, self)
self.__index = self
-- table to store the parts of the element
self.element = {}
-- data
self.element[1] = data
-- elementDataSize
self.elementSize = #data
return o
end
function testClass:getSize()
return self.elementSize
end
function testClass:addElement(data)
-- add data to element
self.element[#self.element+1] = data
self.elementSize = self.elementSize + #data
end
function testClass:printElement(element)
-- print elements data
element = element or self.element
local content = ""
for i=1, #element do
content = content .." " .. tostring(element[i])
end
print("Elements: " .. content)
end
function printAll(element)
print("Size: " .. tostring(element:getSize()))
element:printElement()
end
test = testClass:new("E1")
printAll(test)
test:addElement("a")
printAll(test)
test2 = testClass:new("E2")
printAll(test2)
test2:addElement("cde")
printAll(test2)
print("............")
printAll(test)
This implementation returns:
$lua main.lua
Size: 2
Elements: E1
Size: 3
Elements: E1 a
Size: 2
Elements: E2
Size: 5
Elements: E2 cde
............
Size: 3
Elements: E2 cde
For the last output I need
Size: 3
Elements: E1 a

In testClass:new() self refers to testClass.
local test = testClass:new()
test.element will refer to testClass.element
Your instance is o, so when you want each instance to have its own element replace self.element = {} with o.element = {}

You are making a common mistake in your :new function.
You assign self.element but this should be o.element. self in this function refers to the testClass table not to the object you are creating. To make element unique to each object you need to assign it to o, the object being created.
function testClass:new (data)
local o = {}
setmetatable(o, self)
self.__index = self
-- table to store the parts of the element
o.element = {}
-- data
o.element[1] = data
-- elementDataSize
o.elementSize = #data
return o
end

Related

Creating of a new object of a different class gets overriden every time it's created

I'm still fairly new to OOP but I can't figure out what I'm doing wrong here.
-- TestModule
testClass = {}
local thingClassModule = require(script["ThingModule"])
function testClass:new()
setmetatable({}, self)
self.__index = self
self.Thing = thingClassModule:new(10, 15)
self.Thing2 = thingClassModule:new(30, 70)
end
return testClass
the thing class module:
-- ThingModule
thing = {}
function thing:new(a, b)
local obj = {}
setmetatable(obj, self)
self.__index = self
self.A = a or 0
self.B = b or 0
return obj
end
return thing
The issue is that Thing gets overriden by Thing2.
I believe your problem is not assigning self to the metatable of the object instead it's being assigned to the module instead, therefore it's overwriting the data instead of creating a new object.
Here's a working example of what you're trying to achieve:
-- Thing Class
local Thing = {}
Thing.__index = Thing
function Thing.new(a, b)
local self = {}
setmetatable(self, Thing)
self.A = a
self.B = b
return self
end
return Thing
local Thing = require(script.Parent.Thing)
local TestClass = {}
TestClass.__index = TestClass
function TestClass.new()
local self = {}
setmetatable(self, TestClass)
self.Thing = Thing.new(10, 15)
self.Thing2 = Thing.new(30, 70)
return self
end
return TestClass
You can learn more about Object-oriented through this great article:
https://devforum.roblox.com/t/all-about-object-oriented-programming/8585
In a method, self is whatever comes before the colon in the method call. In thing.new, you create a new table called obj, but you then assign A and B within self, which is the thing table (or thingClassModule; they're both the same table). In testClass.new, you set the metatable of a new table, but you don't store it to a variable. You then go on to modify self, which is testClass.

How can I store layer information within a Layer table [duplicate]

I need a table variable in a Lua class, which is unique for each instance of the class.
In the example listed below the variable self.element seems to be a static variable, that is used by all class instances.
How do I have to change the testClass to get a non static self.element table variable?
Example:
local testClass ={dataSize=0, elementSize=0, element = {} }
function testClass:new (data)
local o = {}
setmetatable(o, self)
self.__index = self
-- table to store the parts of the element
self.element = {}
-- data
self.element[1] = data
-- elementDataSize
self.elementSize = #data
return o
end
function testClass:getSize()
return self.elementSize
end
function testClass:addElement(data)
-- add data to element
self.element[#self.element+1] = data
self.elementSize = self.elementSize + #data
end
function testClass:printElement(element)
-- print elements data
element = element or self.element
local content = ""
for i=1, #element do
content = content .." " .. tostring(element[i])
end
print("Elements: " .. content)
end
function printAll(element)
print("Size: " .. tostring(element:getSize()))
element:printElement()
end
test = testClass:new("E1")
printAll(test)
test:addElement("a")
printAll(test)
test2 = testClass:new("E2")
printAll(test2)
test2:addElement("cde")
printAll(test2)
print("............")
printAll(test)
This implementation returns:
$lua main.lua
Size: 2
Elements: E1
Size: 3
Elements: E1 a
Size: 2
Elements: E2
Size: 5
Elements: E2 cde
............
Size: 3
Elements: E2 cde
For the last output I need
Size: 3
Elements: E1 a
In testClass:new() self refers to testClass.
local test = testClass:new()
test.element will refer to testClass.element
Your instance is o, so when you want each instance to have its own element replace self.element = {} with o.element = {}
You are making a common mistake in your :new function.
You assign self.element but this should be o.element. self in this function refers to the testClass table not to the object you are creating. To make element unique to each object you need to assign it to o, the object being created.
function testClass:new (data)
local o = {}
setmetatable(o, self)
self.__index = self
-- table to store the parts of the element
o.element = {}
-- data
o.element[1] = data
-- elementDataSize
o.elementSize = #data
return o
end

Lua OOP: Problems with tables

There some problems with my OOP.
I have parent with clear table and child with same table.
When i'm trying to add object to table of child, object adds to parent's table.
Simple example:
Account = {}
Account.__index = Account
Account.kit = {}
function Account.create(balance)
local acnt = {} -- our new object
setmetatable(acnt,Account) -- make Account handle lookup
acnt.balance = balance -- initialize our object
return acnt
end
function Account:withdraw(amount)
self.balance = self.balance - amount
end
-- create and use an Account
acc = Account.create(1000)
acc:withdraw(100)
table.insert(acc.kit, "1")
print(#Account.kit)
print(#acc.kit)
Result is 1 and 1.
But must be 0 and 1.
How i can isolate child table from parent?
In Lua using acc.kit where acc is a table with the metatable Account will first search the key kit from the table acc and then from table Account.
In your code acc does not have anything with key kit, so the Account.kit will be accessed.
You can solve this simply by defining the kit table for the acc on creation
Account = {}
Account.__index = Account
Account.kit = {} -- You can now remove this if you do not use it - I preserved it to make the test prints to still work.
function Account.create(balance)
local acnt = {} -- our new object
setmetatable(acnt,Account) -- make Account handle lookup
acnt.balance = balance -- initialize our object
acnt.kit = {} -- define kit to be a subtable
return acnt
end
Example:
https://repl.it/B6P1
I'd recommend using closures to implement OOP:
local Animal = {}
function Animal.new(name)
local self = {}
self.name = name
function self.PrintName()
print("My name is " .. self.name)
end
return self
end
--now a class dog that will inherit from animal
local Dog = {}
function Dog.new(name)
-- to inherit from Animal, we create an instance of it
local self = Animal.new(name)
function self.Bark()
print(self.name .. " barked!")
end
return self
end
local fred = Dog.new("Fred")
fred.Bark()
fred.PrintName()
output:
Fred barked!
My name is Fred

Getting a 'nil' value when attaching an addEventListener method to a created Object

I just started getting my feet wet with Corona and trying to work with OOP. This is just a simple Match Making Game to help me along with thinking like OOP. I have 2 classes, one class will be creating an instances of a Card (i will be making multiple objects of this type of Card Class) and the other is the MatchCardsManager Class - this creates the cards and applies the properties
The error I am getting is, after i have created the object "MatchCard" i tried to apply an "addEventListener" to the object. but when i do i receive an error of the following
Support/Outlaw/Sandbox/5/MatchCardsManager.lua:53:
attempt to call method 'addEventListener' (a nil value)
stack traceback:
If i comment out the info on addEventListener, all objects are displayed accordingly to the constructor i created in MatchCard Class.
Below are my files - the error i am getting is in the MatchCardsManager class
mCard[i] = MatchCardsManager:displayPlacementCard(i, temp, x, y)
mCard[i]:addEventListener("touch", myTouch)
Any help or suggestions about fixing this or better approach would be greatly appreciated. Thank you.
The MatchCard Class will be just a simple constructor for now as this is not my issue
-- MatchCard Class
-- Meta Data
local sceneGroup = sceneGroup
local MatchCard = { }
local MatchCard_mt = { __index = MatchCard } -- metatable
------------------------------------------------
-- PRIVATE FUNCTION
------------------------------------------------
------------------------------------------------
-- PUBLIC FUNCTION
------------------------------------------------
-- constructor
function MatchCard.new (id, animal, state, imageId, x, y)
local newMCard = display.newRoundedRect( x, y, 59, 47, 5)
newMCard.strokeWidth = 3
newMCard:setFillColor( 0.5 )
newMCard:setStrokeColor( 1, 0, 0 )
newMCard.properties = {
id = id or nil,
animal = animal or nil,
state = state or 0,
imageId = imageId,
}
return setmetatable ( newMCard, MatchCard_mt )
end
MatchCardsManager Class is there I plan to create an many instances of cards
-- require files
local MatchCard = require('MatchCard') --MatchCard
local sceneGroup = sceneGroup
local MatchCardsManager = {} -- originally we should use a displayGroup
-- TODO: insert group into scene
local animalPicsReference = { "dog", "dog", "cat", "cat", "pig", "pig" , "fish", "fish"}
-- manager class properties
MatchCardsManager.totalCards = 8
MatchCardsManager.totalPairs = 4
MatchCardsManager.pairsFound = 0
MatchCardsManager.firstCardSelected = 0
MatchCardsManager.secondCardSelected = 0
-- lets create 6 MatchCardFiles
function MatchCardsManager:create()
local animalPics = animalPicsReference
local x = 108 - 85
local y = 125
print("do we go here never works")
local mCard = {}
for i=1, 4
do
x = x + 85
num = math.random(1, #animalPics)
temp = animalPics[num]
table.remove(animalPics, num)
mCard[i] = MatchCardsManager:displayPlacementCard(i, temp, x, y)
mCard[i]:addEventListener("touch", myTouch)
end
x = 108 - 85
y = 195
for j = 5, 8 do
x = x + 85
num = math.random(1, #animalPics)
temp = animalPics[num]
table.remove(animalPics, num)
mCard[j] = MatchCardsManager:displayPlacementCard(j, temp, x, y)
print(type(mCard[j]))
mCard[j]:addEventListener("touch", myTouch)
end
--mCards:addEventListener("touch", myTouch)
return mCard
end
local function myTouch( event )
if event.phase == "began" then
print( "You touched the object! "..event.target.imageId)
end
end
function MatchCardsManager:displayPlacementCard(idx, animal, x, y)
-- randomly place the cards in the object id
local card = MatchCard.new(idx, animal, 0, animal, x, y)
--card:show(x,y) -- displays card and that is it
print("animal added is "..card.properties.imageId)
return card
end
return MatchCardsManager
The problem is in the constructor.
local newMCard = display.newRoundedRect(...)
creates a display object, but the line:
return setmetatable(newMCard, MatchCard_mt)
overwrites the metatable that the display object had and so it no longer has access to display's __index metamethod that is used to find addEventListener.
To fix this, you need to look into how inheritance is added in Lua.
See Inheritance Tutorial so you can inherit addEventListener. The solution will be something like: setmetatable(MatchCard, {__index=ShapeObject}) or =display.ShapeObject}---I can't be sure how Corona implements its classes.

Can't inherit table attribute from parent

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?
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.
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.
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