reference to parent class in Lua (Corona) - lua

in my game.lua file I have this:
function new()
local obj = display.newGroup();
currentLevel = Level.new(1);
currentLevel.game = obj; //also tried currentLevel.game = self;
function obj:replay()
print("game - replay")
end
return obj;
end
In the Level lua file, I try to call the replay function in game.lua:
game = {};
...
game:replay();
But I get this error:
attempt to call method 'replay' (a nil value)
How can I keep a reference to the game file in level.lua?

Don't you mean game = new(), instead of game = {}? If you create game with {} then it is an empty table.

Related

Lua Class keeping old values

I'm new to Lua so I'm sure I'm missing something but I have this class and it seems to be behaving unexpectedly.
Item = {elm = nil, __index = {}}
function Item:new(obj)
setmetatable({}, Item)
self.elm = obj.elm
return self
end
function Item:collectItem()
print(self.elm);
end
local itm = Item:new{elm = "val1"}
local itm2 = Item:new{elm = "val2"}
itm:collectItem()
itm2:collectItem()
This outputs:
>val2
>val2
When I would expect:
val1
val2
What am I missing here?
The issue here in that your Item:new function keeps modifying the same table: Item (self in the context of Item:new). What you want to do is create a new table for each new Item object you create. Here is one way you can do this:
Item = {elm = nil}
function Item:new(obj)
-- Create a new table whose metatable's __index is the Item table
local instance = setmetatable({}, {
__index = self
})
-- Modify the new table, not Item (self)
instance.elm = obj.elm
-- Return the new object
return instance
end

Lua Scope for Corona SDK

I was wondering How I might be able to access Obj.isActive from an outside function such as "Object:setActive()". I would pull it up to the Object table However i need multiple instances of the isActive property for all the individual Objects. Just trying to figure out a way to do so.
Object
Object = {};
ObjectMeta = {__index = Object};
function Object.new(args)
Obj = {};
Obj.isActive= false;
return setmetatable(Obj,ObjectMeta);
end
function Object:setActive()
--??????????????????????????
--self.isActive = nil
end
return Object;
For metatables, you can use self as follows:
function Object:setActive()
self.isActive = true
end
Here is a SSCCE for your code: http://eval.in/25148

Issues with setting a property

Below is the gist of the system i'm having issues with. I seem to understand self, ., and :. I just seem to be missing something. What's happening is that when it calls "Object:setSomeObjectIsAttachedTo()" if I simply print "self" i'll get a table address printed. If i go a step further and try to print "self.someObject" i get nil, which shouldn't happen because in Object it has a key someObject which was created at the start in "Object.new(args)" of course if tried to go a step further it wouldn't even be able to go there since its nil. Please Help!!
Object File
Object = {};
ObjectMeta = {__index = Object};
function Object.new(args)
Obj = {};
Object.someObject = OtherObject.new(args)
return setmetatable(Obj,ObjectMeta );
end
function Object:setSomeObjectIsAttachedTo()
--OtherObject instance Should set its attached property to
--This instance of Object
self.someObject.ObjectImAttachedTo = self;
end
--Calls after new to set the ObjectImAttachedTo Property, So it isnt nil
Object:setSomeObjectIsAttachedTo();
return Object;
OtherObject File
OtherObject = {};
OtherObjectMeta = {__index = OtherObject};
function OtherObject.new(args)
Obj = {};
Obj.ObjectImAttachedTo =nil;
return setmetatable(Obj,ObjectMeta );
end
return Object;
UPDATE
Scene
Scene = {};
ObjectContainer = {};
function Scene.new()
end
function Scene.addObjects()
local Object= require "Object"
local StartX = 50;
local StartY = 20;
local counter = 0;
for i=0, 17 do
ObjectContainer[i] = Object.new({x=StartX,y=StartY});
end
end
Scene.addObjects();
return Scene
end
The table Object does not have a field named someObject, though instances returned by Object.new() do have that field. These are two different tables, roughly corresponding to a class and one of its instances.
ADDENDUM
With the revised code, Object doesn't have the field someObject until you call Object.new(). So, you must call Object.new() before you call Object:setSomeObjectIsAttachedTo();. Note that OtherObject.new() must be defined before you can call Object.new().
ADDENDUM2 in answer to question "so what would you suggest i do to fix this?"
function Object.new(args)
Obj = {};
Obj.someObject = OtherObject.new(args)
Obj.someObject.ObjectImAttachedTo = Obj;
return setmetatable(Obj,ObjectMeta );
end
and get rid of Object:setSomeObjectIsAttachedTo();

Some insight on Object key accessing in lua

Im just alittle curious, as well as a bit confused. In my lua code im setting a new object like so from the start.
enemy = {};
enemy.__index = enemy;
function enemy.new(args)
Obj = {};
setmetatable(Obj,enemy);
Obj.name = "bullet";
Obj.x = args.x;
Obj.y = args.y;
Obj.spriteTexFile= "Invader.png";
Obj.sprite = display.newImage( Obj.spriteTexFile);
Obj.sprite:setReferencePoint ( display.TopLeftReferencePoint );
Obj.sprite.x = Obj.x;
Obj.sprite.y = Obj.y;
Obj.sprite.alpha = 0;
Obj.health = 100;
Obj.activeBul = false;
Obj.bullet = Bullet.new({x=Obj.sprite.x,y=Obj.sprite.y});
return Obj;
end
...
return enemy;
end
So when instantiating a new Enemy obj I call the new function above. NOW in the same file, a function in the Enemy Object I have the following function for example which allows me to acces the "self.bullet", a Bullet Object created when the Enemy is created. It also allows me to call the function trajectBullet in this Bullet instants.
function enemy:shoot()
local Bullet = require "Bullet";
local DEFAULTTIME = 5;--Movement time per space
self.bullet:trajectBullet({x=self.sprite.x,y=display.contentHeight, time =
DEFAULTTIME*display.contentHeight-self.sprite.y)});
end
My Question comes with a call like the following. If I try setting a property of a Bullet in this case, the owner property, i get a nil error and wont let me change it. If someone could help me understand alittle how accessing keys and properties really works that would help me out alot.
function enemy:setBulletOwner()
self.bullet.owner = self;
end
UPDATE:
bullet = {};
bullet.__index = bullet;
function bullet.new(arg)
local Obj = {};
setmetatable ( Obj, bullet );
Obj.sprite = display.newRect( 0, 0, 3, 7 );
Obj.sprite.x = arg.x;
Obj.sprite.y = arg.y;
Obj.sprite:setFillColor ( 255, 255, 255 );
Obj.sprite:setReferencePoint ( display.TopLeftReferencePoint );
Obj.owner = nil;
return Obj;
end
function bullet:trajectBullet(arg)
self.sprite.tween = transition.to(self.sprite,{ tansistion = easing.outExpo, y = arg.y, x=arg.x,time= arg.time,onComplete = function() bullet:cancelTween(self.sprite);
self.owner.sprite:dispatchEvent( {name = "canShootAgain"} ); end});
end
Keep in mind Obj.owner should be getting set from the function below.
function enemy:setBulletOwner()
print("BULLET MADE");
self.bullet.owner = self;
end
You should have your classes set up like this
Bullet
Bullet = {}
Bullet_mt = { __index = Bullet }
function Bullet:new(co_ordinates)
local obj = {x=co_ordinates[1],y=co_ordinates[2]}
obj.owner = "You" --etc...
return setmetatable(obj,Bullet_mt)
end
Enemy
Enemy = {slogan="Gettm!'"}
Enemy_mt = {__index = Enemy;}
function Enemy:new(args)
local obj = {}
--etc..
obj.bullet = Bullet:new({0,0})
return setmetatable(obj,Enemy_mt)
--alert return setmetatable(obj,getmetatable(self))
end
function Enemy:getBulletOwner()
return self.bullet.owner;
end
You shouldn't be requiring "Bullet" each time the enemy shoots in enemy:shoot. When you want to create a bullet for an enemy if you only want the enemy to have one bullet you should
create a new 'instance' of the bullet class and associate it with the key bullet like you've been doing obj.bullet= Bullet.new(...) but also introduce this functionality into a method of Enemy (so you can add a new bullet after the old one goes out of range etc...).
If a index doesn't exist within a table, it will go looking for the index in the table associated with __index in the metatable assigned to the table in question. As an example say a = Enemy:new(), and we wanted to find out the slogan of the enemy, via a.slogan we would look for the index slogan in a but not find it. So we would then go check what __index was associated with in the metatable of a, in this case Enemy. So we look for slogan in Enemy, it exists so we end up with `"Gettm!'".
Adding the following code beneath the class definitions
en = Enemy:new()
print(en:getBulletOwner())
print(en.slogan)
Produces
You
Gettm!'
Also be weary of the difference between a:b(arg1,arg2) and a.b(arg1,arg2). a:b(arg1,arg2) is essentially equivalent to a.b(a,arg1,arg2) where a is bound to self within the function. An example of this would be:
print(en.getBulletOwner())
produces
lua: l.lua:22: attempt to index local 'self' (a nil value)
while
print(en:getBulletOwner())
produces
You

Issues with eventListeners in Corona SDK, lua

Im having a problem creating a event in my program. when I try running it with the following system setup i get the error "attempt to call method 'addEventListener (a nil value)" The effect im looking for is the OtherObject file sends a signal,the event, to the Object file telling the particular instance it has finished some task in the OtherObject file. Any help or guidance to get me on the right path will be very much appreciated.
Object File
Object = {};
ObjectMeta = {__index = Object};
function Object:onTrigger()
--Event Triggered
end
function Object.new(args)
Obj = {};
Obj.sprite = display.newImage("Picture.png");
Object.someObject = OtherObject.new(args);
Object.someObject.owner = Object;
Object:addEventListener("onTriggered", Obj);
return setmetatable(Obj,ObjectMeta );
end
return Object;
OtherObject File
OtherObject = {};
OtherObjectMeta = {__index = OtherObject};
function OtherObject.new(args)
Obj = {};
Obj.sprite = display.newRect(0,0,3,7);
Obj.ObjectImAttachedTo =nil;
return setmetatable(Obj,OtherObjectMeta );
end
function OtherObject:doSomething()
self.ObjectImAttachedTo:dispatchEvent( {name = "triggered"} );
end
return OtherObject;
local Object = {}
local ObjectMeta = {__index = Object}
function Object:triggered(event)
--Event Triggered
end
function Object.new(args)
local Obj = {}
Obj.someObject = OtherObject.new(args)
Obj.someObject.ObjectImAttachedTo = Obj
setmetatable(Obj, ObjectMeta)
Runtime:addEventListener("triggered", Obj)
return Obj
end
return Object

Resources