"quit" read as nil field? - lua

I am making a menu file for my game, and it's can't call "quit" as a field. It always returns nil. Can anyone tell me why this is happening? Note, it is declared earlier in the code and the other button function does work. Thanks!
function love.mousepressed( x, y, button )
if button == "l" then
for k, v in pairs(buttons) do
local ins = insideBox( x, y, v.x - (v.w/2), v.y - (v.h/2), v.w, v.h)
if ins then
if v.action == "play" then
loadState("game")
end
end
if ins then
if v.action == "quit" then
love.event.quit()
end
end
end
end
end

Why would you have play and quit bound to the same button? o.O
Also, there's no need to check ins twice. Duplicate code should be a red flag:
if ins then
if v.action == "play" then
loadState("game")
end
end
if ins then
if v.action == "quit" then
love.event.quit()
end
end
That could be:
if ins then
if v.action == "play" then
loadState("game")
elseif v.action == "quit" then
love.event.quit()
end
end
But short of using a debugger, here's how you track down such problems:
1. Create a file called conf.lua in your project folder.
2. Have at least this much inside it, to attach a console to your app:
function love.conf(t)
t.console = true -- Attach a console (Windows only)
end
3. Add debugging output to your mousepressed function so you can see what's going on.
First define this somewhere early in your app execution. Handy printing function:
function printf(...) print(string.format(...)) end
Then add some debugging stuff to your function:
function love.mousepressed(x, y, button)
print('mouse button %d pressed at %d, %d', button, x, y)
if button == "l" then
printf('checking %d buttons', #buttons)
for k, v in pairs(buttons) do
local ins = insideBox( x, y, v.x - (v.w/2), v.y - (v.h/2), v.w, v.h)
printf('%d, %d is%sinside button %s (%d, %d, %d, %d)',
ins and ' ' or ' not ', k, x, y, v.x, v.y, v.w, v.h)
if ins then
print('executing action', v.action)
if v.action == "play" then
loadState("game")
elseif v.action == "quit" then
love.event.quit()
end
end
end
end
end
You should also used meaningful variables names. v can be button. What is k? An index? Then perhaps i or index. Is it a name? Then name. So on and so forth. k tells us nothing.

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

Having problems with TIC-80

heyo! i'm trying to do a simple TIC-80 (basically lüa) script, but i'm getting an error.
error started appearing after i added the lastfaced() function. honestly idk what i did wrong.
here's the code:
--width and height vars
w=240
h=136
-- Last faced var
lf='r'
--Player X and Y, W, H, ID vars
p = {
id=0,
x=w/2,
y=h/2,
w=16,
h=16,
draw = function()
spr(p.id, p.x, p.y, 1, 1)
end
}
--movement function here
function lastfaced()
if btn(2) then
lf='l'
elseif btn(3) then
lf='r'
elseif lf="l" then
p.id=4
elseif lf="r" then
p.id=0
end
end
function TIC()
cls(12)
move()
p.draw()
lastfaced()
end
and here's the error:
[string "..."]:49: 'then' expected near '='
can anyone help?
Ehm, when you want to compare you must use == for it to work, one = will not work...
function lastfaced()
if btn(2) then
lf='l'
elseif btn(3) then
lf='r'
elseif lf="l" then
p.id==4
elseif lf=="r" then
p.id=0
end
end

How i use the same keypress for 2 variables?(LUA)

EXAMPLE: If i press the M6 button, my cursor go to a X place, if i press the M6 button again he goes to a Y place, how can i does this alternation ?
local TOPX, TOPY, MIDX, MIDY
TOPX = 59305 -- Top side X
TOPY = 54527 -- Top side Y
MIDX = 61764 -- Mid lane X
MIDY = 58683 -- Mid lane Y
function OnEvent(event, arg)
for n = 1,2
do
if event == "MOUSE_BUTTON_RELEASED" and arg == 6 then
MoveMouseTo(MIDX, MIDY);
for n = 2,4
do
if
event == "MOUSE_BUTTON_RELEASED" and arg == 6 then
MoveMouseTo(TOPX, TOPY);
end
end
end
end
end
One way to do it would be having an outter flag boolean variable which would allow you to identify the state of the M6 button strokes.
local buttonPressedOnce = true
function onEvent(event, arg)
-- Check if the button is the one we desire.
if (event == "MOUSE_BUTTON_RELEASED" and arg == 6) then
if (buttonPressedOnce) then
-- execute X update code
else
-- execute Y update code
end
buttonPressedOnce = not(buttonPressedOnce)
end
end
Explanation: The first press will always be the X axis update code, so we initialize the flag as true, and with each click call we proceed to update the flag value, making sure each button stroke will switch to the desired state.

How to increment by one when key is pressed?

Using love2d, I can not increment a variable by one when something happens.
For example, when the space bar is pressed I would like x to increment by only one, and not change again until the space bar is pressed again. Currently, while the space bar is down it keeps adding one at a very quick speed, and continues until I release the space bar.
Here is an example of the code as it is now.
function love.load()
x = 0
end
function love.update(dt)
if love.keyboard.isDown(" ") then
x = x +1
end
end
function love.draw()
love.graphics.print("space pressed for "..x.." times.",100,100)
end
You can achieve better results using the love.keypressed event handler.
function love.load ()
x = 0
end
function love.keypressed (key)
if key == ' ' then
x = x + 1
end
end
function love.draw ()
love.graphics.print ("space pressed for "..x.." times.", 100, 100)
end
If you have repeated keys on, via love.keyboard.setKeyRepeat:
love.keyboard.setKeyRepeat (true)
function love.load ()
x = 0
end
function love.keypressed (key, rep)
if key == ' ' and not rep then
x = x + 1
end
end
function love.draw ()
love.graphics.print ("space pressed for "..x.." times.", 100, 100)
end

(Lua) Condition statements not behaving as expected

My math teacher has an extra credit halloween problem that goes like this:
each letter represents a digit 2-9, and you need the following problem to work:
trick + or = treat
I decided I want to find ALL possible solutions to the problem (To impress him) so I decide to write a computer program that would tell me the all the answers. Here is my following code:
local function checkAdd()
local trick =k+(10*c)+(100*i)+(1000*r)+(10000*t) local _or =r+(10*o)
local treat = t+(10*a)+(100*e)+(1000*r)+(10000*t) if trick + _or ==
treat then print(trick) print(" ".._or) print(treat)
print(t) print(r) print(i) print(c) print(k) print(o) print(e) print(a) end --print("end")
timer.performWithDelay(1,newNumbers) end local function
checkNumbers8() if t or r or i or c or k or o or e or a == "9" then
checkAdd() else newNumbers() end end
local function checkNumbers7() if t or r or i or c or k or o or e or
a == "8" then checkNumbers8() else newNumbers() end end
local function checkNumbers6() if t or r or i or c or k or o or e or
a == "7" then checkNumbers7() else newNumbers() end end
local function checkNumbers5() if t or r or i or c or k or o or e or
a == "6" then checkNumbers6() else newNumbers() end end
local function checkNumbers4() if t or r or i or c or k or o or e or
a == "5" then checkNumbers5() else newNumbers() end end
local function checkNumbers3() if t or r or i or c or k or o or e or
a == "4" then checkNumbers4() else newNumbers() end end
local function checkNumbers2() if t or r or i or c or k or o or e or
a == "3" then checkNumbers3() else newNumbers() end end
local function checkNumbers() if t or r or i or c or k or o or e or a
== "2" then checkNumbers2() else newNumbers()
end end
function newNumbers() t = mRandom(2,9) r = mRandom(2,9) i =
mRandom(2,9) c = mRandom(2,9) k = mRandom(2,9) o = mRandom(2,9) e
= mRandom(2,9) a = mRandom(2,9) checkNumbers() end
newNumbers()
*Please note that on in the function checkAdd I call the function timer.performwithdelay ( waits 1 milisecond before calling the function). This is because if I run this code just regularly without the function call, I get a stack overflow error. So i put my code into a framework I use for app developement that had the timer.performwithdelay call, and I implemented that into my code so the computer won't be so overwhelmed and cause an overflow error.
I get the following print statements:
97552
27
97579
9
7
5
5
2
2
5
7
and:
49325
59
49384
4
9
3
2
5
5
3
8
I am getting some letters equaling the same as other letters! and not all numbers 2-9 are used! What is wrong with my code? I test to see if every number 2-9 is used
I think there are two main issues. I don't see the function mRandom, but I assume it returns a number and you are comparing it with a string. Number 2 is not the same as string '2', so 2 == '2' returns false.
The second issue is that (it seems) you are trying to compare if either of variables has a specific value, but you can't do if a or b == 2 then meaning: execute if either a or b equals 2. For that you need to write if a == 2 or b == 2. What you have is evaluated as: if a is evaluated as true (which is when it's not nil or false) or b equals 2.

Resources