audio.play not working - lua

I get an "upvalue error" while I try to play audio in my app.
I have 2 files:
sound_board.lua
local enemy_damaged = audio.loadSound( "assets/audio/enemy_damaged.wav" )
local ouch = audio.loadSound( "assets/audio/ouch.wav" )
local pew = audio.loadSound( "assets/audio/pew.wav" )
local function playSound(to_play)
audio.play( to_play )
end
level1.lua
local sound_board = require("sound_board")
-- some code
function fireSinglebullet()
sound_board:playSound(pew) -- line 295
-- some other code
end
At launch I get this error:
level1.lua:295: attempt to index upvalue 'sound_board' (a boolean value)
What's wrong?

Look carefully what you return in sound_board.lua file. Error message tells that local variable sound_board in level.lua is a boolean value.
To get access to variables from another file use modules like that:
-- sound_board.lua
local M = {}
M.sounds = {
"enemy_damaged" = audio.loadSound( "assets/audio/enemy_damaged.wav" )
"ouch" = audio.loadSound( "assets/audio/ouch.wav" )
"pew" = audio.loadSound( "assets/audio/pew.wav" )
}
function M:playSound( to_play )
audio.play( self.sounds[to_play] )
end
return M
and
-- level1.lua
local sound_board = require( "sound_board" )
-- some code
function fireSinglebullet()
sound_board:playSound( "pew" ) -- line 295
-- some other code
end
Read more: External Modules in Corona

Related

Attempt to index local (a boolean value)

I have 2 different Lua files, main.lua and game_model.lua. I'm trying to save some details in a JSON file (I googled that using a JSON file would be the best way to save a user's settings and score), but I'm getting the following error:
Error: File: main.lua
Line: 11
Attempt to index local 'game' (a boolean value)
Why is am I getting this error and how can fix it?
Here is the code in my main.lua:
--Main.lua
display.setStatusBar( display.HiddenStatusBar )
local composer = require( "composer" )
local game = require("data.game_model")
myGameSettings = {}
myGameSettings.highScore = 1000
myGameSettings.soundOn = true
myGameSettings.musicOff = true
myGameSettings.playerName = "Andrian Gungon"
game.saveTable(myGameSettings, "mygamesettings.json")
composer.gotoScene("scripts.menu")
game_model.lua (in the data subdirectory) contains this code:
--game_model.lua (located at data/game_model.lua)
local json = require("json")
function saveTable(t, filename)
local path = system.pathForFile( filename, system.DocumentsDirectory)
local file = io.open(path, "w")
if (file) then
local contents = json.encode(t)
file:write( contents )
io.close( file )
return true
else
print( "Error!" )
return false
end
end
function loadTable(filename)
local path = system.pathForFile( filename, system.DocumentsDirectory)
local contents = ""
local myTable = {}
local file = io.open( path, "r" )
if (file) then
local contents = file:read( "*a" )
myTable = json.decode(contents);
io.close( file )
return myTable
end
return nil
end
It means that the module data.game_model did not return anything when it was loaded.
In this case, require returns true.
To fix the problem identified in lhf's answer, you can put your table saving and loading functions in a table that is returned by data.game_model, like this:
-- Filename: data/game_model.lua
local model = {}
local json = require("json")
function model.saveTable( t, filename )
-- code for saving
end
function model.loadTable( filename )
-- code for loading
end
return model
Note also that a common mistake would be to declare the functions as model:saveTable( t, fn ) instead of model.saveTable( t, fn ). Remember, the former is syntactic sugar for model.saveTable( model, t, fn ).
Now the variable game in local game = require( "data.game_model" ) should be initialized to a table containing your functions. You can easily check this:
local game = require("data.game_model")
print( type( game ) )
for k,v in pairs(game) do
print(k,v)
end
Produces output like:
table
loadTable function: 0x7f87925afa50
saveTable function: 0x7f8794d73cf0
Use code below to save/load. All code comes from github/robmiracle.
local M = {}
local json = require("json")
local _defaultLocation = system.DocumentsDirectory
local _realDefaultLocation = _defaultLocation
local _validLocations = {
[system.DocumentsDirectory] = true,
[system.CachesDirectory] = true,
[system.TemporaryDirectory] = true
}
function M.saveTable(t, filename, location)
if location and (not _validLocations[location]) then
error("Attempted to save a table to an invalid location", 2)
elseif not location then
location = _defaultLocation
end
local path = system.pathForFile( filename, location)
local file = io.open(path, "w")
if file then
local contents = json.encode(t)
file:write( contents )
io.close( file )
return true
else
return false
end
end
function M.loadTable(filename, location)
if location and (not _validLocations[location]) then
error("Attempted to load a table from an invalid location", 2)
elseif not location then
location = _defaultLocation
end
local path = system.pathForFile( filename, location)
local contents = ""
local myTable = {}
local file = io.open( path, "r" )
if file then
-- read all contents of file into a string
local contents = file:read( "*a" )
myTable = json.decode(contents);
io.close( file )
return myTable
end
return nil
end
function M.changeDefault(location)
if location and (not location) then
error("Attempted to change the default location to an invalid location", 2)
elseif not location then
location = _realDefaultLocation
end
_defaultLocation = location
return true
end
function M.print_r ( t )
local print_r_cache={}
local function sub_print_r(t,indent)
if (print_r_cache[tostring(t)]) then
print(indent.."*"..tostring(t))
else
print_r_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_print_r(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_print_r(t," ")
print("}")
else
sub_print_r(t," ")
end
print()
end
M.printTable = M.print_r
return M
Usage
local loadsave = require("loadsave")
myTable = {}
myTable.musicOn = false
myTable.soundOn = true
loadsave.saveTable(myTable, "myTable.json")

Corona pass parameter in gotoScene

I refer to corona website reference using these to pass parameters to another scene.
main.lua
local options =
{
effect = "slideLeft",
time = 800,
params = { var1 = "custom", myVar = "another" }
}
storyboard.gotoScene( "notificationPage", options )
then on my other scene
notificationPage.lua
function scene:enterScene( event )
local group = self.view
local params = event.params
print( params.var1 )
print( params.myVar )
end
it return error attempt to index local 'params' (a nil value). why is that ? and how do i do it correctly?
It should be placed in "createScene" instead of "enterScene".
And as you may read in Corona Docs "This library is planned for deprecation. If you are starting a new project, you should use the composer.* scene management library instead."
It's in the 'createScene' event handler only, try this code:
function oScene:createScene( oEvent )
local oGroup = self.view
local aParams = oEvent.params
if aParams then
print (aParams.var1)
print (aParams.myVar)
end
You should use scene:create function:
function scene:create( event )
local sceneGroup = self.view
local params = event.params
print( params.var1 )
print( params.myvar )
end
you can download scene template from coronalabs.com

Director Error : The scene name must be a string. scene = nil. CORONA SDK

I am trying my first application in corona using director class but facing problem in my initial code here's my code:
_W = display.contentWidth
_H = display.contentHeight
local director = require("director")
local mainGroup = display.newGroup()
local main = function ()
mainGroup:insert(director.directorView)
director.changeScene("splashscreen")
return true
end
main()
And here is my splashscreen code:
module(..., package.seall)
function new()
local localGroup = display.newGroup ( );
local bgImage = display.newImageRect ( "splash_screen_images.png", _W, _H );
bgImage:setReferencePoint(display.CentreRefrencePoint);
bgImage.x = _W/2;
bgImage.y = _H/2;
localGroup:insert(bgImage);
local delayTimer = timer.performWithDelay ( 3000, changeScreen, 1 )
local function changeScreen1
director:changeScene("meuscreen");
timer.cancel ( delayTimer );
end
return localGroup
end
I am not able to run this code, always getting this error:
Director Error : The scene name must be a string. scene = nil
In your main.lua page, replace the following:
director.changeScene("splashscreen")
with:
director:changeScene("splashscreen")
Note that dot(.) is changed to colon(:)

Corona Sdk - Is there a way to call and group:insert() an object from another lua file?

As stated in the title I would like to not only call an object from an external Lua file, but I would also like to group:insert() this object into my Menu page with the properties given to it in the external lua file. Is this possible and/or efficient? I would just really like to make sure data isn't repeated through out my project.
EDIT
Here's my code so far:
The group:insert() function is throwing me an error stating it was expecting a table and that I might have been trying to call a function in which case i should use ":" instead of "."
This is menu.lua:
local storyboard = require( "storyboard" )
local scene = storyboard.newScene()
local widget = require "widget"
local m = require ("myData")
local menuFunction = require("menuFunction")
local menuSwipe
-- =======================
-- menuSwipe()
-- =======================
menuSwipe = function(self, event)
local phase = event.phase
local touchID = event.id
if(phase == "began") then
elseif(phase == "moved") then
elseif(phase == "ended" or phase == "cancelled") then
if(m.menuActivator > 0) then
menuDown(m.invisiBar, event)
else
--m.layerInfo = layers
transition.to( menuFunction.menuBar, { x = menuFunction.menuBar.x, y = 0, time = 200 } )
--transition.to( layers, { x = menuFunction.menuBar.x, y = h, time = 100 } )
m.invisiBar = display.newRect( 0,0,w,25,6)
m.invisiBar.alpha = 0
m.menuActivator = 1
end
end
end
-- ++++++++++++++++++++++
-- menuDown()
-- ++++++++++++++++++++++
function menuDown(self, event)
local phase = event.phase
local touchID = event.id
if(phase == "began") then
elseif(phase == "moved") then
elseif(phase == "ended" or phase == "cancelled") then
if(m.menuActivator == 1) then
transition.to( menuFunction.menuBar, { x = m.menuInfo.x, y = h*.964, time = 200 } )
--transition.to( group, { x = 0, y = 0, time = 10 } )
m.menuActivator = 0
end
end
end
function scene:createScene( event )
local group = self.view
group:insert( menuFunction.menuBar ) -- *** ERROR occurs here
end
function scene:enterScene( event )
local group = self.view
end
function scene:exitScene( event )
local group = self.view
end
function scene:destroyScene( event )
local group = self.view
end
scene:addEventListener( "createScene", scene )
scene:addEventListener( "enterScene", scene )
scene:addEventListener( "exitScene", scene )
scene:addEventListener( "destroyScene", scene )
return scene
This is menuFunction.lua:
local m = require("myData")
local menu = require ("menu")
local w = display.contentWidth
local h = display.contentHeight
local menuFunction = {}
--menuBar
menuFunction.menuBar = display.newImage( "images/menuBar1.png")
menuFunction.menuBar.x = w*(1/2)
menuFunction.menuBar.y = h*1.465
menuFunction.menuBar.height = h
menuFunction.menuBar:setReferencePoint(display.TopLeftReferencePoint)
menuFunction.menuBar.touch = menu.menuSwipe
menuFunction.menuBar:addEventListener("touch", menuFunction.menuBar)
return menuFunction
This is the exact error message:
ERROR: table expected. If this is a function call, you might have used '.' instead of ':'
message**
Does this happen every time this code is called, or does it by any chance work the first time and then crashes? In your case, code could work the first time you enter the scene, but the second time you do, it may crash [if you remove scenes in between].
When you do a 'require' of a file, its contents are executed and returned value is saved in the global packages table. When you require the same file again, the returned value is taken from the global packages table instead, the code is not executed again.
So if you by any chance require this file in one spot of your app, and then call :removeSelf() and nil the reference of the menuBar, the display object will be removed and its reference will cease to exist, and calling the require again, will not recreate the object. Fully removing a scene will also remove the display objects.
So what you wanted to achieve is very sensible [contrary to what #Schollii says], but your "module" should allow creation of multiple objects if you want to get rid of them during runtime.
I'm not going to correct your code, just a simple example of how you can achieve this:
-- menu.lua
local menuCreator = {}
menuCreator.newMenu = function(params)
local menu = display.newGroup()
-- create your menu here
return menu
end
return menuCreator
Now anytime you do:
local menuCreator = require("menu.lua")
you will be able to call:
local menu = menuCreator.newMenu(someParams)
and get yourself a nice new menu wherever you need.
If it's not shown all the time on screen, it may be better to create a new one whenever you need it, and then remove it from the memory.
There are several issues with this, and none of them seem related to your error but fixing them will either also fix the error or make the cause of the error more obvious. Please fix following and update:
Although Lua allows it, don't use circular includes, where A includes B which includes A. Instead have menu require menuFunction and then call a creation function in menuFuntion:
-- menuFunction.lua
local m = require("myData")
-- require("menu") -- BAD! :)
local w = display.contentWidth
local h = display.contentHeight
local menuBar = display.newImage( "images/menuBar1.png")
menuBar.x = w*(1/2)
menuBar.y = h*1.465
menuBar.height = h
menuBar:setReferencePoint(display.TopLeftReferencePoint)
local menuFunction = { menuBar = menuBar }
function createMenuBar(menuSwipe)
menuFunction.menuBar.touch = menuSwipe
menuFunction.menuBar:addEventListener("touch", menuFunction.menuBar)
return menuFunction
end
-- menu.lua
function createScene(event)
local mf = require('menuFunction')
mfFunction = mf.createMenuBar(menuSwipe)
group:insert(menuFunction.menuBar)
end
Secondly out of the four calls to group:insert() the first 3 refer to objects that are not shown in the code and don't see relevant to problem, they should be removed or if you think relevant, comment why their code now shown, or show their code.

Am not able to test inapp restore functionality in my version 2

I'v tested & uploaded my app on appStore it's inapp purchases was working perfectly fine, I was able to restore the app too.
But now I want to test it's version 2 but now am able to buy but restore isn't working.
module(..., package.seeall)
require("store")
require("ui")
local inappfile = require("inappfile")
local validProducts, invalidProducts = {}, {}
local listOfProducts =
{
-- These Product IDs must already be set up in your store
-- We'll use this list to retrieve prices etc. for each item
-- Note, this simple test only has room for about 4 items, please adjust accordingly
-- The iTunes store will not validate bad Product IDs
"com.tinytapps.pandamath.fullpack",
}
-------------------------------------------------
-- we store everything inside this group at the end
local newActivity = display.newGroup()
-----------------------------------------------------
---------------- IN APP CODE STARTS HERE ------------------
checkIfPurchased = function()
local filePath = system.pathForFile( "purchased.txt", system.DocumentsDirectory )
local file = io.open( filePath, "r" )
if file then
_G["isPurchased"] = true
--AdMediator.hide()
else
_G["isPurchased"] = false
--local_configuration()
end
end
callforpurchase = function()
if _G["isPurchased"] == false then
local cerateFile = function()
_G.noOfQuestionCompleted=0
local filePath = system.pathForFile( "purchased.txt", system.DocumentsDirectory )
local file = io.open( filePath, "r" )
print(file)
if file then
_G["isPurchased"] = true
io.close( file )
else
file = io.open( filePath, "w" )
_G["isPurchased"] = true
io.close( file )
end
end
function showTitle()
if isSimulator then
local myAlert = native.showAlert( "iTunes Store not available in Corona Simulator",
"Offline testing: see console for output.",
{ "OK" } )
end
end
-------------------------------------------------------------------------------
-- Product IDs should match the In App Purchase products set up in iTunes Connect.
-- We cannot get them from the iTunes store so here they are hard coded;
-- your app could obtain them dynamically from your server.
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-- Process and display product information obtained from store.
-- Constructs a button for each item
-------------------------------------------------------------------------------
function unpackValidProducts()
local buttonSpacing = 5
-- Utility to build a buy button
-- Handler for buy button
function newBuyButton (index)
local buttonDefault = "add/buybtn.png"
local buttonOver = "add/buybtn.png"
local buyThis = function ( product )
print ("Purchasing " ..product)
-- Purchase the item
if store.canMakePurchases then
store.purchase( {product} )
else
native.showAlert("Store purchases are not available, please try again later",
{ "OK" } )
end
end
function buyThis_closure ( index )
-- Closure wrapper for buyThis() to remember which button
return function ( event )
buyThis (validProducts[index].productIdentifier)
return true
end
end
local hideDescription = function ( )
--descriptionArea.text = "Select a product..."
end
local describeThis = function ( description )
print ("About this product: " ..description)
end
function describeThis_closure ( index )
-- Closure wrapper for describeThis() to remember which button
return function ( event )
describeThis (validProducts[index].description)
return true
end
end
buyButton = ui.newButton{
default = buttonDefault, over = buttonOver,
onPress = describeThis_closure (index), onRelease = buyThis_closure (index),
}
_G.buyButton=buyButton
return buyButton
end
-- Utility to build a restore button
function newRestoreButton ()
local buttonDefault = "add/restorebtn.png"
local buttonOver = "add/restorebtn.png"
local restore = function ( product )
-- Ask the iTunes Store to initiate restore transaction sequence
print ("Restoring " )
store.restore()
end
local hideDescription = function ( )
--descriptionArea.text = "Select a product..."
end
local describeThis = function ()
-- Display info in description area
print ("Test restore feature")
end
--local label = "Test restore"
restoreButton = ui.newButton{
default = buttonDefault, over = buttonOver,
onPress = describeThis, onRelease = restore,
}
_G.restoreButton = restoreButton
return restoreButton
end
print ("Loading product list")
if not validProducts then
native.showAlert( "In App features not available", "initStore() failed", { "OK" } )
else
print ("Product list loaded")
print( "Country: " .. system.getPreference( "locale", "country" ) )
local buttonSpacing = 5
print( "Found " .. #validProducts .. " valid items ")
-- display the valid products in buttons
for i=1, #validProducts do
-- Debug: print out product info
print ("Item " .. i .. ": " .. validProducts[i].productIdentifier
.. " (" .. validProducts[i].price .. ")")
print (validProducts[i].title .. ", ".. validProducts[i].description)
---------------------------------------------------------------------------
-- create and position product button
local myButton = newBuyButton(i)
myButton.x = 570 --centerX - 200
myButton.y = 450 --centerY + 250
--myButton.xScale = 0.6
--myButton.yScale = 0.6
--newActivity:insert(buyButton)
myButton:toFront()
end
local restoreButton = newRestoreButton()
restoreButton.x = 200 --centerX + 200
restoreButton.y = 450 -- centerY + 250
--restoreButton.xScale = 0.6
--restoreButton.yScale = 0.6
--newActivity:insert(restoreButton)
restoreButton:toFront()
for i=1, #invalidProducts do
-- Debug: display the product info
native.showAlert( "Item " .. invalidProducts[i] .. " is invalid.",
{ "OK" } )
print("Item " .. invalidProducts[i] .. " is invalid.")
end
end
end
-------------------------------------------------------------------------------
-- Handler to receive product information
-- This callback is set up by store.loadProducts()
-------------------------------------------------------------------------------
function loadProductsCallback( event )
-- Debug info for testing
print("In loadProductsCallback()")
print("event, event.name", event, event.name)
print(event.products)
print("#event.products", #event.products)
io.flush() -- remove for production
-- save for later use
validProducts = event.products
invalidProducts = event.invalidProducts
unpackValidProducts ()
end
-------------------------------------------------------------------------------
-- Handler for all store transactions
-- This callback is set up by store.init()
-------------------------------------------------------------------------------
function transactionCallback( event )
local infoString
print("transactionCallback: Received event ", event.name)
if event.transaction.state == "purchased" then
cerateFile()
_G["isPurchased"] = true
--AdMediator.hide()
if buyButton ~= nil then
buyButton=nil
end
if restoreButton ~= nil then
restoreButton=nil
end
infoString = "Transaction successful!"
print (infoString)
inappfile.onClose()
print("transactionCallback() method called inappfile.onClose()")
elseif event.transaction.state == "restored" then
print ("Success! Product restored")
cerateFile()
_G["isPurchased"] = true
if buyButton ~= nil then
buyButton=nil
end
if restoreButton ~= nil then
restoreButton=nil
end
infoString = "Transaction successful!"
print (infoString)
inappfile.onClose()
print("transactionCallback() method called inappfile.onClose()")
elseif event.transaction.state == "cancelled" then
infoString = "Transaction cancelled by user."
elseif event.transaction.state == "failed" then
infoString = "Transaction failed, type: ",
event.transaction.errorType, event.transaction.errorString
else
infoString = "Unknown event"
end
-- Tell the store we are done with the transaction.
-- If you are providing downloadable content, do not call this until
-- the download has completed.
store.finishTransaction( event.transaction )
end
-------------------------------------------------------------------------------
-- Setter upper
-------------------------------------------------------------------------------
function setupMyStore (event)
store.loadProducts( listOfProducts, loadProductsCallback )
print ("After store.loadProducts, waiting for callback")
if isSimulator then
-- No Store, so no callbacks, so exercise our GUI "manually"
validProducts[1] = {}
validProducts[1].title = "Panda Math"
validProducts[1].description = "A wonderful product of Math for testing"
validProducts[1].price = 1.99
validProducts[1].productIdentifier = "com.tinytapps.pandamath.full"
unpackValidProducts()
end
end
-------------------------------------------------------------------------------
-- Main
-------------------------------------------------------------------------------
-- Show title card
showTitle ()
-- Connect to store at startup
store.init (transactionCallback )
print ("After init")
-- Hide title card, run store
timer.performWithDelay (1000, setupMyStore)
end
end

Resources