Corona SDK display.remove() in lua - lua

this code (lua) gives you a random value from the table "local a" by pressing the text "new". Unfortunately the new random value just appears above the old one. I've tried to remove the old value e.g. with display.remove(mmDis), but it doesn't work.
The second problem is that sometimes I also get back the value "nil" and not only the four entries from the table.
Both things must be easy to solve, but as newbie to lua and working on these small things for almost 4 hours now I just don't get what to change to make it work.
-- references
local mmDis
-- functions
function randomText(event)
display.remove(mmDis)
local a = {"Banana!","Apple!","Potato","Pie"}
com = (a[math.random(0.5,#a)])
local mmDis = display.newText(tostring(com),
display.contentWidth*0.57, display.contentHeight*0.7,
display.contentWidth*0.9, display.contentHeight*0.8, "Calibri", 60)
end
-- menu button
local textnew = display.newText("New", 0, 0, "Calibri", 40)
textnew.x = display.contentWidth*0.2
textnew.y = display.contentHeight*0.9
textnew:addEventListener ("tap", randomText )

It's hard to understand what you are trying to do because when you create textnew you have it in one position and size, while in randomeText() you seem to want to replace that text object with a new one, but you put it at a different pos and size. It appears you want to change the object's text every time you press on tap; in this case, you don't need to replace the text object, you just replace its text.
Also:
you have two "local mmDis", the second one will hide the first, not sure what you're after there
read carefully the docs for math.random
com is already a string so you don't need tostring
Try this code and let me know if this is not what you are after:
local menuTextOptions = {
text = "New",
x = display.contentWidth*0.2,
y = display.contentHeight*0.9,
align = 'left',
font = "Calibri",
fontSize = 40,
}
local textnew = display.newText(menuTextOptions)
-- functions
function randomText(event)
local a = {"Banana!","Apple!","Potato","Pie"}
local com = a[math.random(1,#a)]
textnew.text = com
-- if you want to change position too:
-- textnew.x = display.contentWidth*0.2
-- textnew.y = display.contentHeight*0.9
-- if you want to change size too, but only used for multiline text:
-- textnew.width = display.contentWidth*0.9
-- textnew.height = display.contentHeight*0.8
end
textnew:addEventListener ("tap", randomText )
Sometimes it looks like the button doesn't do anything when you tap but that's because the random number happens to be same as previous, you could put a loop to guard against that. Ig you actually want to change the pos and/or width, then the above code makes it clear where you should do that.

So, that's the basic code (without any extras at the moment :)) how it should be. Big thanks to Scholli!:
local menuTextOptions = {
text = "New",
x = display.contentWidth*0.2,
y = display.contentHeight*0.9,
align = 'left',
font = "Calibri",
fontSize = 40,
}
local textnew = display.newText(menuTextOptions)
local replacement = display.newText(menuTextOptions)
replacement.y = display.contentHeight*0.5
-- functions
function randomText(event)
local a = {"Banana!","Apple!","Potato","Pie"}
local com = a[math.random(1,#a)]
replacement.text = com
end
textnew:addEventListener ("tap", randomText )

Related

Why this lua function is modifying tables it shouldn't?

I have this function in my code to load and setup sizes for sprites.
function aux.Sprite:setTexture(renderer,imgPath)
... -- Not important for this question
img = loadImage(renderer,imgPath)
self.texture = img.texture
self.rect.w = img.w
self.rect.h = img.h
end
(loadImage here is the function implemented in C, and is returning the correct values)
Using it should be easy enough
bg = aux.Sprite:new()
bg:setTexture(R, "testfiles/bg.png")
ship = aux.Sprite:new()
ship:setTexture(R, "testfiles/testship.png")
The problem is that after the second call for setTexture the values for the FIRST sprite is changed!
for example
bg = aux.Sprite:new()
bg:setTexture(R, "testfiles/bg.png")
print(bg.rect.w)
ship = aux.Sprite:new()
ship:setTexture(R, "testfiles/testship.png")
print(bg.rect.w)
should return
1920 1920
because I'm printing the width for bg twice
but I'm getting
1920
300
That is, the second setTexture changes the value for "bg" and not only for "ship".
My guess is that self.rect.w = img.w is setting a "pointer", or whatever is called in lua, to img.w and when I use the function later this pointer is updated in all references?
What I'm doing wrong here? Is this the correct lua behavior?
PS: The definition of the Sprite:new function as asked
function aux.Sprite:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
There is nothing in the provided code that actually creates the rect (or aux.Sprite for that matter). I guess this means that is done via something like
aux.Sprite = { rect = {} }
This is a problem because it means all your sprites share the same rect.
aux.Sprite:new() returns a new empty table that has the metatable and its __index set to Sprite. Thus when in setTexture self.rect is searched in this empty table the one from Sprite is returned via __index.
You need to make sure every sprite has its own unique rect.
I don't really know what is the typical Lua object pattern here, but you can eg. have self.rect = { w = img.w, h = img.h } in setTexture or maybe o.rect = {} in new - something that actually sets rect to a new table for this particular sprite.

How to create textbox in love2d

I have been trying to make a box for a user to input data once the user clicks the box. This is what I have so far, but clicking the box does not cause text input to be added to it. Where is the issue?
function love.load ()
txt1 = ""
columnx = { 50, 160, 260, 375, 495, 600, 710 }
columny = { 130, 230, 330, 440, 540, 640 }
if show1 == true then
function love.textinput(t)
txt1 = t
end
end
end
function love.mousepressed (x, y)
if
x >= columnx[4] and
x <= 435 and
y >= columny[1] and
y >= 145 then
show1 = true
end
end
function love.draw ()
love.graphics.print(txt1, columnx[4], columny[1])
end
You're pretty much on the way, but I'll give you some tips on how to create a basic textbox.
Firstly, consider a conceptual textbox to be a singular table, that contains everything it needs to know about itself to properly update and render. It's much easier to reason about something that is self contained.
A textbox needs to know its position, its size, whether it is active, and which text it contains. We can condense that into a table that looks like the following.
local textbox = {
x = 40,
y = 40,
width = 400,
height = 200,
text = '',
active = false,
colors = {
background = { 255, 255, 255, 255 },
text = { 40, 40, 40, 255 }
}
}
(We also store some color info.)
After that the simple way to add text is through love.textinput, as you've seen. In your code we only check if the textbox is active once, in love.load, which it of course isn't since we likely haven't taken any user input yet. Instead of attempting to overload the function, we simply check if the textbox is active or not inside the handler, and proceed accordingly.
function love.textinput (text)
if textbox.active then
textbox.text = textbox.text .. text
end
end
We've covered how to check if the user has clicked within a rectangular area in the question: Love2d cursor positions. We want to deactivate the textbox if it is currently active and the user clicks outside of its space.
function love.mousepressed (x, y)
if
x >= textbox.x and
x <= textbox.x + textbox.width and
y >= textbox.y and
y <= textbox.y + textbox.height
then
textbox.active = true
elseif textbox.active then
textbox.active = false
end
end
And finally we need to render our textbox. We use unpack to expand our color tables, and love.graphics.printf to make sure our text wraps within our textbox's space.
function love.draw ()
love.graphics.setColor(unpack(textbox.colors.background))
love.graphics.rectangle('fill',
textbox.x, textbox.y,
textbox.width, textbox.height)
love.graphics.setColor(unpack(textbox.colors.text))
love.graphics.printf(textbox.text,
textbox.x, textbox.y,
textbox.width, 'left')
end
These are the basic ideas of creating a very rough textbox. It's not perfect. Note that you will need to consider what happens when the text gets longer height-wise than we initially set our textbox's height to, as the two are only loosely related.
To make your program easier to read, and easier to extend, everything you've seen above should really be placed into their own functions that handle textbox tables, instead of cluttering the love handlers with common code. Take a look at Chapter 16 of Programming in Lua, which covers Object-Oriented Programming - a generally vital topic for game development.
See the love.textinput page on how to handle a backspace, to delete characters.
Some extra things to think about:
How can we distinguish an active textbox from an inactive one?
How can we create a list of textboxes, so we can have multiple on screen (but only one active)?
I guess, the love.textinput() callback function is what you are looking for. But as the term 'callback' implies, it will be called by the LÖVE engine, not your code. It will be called whenever the user inputs some text while your game is running. Therefore you need to put it outside the love.load() function.
In the love2d.org wiki is an example for this (the lower one).
As for your example, move the love.textinput() out of love.load() and add an if statement:
function love.load()
txt1 = ""
columnx = {50, 160, 260, 375, 495, 600, 710}
columny = {130, 230, 330, 440, 540, 640}
end
function love.textinput(t)
if (show1) then
txt1 = txt1 .. t
end
end
-- The rest of your code.
-- And maybe mix it with the 'backspace example' from the wiki...
-- But you also might want to have some function to set 'show1' back to 'false' after the text input. Maybe something like this:
function love.keypressed(key)
if (key == "return") and (show1) then
show1 = false
end
end
I hope I could help you a bit!

How to hide native.newTextField after clicking submit?

I'm trying trying to have users name fade in one letter at a time vertically. Example: Adam "A" would appear after 1 second , "d" would appear after 3 seconds under the displayed A, "a" would appear after 5 seconds under the displayed d, "m" would appear after 7 seconds under the displayed a. The visuals would have a sort of domino effect.When they appear they would stay displayed on screen.
When if I comment out userNameField:removeSelf () then the code works fine. I get the effect I want, but the problem is that I still have the userNamefield showing.
Please let me know if you need to see more code.
local greeting = display.newText( "Greetings, enter your name",0,0,native.systemFont, 20 )
greeting.x = display.contentWidth/2
greeting.y = 100
local submitButton = display.newImage( "submit.png" ,display.contentWidth/2, display.contentHeight - 50 )
local userNameField = native.newTextField( display.contentWidth * 0.5 , 150, 250, 45)
userNameField.inputtype = "defualt"
local incrementor = 0
function showNameLetters()
userNameField:removeSelf( )
if incrementor <= string.len ("userNameField.text") then
incrementor = incrementor + 1
personLetters = string.sub (userNameField.text, incrementor,incrementor)
display_personLetters = display.newText (personLetters, 290,30*incrementor, native.systemFont, 30)
display_personLetters.alpha = 0
transition.to(display_personLetters,{time = 3000, alpha = 1, onComplete = showNameLetters})
end
end
Update:
I've found a solution to my problem, by adding userNameField.isVisible = false in my function.
I've also found something very weird, and wish to have someone explain why this happens. If I add greeting:removeSelf() and submitButton:removeSelf() (I've commented them out in my code below to show you where I put them for testing). I get weird result of only the first letter fading in. If i set greeting.isVisible = false and submitButton.isVisible = false. The code works fine.
I'm so confused why object:removeSelf() wouldn't work. Can someone please clear this up for me.
That is, if I replace the following line:
userNameField:removeSelf( )
with:
userNameField.isVisible = false
then the app works fine. Please suggest me why/ any solution for the question. THanks in advance...
It seems like you're calling the showNameLetters multiple times, this means that you're removing the native text field more than once. Nil it and check for nil before removing it like this:
if userNameField ~= nil then
userNameField:removeSelf()
userNameField = nil
end
It shows that you are using data from userNameField after removing it (in the line below):
personLetters = string.sub (userNameField.text, incrementor,incrementor)
As well as you are calling object:removeSelf() again and again without checking its existance (as mentioned by hades2510). So before removing userNameField, check for it's existance:
if userNameField ~= nil then
userNameField:removeSelf()
userNameField = nil
end
And you won't get userNameField.text while userNameField is nil. So use a temporary variable to hold the previous userNameField.text and get the saved data from that variable when needed.
Extra note: Are you sure, you have to check the length of the text "userNameField.text" in the following line, or the variable userNameField.text? If you have to use the data from the text field, then this will also matter.
if incrementor <= string.len ("userNameField.text") then
........
end
Keep coding....................... :)

Attempt to index global 'player' (a nil value)

I'm getting a (a nil value) error when i try to do this :
player = display.newSprite( imageSheet, "sequenceDataPlayer"..math.random(1, 7) )
Looking at a test print :
print ("sequenceDataPlayer"..math.random(1, 7) )
It prints the data oky 'sequenceDataPlayer1'
What Im i doing wrong here ?
Your print statement is just printing the string "sequenceDataPlayer" concatenated with a random number between 1 and 7.
It took me a little while to figure out how to use sprites in Corona, but here's how I do it. I'll use Player for the variables since that's what you're using.
First I create an options variable to get the frames from my Player.lua file:
optionsPlayer =
{
frames = require("player").frames,
}
Then I create a variable for the image sheet:
playerSheet = graphics.newImageSheet( "player.png", optionsPlayer )
After that, I create a variable to set up the name, the sequence of frames, the time it takes to play, and set how many times it will loop:
spriteOptionsPlayer = { name="Player", start=1, count=10, time=500, loopCount = 1}
Finally, I create the new sprite:
spriteInstancePlayer = display.newSprite( playerSheet, spriteOptionsPlayer )
Once I've done all this, I usually set up the x and y positions, xScale and yScale, and other properties along with adding it to a display group.
Last of all, then I play the sprite somewhere:
spriteInstancePlayer:play()
From what it looks like, you want to have 7 different sprites to choose from. Personally, I would just create seven different sprites using all of the steps above and then put them in a table.
sprites = { spriteInstancePlayer, spriteInstancePlayer2, spriteInstancePlayer3, etc.. }
Then when I wanted to play them, I would set the position and visibility and just do:
r = math,random(1, 7)
sprites[r].x = x position
sprites[r].y = y position
sprites[r].isVisible = true
sprites[r]:play()
Of course, then I would want to set listeners to either completely remove the sprite or set the visibility to false when it's done playing, there's a collision(you'd have to add a physics body and set that all up), or whatever else might happen...
There are probably simpler ways to do it, but that's what I do.
Hope this helps.

Character Selection in Corona SDK

I make an endless run game using Corona SDK and I need to make a character selection between 2 characters (boy/girl). I don't have any idea how I should start.
I tried to make 2 portraits of the character on the menu screen, but I don't know what to do on Event Touch on them. I tried to save them in a variable but I don't know how to load them in the game.lua. There I have:
local spriteSheet = sprite.newSpriteSheet("monsterSpriteSheet.png", 100, 100)
local monsterSet = sprite.newSpriteSet(spriteSheet, 1, 7)
sprite.add(monsterSet, "running", 1, 6, 600, 0)
sprite.add(monsterSet, "jumping", 7, 7, 1, 1)
local monster = sprite.newSprite(monsterSet)
monster:prepare("running")
monster:play()
monster.x = 60
monster.y = 200
monster.gravity = -6
monster.accel = 0
monster.isAlive = true
I've got a main.lua a menu.lua and a game.lua. I use director class for transition. Any ideas on how I can do this?
You can pass parameters through storyboard.gotoScene
local options = {
effect = "crossFade",
time = 500,
params = {
character = myCharacter,
}
}
storyboard.gotoScene( "game", options )
and in the game.lua
function scene:createScene( event )
local params = event.params
local character = params.character
end
You could also create a data file and point to that file.
For example:
data.lua
local data = {}
return data
Then in your selection scene require data.lua and save your chosen character to it.
data.chosenCharacter = chosenCharater
Then in your game scene require data.lua again and point your character to what is saved in data.
local character = data.chosenCharacter

Resources