Display an image & hide it according to a variable - lua

I would like to display an image, in a specific area, according to a variable. For example, when the user click on an avatar, it shows an specific image. Once he clicks on other avatar, other image will be displayed.
I've tried to remove the previous image, and display new one, but it said "attempt to call removeself() with a nil value".
Define table in the start :
local item_bigsize = {}
So i tried this :
item[i] = display.newImageRect("items/"..items['pos'..i..'_name']..".png", 80 , 80)
item[i].x = holder_2[i].x+10
item[i].anchorX=0
item[i].y=holder_2[i].y
itemGroup:insert (item[i])
item[i].destination=i
item[i]:addEventListener( "touch", onSwitchPress )
and the function onSwitchPress() works like this :
function onSwitchPress( event )
i=event.target.destination
if (event.phase=="began") then
title_item.text=""
desc_item.text=""
for n=1,3 do
if n~=i then
item_bigsize[n]:removeSelf( )
end
n=n+1
end
elseif (event.phase == "ended") then
item_bigsize[i] = display.newImageRect("items/"..items['pos'..i..'_name']..".png", 240 , 240)
item_bigsize[i].x = 950
item_bigsize[i].anchorX=0
item_bigsize[i].y=display.contentCenterY-130
group:insert (item_bigsize[i])
title_item.text=items['pos'..i..'_title']
desc_item.text=items['pos'..i..'_details']
end
end

Instead of:
if n~=i then
item_bigsize[n]:removeSelf( )
end
Try:
if(n~=i and item_bigsize[n].x~=nil)then --Check whether the object/properties exists
item_bigsize[n]:removeSelf()
end
Keep Coding................ :)

for n=1,3 do
if n~=i then
item_bigsize[n]:removeSelf( )
end
n=n+1
end
First of all why do you increment the value of n manually, the for loop will automatically increments n by 1.So you don't increment it.
So what happens here first time i = 1 and n = 1 the condition fails it will not remove.
second time n increments by and you are manually increments n by 1, so it will become three the condition satisfies because i will 2 be and will enters the loop, it will try to remove the image item_bigsize[3]:removeSelf( )which is not present.
I think this could be the possible error, so remove the n = n+1.
for n=1,3 do
if n~=i then
item_bigsize[n]:removeSelf( )
end
end

You don't have
item_bigsize[i]
Because "i" is not an integer which you want to iterate in "for".

Finally, i've choose to hide/show items as #albert said in previous comment (more simple). I also choose to work with DataBase SQLite3, instead of files because it's faster.
Here is the solution :
function ShowItems( event )
local count = 1
local sql = "SELECT * FROM items WHERE active='oui'"
n=1
number=0
for x in db:urows "select count(*) from items" do
for row in db:nrows(sql) do
item[count] = display.newImageRect("items/"..row.src..".png", 80 , 80)
if n <= 7 then
item[count].x = holder[n].x+10
item[count].y=holder[n].y
elseif n >= 8 and n<15 then
item[count].x = holder_2[n].x+10
item[count].y=holder_2[n].y
elseif n >=15 and n<=21 then
item[count].x = holder_3[n].x+10
item[count].y=holder_3[n].y
end
item[count].anchorX=0
itemGroup:insert (item[count])
item[count].destination=row.id
item[count]:addEventListener( "touch", onSwitchPress )
n=n+1
item_bigsize[count] = display.newImageRect("items/"..row.src..".png", 240 , 240)
item_bigsize[count].x = 950
item_bigsize[count].anchorX=0
item_bigsize[count].y=display.contentCenterY-130
bigimages:insert (item_bigsize[count])
item_bigsize[count].isVisible=false
count = count + 1
end
end
end
and my function to show the "big" size images is :
function onSwitchPress( event )
i=event.target.destination
if (event.phase=="began") then
number = n-1
number_equip = a-1
title_item.text=""
desc_item.text=""
item_bigsize[i].isVisible=true
if n <= 7 then
holder[i].alpha=1
elseif n >= 8 and n<15 then
holder_2[i].alpha=1
elseif n >=15 and n<=21 then
holder_3[i].alpha=1
end
for increment=1,number do
if increment~=i then
if item_bigsize[increment]~= nil then
item_bigsize[increment].isVisible=false
if n <= 7 then
holder[increment].alpha=0.5
elseif n >= 8 and n<15 then
holder_2[increment].alpha=0.5
elseif n >=15 and n<=21 then
holder_3[increment].alpha=0.5
end
--print( increment )
end
end
end
elseif (event.phase == "ended") then
result = "SELECT name,desc FROM items WHERE id ="..i..""
for col1,col2 in db:urows( result ) do
title_item.text=col1
desc_item.text=col2
end
end
end
This solution works very well for me !

Related

How do I keep the renderBlocks() function from going into an infinite loop?

-- This is Minecraft, but 2D, and in Lua.
-- **************************************
-- ID 0: Air
-- ID 1: Stone
-- ID 2 Logs
-- ID 3: Leaves
-- ID 4: Planks
-- ID 5: Crafting Table
-- ID 6: Furnance
-- ID 7: Player position detector block
-- **************************************
blockTable = { -- Stores all the blocks
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6}
}
tableRow = 1 -- Y value for block render pointer
tableColumn = 1 -- X value for block render pointer
runOnce = true -- Run a loop once
tickNum = 0 -- Number of ticks since startup
function renderBlock(X, Y, K) -- Render a block
if K == 1 then -- if blockID == 1, draw a grey square
screen.setColor(100,100,100)
print(X, Y)
screen.drawRectF(X, Y, 8, 8)
end
if K == 6 then -- If the blockID == draw a grey square
screen.setColor(100,100,100)
screen.drawRectF(X, Y, 8, 8)
end
end
function renderBlocks() -- Render all the blocks (Scans though the blockTable in a raster pattern)
while runOnce == true -- Run this code once
do
while #blockTable >= tableRow
do
while #blockTable[tableRow] >= tableColumn
do
print("TC " .. tableColumn)
tableColumn = tableColumn + 1
blockID = blockTable[tableRow][tableColumn]
renderBlock(tableRow, tableColumn, blockID)
if tableColumn > #blockTable[tableRow] then tableColumn = 1 end
end
runOnce = false
end
print("TR " .. tableRow)
tableRow = tableRow + 1
end
end
function onTick()
print("Tick! Tick count: " .. tickNum) -- Print the current tick, as well as say that there has been a tick
tickNum = tickNum + 1
end
function onDraw()
while runOnce == true -- Run this code once
do
renderBlocks()
runOnce = false
end
end
Here's my code in the IDE for the framework: Link
I have no clue why this is happening, I'm at a loss here.
When doing loops over tables it is far better to use for loops than while or repeat loops, that are far more difficult to understand and bugfix.
Use for index,value in ipairs(yourtable) do if you want to get the indices (number in the table) and the values associated or for key,value in pairs(yourtable) do if you want to get the keys (generally strings that is used as key for a value: yourTable["key"] = 0) and the values associated with it.
for row,innerTable in ipairs(blockTable) do
for col,value in ipairs(innerTable) do
print("TC " .. col)
blockID = value
renderBlock(row, col, blockID)
end
end
The last should do it inside your renderBlocks function. But that:
while runOnce == true do
-- Doing something
runOnce = false
end
Is not very nice stuff. If it shall only be called once, do not put it into a loop!
Also it would help to have a little better code identation to understand what is happening faster. And add some Space between blocks of code that handle different concerns.
Edit: So your function could look like this:
function renderBlocks()
if runOnce then
runOnce = false
for row,innerTable in ipairs(blockTable) do
for col,value in ipairs(innerTable) do
blockID = value
renderBlock(row, col, blockID)
end
end
end
end
There are a couple issues in your renderBlocks() function
function renderBlocks()
while runOnce == true do
while #blockTable >= tableRow do
while #blockTable[tableRow] >= tableColumn do
print("TC " .. tableColumn)
tableColumn = tableColumn + 1
blockID = blockTable[tableRow][tableColumn]
renderBlock(tableRow, tableColumn, blockID)
if tableColumn > #blockTable[tableRow] then
tableColumn = 1
end
end
runOnce = false
end
print("TR " .. tableRow)
tableRow = tableRow + 1
end
end
First we can look at the inner most loop. Here we have a problem with the contrition used to evaluate the loop and how it is incremented.
while #blockTable[tableRow] >= tableColumn do
print("TC " .. tableColumn)
tableColumn = tableColumn + 1 -- incremented here
blockID = blockTable[tableRow][tableColumn]
renderBlock(tableRow, tableColumn, blockID)
if tableColumn > #blockTable[tableRow] then
tableColumn = 1 -- reset here
end
end
in the loop body you do tableColumn = tableColumn + 1 and later in the same body you do if tableColumn > #blockTable[tableRow] then tableColumn = 1 end so this is a problem when tableColumn is increased to a value that would end the loop we reset it to 1 preventing the loop from ever ending.
Now lets look at the next loop up. Here we never increment tableRow it is incremented just after the end of this loop so it is not possible for the loop to end.
while #blockTable >= tableRow do
while #blockTable[tableRow] >= tableColumn do
...
end
runOnce = false
end
I believe you intended
print("TR " .. tableRow)
tableRow = tableRow + 1
to occur within this loop not outside of it.
You're missing a few block definitions here. Don't think that's what's sending it into an infinite loop, but you might not see results, otherwise.
function renderBlock(X, Y, blockID) -- Render a block
if blockID == 0 then -- Air
-- screen.setColor(10, 20, 220, 0) -- is there an alpha channel?
screen.setColor(10, 20, 220)
elseif blockID == 1 then -- Stone
screen.setColor(100, 100, 100)
elseif blockID == 2 then -- Logs
screen.setColor(200, 50, 50)
elseif blockID == 3 then -- Leaves
screen.setColor(20, 220, 40)
elseif blockID == 4 then -- Planks
screen.setColor(180, 30, 10)
elseif blockID == 5 then -- Craft Table
screen.setColor(180, 30, 10)
elseif blockID == 6 then -- Furnace
screen.setColor(100, 100, 100)
elseif blockID == 7 then -- Player detect
screen.setColor(220, 30, 30)
end
print(X, Y)
screen.drawRectF(X, Y, 8, 8)
end
It's easy to use for loops. set initial condition, then the final, completed condition, and let it run the course.
function renderBlocks() -- Render all blocks (Scans though blockTable in a raster pattern)
for row = 1, #blockTable do
for col = 1, #blockTable[row] do
print("TC " ..col)
local blockID = blockTable[row][col]
renderBlock(row, col, blockID)
end
print("TR " ..row)
end
end
You likely don't need that runOnce. If you find you do for something else, go ahead, but it shouldn't be needed with a nested for loop.
function onDraw()
renderBlocks()
end

Minimum Change Maker Returning Optimal Solution and No Solution

I need Help adding a if clause to my Change Maker, so that if say I have denominations of coins that can't equal the input coin value. For Example I have Coins worth 2,4,6 and I have a Value of 1. I Want it to return Change Not Possible I tried adding a clause to it below but when I test it I get 1.#INF
I also am curious how I can find the optimal coin solution, So on top of saying the minimum number of coins it returns the optimal coin setup if there is one.
function ChangeMaking(D,n)
--[[
//Applies dynamic programming to find the minimum number of coins
//of denominations d1< d2 < . . . < dm where d1 = 1 that add up to a
//given amount n
//Input: Positive integer n and array D[1..m] of increasing positive
// integers indicating the coin denominations where D[1]= 1
//Output: The minimum number of coins that add up to n
]]
F = {} -- F is List Array of Coins
m = tablelength(D)
F[0] = 0
for i =1,n do
temp = math.huge
j = 1
while j <= m and i >= D[j] do
temp = math.min(F[ i - D[j] ], temp)
j = j + 1
end
F[i] = temp + 1
end
--I wanted to Catch the failed Solution here but I return 1.#INF instead
--if F[n] <= 0 and F[n] == 1.#INF then print("No Change Possible") return end
return F[n]
end
function main()
--[[
//Prints a Greeting, Asks for Denominations separated by spaces.
// Iterates through the input and assigns values to table
// Table is then input into ChangeMaker, and a while loop takes an n value for user input.
// User Enters 0 to end the Loop
]]
io.write("Hello Welcome the to Change Maker - LUA Edition\nEnter a series of change denominations, separated by spaces: ")
input = io.read()
deno = {}
for num in input:gmatch("%d+") do table.insert(deno,tonumber(num)) end
local i = 1
while i ~= 0 do
io.write("Please Enter Total for Change Maker, When Finished Enter 0 to Exit: ")
input2 = io.read("*n")
if input2 ~= 0 then io.write("\nMinimum # of Coins: " .. ChangeMaking(deno,input2).."\n") end
if input2 == 0 then i=0 print("0 Entered, Exiting Change Maker") end
end
end
function tablelength(T)
--[[
//Function for grabbing the total length of a table.
]]
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
main()

Lua #Table returning 0, despite Table containing 3 elements (tables)? [duplicate]

Sounds like a "let me google it for you" question, but somehow I can't find an answer. The Lua # operator only counts entries with integer keys, and so does table.getn:
tbl = {}
tbl["test"] = 47
tbl[1] = 48
print(#tbl, table.getn(tbl)) -- prints "1 1"
count = 0
for _ in pairs(tbl) do count = count + 1 end
print(count) -- prints "2"
How do I get the number of all entries without counting them?
You already have the solution in the question -- the only way is to iterate the whole table with pairs(..).
function tablelength(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
Also, notice that the "#" operator's definition is a bit more complicated than that. Let me illustrate that by taking this table:
t = {1,2,3}
t[5] = 1
t[9] = 1
According to the manual, any of 3, 5 and 9 are valid results for #t. The only sane way to use it is with arrays of one contiguous part without nil values.
You can set up a meta-table to track the number of entries, this may be faster than iteration if this information is a needed frequently.
The easiest way that I know of to get the number of entries in a table is with '#'. #tableName gets the number of entries as long as they are numbered:
tbl={
[1]
[2]
[3]
[4]
[5]
}
print(#tbl)--prints the highest number in the table: 5
Sadly, if they are not numbered, it won't work.
There's one way, but it might be disappointing: use an additional variable (or one of the table's field) for storing the count, and increase it every time you make an insertion.
count = 0
tbl = {}
tbl["test"] = 47
count = count + 1
tbl[1] = 48
count = count + 1
print(count) -- prints "2"
There's no other way, the # operator will only work on array-like tables with consecutive keys.
function GetTableLng(tbl)
local getN = 0
for n in pairs(tbl) do
getN = getN + 1
end
return getN
end
You're right. There are no other way to get length of table
You could use penlight library. This has a function size which gives the actual size of the table.
It has implemented many of the function that we may need while programming and missing in Lua.
Here is the sample for using it.
> tablex = require "pl.tablex"
> a = {}
> a[2] = 2
> a[3] = 3
> a['blah'] = 24
> #a
0
> tablex.size(a)
3
local function CountedTable(x)
assert(type(x) == 'table', 'bad parameter #1: must be table')
local new_t = {}
local mt = {}
-- `all` will represent the number of both
local all = 0
for k, v in pairs(x) do
all = all + 1
end
mt.__newindex = function(t, k, v)
if v == nil then
if rawget(x, k) ~= nil then
all = all - 1
end
else
if rawget(x, k) == nil then
all = all + 1
end
end
rawset(x, k, v)
end
mt.__index = function(t, k)
if k == 'totalCount' then return all
else return rawget(x, k) end
end
return setmetatable(new_t, mt)
end
local bar = CountedTable { x = 23, y = 43, z = 334, [true] = true }
assert(bar.totalCount == 4)
assert(bar.x == 23)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = 24
bar.x = 25
assert(bar.x == 25)
assert(bar.totalCount == 4)
I stumbled upon this thread and want to post another option. I'm using Luad generated from a block controller, but it essentially works by checking values in the table, then incrementing which value is being checked by 1. Eventually, the table will run out, and the value at that index will be Nil.
So subtract 1 from the index that returned a nil, and that's the size of the table.
I have a global Variable for TableSize that is set to the result of this count.
function Check_Table_Size()
local Count = 1
local CurrentVal = (CueNames[tonumber(Count)])
local repeating = true
print(Count)
while repeating == true do
if CurrentVal ~= nil then
Count = Count + 1
CurrentVal = CueNames[tonumber(Count)]
else
repeating = false
TableSize = Count - 1
end
end
print(TableSize)
end
seems when the elements of the table is added by insert method, getn will return correctly. Otherwise, we have to count all elements
mytable = {}
element1 = {version = 1.1}
element2 = {version = 1.2}
table.insert(mytable, element1)
table.insert(mytable, element2)
print(table.getn(mytable))
It will print 2 correctly

Table value doesn't change

I have a 2 dim array and all it's cells filled with zeros.
What i'm trying to do is to take some randomly chosen cells and fill it with 4 or 5
but what i get is either empty gird with all value equal to zero or i get just one value that has changed to 4 or 5 and that's my code below:
local grid = {}
for i=1,10 do
grid[i] = {}
for j=1,10 do
grid[i][j] = 0
end
end
local empty={}
for i=1,10 do
for j=1,10 do
if grid[i][j]==0 then
table.insert(empty,i ..'-'.. j)
end
end
end
local fp=math.floor(table.maxn(empty)/3)
local fx,fy
for i=1,fp do
math.randomseed(os.time())
math.random(0,1)
local fo=math.random(0,1)
math.random(table.maxn(empty))
local temp= empty[math.random(table.maxn(empty))]
local dashindex=string.find(temp,'-')
fx=tonumber(string.sub(temp,1,dashindex-1))
fy=tonumber(string.sub(temp,dashindex+1,string.len(temp)))
if fo==0 then
grid[fx][fy]=4
elseif fo==1 then
grid[fx][fy]=5
end
end
for i=1,10 do
for j=1,10 do
print(grid[i][j])
end
print('\n')
end
I'm not sure what the for i=1,fp loop is doing with temp and fo, for example the seed should only be set once, and also, the return value on line after local fo is ignored, seems very messy. But based on your post, if you really just want to randomly select N cells from your 2D array and set those to either 4 or 5 (randomly), this should work:
-- maybe N = fp
local N = 5
math.randomseed(os.time())
local i = 1
repeat
fx = math.random(1, 10)
fy = math.random(1, 10)
if grid[fx][fy] == 0 then
grid[fx][fy] = math.random(4,5)
i = i + 1
end
until i > N
Note however that the closer N is to number of items in array (100 in your example), the longer it will take for the loop to complete. If this is a concern, then for large N values, you could do the opposite: initialize each cell to 4 or 5 randomly, and then randomly set size - N of them to 0.
math.randomseed(os.time())
local rows = 10
local columns = 10
local grid = {}
if N > rows*columns/2 then
for i=1,rows do
grid[i] = {}
for j=1,columns do
grid[i][j] = math.random(4,5)
end
end
local i = 1
repeat
fx = math.random(1, 10)
fy = math.random(1, 10)
if grid[fx][fy] ~= 0 then
grid[fx][fy] = 0
i = i + 1
end
until i > N
else
for i=1,rows do
grid[i] = {}
for j=1,columns do
grid[i][j] = 0
end
end
local i = 1
repeat
fx = math.random(1, 10)
fy = math.random(1, 10)
if grid[fx][fy] == 0 then
grid[fx][fy] = math.random(4,5)
i = i + 1
end
until i > N
end

How to get number of entries in a Lua table?

Sounds like a "let me google it for you" question, but somehow I can't find an answer. The Lua # operator only counts entries with integer keys, and so does table.getn:
tbl = {}
tbl["test"] = 47
tbl[1] = 48
print(#tbl, table.getn(tbl)) -- prints "1 1"
count = 0
for _ in pairs(tbl) do count = count + 1 end
print(count) -- prints "2"
How do I get the number of all entries without counting them?
You already have the solution in the question -- the only way is to iterate the whole table with pairs(..).
function tablelength(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
Also, notice that the "#" operator's definition is a bit more complicated than that. Let me illustrate that by taking this table:
t = {1,2,3}
t[5] = 1
t[9] = 1
According to the manual, any of 3, 5 and 9 are valid results for #t. The only sane way to use it is with arrays of one contiguous part without nil values.
You can set up a meta-table to track the number of entries, this may be faster than iteration if this information is a needed frequently.
The easiest way that I know of to get the number of entries in a table is with '#'. #tableName gets the number of entries as long as they are numbered:
tbl={
[1]
[2]
[3]
[4]
[5]
}
print(#tbl)--prints the highest number in the table: 5
Sadly, if they are not numbered, it won't work.
There's one way, but it might be disappointing: use an additional variable (or one of the table's field) for storing the count, and increase it every time you make an insertion.
count = 0
tbl = {}
tbl["test"] = 47
count = count + 1
tbl[1] = 48
count = count + 1
print(count) -- prints "2"
There's no other way, the # operator will only work on array-like tables with consecutive keys.
function GetTableLng(tbl)
local getN = 0
for n in pairs(tbl) do
getN = getN + 1
end
return getN
end
You're right. There are no other way to get length of table
You could use penlight library. This has a function size which gives the actual size of the table.
It has implemented many of the function that we may need while programming and missing in Lua.
Here is the sample for using it.
> tablex = require "pl.tablex"
> a = {}
> a[2] = 2
> a[3] = 3
> a['blah'] = 24
> #a
0
> tablex.size(a)
3
local function CountedTable(x)
assert(type(x) == 'table', 'bad parameter #1: must be table')
local new_t = {}
local mt = {}
-- `all` will represent the number of both
local all = 0
for k, v in pairs(x) do
all = all + 1
end
mt.__newindex = function(t, k, v)
if v == nil then
if rawget(x, k) ~= nil then
all = all - 1
end
else
if rawget(x, k) == nil then
all = all + 1
end
end
rawset(x, k, v)
end
mt.__index = function(t, k)
if k == 'totalCount' then return all
else return rawget(x, k) end
end
return setmetatable(new_t, mt)
end
local bar = CountedTable { x = 23, y = 43, z = 334, [true] = true }
assert(bar.totalCount == 4)
assert(bar.x == 23)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = 24
bar.x = 25
assert(bar.x == 25)
assert(bar.totalCount == 4)
I stumbled upon this thread and want to post another option. I'm using Luad generated from a block controller, but it essentially works by checking values in the table, then incrementing which value is being checked by 1. Eventually, the table will run out, and the value at that index will be Nil.
So subtract 1 from the index that returned a nil, and that's the size of the table.
I have a global Variable for TableSize that is set to the result of this count.
function Check_Table_Size()
local Count = 1
local CurrentVal = (CueNames[tonumber(Count)])
local repeating = true
print(Count)
while repeating == true do
if CurrentVal ~= nil then
Count = Count + 1
CurrentVal = CueNames[tonumber(Count)]
else
repeating = false
TableSize = Count - 1
end
end
print(TableSize)
end
seems when the elements of the table is added by insert method, getn will return correctly. Otherwise, we have to count all elements
mytable = {}
element1 = {version = 1.1}
element2 = {version = 1.2}
table.insert(mytable, element1)
table.insert(mytable, element2)
print(table.getn(mytable))
It will print 2 correctly

Resources