How to increment by one when key is pressed? - lua

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

Related

Lua says that these variables are numbers but I can't use them to make a circle in Love2d

edit: terrible mistake, just forgot to provide radius lol. Thanks for helping :)
I am so confused by this happening. I'm fairly certain all parts of my code work but for some reason, the x and y co-ordinates are not being printed by Love2D, despite showing them on screen and using type() to show that they're numbers.
function love.load()
window = {}
window.x, window.y = love.graphics.getDimensions()
enemies = {}
end
function newenemy()
x = math.random(0, window.x)
y = math.random(0, window.y)
table.insert(enemies, {x = x, y = y, speed = 5})
end
function love.update(dt)
newenemy()
for i=#enemies, 1, -1 do
local angle = math.atan((love.mouse.getY()-enemies[i]['y'])/(love.mouse.getX()-enemies[i]['x']))
if love.mouse.getX() < enemies[i]['x'] then angle = angle + math.pi end
enemies[i]['x'] = enemies[i]['x'] + math.cos(angle)*enemies[i]['speed']
enemies[i]['y'] = enemies[i]['y'] + math.sin(angle)*enemies[i]['speed']
end
end
function love.draw()
for i=1, #enemies do
love.graphics.print('('..enemies[i]['x']..','..enemies[i]['y']..')')
love.graphics.circle('fill', enemies[i]['x'], enemies[i]['y'])
end
end
To show the actual numbers, I've been commenting out the line to draw the circle and watching the numbers change as I move my cursor across the screen. I truly don't know what is going on. This code is from a much larger (~400 lines) script that I'm writing for and I thought there was some error with the variables but it still seems tp occur in 30 lines of code.
Error
main.lua:27: bad argument #4 to 'circle' (number expected, got no value)
Traceback
[C]: in function 'circle'
main.lua:27: in function 'draw'
[C]: in function 'xpcall'
Note the error
main.lua:27: bad argument #4
speaks of the fourth argument, wherein you are only providing three.
The fourth argument to love.graphics.circle is the radius of the circle.
love.graphics.circle('fill', enemies[i]['x'], enemies[i]['y'], 10)

Calling a lua function at random time intervals in love2d

So basically I want to call a function in lua at random time intervals in love2d. Iam clueless of how to do this so any help is appreciated.
local t = math.random(MIN, MAX);
function love.update(dt)
t = t - dt
if t <= 0 then
FUNCTION()
t = math.random(MIN, MAX);
end
end
try:
function love.load()
Time = math.random(1, (max number here))
end
function love.update(dt)
Time = Time - dt
if Time < 0 then
-- magic
Time = math.random(1, (max number here))
end
end

Lua Love2d Write Code Instance Once, Use Multiple Times With Each One Being Unique

I have asked a question similar to this, but i was asking it for Processing.JS. Now i am making something out of LOVE2D Lua, what I'm trying to do is that i have a button where when clicked it adds a circle on-screen. I already have code that when i click and hold on the circle, i can move it around. But when i add a second circle, they both are using he same variables. I want it so i write once instance of the code to move and add the circle, but i can call it multiple times and each one be unique without writing code to anticipate an infinite amount of circles. Here is my code:
obn = 0
ellipsex = 50
ellipsey = 50
ellipsew = 50
ellipseh = 50
ellipser = 255
ellipseg = 0
ellipseb = 0
function love.draw()
mousex, mousey = love.mouse.getPosition()
for i=0,obn,1 do
ellipse()
end
end
function love.mousereleased(x, y, button)
if button == 2 then
obn = obn + 1
end
end
function love.update(dt)
if love.mouse.isDown(1) then
if mousex > ellipsex and mousex < ellipsex + ellipsew and mousey > ellipsey and mousey < ellipsey + ellipseh then
ellipsex = mousex
ellipsey = mousey
end
end
end
function ellipse()
love.graphics.setColor(ellipser, ellipseg, ellipseb)
love.graphics.ellipse("fill", ellipsex, ellipsey, ellipsew, ellipseh)
end
But when i right-click to add a circle(increment how many times the for-loop runs) it doesnt add a second circle for me to move independent from the first one. Help?
The way I would go about handling multiple instances of ellipses is creating a table for every ellipse that would hold it's properties and a draw function.
local ellipses = {} -- store all ellipses into a table
function create_ellipse(x,y,w,h,r,g,b)
local ellipse = {
x = x,
y = y,
w = w,
h = h,
r = r,
g = g,
b = b
}
function ellipse.draw()
love.graphics.setColor(ellipse.r,ellipse.g,ellipse.b)
love.graphics.ellipse("fill",ellipse.x,ellipse.y,ellipse.w,ellipse.h)
end
ellipses[#ellipses+1] = ellipse -- insert new ellipse into ellipses table
return ellipse
end
function love.draw()
for i = 1,#ellipses do
ellipses[i].draw(); -- call each ellipse's separate draw function
end
end
function love.mousereleased(x,y,button)
if button == 2 then
create_ellipse(x,y,50,50,255,0,0) -- bonus: every ellipse is created where the user clicked
end
end
function love.update(dt)
if love.mouse.isDown(1) then
local mousex,mousey = love.mouse.getPosition() -- there is no need to request the mouse position every frame, but only when a user clicks anywhere on the screen
for i = 1,#ellipses do
local current_ellipse = ellipses[i]
if mousex >= current_ellipse.x and mousex <= current_ellipse.x+current_ellipse.w and mousey >= current_ellipse.y and mousey <= current_ellipse.y+current_ellipse.h then
current_ellipse.x = mousex
current_ellipse.y = mousey
end
end
end
end
You could even make your own Ellipse class if you're into OOP.

Display an image & hide it according to a variable

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 !

lua - table maintenance (particle system related)

The update() function below gets called on every frame of a game. If the Drop particle has y value greater than 160 I want to remove it from the table. The problem is that I get "attempt to compare number with nil" errors, on the line notated below:
local particles = {};
function update()
local num = math.random(1,10);
if(num < 4) then
local drop = Drop.new()
table.insert ( particles, drop );
end
for i,val in ipairs(particles) do
if(val.y > 160) then --ERROR attempt to compare number with nil
val:removeSelf(); --removeSelf() is Corona function that removes the display object from the screen
val = nil;
end
end
end
What am I doing wrong? Obviously val is nil, but I don't understand why the table iteration would find val in the first place since I set it to nil when it's y value gets larger than 160.
Thanks for the answers, they were all helpful. Here is what ended up working for me. The table.remove call is necessary to keep the loop running properly.
for i = #particles, 1, -1 do
if particles[i].y > 160 then
local child = table.remove(particles, i)
if child ~= nil then
display.remove(child)
child = nil
end
end
end
You're looking in the wrong place, the problem isn't that val is nil, it's val.y that's nil. See this example:
> x=nil
> if x.y > 10 then print("test") end
stdin:1: attempt to index global 'x' (a nil value)
stack traceback:
stdin:1: in main chunk
[C]: ?
> x={y=nil}
> if x.y > 10 then print("test") end
stdin:1: attempt to compare number with nil
stack traceback:
stdin:1: in main chunk
[C]: ?
Also, when you set val to nil, that may not be doing anything (I believe val is a copy):
> t={"a", "b", "c", "d"}
> for i,val in ipairs(t) do print(i, val) end
1 a
2 b
3 c
4 d
> for i,val in ipairs(t) do if i==3 then print("delete", val); val=nil end end
delete c
> for i,val in ipairs(t) do print(i, val) end
1 a
2 b
3 c
4 d
Edit: to delete an element from a table, you want table.remove:
> t[3]=nil
> for i,val in ipairs(t) do print(i, val) end
1 a
2 b
> t[3]="c"
> for i,val in ipairs(t) do print(i, val) end
1 a
2 b
3 c
4 d
> for i,val in ipairs(t) do if i==3 then print("delete", val); table.remove(t, i) end end
delete c
> for i,val in ipairs(t) do print(i, val) end
1 a
2 b
3 d
JeffK's solution should work, but I think the reason it will work is not because of the fact that he's traversing the list backwards, but because he is setting particles[i] = nil instead of val = nil. If you run val = nil you're only setting the local copy of val to nil, not the entry in the table.
Try this:
for i,val in ipairs(particles) do
if(val.y > 160) then
particles[i]:removeSelf()
particles[i] = nil;
end
end
I don't think you are allowed to modify the contents of a table while ipairs is iterating through it. I vaguely remember reading that my hardcopy of the Lua 5.1 Reference Manual, but I can't seem to locate it now. When you set val to nil, it removes an element from the particles table.
You might try processing the table in reverse, since your function is doing a full sweep of the particles table, conditionally removing some items:
for x = #particles, 1, -1 do
if particles[x].y > 160 then
particles[x]:removeSelf()
particles[x] = nil
end
end

Resources