Using Corona, i would like to move object when i delete it from a table. The problem is that i iterate the table on every frame. When x > WIDTH - 50 i would like for the monkey to stop moving in a sinuswave form and jump into the removeMonkeys function.
My Code:
local function removeMonkeys(obj)
transition.to(obj, {time = 1500, y = 2*HEIGHT/3, onComplete = obj:removeSelf()})
numMonkeys = numMonkeys - 1;
end
function startGame()
timer.performWithDelay(500, spawn, maxNumMonkeys)
local function onEveryFrame( event )
for i = 1, #monkeySet do
if(monkeySet[i] ~= nil) then
monkeySet[i].x = monkeySet[i].x + 2
monkeySet[i].y = monkeySet[i].y + math.sin(monkeySet[i].x/monkeySpeed)*Amplitude/5
if(monkeySet[i].x > WIDTH -50) then
removeMonkeys(monkeySet[i])
table.remove(monkeySet, i)
print(#monkeySet)
end
end
end
end
Runtime:addEventListener( "enterFrame", onEveryFrame )
Is there anything I'm missing here?
Not sure what exactly you're asking here, but if your transition.to doesn't work check that you aren't you killing the only reference to monkeySet[i] when you do
table.remove(monkeySet, i)
Related
I do not understand why I get the following error:
Line: 107
Bad argument #1 to 'newLine' (number expected, got nil)
I am trying to create a line between two touched objects.
Here is my code:
function createstar()
ie = ie - 300
astar = display.newImage('ls.png', math.random( 1, 10) * 33, ie)
astar:addEventListener( "touch", star)
physics.addBody(astar)
stars:insert(astar)
sceneGroup:insert(stars)
end
function update(e)
if(stars ~= nil)then
for i = 1, stars.numChildren do
stars[i].y = stars[i].y + 3
end
end
end
function star:touch( event )
if event.phase == "began" then
-- Insert touched star into array
table.insert(touchedStarArray, self)
-- Check if array holds 2 stars yet
if table.getn(touchedStarArray) >= 2 then
-- if it does then draw a line between the 2 stars
line = display.newLine( touchedStarArray[1].x, touchedStarArray[1].y, touchedStarArray[2].x, touchedStarArray[1].y)
-- and empty array
touchedStarArray = {}
end
end
end
Thanks in advance, all help is greatly appreciated!
I assume from code you pasted that you have one table listener and it's not the same object as each star created.
The problem is in this line
table.insert(touchedStarArray, self)
There are to ways to solve it.
One, very simple would be to put into touchedStarArray event.target not self (self is table star, not star's objects you are createing in createstar function.
table.insert(touchedStarArray, event.target)
Other solution would be to put listener into star creation function
function createstar()
ie = ie - 300
astar = display.newImage('ls.png', math.random( 1, 10) * 33, ie)
astar:addEventListener( "touch", astar)
function astar:touch( event )
if event.phase == "began" then
-- Insert touched star into array
table.insert(touchedStarArray, self)
-- Check if array holds 2 stars yet
if table.getn(touchedStarArray) >= 2 then
-- if it does then draw a line between the 2 stars
line = display.newLine( touchedStarArray[1].x, touchedStarArray[1].y, touchedStarArray[2].x, touchedStarArray[1].y)
-- and empty array
touchedStarArray = {}
end
end
end
physics.addBody(astar)
stars:insert(astar)
sceneGroup:insert(stars)
end
I would put in some print statements and make sure that touchedStarArray[1] really has a .x attribute.
\
How can i change the time value of a transition while is executing? For example I have the object "cesta" moving from the left to the right with a time of 4000ms then for some reason I want to change the time value to move it faster.
function createCesta()
...
transition.to(cesta, {time = 4000, x = screenW + 110})
...
end
function touchScreen(event)
if event.phase == "began" then
end
if event.phase == "ended" then
--change the time value from here "from 4000 to 2000"
end
end
The docs at http://docs.coronalabs.com/api/library/transition/index.html indicate that there is no function call to do this. You would therefore have to cancel the current incomplete transition and create a new one. For example,
local trans
local transTime = 4000 -- ms
local transStart
local object
function someEventHandler(event)
transition.cancel(trans)
local remaining = system.getTimer() - transStart - transTime
if remaining > 0 then
trans = transition.to(object, { time = remaining/2, x = ... }
end
end
function spawn()
object = display.newText(...)
trans = transition.to(object, {time = transTime}
transStart = system.getTimer()
end
This shows a spawn function where you create a display object and make it move via transition to some x, and an event handler that will get called at some point. It computes how much time is left in the transition and if > 0, creates a new transition with half that remaining time so double the "motion" speed of x.
What is the best way to remove all spawned coins when the game is over?
Here is the code that spawns the coins:
screenGroup = self.view
coin = {}
coinspawn = function()
i = display.newSprite( imageSheet1, sequenceData1 )
i.x = display.contentWidth
i.y = math.random(0, display.contentHeight-50)
i:play()
i.collided = true
i.name = "coin"
physics.addBody(i, "dynamic",
{density=.1, bounce=0.1, friction=.2, shape= shape2 ,filter=playerCollisionFilter }
)
--player.gravityScale = 0.5
coinIntro = transition.to(i,{time=2500, x=display.contentWidth - display.contentWidth -500 ,onComplete=jetReady , transition=easing.OutExpo } ) --
coin[#coin+1] = i
end
tmrcoin = timer.performWithDelay( 1000, coinspawn, 0 )
First you would remove all coins from the display. Then you would clear the coin table:
for i=1,#coin do
coin[i]:removeSelf()
end
coin = {} -- forget all coins
Assuming coin table is the only other place you store your coins, this will do it.
Note that you can't use coin[i]=nil in the loop after removeSelf: as soon as table has holes, the # operator is basically unusable. You can't use table.remove either, because i gets incremented every time, so you'll miss items (try, you'll see). Same issue with pairs: you can't edit a table while iterating through it. You could however do this:
local numCoins = #coin
for i=1,numCoins do
coin[i]:removeSelf()
coin[i]=nil
end
-- now coin is {}
The only reason I can think of to nil N items instead of letting the gc take care of it with one table = {} statement is if you have more than one reference to your coin table (which I would rename to coins, BTW, for clarity).
I am making a shooter game using the corona sdk...
My problem is that i am trying to delete an object(that is part of an array)when it leaves the screen.. when i do, i get an error that says 'trying to compare nil value to variable' which refers to a simple move function for every object in the array. Here is relevant parts of code:
function addAlien()
listeners('add')
end
function listeners(action)
if(action == 'add') then
Runtime:addEventListener('enterFrame',update)
enemyTimer = timer.performWithDelay(800,addEnemy,0)
else
Runtime:removeEventListener('enterFrame',update)
timer.cancel(enemyTimer)
end
end
function addEnemy(e)
enemy = display.newImage('drone.png')
enemy.x = 500
enemy.y = math.floor(math.random()*300)
enemy:scale(-0.1,0.1)
enemy.speed = math.random(2,6)
enemies.insert(enemies,enemy)
enemy.enterFrame = moveEnemy
Runtime:addEventListener('enterFrame',enemy)
end
function moveEnemy(self,event)
--if self.x < 100 then
---self:removeSelf()
--self = nil
--removeSelf()
--else
self.x = self.x-self.speed
--end
end
function update(e)
if(enemies.numChildren ~= 0)then
for i = 1,enemies.numChildren do
if(enemies[i] ~= nil)then
--enemies[i].x = enemies[i].x-3
if(enemies[i].x<100)then
--enemies:remove(enemies[i])
--display.remove(enemies[i])
--enemies[i] = nil
end
end
end
end
end
I have commented out the parts that give me errors.
Any help would be appreciated,
thanks
You might want to try and put the delete code in it's own function and then use a timer to remove it so that the function where you are currently deleting the object can return and you're not deleting yourself.
Another option would be to make it temporarily invisible and then loop through the table periodically and remove anything outside of the move handler.
You have a problem with the following code:
function listeners(action)
if(action == 'add') then
Runtime:addEventListener('enterFrame',update)
enemyTimer = timer.performWithDelay(800,addEnemy,0)
else
Runtime:removeEventListener('enterFrame',update)
timer.cancel(enemyTimer)
end
end
You only want to Runtime:addEventListener('enterFrame', update) once. If you do it everytime you add an enemy things will go wrong. The problem is your code runs again and again after the objects have been removed already.
hmmm. did you use the scene template? if so, you should only put the :removeself () and = nil values in the scene destroy section at the bottom. you also dont need the second removeself that is not attached to an object as that is probably the nil issue.
to summarize.
1-put all remove self () and = nil at the destroy section of scene template and use object.isVisible = false instead.
2-the nil error is most likely coming from the removeself() statement with no object. so change it to moveenemy:removeself ()
if my understanding is right this is how i would do it without using runtime
and using timer instead. ask away if you have question
local scrWidth = display.actualContentWidth
local scrHeight = display.actualContentHeight
local enemy = {} --this will hold your aliens
function addEnemy()
enemy[#enemy + 1] = display.newImage("drone.png")
enemy[#enemy].x = 500
enemy[#enemy].y = math.floor(math.random()*300)
enemy[#enemy]:scale(-0.1,0.1)
enemy[#enemy].speed = math.random(2,6)
end
local function update()
addEnemy()
--this will move the enemy to the left from right
for i=1,#enemy,1 do
enemy[i].x = enemy[i].x - enemy[i].speed
end
--the below codes will destroy each enemy that is out side the screen on the left
local function destroyWhenOutside()
for i=1,#enemy,1 do
if enemy[i].x < 0 - enemy[i].width then
enemy[i]:removeSelf()
enemy[i] = nil
elseif enemy[i].y < 0 - enemy[i].height then
enemy[i]:removeSelf()
enemy[i] = nil
end
end
end
destroyWhenOutside()
end
--this will loop the update every 1/1000 seconds
local timerUpdate = timer.performWithDelay(1,update,-1)
.
I'm trying to move an object randomly to different locations, so I came out with the following: transition.to generates the x,y randomly as well as the time, and on finish runs another function which checks if the object is still there and sends it to a different location.
but I'm getting an error:
Runtime error
main.lua:352: stack overflow
stack traceback:
main.lua:352: in function
'toAnotherPlace'
looks like corona doesn't really waits for transition complete, so it goes on infinite loop
code
function toAnotherPlace(object)
if object ~= nil then
transition.to( object,
{
time=math.random(1500,6000),
alpha=1,
x=(math.random(10, 310)),
y=(math.random(10, 400)),
onComplete=toAnotherPlace(object)
})
end
end
transition.to( bossess[boss],
{
time=math.random(1500,6000),
alpha=1,
x=(math.random(10, 310)),
y=(math.random(10, 400)),
onComplete=toAnotherPlace(bossess[boss])
})
You can try this, I added an onComplete = function() ... end and I call the toAnotherPlace(object) function inside it.
I think it's a bug if you directly call a function on onComplete
function toAnotherPlace(object)
print(object.width)
if object ~= nil then
transition.to( object,
{
time = math.random(1500,6000),
alpha = 1,
x = math.random(10, 310),
y = math.random(10, 400),
onComplete = function()
toAnotherPlace(object)
end
})
end
end
transition.to(bossess[boss],
{
time = math.random(1500,6000),
alpha = 1,
x = math.random(10, 310),
y = math.random(10, 400),
onComplete = function()
toAnotherPlace(bossess[boss])
end
})
I tried this and is working fine, no errors.
If you still getting errors, check the bossess[boss] if there is a reference to your object