I have a bunch of variables like "Upgrades bought", "Amount of money" etc.
I want the most efficient way to save these variables and load them upon starting the game, as you never even exited the game (every single thing stays the same).
So, all the settings and variables stay the same, until you reset the game.
I am asking since I think this is a huge and really important part and I want to begin with the best technique.
What are your suggestions and how can I implement that in my game?
You can store them as table fields and then serialize the table using one of the many options for serializers. See also the Serialization chapter in Programming in Lua.
There are two ways to do fairly easily:
Using a simple text file saved to your DocumentDirectory:
local filePath = system.pathForFile( "data.txt", system.DocumentsDirectory )
local file = io.open( filePath, "r" )
if file then
-- read all contents of file into a string
local contents = file:read( "*a" )
print( "Contents of " .. filePath )
print( contents )
io.close( file )
local t = display.newText( "Contents of ", 5, 80, nil, 16 );
t:setFillColor( 1, 1, 136/255 );
local t = display.newText( filePath, 5, 100, nil, 10 );
t:setFillColor( 1, 1, 136/255 );
local ylast = 130
for line in io.lines(filePath) do
local t = display.newText( line, 15, ylast, nil, 14 );
t:setFillColor( 1, 1, 1 );
ylast = ylast + 20
end
else
print( "Creating file..." )
-- create file b/c it doesn't exist yet
file = io.open( filePath, "w" )
file:write( "Feed me data!\n" )
local numbers = {1,2,3,4,5,6,7,8,9}
file:write( numbers[1], numbers[2], numbers[3], "\n" )
for _,v in ipairs( numbers ) do
file:write( v, " " )
end
file:write( "\nNo more data\n" )
io.close( file )
local t = display.newText( "Created file at:", 5, 80, nil, 16 );
t:setFillColor( 1, 1, 136/255 );
local t = display.newText( filePath, 5, 100, nil, 10 );
t:setFillColor( 1, 1, 136/255 );
local t = display.newText( "Run app again to test file read.", 5, 130, nil, 12 );
t:setFillColor( 1, 1, 136/255 );
-- This removes the file just created
-- os.remove( filePath )
end
2) Using a sqlite file saved to your DocumentDirectory:
--Include sqlite
require "sqlite3"
--Open data.db. If the file doesn't exist it will be created
local path = system.pathForFile("data.db", system.DocumentsDirectory)
db = sqlite3.open( path )
--Handle the applicationExit event to close the db
local function onSystemEvent( event )
if( event.type == "applicationExit" ) then
db:close()
end
end
--Setup the table if it doesn't exist
local tablesetup = [[CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, content, content2);]]
print(tablesetup)
db:exec( tablesetup )
--Add rows with a auto index in 'id'. You don't need to specify a set of values because we're populating all of them
local testvalue = {}
testvalue[1] = 'Hello'
testvalue[2] = 'World'
testvalue[3] = 'Lua'
local tablefill =[[INSERT INTO test VALUES (NULL, ']]..testvalue[1]..[[',']]..testvalue[2]..[['); ]]
local tablefill2 =[[INSERT INTO test VALUES (NULL, ']]..testvalue[2]..[[',']]..testvalue[1]..[['); ]]
local tablefill3 =[[INSERT INTO test VALUES (NULL, ']]..testvalue[1]..[[',']]..testvalue[3]..[['); ]]
db:exec( tablefill )
db:exec( tablefill2 )
db:exec( tablefill3 )
--print the sqlite version to the terminal
print( "version " .. sqlite3.version() )
--print all the table contents
for row in db:nrows("SELECT * FROM test") do
local text = row.content.." "..row.content2
local t = display.newText(text, 20, 120 + (20 * row.id), native.systemFont, 16)
t:setFillColor(1,0,1)
end
You can also use a cloud based which is virtually the same thing with more mobility.
Related
I followed this tutorial in Corona SDK documentation.
I am trying to print all the entries and subtables, and the entries in those subtables from a display object.
In Corona SDK, a display object is a Lua table and so I tried the basic things, as listed in the tutorial.
for k,v in pairs(myTable) do
print( k,v )
end
There is also a fancier function that should output all subtables, namely:
local function printTable( t )
local printTable_cache = {}
local function sub_printTable( t, indent )
if ( printTable_cache[tostring(t)] ) then
print( indent .. "*" .. tostring(t) )
else
printTable_cache[tostring(t)] = true
if ( type( t ) == "table" ) then
for pos,val in pairs( t ) do
if ( type(val) == "table" ) then
print( indent .. "[" .. pos .. "] => " .. tostring( t ).. " {" )
sub_printTable( val, indent .. string.rep( " ", string.len(pos)+8 ) )
print( indent .. string.rep( " ", string.len(pos)+6 ) .. "}" )
elseif ( type(val) == "string" ) then
print( indent .. "[" .. pos .. '] => "' .. val .. '"' )
else
print( indent .. "[" .. pos .. "] => " .. tostring(val) )
end
end
else
print( indent..tostring(t) )
end
end
end
if ( type(t) == "table" ) then
print( tostring(t) .. " {" )
sub_printTable( t, " " )
print( "}" )
else
sub_printTable( t, " " )
end
end
But neither of these actually print out all the entries in these tables. If I create a simple rectangle and try to use either of the functions, I only get two tables but I know that there's more there:
local myRectangle = display.newRect( 0, 0, 120, 40 )
for k,v in pairs(myRectangle) do
print( k,v ) -- prints out "_class table, _proxy userdata"
end
print( myRectangle.x, myRectangle.width ) -- but this prints out "0, 120"
-- But if I were to add something to the table, then the loop finds that as well, e.g.
local myRectangle = display.newRect( 0, 0, 120, 40 )
myRectangle.secret = "hello"
for k,v in pairs(myRectangle) do
print( k,v ) -- prints out "_class table, _proxy userdata, secret hello"
end
So, how can I print out everything included in a display object? Clearly these two approaches don't get the entries in the main display object table.
In general you can't, as you may have a metatable associated with that table that will generate results for fields "on the fly". In this case you get back something like a ShapeObject that provides methods like fill, path, setFillColor and others, but these methods are hidden behind a userdata object. It also provides inheritance, so there are some fields you can query that "belong" to other classes. You can use pairs/ipairs to get the list of keys in the table, which is what you get in your example (and setting secret adds a new key to the table).
Regarding properties (not methods) of display object - display objects in Corona have special property displayObject._properties Documentation
_properties will return string, so you have two approaches of printing it:
local myRectangle = display.newRect( 0, 0, 120, 40 )
-- Approach 1:
-- Prettify here to make better readability to json
local json = require("json")
print("myRectangle._properties: ", json.prettify( myRectangle._properties ) )
-- Approach 2:
local json = require("json")
local myRectangleProps = json.decode(myRectangle._properties) -- I skipped error handling here, because there shouldn't be any
for k,v in pairs(myRectangleProps) do
print( k,v ) -- prints x 0, width 120, etc
end
Lately Ive been trying to make a basic word added. I want to make it so you tap on the text field and then you type what you need then it writes it to a .txt file (precreated or not) Im not great with coding and Im struggling to use the samples/other peoples Stack Exchange question to learn off. All I have is bits of code that dont work together and im not sure what I need to do to make them work (the code isnt mine)
local textBox = native.newTextBox( 200, 200, 280, 140 )
textBox.text = "This is line 1.\nAnd this is line2"
textBox.isEditable = true
local file = io.open( filePath, "r" )
if file then
-- read all contents of file into a string
local contents = file:read( "*a" )
print( "Contents of " .. filePath )
print( contents )
io.close( file ) -- Important to close (python knowledge)
local t = display.newText( "Contents of ", 5, 80, nil, 16 ); -- w, h, ?, size
t:setFillColor( 1, 1, 135/255 ); -- edit
local t = display.newText( filePath, 5, 100, nil, 10 );
t:setFillColor( 1, 1, 135/255 );
local ylast = 130 -- how far down the Y value it can make words on the screen
for line in io.lines(filePath) do
local t = display.newText ( line, 15, ylast, nil, 14); -- dont understand
t:setFillColor( 1, 1, 1 );
ylast = ylast + 20
end
end
local function inputListener( event )
if event.phase == "began" then
-- user begins editing textBox
print( event.text )
elseif event.phase == "ended" then
textBox.text = event.text
local path = system.pathForFile( "myfile.txt", system.DocumentsDirectory )
local file = io.open( path, "w" )
file:write( textBox.text )
io.close( file )
file = nil
elseif event.phase == "editing" then
print( event.newCharacters )
print( event.oldText )
print( event.startPosition )
print( event.text )
end
end
textBox:addEventListener( "userInput", inputListener )
I suggest using the loadsave functions it makes it easier.
You can download these functions from here.
https://github.com/robmiracle/Simple-Table-Load-Save-Functions-for-Corona-SDK
Once downloaded just drop the loadsave.lua file into your main project folder.
Now you can use it like this.
Example:
local loadsave = require("loadsave")
local tableToSave = {}
-- load text into a table
tableToSave ['saved-text'] = textYouWantToSave
-- save text
loadsave.saveTable(tableToSave, "filename.json")
local savedTable = {}
-- load text
savedTable = loadsave.loadTable("filename.json")
-- text is stored here
savedTable['saved-text']
I attempt to get data (in a global variable) from user through a textbox from the user in functions, and use these variables to insert into a sqlite table.
But, when I attempt to do so, I get an error like "attempt to call global locationGlobal (a nil value)" in the INSERT INTO line, after I click the submit button.
NOTE : I input values in the textbox by using Bluestacks android simulator as inputting the text is not possible in windows Corona SDK.
Here is my code :
local widget = require("widget")
require "sqlite3"
local path = system.pathForFile("testUser.db", system.DocumentsDirectory)
db = sqlite3.open( path )
--local location,area,arrivalTime,departTime,eventAttended
local function onSystemEvent( event )
if( event.type == "applicationExit" ) then
db:close()
end
end
--local tablesetup = [[CREATE TABLE IF NOT EXISTS visitPlace (id INTEGER PRIMARY KEY autoincrement, location, area, arrivalTime, departTime, eventAttended);]]
local tablesetup = [[CREATE TABLE place (id INTEGER PRIMARY KEY autoincrement, location);]]
print(tablesetup)
db:exec( tablesetup )
_W = display.viewableContentWidth
_H = display.viewableContentHeight
local background = display.newRect(0,0,_W,_H)
background:setFillColor(0,0,0)
local function textListenerLocation( event )
if ( event.phase == "began" ) then
-- user begins editing defaultField
event.target.text = ''
print(location)
print( event.text )
elseif ( event.phase == "ended" ) then
-- do something with defaultField text
locationGlobal = tostring( event.target.text)
elseif ( event.phase == "editing" ) then
print( event.newCharacters )
print( event.oldText )
print( event.startPosition )
print( event.text )
elseif ( event.phase == "submitted" ) then
locationGlobal =tostring( event.target.text)
--local label = display.newText( location, 180, 30, native.systemFontBold, 20 )
-- label:setFillColor( 190/255, 190/255, 1 )
end
end
local function SubmitEvent( event )
--local label = display.newText( location, 180, 30, native.systemFontBold, 20 )
--label:setFillColor( 190/255, 190/255, 1 )
local insertionTable = [[INSERT INTO visitPlace VALUES(NULL,']]..locationGlobal..[[) ]]
db:exec(insertionTable)
for row in db:nrows("SELECT * FROM visitPlace") do
local text = row.location
local t = display.newText(text, 450, 120*row.id, native.systemFont, 40)
t:setFillColor(1,0,1)
end
local label1 = display.newText( "Submitted", 180, 30, native.systemFontBold, 20 )
label1:setFillColor( 190/255, 190/255, 1 )
end
function background:tap( event )
native.setKeyboardFocus(nil)
end
local locationTxtbox = native.newTextField(180,140,280,100)
locationTxtbox.size = 34
locationTxtbox:addEventListener("textListenerLocation",locationTxtbox)
local submitButton = widget.newButton
{
label = "Submit",
onEvent = SubmitEvent,
shape = "roundedRect",
width = 100,
height = 30,
cornerRadius = 2
}
submitButton.x = display.contentCenterX + (display.contentCenterX/2)
submitButton.Y = display.contentCenterY + (display.contentCenterY/2)
background:addEventListener("tap",background)
Runtime:addEventListener( "system", onSystemEvent )
--defaultField = native.newTextField( 150, 150, 180, 30 )
--defaultField:addEventListener( "userInput", textListener )
currently your textlistenerlocation function is not being called. So when you hit the submit button, locationGlobal has not yet been defined.
The following looks suspicious:
locationTxtbox:addEventListener("textListenerLocation",locationTxtbox)
the addEventListener should take an event string and then a function to call when the event happens. textListenerLocation is your event handling function, it is not the event string.
locationTxtbox:addEventListener("userInput", textListenerLocation)
First time post and I sincerely apologize if this has been answered in any other post but I have not been able to find a resolution for the problem I'm facing on this or any other site. I'm a new programmer self-teaching with web tutorials and any other resource I have found. I am trying to create code which will spawn characters and allow you to call them. I've had trouble assigning an index value to the individual instances I have created with a for function. I have tried to establish the instance as both a table and a group display object. If anyone is able to point me in the direction of any resources to get a more indepth understanding of tables and group display objects for the Corona SDK implementation of Lua I'm sure that my problem is that I don't have a thorough enough understanding of these particular functionalities and how they work. Here is the code I've written so far.
-- Character Game
require "sprite"
require "ui"
local background = display.newImage("Background Placeholder.png")
halfW = display.viewableContentWidth / 2
halfH = display.viewableContentHeight / 2
local numCharacters = 20
local roundedRect = display.newRoundedRect( 365, 20, 110, 40, 8 )
roundedRect:setFillColor( 0, 255, 0, 80 )
score = 0
t = ui.newLabel{ bounds = { 370, 30, 100, 40 },
text = "Score " .. score,
textColor = { 255, 0, 20, 255 },
size = 18,
align = "center"
}
local scoreboard = function ( event )
t:setText( "Score " .. score )
end
Runtime:addEventListener( "enterFrame", scoreboard )
local group = display.newGroup()
local character = sprite.newSpriteSheetFromData( "Character Placeholder.png", require("Character Placeholder").getSpriteSheetData() )
local characterSet1 = sprite.newSpriteSet(character,1,8)
sprite.add(characterSet1,"character",1,8,1500,0)
local characterplay = function( event )
score = score + group.points
group[i]:removeSelf()
end
do
for i=1, numCharacters do
group:insert(sprite.newSprite(characterSet1))
group[i].xScale = .2
group[i].yScale = .2
group.points = 50
group[i]:setReferencePoint ( display.BottomCenterReferencePoint )
group[i]:translate( halfW + math.random( -100, 100 ), halfH + math.random( -130, -110 ) )
end
timer.performWithDelay( 500, charactermovie )
for i=1, 21 do
timer.performWithDelay( math.random( 500, 5000 ) , charactermove )
charactermove = function(event )
transition.to( group[i], { time=10000, y = 580 } )
transition.to( group[i], { time=8000, x = math.random( 0, 480 ) } )
transition.to( group[i], { time=7000, xScale = 1.5} )
transition.to( group[i], { time=7000, yScale = 1.5} )
group[i]:prepare("character")
group[i]:play()
end
group[i]:addEventListener( "tap", characterplay )
end
end
charactermovie = function( event )
group[i]:prepare("character")
group[i]:play()
end
local function spriteListener( event )
print( "Sprite event: ", event.sprite, event.sprite.sequence, event.phase )
end
for i, group in pairs(group) do print (group, i, v) end
I'm currently getting an "attempt to index field '?' at the line containing this code "group[i]:addEventListener( "tap", zombieplay )" upon launch and a "nil key supplied for property lookup" error at the "group[i]:removeSelf()" line of the "zombieplay" function. I've tried moving the offending code to a variety of locations to see if this is a scoping issue but I largely run into the same error and believe I may not properly understand indexes and keys... I've found that the app functions as intended but I have to call index keys 1 through 21 to get them all to move even though I am only calling for 20 characters and the removeSelf line throwing errors is not removing the individual characters. I'm going to try writing a module for the characters and see if that helps clear any of this up. I will post my results shortly.
Your characterplay and charactermovie functions are trying to use the variable i, this is outside the functions scope.
There is a property of event called target, which is used to get the event callee. You want to do something like this:
local characterplay = function( event )
score = score + group.points
event.target:removeSelf()
end
I am brand new to Lua from a pure VB.Net background. I have a large file of maplines that I need to iterate through. The data is in the form of:
;XX.XXX YY.YYY Name
;
[Airways]
58.50 -12.44 58.21 -13.73
58.21 -13.73 57.89 -15.02
57.89 -15.02 57.54 -16.30
57.54 -16.30 57.17 -17.58
57.17 -17.58 56.76 -18.84
56.76 -18.84 56.33 -20.10
56.33 -20.10 55.87 -21.35
54.33 -25.02 53.77 -26.22
I have tried this but keep getting an error.
local mapLines = {}
local filePath = system.pathForFile( "data.ini", system.DocumentsDirectory )
local file = io.open( filePath, "r" )
if file then
local contents = file:read( "*a" )
--print( "Contents of " .. filePath )
--print( contents )
io.close( file )
local t = display.newText( "Contents of ", 5, 80, nil, 16 );
t:setTextColor( 255, 255, 136, 255 );
local t = display.newText( filePath, 5, 100, nil, 10 );
t:setTextColor( 255, 255, 136, 255 );
local ylast = 130
for line in io.lines(filePath) do
local t = display.newText( line, 15, ylast, nil, 14 );
t:setTextColor( 255, 255, 255 );
ylast = ylast + 20
n = tonumber(line);
if n == nil then
local f = {}
s = "1 2 3 4"
for k, v in string.gmatch(s, "(%w+) (%w+)") do
f[k] = v
end
local myLine = newLine(tonumber(f[1]), tonumber(f[2]), tonumber(f[3]), tonumber(f[4]))
table.insert( mapLines, myLine )
end
end
end
-- Example of shape drawing func
local function newLine(x,y,x1,y1)
-- need initial segment to start
local Line = display.newLine( x, y, x1, y1 )
Line:setColor( 30, 155, 30, 100 )
Line.width = 3
return Line
end
Runtime:addEventListener( "enterFrame", mapLines )
Any help would be greatly appreciated!
Dave
answering the question in the topic:
local string_to_parse = '1 2 3 4'
for s in string_to_parse:gmatch('%d+') do
print(s)
end
sample code on codepad