I am attempting to create a list of items using the TableView widget in Corona. I followed their online examples and created the TableView. It appears on the screen and is scrollable, but no event is fired when I click a row, even though I set a listener for OnRowTouch.
local options_for_list_view = {
id = "list_view",
top = 0,
left = 0,
width = display.contentWidth,
height = display.contentHeight,
hideBackground = true,
hideScrollBar = true,
listener = on_table_touch,
onRowRender = onRowRender,
onRowTouch = on_row_touch, -- registering listener
}
list_view = widget.newTableView(options_for_list_view)
for key, value in pairs(trophy_list) do
local params =
{
name = key
}
list_view:insertRow
{
isCategory = false,
rowHeight = total_height * 0.1,
rowColor = rowColor,
lineColor = { 0, 0, 0 },
params = params
}
end
Here is the listener:
local function on_row_touch( event )
print("error")
end
Does anyone know what the issue could be?
You should define Your on_row_touch( event ) function BEFORE adding it to the options_for_list_view Table.
Objects in Lua are created in the same order as listed in sources. So, in Your case, You're just putting a nil into the onRowTouch event's listener place. And just after that creating a local function which was supposed to be an event listener :)
Some proper static analysis tool should help getting rid of this kind of errors...
Good luck ;)
Simplified version:
print(foo())
function foo()
return "some_value..."
end
Output:
lua: ./call_test.lua:1: attempt to call global 'foo' (a nil value)
Related
Thanks to this great community, I managed to make a save system for my game! However, it is kind of long and painful to write. I need help on how to (if possible) make this a little bit shorter and easier.
So, this is what I got (this example uses ONLY 1 variable to get the idea):
GameState = loadsave.loadTable("GameState.json")
if GameState == nil then
GameState = {
TotalPixoosGS = 0,
}
loadsave.saveTable(GameState, "GameState.json")
end
TotalPixoos = GameState.TotalPixoosGS
Let me quickly explain what I got here: GameState = loadsave.loadTable("GameState.json") is declaration of a table from .json file. I used .loadTable function which I got from here:
https://code.coronalabs.com/code/easy-saveload-table-data-corona-sdk
if GameState == nil then
GameState = {
TotalPixoosGS = 0,
}
If the file doesn't exist, it simply creates default game settings, in this case sets TotalPixoosGS variable to value of 0.
loadsave.saveTable(GameState, "GameState.json")
Again a function from the link above which simply creates .json file from GameState table, calls it GameState.json.
TotalPixoos = GameState.TotalPixoosGS
Finally, assigns the value of GameState.TotalPixoosGS to our variable TotalPixoos (if GameState.json doesn't exist, it will assign the value of 0). So far, pretty straight-forward, right?
Now, this code was called upon OPENING the application.
The following code is what I use upon EXITING application:
if ( event.type == "applicationExit" ) then
GameState = {
TotalPixoosGS = TotalPixoos,
}
loadsave.saveTable(GameState, "GameState.json")
end
Basically, what this does is: When the app is about to exit, you simply change the value of TotalPixoosGS to our current value of TotalPixoos (that is the variable which changes over time). Finally, we save the GameState table with the new, changed TotalPixoosGS.
Once the app launches again, the process will repeat.
Now, what is the problem? Well, when you have 1 variable, like in this case, it looks simple. However, when you gotta manage over 50 variables, it can be a pain to write. Is there any way I could shorten this?
Anyway, this is just a small chunk of code, to get the idea:
GameState = loadsave.loadTable("GameState.json")
if GameState == nil then
GameState = {
TotalPixoosGS = 0,
PixoosQuantityGS = 0,
PixoosPerSecondGS = 0,
BottlesQuantityGS = 0,
MaxBottlesFoundGS = 0,
BottlesPriceGS = 0.005,
WillFindBottlesChanceGS = 10,
CanFindBottlesGS = 0,
MaxClickableGS = 5,
MaxTrashCanValueGS = 5,
}
loadsave.saveTable(GameState, "GameState.json")
end
TotalPixoos = GameState.TotalPixoosGS
PixoosQuantity = GameState.PixoosQuantityGS
PixoosPerSecond = GameState.PixoosPerSecondGS
BottlesQuantity = GameState.BottlesQuantityGS
MaxBottlesFound = GameState.MaxBottlesFoundGS
BottlesPrice = GameState.BottlesPriceGS
WillFindBottlesChance = GameState.WillFindBottlesChanceGS
CanFindBottles = GameState.CanFindBottlesGS
MaxClickable = GameState.MaxClickableGS
MaxTrashCanValue = GameState.MaxTrashCanValueGS
See how much of ugly code there is? And this is upon exit:
if ( event.type == "applicationExit" ) then
GameState = {
TotalPixoosGS = TotalPixoos,
PixoosQuantityGS = PixoosQuantity,
PixoosPerSecondGS = PixoosPerSecond,
BottlesQuantityGS = BottlesQuantity,
MaxBottlesFoundGS = MaxBottlesFound,
BottlesPriceGS = BottlesPrice,
WillFindBottlesChanceGS = WillFindBottlesChance,
CanFindBottlesGS = CanFindBottles,
MaxClickableGS = MaxClickable,
MaxTrashCanValueGS = MaxTrashCanValue,
}
loadsave.saveTable(GameState, "GameState.json")
end
Anyone with a better way, or idea on how to deal with this?
The problem here is that you are storing the data in independent global variables that you need to store in the table to save and then fetch from the table to load.
You can avoid needing to do all of that if you just use the table itself as the global variable in your general code.
So instead of writing code that uses TotalPixoosGS or PixoosQuantityGS when checking the values/etc. you write code that uses GameState.TotalPixoosGS and GameState.PixoosQuantityGS instead and then just save and load directly from/to the global GameState table.
I have a search feature in Corona SDK that displays results from my website. The first run works perfect but the second search results lay over top the old results.
txt_mybest get repeated and inserted in to a scroll view. I can figure out how to remove the previous results.
If I remove the scroll group it becomes unusable
local function sumbitConnented( event )
if ( event.isError ) then
local alert = native.showAlert( "Connection Error", "Your information was not sent.
Please check your connection" , { "OK" }, onComplete )
else
nyHeight = 35
local t_ninja = json.decode( event.response )
for key in pairs(t_ninja) do
local xxteam_name = t_ninja[key]["team_name"]
nyHeight = nyHeight + 60
txt_mybest = display.newText("Team: "..xxteam_name,0,0,native.systemFont,13)
txt_mybest.anchorX = 0
txt_mybest.x = 85
txt_mybest.y = 38 +nyHeight
txt_mybest:setTextColor( 20/255, 20/255, 20/255 )
scroll:insert(txt_mybest)
end
function onSearchRelease()
sendInfo = {["findTeam"] = findTeam.text}
local headers = {
["Content-Type"] = "application/json",
["Accept-Language"] = "en-US",
}
local params = {}
params.headers = headers
params.body = json.encode( sendInfo )
network.request( "http://www.website.com/team-search.php?f=hw&u_device="..muserID, "POST", sumbitConnented, params )
end
Hopefully "Bohemian" has the mental ability to comprehend this question
you can use txt_mybest.text= "your new text" .. this will change text for your display.newText object as long as the object exsits.
You can add a display group in your scroll view and add all the text in it. When you want to remove the results, simply remove the group and add another one into scroll view. Like that you won't risk destroying your Scroll View and your results would clear off easily.
I have two questions. what I am
trying to do is every time I shoot a enemy/vine it should be
removed and a explosion should occur. the removal works perfect
but the sprite is not called to explode
What's this in the for loop #sections[sectInt]["vines"] ?
Are they parent/ child references? Can someone break this
down to the letter even telling me what the # is?
How can I use my explosion sprite after each vine is destroyed?
I am having a difficult time figuring out how to call every x and y
vine in the for loop to explode when removed.
Code:
local sections = require("sectionData")
local lastSection = 0
function createSection()
--Create a random number. If its eqaul to the last one, random it again.
local sectInt = mR(1,#sections)
if sectInt == lastSection then sectInt = mR(1,#sections) end
lastSection = sectInt
--Get a random section from the sectionData file and then
--Loop through creating everything with the right properties.
local i
-- the random creation of vines throughout the screen
for i=1, #sections[sectInt]["vines"] do
local object = sections[sectInt]["vines"][i]
local vine = display.newImageRect(objectGroup, "images/vine"..object["type"]..".png", object["widthHeight"][1], object["widthHeight"][2])
vine.x = object["position"][1]+(480*object["screen"]); vine.y = object["position"][2]; vine.name = "vine"
local rad = (vine.width*0.5)-8; local height = (vine.height*0.5)-8
local physicsShape = { -rad, -height, rad, -height, rad, height, -rad, height }
physics.addBody( vine, "static", { isSensor = true, shape = physicsShape } )
end
end
-- explosion sprite
options1 =
{
width = 96, height = 96,
numFrames = 16,
sheetContentWidth = 480,
sheetContentHeight = 384
}
playerSheet1 = graphics.newImageSheet( "images/explosion.png", options1)
playerSprite1 = {
{name="explosion", start=1, count=16, time = 400, loopCount = 1 },
}
explode = display.newSprite(playerSheet1, playerSprite1)
explode.anchorX = 0.5
explode.anchorY = 1
--player:setReferencePoint(display.BottomCenterReferencePoint)
-- i want to reference the for loop position if each vine so it plays sprite when they are removed
explode.x = "vine.x" ; explode.y = "vine .y"
explode.name = "explode"
explode.position=1
extraGroup:insert(explode)
1) What's this in the for loop #sections[sectInt]["vines"] ? Are they parent/ child references? Can someone break this down to the letter even telling me what the # is?
As I said in my comment the # is table length.
The loop is looping over each bit of "vine" data in the selected segment data (whatever that means exactly in terms of the game) and then creates the objects for those vines.
When it's time to make your vine explode, you play the sprite. If you want to explode every vine, you would have something like:
sheetOptions =
{
width = 96, height = 96,
numFrames = 16,
sheetContentWidth = 480,
sheetContentHeight = 384
}
playerSheet = graphics.newImageSheet( "images/explosion.png", sheetOptions)
spriteSequence = {
{name="explosion", start=1, count=16, time = 400, loopCount = 1 },
}
for i, vine in ipairs(objectGroup) do
local explode = display.newSprite(playerSheet, spriteSequence)
explode.anchorX = 0.5
explode.anchorY = 1
explode.x = vine.x
explode.y = vine.y
explode.name = "explode"
explode.position=1
explode:play()
extraGroup:insert(explode)
end
Note: not tested, let me know of if any issues you can't resolve.
ok so, this is what i did to get my object to have a explosion, for anybody that is having the same issue.
function isShot( event )
print('shot!!!')
if (event.other.class == "enemy") then
if (event.other.name == "limitLine") then
event.target:doRemove() --remove bullet if hits the limitLine
elseif (event.other.name == "vine") then
event.other:doRemove()
spriteExplode(event.other.x, event.other.y) -- this function calls itself & runs the sprite
if event.other.name == "vine" then
if event.other.name == "explode" then
event.other:doRemove() --this removes the explosion sprite
end
end
end
-- remove the bullet & explosion sprite
timer.performWithDelay( 5000, function(event) explode:doRemove(); end, 1 )
event.target:doRemove()
end
return true
end
function spriteExplode( x, y)
explode.isVisible = true
explode:play()
print("play explode")
if (x and y) then -- this is the code that keeps my sprite updating upon removal of vine
explode.x, explode.y = x, y
end
function explode:doRemove(event)
timer.performWithDelay(
1,
function(event)
display.remove(self)
self= nil
end,
1 )
end
end
i added the isShot function eventListener inside of the Bullet function
bullet:addEventListener("collision", isShot) & a bullet:doRemove function is inside the bullet function as well.
hope this helps.
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
I have the following code :
{
identifier = "hand:" .. card.name,
area = { x, y, 100, 100 },
on_click = function()
-- Code goes here
end
}
I want to use the card variable and a reference to the object where this code is placed to modify a variable of the class with a value of the card variable.
So, how can I give parameters from the local context to the function who will be called in other pieces of code ?
I wish to launch the on_click function in an event management loop.
If I understand the question correctly, you want to be able to reference from on_click handler the object that on_click handler belongs to. To do this, you need to split the statement you have:
local card = { name = "my card" }
local object = {
identifier = "hand:" .. card.name,
area = { x, y, 100, 100 },
}
object.on_click = function()
-- Code goes here
-- you can reference card and object here (they are upvalues in this context)
print(card.name, object.area[3])
end
object.click()
You can also define on_click a bit differently; in this case you get object as implicitly declared self variable (note that you call it a bit differently too):
function object:on_click()
-- Code goes here
-- you can reference card and object here
print(card.name, self.area[3])
end
object:click() -- this is the same as object.click(object)
save it when you assign the function, like this
{
identifier = "hand:" .. card.name,
area = { x, y, 100, 100 },
on_click = function()
local a_card = card
print(a_card.name)
end
}