Have nil value on parameter - lua

I am creating a game in which liquid will come out. I am using the particle systems of the physics engine of Corona. For the parameter of particle group, i get it from a method. When i run the program i get an error message saying that the parameter is a nil value.
Code:
-- Will randomly drop water stream at random locations and with random colors
--Delcare class variables
local physics = (require"physics")
physics.start()
local w = display.contentWidth
local h = display.contentHeight
local particleSystem = physics.newParticleSystem({
filename = "particle.png",
colorMixingStrength = 0.1,
radius = 3,
imageRadius = 6
})
--function to start the water stream
local function start()
end
--fucntion to end the water stream
local function stop()
end
--a function to create particle paramerters
-- flag to determine if the particle parameter should have random colors
-- WILL have RANDOM location
local function createParticleParameter(flag, x, y, color)
local param = {
flags = flags,
x = x,
y = y,
color = color,
radius = 10,
linearVelocityX = 0,
linearVelocityY = 10,
lifetime = 10
}
return param
end
local function onTimer()
local parmas = createParticleParameter("water", math.random(0, display.contentWidth), 0, {0, 1, 0})
particleSystem:createGroup(params)
end
timer.performWithDelay( 1000, onTimer, 0 )
The error message:
---------------------------
Corona Runtime Error
---------------------------
attempt to index a nil value
stack traceback:
[C]: in function 'createGroup'
main.lua:47: in function '_listener'
?: in function <?:167>
?: in function <?:221>
I checked if the parameter was right, and it was because when i ran this program it worked for some reason:
-- Will randomly drop water stream at random locations and with random colors
--Delcare class variables
local physics = (require"physics")
physics.start()
local w = display.contentWidth
local h = display.contentHeight
local particleSystem = physics.newParticleSystem({
filename = "particle.png",
colorMixingStrength = 0.1,
radius = 3,
imageRadius = 6
})
--function to start the water stream
local function start()
end
--fucntion to end the water stream
local function stop()
end
--a function to create particle paramerters
-- flag to determine if the particle parameter should have random colors
-- WILL have RANDOM location
local function createParticleParameter(flag, x, y, color)
local param = {
flags = flags,
x = x,
y = y,
color = color,
radius = 10,
linearVelocityX = 0,
linearVelocityY = 10,
lifetime = 10
}
return param
end
local function onTimer()
local parmas = createParticleParameter("water", math.random(0, display.contentWidth), 0, { 0,1,0})
particleSystem:createGroup({
flags = "water",
x = math.random(0, display.contentWidth),
y = 0,
color = {0, 1,0 },
radius = 10,
linearVelocityX = 0,
linearVelocityY = 10,
lifetime = 10
})
end
timer.performWithDelay( 1000, onTimer, 0 )
With the only major difference is that I manually placed the parameters.
Why is this happening?

You spelled params wrong
local parmas = createParticleParameter("water", math.random(0, display.contentWidth), 0, {0, 1, 0})

Related

Runtime event listener works, but not object (LUA, SUBLIME TEXT 3, CORONA SDK)

Related to a previous topic, helpfully answered by Piglet who directed me to documentation in this question: Using a table in Lua to display text isn't working?... for reference.
Because of how long the project has taken me, I decided to rework a good chunk of the program in order to meet my deadline. I used the documentation's help to properly fix the .text display. However, I should have had a functional changing "vnText" object that I could adjust the text of. However... it only works when I use Runtime event listener, and not the object itself.
While I am perfectly happy using the Runtime event listener to complete my project by the deadline, I would like to know why object:addEventListener didn't work as usual. Is there something I am missing in my code, something that Runtime accomplished that clicking on "textRect" won't?
The line in particular is
Runtime:addEventListener("tap", changePage)
It works perfectly now when I run it. The values are drawn from the table, the command print("change text") is displayed.
The object I tried to use in its place was textRect, which is defined earlier on in the program, a couple tables above. That didn't work to draw the text out and put it in the text. But Runtime did and I, for the life of me, cannot understand why.
HOWEVER, an interesting fact is that when I used textRect, "change text" was printed. But the function didn't change vnText.text...? Which is the whole reason I wrote up the program.
I have scoured documentation and other threads hoping to find an answer to this. The code, however, is much more complicated than my own level, since I'm just a high school student learning from class powerpoints ; right now I'm just searching for an answer as to why Runtime works? And if there is anything I can do to make the object work instead.
Thanks for your help, members of Stack Overflow! You all have helped me to learn tons in the past month.
local store = require( "plugin.google.iap.v3" )
local composer = require("composer")
local scene = composer.newScene()
display.setStatusBar( display.HiddenStatusBar ) -- Removes status bar
coins = 5 --[[variable that defines the number of coins player has in the game. It will be different
in a stand alone game, but as a small app meant to demonstrate function, it's necessary to start off
with a small, defined number in the beginning.]]
local logo = display.newImage("/Images/logo.png", 155, 275) --code for my personal logo, drawn by me.
--Not actually showcased in the video because of time limit.
logo.alpha = 0
local function makeTitleTrue() --this function makes the title true once the logo has been shown and faded out
logo:removeSelf() -- removes logo from screen
print("menu should be TRUE")
titleScreen() -- calls function titleScreen (which is thetitle menu)
end
local function fadeOut()
transition.to(logo, {time = 1000, alpha = 0, onComplete = makeTitleTrue})
end
transition.to(logo, {time = 1000, alpha = 1, onComplete = fadeOut}) -- end of logo code
function titleScreen() -- beginning of title code, which is not managed as a separate scene
title = true
titleImg = display.newImage("/Images/vn_bg.png", 155, 275)
--titleWords = display.newImage("/Images/TitleWords.png", 155, 275)
--particles that flow across the screen as a cool effect. fix to flow towards the upper right corner.
local flare = display.newImage("/Images/flare2.png", 40, 30)
flare.xScale = .5
flare.yScale = .5
local flare2 = display.newImage("/Images/flare2.png", 400, 70)
flare2.xScale = .6
flare2.yScale = .6
local flare3 = display.newImage("/Images/flare2.png", -30, 100)
flare3.xScale = .4
flare3.yScale = .4
local flare4 = display.newImage("/Images/flare2.png", 100, 400)
flare4.xScale = .4
flare4.yScale = .4
local flare5 = display.newImage("/Images/flare2.png", 400, 400)
flare5.xScale = .3
flare5.yScale = .3
local flare6 = display.newImage("/Images/flare2.png", 250, 200)
flare6.xScale = .3
flare6.yScale = .3
local function moveFlare1()
transition.to(flare, {time=2000, x = math.random(-100, 450), y = math.random(-100, 700), onComplete = moveFlare1})
end
local function moveFlare2()
transition.to(flare2, {time=2000, x = math.random(-100, 450), y = math.random(-100, 700), onComplete = moveFlare2})
end
local function moveFlare3()
transition.to(flare3, {time=2000, x = math.random(-100, 450), y = math.random(-100, 700), onComplete = moveFlare3})
end
local function moveFlare4()
transition.to(flare4, {time=2000, x = math.random(-100, 450), y = math.random(-100, 700), onComplete = moveFlare4})
end
local function moveFlare5()
transition.to(flare5, {time=2000, x = math.random(-100, 450), y = math.random(-100, 700), onComplete = moveFlare5})
end
local function moveFlare6()
transition.to(flare6, {time=2000, x = math.random(-100, 450), y = math.random(-100, 700), onComplete = moveFlare6})
end
transition.to(flare, {time=2000, x = math.random(-100, 450), y = math.random(-100, 700), onComplete = moveFlare1})
transition.to(flare2, {time=2500, x = math.random(-100, 450), y = math.random(-100, 700), onComplete = moveFlare2})
transition.to(flare3, {time=2000, x = math.random(-100, 450), y = math.random(-100, 700), onComplete = moveFlare3})
transition.to(flare4, {time=2000, x = math.random(-100, 450), y = math.random(-100, 700), onComplete = moveFlare4})
transition.to(flare5, {time=2000, x = math.random(-100, 450), y = math.random(-100, 700), onComplete = moveFlare5})
transition.to(flare6, {time=2000, x = math.random(-100, 450), y = math.random(-100, 700), onComplete = moveFlare6})
--add options that can when the screen is tapped, tap on an option twice to select
--local newGame_op = display.newImage("", )
--local cont_op = display.newImage("", )
--local coin_op = display.newImage("",)
--local end_op = display.newImage("",)
-- start story
-- continue story
-- coin gambling
-- end game
if (title == true) then
Runtime:addEventListener("tap", sceneVN)
end
--coin_op:addEventListener("tap", coinShop)
end
function forceQuit()
function quit()
os.exit()
end
timer.performWithDelay(1000,quit)
end
function sceneVNChapter2()
return
end
function sceneVN() -- the actual visual novel code itself
display.remove(titleImg)
display.remove(flare)
display.remove(flare2)
display.remove(flare3)
display.remove(flare4)
display.remove(flare5)
display.remove(flare6)
title = false
Runtime:removeEventListener()
page = 0
local coinSheetData =
{
width = 32,
height = 32,
numFrames = 8,
}
local coinimageSheet = graphics.newImageSheet( "/Images/spinning_coin.png", coinSheetData )
local sequenceData =
{
name= "spinning_coin",
start = 1,
count = 8,
time = 1000,
loopCount = 0
}
--the properties of the name plate that can be changed ingame by using ".text" property
local nameOptions =
{
text = "Frankenstein",
x = 165,
y = 450,
width = 310,
font = "Charlesworth.ttf",
fontSize = 22,
align = "left"
}
local bg = display.newImage("/Images/bg4.jpg", 155, 275)
local bust_display = display.newImage( "/Images/f_bust1.png", 155, 223 )
textRect = display.newRect(155, 525, 325, 200)
textRect:setFillColor(.02, .02, .02)
textRect.alpha = .9
local frames = display.newImage("/Images/windowframes_gold.png", 155, 275)
display.newText(nameOptions)
local scriptIntro =
{
[1] = "\"I see. So I\'m supposed to pretend I am\na character in a multi-chapter phone\napp that you\'ve been reading...\"",
[2] = "\"So the purpose of this game is to flirt\nwith me until the meter fills up, and\nyou earn enough coins for a date?\"",
[3] = "\"Then let's see how far you get. Charm\nme by picking the right compliments\nto praise me, my lady.\"",
[4] = "\"When the meter is full, you'll be able\nto ask me on a date to progress the\ngame.\"",
[5] = "\"Let's start the game, then... Can you\ncharm me, the butler of the Raizel\nhousehold?\""
}
vnText = display.newText("\"Good evening. This is a demonstration\nof a visual novel and minigame...\"", 160, 500, "Goudy Old Style Regular.ttf", 17)
vnText.x = 20 ; vnText.y = 495
vnText:setFillColor( 1, 1, 1 )
vnText.anchorX = 0
local function changePage()
page = page + 1
print("change text")
vnText.text = scriptIntro[page]
end
Runtime:addEventListener("tap", changePage)
function choiceGame()
local c_Complimented = {
[1] = "\"Aha... thank you so much. I do my best.\"",
[2] = "\"Ah, please, you flatter me too much! I\ncannot even begin to compare with\nyour praises.\"",
[3] = "\"You're making me blush, my lady. Where\ndid you learn such charm?\"",
[4] = "\"I really don't know what to say... how\nsweet.\""
}
local c_Insulted = {
[1] = "\"Is that really your best attempt at a\nflirt? Pathetic...\"",
[2] = "\"A butler of the Raizel household can\'t\n even begin to contemplate the idea\n of dating you.\"",
[3] = "\"Haha... what a wonderful choice... NOT.\nTry again, darling.\"",
[4] = "\"Such insults are below even your calibre,\n my lady.\""
}
local function optionChosen()
if (compliment == true) then
displayStatus.text = c_Complimented[math.random(1,4)]
else
displayStatus.text = c_Insulted[math.random(1,4)]
end
end
displayStatus = display.newText("Haha... I look forward to your attempts\nat flirting with me.", 160, 500, "Goudy Old Style Regular.ttf", 17)
Runtime:addEventListener("tap", optionChosen)
end -- end of choice game
local function flirtComplete()
local scriptComplete =
{
[1] = "\"Then, seeing as this is a simulation of\n a visual novel dating sim, I have no\n choice but to ask you...\"",
[2] = "\"My lady, would you go on a date with me?\nFrankenstein... butler of the finest noble,\nCadis Etrama di Raizel?\"",
[3] = "\"So, have you made a decision about whether\nyou would like to date yet?\""
}
end
if (coins < 10) then
coinsDigits = 2
else
if (coins > 9) and (coins < 100) then
coinsDigits = 3
else
if (coins > 99) and (coins < 1000) then
coinsDigits = 4
else
if (coins > 999) and (coins < 10000) then
coinsDigits = 5
else
if (coins > 9999) and (coins < 100000) then
coinsDigits = 6
end
end
end
end
end
cooin = display.newSprite(coinimageSheet, sequenceData)
cooin.x = 25
cooin.y = 30
cooin:play()
coinText = display.newText("1", 57 + 4 * coinsDigits, 32, "VCR_OSD_MONO_1.001.ttf", 25)
coinText.text = coins
coinTimer = timer.performWithDelay(2000, cooin, 1)
end
function choiceMade( event ) --the scenes where all the choices are made
if (event.action == "clicked") then
local i = event.index
if (i == 1) then
Runtime:removeEventListener()
titleScreen()
else
if (i == 2) then
system.openURL( "https://www.paypal.com/us/home" )
else
if (i == 3) then
return
end
end
end
end
end -- end of choice scenes
function Outofcoins()
--native alert lack of zero coins
local alertMessage = "Uh oh, looks like you've run out of coins! Would you like to keep flirting, or buy more?"
native.showAlert( "Out of coins!", alertMessage, {"Continue flirting", "Purchase coins", "Exit to Menu"}, choiceMade)
end
function sceneGambleStart()
function earntCoins()
numberEarnt = 0
local coinsGot = display.newImage("/Images/coins_gold.png", 155, 275)
coinsGot.alpha = 0
local function fadeOutCoinsEart()
transition.to(logo, {time = 2000, alpha = 0})
display.remove(coinsGot)
end
local transitionFade = transition.to(logo, {time = 2000, alpha = 1, onComplete = fadeOutCoinsEarnt})
timer.performWithDelay(2000, transitionFade, 1)
coinText.text = coins + numberEarnt
end
end
As your code is, textRect and vnText are both global in scope but scriptIntro is local and declared after textRect. So if you tried to add a tap listener to textRect in which you refer to scriptIntro, it wouldn't work. In fact, all of these variables could be local; just declare them in the right order:
local scriptIntro = ... -- an array of strings
local vnText = display.newText(...
vnText.text = scriptIntro[1]
local n = 1
local textRect = display.newRect(...
function textRect:tap( event )
n = n + 1
if n > #scriptIntro then
n = 1
end
vnText.text = scriptIntro[n]
return true
end
textRect:addEventListener( "tap", textRect )

addEventListner not working in Lua

Here's the relevant functions in my code, I get the following error:
Stack traceback:
[C]: in function 'error'
?: in function 'getOrCreateTable'
?: in function 'addEventListener'
?: in function 'addEventListener'
main.lua:26: in function 'createPlayScreen'
main.lua:79: in main chunk
My code:
-- set up forward references
local spawnEnemy
--create play screen
local function createPlayScreen()
local background = display.newImage("SpaceBackground.jpg")
background.x = centerX
background.y = -100
background.alpha = 0
background:addEventListener ( "tap", shipSmash )
local planet = display.newImage("Earth.png")
planet.x = centerX
planet.y = display.contentHeight+60
planet.alpha = .2
planet.xScale = 2
planet.yScale = 2
planet:addEventListener ( "tap", shipSmash )
transition.to(background, {time = 2000, alpha = 1, y = centerY, x = centerX})
local function showTitle()
local gameTitle = display.newImage("gametitle.png")
gameTitle.alpha = 0
gameTitle:scale(4,4)
transition.to(gameTitle, {time=500, alpha = 1, xScale = 1, yScale = 1})
spawnEnemy()
end
transition.to(planet, {time = 2000, xScale = .75, yScale = .75, alpha = 1, y = centerY, onComplete = showTitle})
end
--game functions
function spawnEnemy()
local enemy = display.newImage("asteroid.png")
enemy.x = math.random(20, display.contentWidth-20)
enemy.y = math.random(20, display.contentHeight-20)
enemy.alpha = 0
transition.to(enemy, {time = 200 , alpha =1})
enemy:addEventListener ( "tap", shipSmash )
end
local function shipSmash(event)
local obj = event.target
display.remove(obj)
return true
end
createPlayScreen()
startGame()
What is the problem here ?
You are referencing a local function shipSmash in your addEventListener calls (enemy:addEventListener ( "tap", shipSmash )), but the function is not defined at that point. You need to move the definition of shipSmash before the functions where you expect to use it.
If you run a static code analyzer on your file (using lua-inspect, ZeroBrane Studio, or another tool from this list), you'll see something like these two warnings among other things, which should give you an idea that this function is not properly referenced:
file.lua:6: first use of unknown global variable 'shipSmash'
file.lua:41: unused local function 'shipSmash'

Attempt to Index GlobalCredits 'event' (a nil value)

I have just started to learn LUA in school, but i cannot find many helpful tutorials o the internet to aid in my learning. I have made a simple game (which doesn't work yet, i realize that) and a main menu. However, when i try to start the app, it gives me this error:
/Users/jordanmcbride/Desktop/Lua Projects/Tapinator/main.lua:47: attempt to index global 'showCredits' (a nil value)
stack traceback:
/Users/jordanmcbride/Desktop/Lua Projects/Tapinator/main.lua:47: in main chunk
[Finished in 9.4s]
I have looked the error, and I cannot seem to understand how to fix it. The other questions have said something about returning the function returning a nil value, and that I should add a return statement to the end, but that doesn't work either.
Here is the code # line 47.
function showCredits.touch(e)
playButton.isVisible = false
creditsButton.isVisible = false
creditsView = display.newImage('credits.png', 0, display.contentHeight)
lastY = name.y
transition.to(name, {time = 300, y = display.contentHeight * 0.5 - title.height - 25})
transition.to(creditsView, {time = 300, y = display.contentHeight * 0.5 + creditsView.height, onComplete = function() creditsView:addEventListener('tap', hideCredits) end})
end
Here is my full code, in case the problem lies elsewhere:
display.setStatusBar(display.HiddenStatusBar)
radius = 40
smallTime = 200
bigTime = 800
score = 0
scoreInc = 2000
--HomePage
local name
local playButton
local creditsButton
local homePage
--Credits
local creditsPage
--Sounds
local circleSpawn = audio.loadSound( "circle_spawn.wav" )
local circleTap = audio.loadSound( "circle_tap.wav" )
function Main()
name = display.newImage('title.png', display.contentWidth / 2, 53)
name:scale( .5, .5 )
playButton = display.newImage('playButton.png', display.contentWidth / 2, 245)
playButton:scale( .5, .5 )
creditsButton = display.newImage('creditsButton.png', display.contentWidth / 2, 305)
creditsButton:scale( .5, .5 )
homePage = display.newGroup(name, playButton, creditsButton)
startButtonListeners('add')
end
function showCredits.touch(e)
playButton.isVisible = false
creditsButton.isVisible = false
creditsView = display.newImage('credits.png', 0, display.contentHeight)
lastY = name.y
transition.to(name, {time = 300, y = display.contentHeight * 0.5 - title.height - 25})
transition.to(creditsView, {time = 300, y = display.contentHeight * 0.5 + creditsView.height, onComplete = function() creditsView:addEventListener('tap', hideCredits) end})
end
function hideCredits.touch(e)
transition.to(creditsView, {time = 300, y = display.contentHeight, onComplete = function() creditsButton.isVisible = true playButton.isVisible = true creditsView:removeEventListener('tap', hideCredits) display.remove(creditsView) creditsView = nil end})
transition.to(name, {time = 300, y = lastY});
end
function startButtonListeners(action)
if(action == 'add') then
playButton:addEventListener('touch', playGame)
creditsButton:addEventListener('touch', showCredits)
else
playButton:removeEventListener('touch', playGame)
creditsButton:removeEventListener('touch', showCredits)
end
end
Main()
printScore = display.newText("Score: " .. tostring(score), display.contentWidth-80, 40, native.systemFontBold, 20)
-- A function that creates random circles
function generateCircle ()
-- Creates a new circle between 0 (the left most bounds) and the width of the display (being the content width), and also
-- 0 (the upper most bounds) and the height of the display (being the content height). The radius of the circle is 'radius'
x = math.random(radius, display.contentWidth-radius)
y = math.random(80, display.contentHeight)
score = score + scoreInc
myCircle = display.newCircle( x, y, radius )
myCircle:setFillColor( math.random(), math.random(), math.random() )
delayTime = math.random(smallTime, bigTime)
score = score + scoreInc
printScore.text = "Score:"..tostring(scores)
local spawnChannel = audio.play( circleSpawn )
timer.performWithDelay( delayTime, generateCircle )
end
generateCircle()
function myCircle:touch( event )
local tapChannel = audio.play( circleTap )
myCircle:removeSelf()
end
myCircle:addEventListener( "touch", myCircle )
The answer by greatwolf will work. But just a tip from my experience. One way I like to create functions is to try to define the name of the function first near the top of the lua file. Then I will define the function later on in the file. Something like this:
--function preallocation
local onPlayTap
local onSoundOnTap
local onSoundOffTap
local onCreditsTap
local onHelpTap
---------------------------------------------------------------------------------
-- Custom Function Definitions
---------------------------------------------------------------------------------
--Called when Sound On Button is tapped, turn off sound
onSoundOnTap = function(event)
end
--Called when Sound Off Button is tapped, turn on sound
onSoundOffTap = function(event)
end
--Called when Credits button is tapped, shows credits
onCreditsTap = function(event)
end
--Called when Help button is tapped, shows help
onHelpTap = function(event)
end
--Callback to Play button. Moves scene to Level Picker Scene
onPlayTap = function(event)
end
What this does is allow each function to be called by any other function in the file. If you do it the way you are doing it by adding the function name before the function like so:
local showCredits = {}
function showCredits.touch(e)
end
local hideCredits = {}
function hideCredits.touch(e)
end
your showCredit function will not be able to call the hideCredits function below it because the hideCredits variable has not been defined yet when the showCredit function was defined. Although this may not effect your current game, in future apps or games, you may need to call functions inside of other functions. To make this work properly, predefine all your function variables first, then define all your function afterwards. Hope this helps.

How to Spawn multiple objects every 10 seconds

How to make this spawn 'math.random(1,3)' smile.png every 10 seconds , and delete the smile.png after the left screen
<code>
local physics = require ("physics");
physics.start();
local function listener(me)
transition.to (me, {time = math.random(1000,4000), x = math.random(10,310), y = -30, onComplete = function()listener(me)end});
end
--Spawning multiple objects in randoms locations
local function spawnsmile()
local smile = display.newImageRect("smile.png", 45, 45);
smile:setReferencePoint(display.CenterReferencePoint);
smile.x = math.random(-10, 400);
smile.y = -40;
transition.to( smile, {time = math.random(2000, 8000), x = math.random(-10, 400) , y = 600,});
physics.addBody(smile, "dynamic", {density = 0.1, bounce = 0.1, friction = .1, radius = 0});
--Adding touch event
smile:addEventListener("touch", smile);
end
tmr = timer.performWithDelay(0, spawnsmile, total_smiles);
<code>
Regards Kevin
Your code was missing total_smiles value assignment and delay argument.
Working code:
local physics = require ("physics");
physics.start();
local function listener(me)
transition.to (me, {time = math.random(1000,4000), x = math.random(10,310), y = -30, onComplete = function()listener(me)end});
end
--Spawning multiple objects in randoms locations
local function spawnsmile()
local smile = display.newImageRect("Button.png", 45, 45);
smile:setReferencePoint(display.CenterReferencePoint);
smile.x = math.random(-10, 400);
smile.y = -40;
transition.to( smile, {time = math.random(2000, 8000), x = math.random(-10, 400) , y = 600,});
physics.addBody(smile, "dynamic", {density = 0.1, bounce = 0.1, friction = .1, radius = 0});
--Adding touch event
smile:addEventListener("touch", smile);
end
local total_smiles = 15
tmr = timer.performWithDelay(10000, spawnsmile, total_smiles);
Moreover, you should store references to created smiles in order to properly destroy them and don't leak memory. more info on memory managment
local smiles = {}
table.insert(smiles, smile)
And disposal:
for i=#smiles,1,-1 do
smiles[i]:removeSelf()
smiles[i] = nil
end
change your timer to perform every 10.000 ms instead of 0. And your listener function doesnt really fill any purpose, remove that and change your transition.to inside of spawnsmile function to
transition.to( smile, {time = math.random(2000, 8000), x = math.random(-10, 400) , y = 600, onComplete = function(obj) obj:removeSelf() obj = nil end});
That should do what you want it to do =) Also there needs to be a value inside total_smiles, but i guess you have it elsewhere.

Corona SDK - frame-by-frame animation and accelerometer problem

we are doing a game with moving objects around frame-by-frame and also using accelerometer.
We have hooked on two events - about drawing the frame and for the acc.
The problem is, after we receive the acc event, we immediately put the x value in a variable.
Then we use this variable to move an object on the screen, but there is CONSIDERABLE slow down. ( I turn the phone, and after a second the object is moving properly, but a second is just way too much for a game, I expect immediate response).
What am I doing wrong? Is there another workaround to do this, or can I give some params to the accelerometer?
Unfortunately this is a serious problem - a real blocker. If this does not work, I have to find another solution (not Corona) for implementing the game.
Thanks in advance!!!
Danail
PS: here's some source:
local lastXGravity = 0
local function move(event)
eventTime=event.time
elapsedTime = eventTime - lastDrawTime
lastDrawTime = eventTime
xSpeed = lastXGravity
local xMoved = xSpeed * elapsedTime
object.x= object.x + xMoved
end
function acc(event)
lastXGravity = event.xGravity
end
Runtime:addEventListener("accelerometer", acc)
Runtime:addEventListener( "enterFrame", move )
I don't know anything about Corona development, but there are some general issues. First what is gravity containing? Just the gravity vector or total acceleration = gravity + userAcceleration? You will need to get userAcceleration = totalAcceleration - gravity or some member from event providing it directly, otherwise there is no chance.
If you have user acceleration, you need to integrate twice to get the position. See Equations of motion. In your case the code will be like:
velocity = userAcceleration * elapsedTime
position = 0.5*userAcceleration * elapsedTime^2
In general precise position detection by accelerometer and gyroscope is still an unresolved problem, so don't expect precise results. But if you are interested in just evaluating that there is an impulse in one direction, it might work. See for example Getting displacement from accelerometer data with Core Motion
The guys at Ansca's forum just got this out:
system.setAccelerometerInterval( 50 )
This didn't quite actually did the trick, but
system.setAccelerometerInterval( 100 ) -- warning - battery drainer!!
did it :)
I open-sourced my first Corona SDK-made game (which actually did really well) which uses Tilting in the same manner you describe (the more the tilt, the faster the movement and vice-versa).
It's called 'Tilt Monster' and you can download it here:
http://developer.anscamobile.com/code/tilt-monster
local isSimulator = "simulator" == system.getInfo("environment")
-- Accelerator is not supported on Simulator
if isSimulator then
-- Please display an Alert Box
end
-- Text parameters
local labelx = 50
local x = 220
local y = 95
local fontSize = 24
local frameUpdate = false
local xglabel = display.newText( "gravity x = ", labelx, y, native.systemFont, fontSize )
xglabel:setTextColor(255,255,255)
local xg = display.newText( "0.0", x, y, native.systemFont, fontSize )
xg:setTextColor(255,255,255)
y = y + 25
local yglabel = display.newText( "gravity y = ", labelx, y, native.systemFont, fontSize )
local yg = display.newText( "0.0", x, y, native.systemFont, fontSize )
yglabel:setTextColor(255,255,255)
yg:setTextColor(255,255,255)
y = y + 25
local zglabel = display.newText( "gravity z = ", labelx, y, native.systemFont, fontSize )
local zg = display.newText( "0.0", x, y, native.systemFont, fontSize )
zglabel:setTextColor(255,255,255)
zg:setTextColor(255,255,255)
y = y + 50
local xilabel = display.newText( "instant x = ", labelx, y, native.systemFont, fontSize )
local xi = display.newText( "0.0", x, y, native.systemFont, fontSize )
xilabel:setTextColor(255,255,255)
xi:setTextColor(255,255,255)
y = y + 25
local yilabel = display.newText( "instant y = ", labelx, y, native.systemFont, fontSize )
local yi = display.newText( "0.0", x, y, native.systemFont, fontSize )
yilabel:setTextColor(255,255,255)
yi:setTextColor(255,255,255)
y = y + 25
local zilabel = display.newText( "instant z = ", labelx, y, native.systemFont, fontSize )
local zi = display.newText( "0.0", x, y, native.systemFont, fontSize )
zilabel:setTextColor(255,255,255)
zi:setTextColor(255,255,255)
-- Create a circle that moves with Accelerator events
local centerX = display.contentWidth / 2
local centerY = display.contentHeight / 2
Circle = display.newCircle(0, 0, 20)
Circle.x = centerX
Circle.y = centerY
Circle:setFillColor( 0, 0, 255 ) -- blue
local textMessage = function( str, location, scrTime, size, color, font )
local x, t
size = tonumber(size) or 24
color = color or {255, 255, 255}
font = font or "Helvetica"
if "string" == type(location) then
if "Top" == location then
x = display.contentHeight/4
elseif "Bottom" == location then
x = (display.contentHeight/4)*3
else
-- Assume middle location
x = display.contentHeight/2
end
else
-- Assume it's a number -- default to Middle if not
x = tonumber(location) or display.contentHeight/2
end
scrTime = (tonumber(scrTime) or 3) * 1000 -- default to 3 seconds (3000) if no time given
t = display.newText(str, 0, 0, font, size )
t.x = display.contentWidth/2
t.y = x
t:setTextColor( color[1], color[2], color[3] )
-- Time of 0 = keeps on screen forever (unless removed by calling routine)
if scrTime ~= 0 then
-- Function called after screen delay to fade out and remove text message object
local textMsgTimerEnd = function()
transition.to( t, {time = 500, alpha = 0},
function() t.removeSelf() end )
end
-- Keep the message on the screen for the specified time delay
timer.performWithDelay( scrTime, textMsgTimerEnd )
end
return t -- return our text object in case it's needed
end -- textMessage()
local function xyzFormat( obj, value)
obj.text = string.format( "%1.3f", value )
-- Exit if not time to update text color
if not frameUpdate then return end
if value < 0.0 then
-- Only update the text color if the value has changed
if obj.positive ~= false then
obj:setTextColor( 255, 0, 0 ) -- red if negative
obj.positive = false
print("[---]")
end
else
if obj.positive ~= true then
obj:setTextColor( 255, 255, 255) -- white if postive
obj.positive = true
print("+++")
end
end
end
local function onAccelerate( event )
xyzFormat( xg, event.xGravity)
xyzFormat( yg, event.yGravity)
xyzFormat( zg, event.zGravity)
xyzFormat( xi, event.xInstant)
xyzFormat( yi, event.yInstant)
xyzFormat( zi, event.zInstant)
frameUpdate = false -- update done
-- Move our object based on the accelerator values
Circle.x = centerX + (centerX * event.xGravity)
Circle.y = centerY + (centerY * event.yGravity * -1)
-- Display message and sound beep if Shake'n
if event.isShake == true then
-- str, location, scrTime, size, color, font
textMessage( "Shake!", 400, 3, 52, {255, 255, 0} )
end
end
local function onFrame()
frameUpdate = true
end
-- Add runtime listeners
Runtime:addEventListener ("accelerometer", onAccelerate);
Runtime:addEventListener ("enterFrame", onFrame);
I hope, this code will help you.

Resources