Modify the time value of a transition - lua

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.

Related

How can I dynamically retrieve the variable used to initialize an instance?

I'm trying to implement a speed-based turn system for a roguelike. I've set up a Mob class using metamethods, so that assigning the following to a variable will spawn a mob into the map at certain grid coordinates:
function Mob:spawn(x,y,m)
local mob = {}
setmetatable(mob, Mob)
mob.x = x
mob.y = y
mob.is_monster = m
return mob
end
Once that's done, I call the following:
function Mob:roll_call()
who_is_here[self.y][self.x] = self.is_monster
self.turn_counter = self.turn_counter * math.random(0.9, 1.1)
table.insert(allTurnCounters, self.turn_counter)
end
This puts the mob's self.turn_counter into a table. Meanwhile, in another module, I've defined these two functions, the heart of the problem:
function turn.decrement_counters(dt) -- runs in Dungeon.update(dt) and subtracts from allTurnCounters
for i = 1,#allMobsSpawned do
if allTurnCounters[i] <= 0 then
allTurnCounters[i] = 0
turn_active = true
whose_turn = i
return
elseif allTurnCounters[i] > 0 then
allTurnCounters[i] = allTurnCounters[i] - (10 * dt)
end
end
end
function turn.whose_is_it() -- called when an entry in allTurnCounters goes zero
if whose_turn == 1 then -- spots 1 and 2 in the spawn list are only ever for players
player1.my_turn = true -- turns on player 1's keys
elseif whose_turn == 2 then
player2.my_turn = true -- turns on player 2's keys
elseif whose_turn >= 3 then -- above 3 we're in monster territory
end
end
I've decided that the first two instances of Mob to be initialized will always be players 1 and 2, assigned to the variables player1 and player2, respectively. And, as it is, it works fine for passing control back and forth between players! But obviously, that's not enough for a fully-featured game. I need monsters, too.
The allTurnCounters table gets new entries, in order, from every mob that spawns (a class which includes both the players and the monsters, so they can share stats). Here's my question: How can I get Lua to dynamically retrieve the name of the table associated with a given turn_counter/value within that table, and use it to take turn priority, even in the event that I don't know what's been procedurally spawned ahead of time or what place it will occupy in the spawn order?
I have 3 ideas, none of which I'm solid on how to implement. One method would be something like sending the entire instance table to another table, rather than just their turn_counters, and then somehow grabbing a pair of values (the table itself and my_turn within the table), updating my_turn's value directly.
Another method might be to use the environment _G... somehow. I'm still poring over Chapter 14 of PiL trying to adapt it to my purposes, but value = _G[varname] seems to be a powerful bit of code I might be able to use for this. Not sure how, just yet.
My last idea was to maybe write some kind of string-sensing find-replace that can grab some other value in each mob's table and then pop it on the front of my_turn. Like, assigning some value with a known pattern for each mob type, that I can use in a string.find and then a string.gsub, to like... manually make the code line read as intended. Seems inelegant, though.
I had good luck with asking my previous Lua/Love2D question here, so I figured let's toss it out there while I'm thinking!
Here is my suggestion for how you should implement this:
Instead of allTurnCounters[i], give mobs a turn_counter property and use allMobsSpawned[i].turn_counter. Then, delete allTurnCounters.
Instead of storing the mob number in whose_turn, store the mob itself. (Note: when I say "the mob itself", it's short for "a reference to the mob itself")
So instead of
whose_turn = i
you would have:
whose_turn = allMobsSpawned[i]
Now whose_turn holds the mob whose turn it is. You can easily check whose_turn == player1, whose_turn == player2, etc. As a bonus, it doesn't rely on the players being the first mobs any more.
You can access the mob's properties through whose_turn - if whose_turn == player1 is true for example then whose_turn.x accesses the same field as player1.x
Here's a somewhat janky solution that can be made more elegant by incorporating the method from the other answer. This is what I came up with on my own while waiting for an answer.
-- in "Mob.lua" module
function Mob:roll_call()
who_is_here[self.y][self.x] = self.is_monster
self.turn_counter = self.turn_counter * math.random(0.9, 1.1)
table.insert(allMobs, {self.name, self.turn_counter})
if self.is_monster == true then
table.insert(allMonsters, {self.name, self.turn_counter})
end
end
function Mob:move(dx, dy)
who_is_here[self.y][self.x] = nil
self.x, self.y = self.x + dx, self.y + dy
who_is_here[self.y][self.x] = self.is_monster
self.turn_counter = 1 * self.speed
for k,v in ipairs(allMobs) do
if v[1] == self.name then
v[2] = self.turn_counter
end
end
self.my_turn = false -- flags turn is over
turn_active = false -- flags no active turn
end
-- in "turn.lua" module
function turn.decrement_counters(dt)
if turn_active == false then
for k,v in ipairs(allMobs) do
v[2] = v[2] - (10 * dt)
if v[2] < 0 then
v[2] = 0
turn_active = true
whose_turn = v[1]
return
end
end
else turn.whose_is_it()
end
end
function turn.whose_is_it()
if whose_turn == player1.name then
player1.my_turn = true
elseif whose_turn == player2.name then
player2.my_turn = true
elseif whose_turn == ant1.name then
ant1.my_turn = true
end
end
turn.whose_is_it() is the part that will need refining. If I use immibis' method of assigning allMobs[i].turn_counter, that will simplify things considerably and allow for future expansion. This answer only works for player1, player2, and an ant called ant1 in particular.

How to make an enemy follow a certain path

How do I make my enemy follow a certain path? This is all I have right now, I'm using Tiled for the images and such. I'm trying to make a game where the player enters an area, and has to avoid the enemy to get the coin so the door will open to the next area. But because my enemy is patrolling the enemy sometimes enters the hallway to the next area and that's not supposed to happen obviously.
I also had a problem with the door, it doesn't disappear when I pick up the coin. I thought that the easiest way to do this is that when I reach a certain score, the door is removed, but it doesnt disappear until the player touches the door. Any suggestions? Maybe link the coin with the door so that when it's picked up, they both disappear somehow?
Level.Load ("Game.tmx")
player = {
object = nil,
score = 0,
health = 100,
speed = 3,
}
function Start()
--Identify the objects, naming them
player.object = Level.GetObject ("Player")
enemy = Level.GetObject ("Enemy")
-- music = Sound.Load ("music.mp3", true, true)
Hud.Message ( " Start ", 2)
end
function DoPlayer()
player.object = Level.GetObject( "Player")
end
function DoEnemey()
enemy = Level.GetObjects( "Enemey" )
end
function DoSign()
Sign = Level.GetObject( "Sign" )
end
function DoDoor()
door = Level.GetObject( "door" )
end
function Update()
--HUD
Hud.Score ("Score : " ..player.score )
Hud.Health ("Health : " ..player.health )
--Controllers
Controller.Wasd (player.object, player.speed)
Controller.Patrol (enemy, 2)
Camera.Follow (player.object)
end
function info()
Hud.Message ("Pick up coins to proceed to the next area!", 3)
end
function CoinPickup( target, source)
if target == player.object then
player.score = player.score + 1
Level.RemoveObject( source )
end
end
function DoorOpen( target, source)
if target == player.object
and player.score == 2
then Level.RemoveObject ( source )
end
end

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.

Corona SDK 'nil value' issue

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)
.

Corona, transition.to upon removal from table

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)

Resources