Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

Function RestoreShip works only when called from game.lua file, but not from a module
Started by robertom.ranieri Jun 26 2019 06:58 AM

7 replies to this topic

Best Answer SGS , 26 June 2019 - 02:18 PM

try

timer.performWithDelay(1000, function() shipManage.restoreShip(ship) end)

also use : notation instead of . notation as this will reference your object by default.  i.e.

ship:restoreShip()

You will need to restructure your functions accordingly.  But generally this is the preferred way.  

 

You then reference self within those functions and that will give you a direct reference to ship.

[TOPIC CONTROLS]
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

robertom.ranieri

[GLOBAL: userInfoPane.html]
robertom.ranieri
  • Observer

  • 5 posts
  • Corona SDK

Hello guys, I'm having kind of an odd issue. 
I'm basing my project off of the Corona Tutorial for the space shoot 'em up game, which contains the following function in order for the player to gain some invincibility frames upon getting hit, which works without any issues.
It's contained within the game.lua file and, as such, the ship referenced in the function itself is a local variable.

local function restoreShip()

	ship.isBodyActive = false
	ship.x = display.contentCenterX
	ship.y = display.contentHeight - 100

	-- Fade in the ship
	transition.to( ship, { alpha=1, time=4000,
		onComplete = function()
			ship.isBodyActive = true
			died = false
		end
	} )
end

This is my version of said function, contained within a module which I called shipManage.lua

shipManage.restoreShip = function (ship)
    ship.isBodyActive = false
    ship.x = display.contentCenterX
    ship.y = display.contentHeight * 0.8
    -- Fade in the ship
    transition.to(
        ship,
        {
            alpha = 1,
            time = 4000,
            onComplete = function()
                ship.isBodyActive = true
            end
        }
    )
end

It works well if I put it in my game.lua file (with the only alteration being, in that case, that the ship isn't passed as a parameter to the function but is instead a local variable). However, if I put it in the shipManage.lua module, and pass the ship as a parameter to the function itself, I start getting the following error:
oVuFGCI.jpg

"property isBodyActive cannot be set cannot be called when the world is locked and in the middle of number crunching, such as during a collision event"

 

Which doesn't make sense to me because the function, wether it's in shipManage.lua or game.lua is called with the same exact delay in milliseconds (and altering it has proven to be useless).

Could somebody help me shed some light into this issue?



[TOPIC: post.html]
#2

Rob Miracle

[GLOBAL: userInfoPane.html]
Rob Miracle
  • Moderator

  • 26,072 posts
  • Enterprise

Which line is the error happening on? Setting the ship.isBodyActive to false at the beginning of the function or the ship.isBodyActive = true inside the onComplete function?

 

Where is the code calling shipManage.restoreShip()? Can you share that?

 

Rob



[TOPIC: post.html]
#3

robertom.ranieri

[GLOBAL: userInfoPane.html]
robertom.ranieri
  • Observer

  • 5 posts
  • Corona SDK

Which line is the error happening on? Setting the ship.isBodyActive to false at the beginning of the function or the ship.isBodyActive = true inside the onComplete function?

 

The error is happening at the beginning of the function, where ship.isBodyActive is set to false.

 

Where is the code calling shipManage.restoreShip()? Can you share that?

 Yeah, sure thing!

local function onCollision(event)
	-- TODO: Create a file called collisions that returns handles collisions, or at least a collision table
	local lostLife, newScore, makeSound, remove = level.onCollision(event)

	-- remove collided objects
	if ((remove == nil) == false) then
		for i = #enemyTable, 1, -1 do
			if (enemyTable[i] == remove[1] or enemyTable[i] == remove[2]) then
				table.remove(enemyTable, i)
				break
			end
		end
	end

	-- Play explosion sound
	if (makeSound) then
		audio.play(soundManage.explosionSound)
	end

	-- Increase score
	score = score + newScore
	updateText()

	-- update lives or die
	if ((lostLife == 0) == false) then
		died = true
		-- Play explosion sound
		-- Update lives
		if (lostLife > lives) then
			lives = 0
		else
			lives = lives - lostLife
			updateText()
			-- Check on the player's lives
			if (lives <= 0) then
				endGame()
			else
				ship.alpha = 0
				died = false
				timer.performWithDelay(1000, shipManage.restoreShip(ship))
			end
		end
	end
end

Thank you in advance!
 



[TOPIC: post.html]
#4

SGS

[GLOBAL: userInfoPane.html]
SGS
  • Corona Geek

  • 2,120 posts
  • Corona SDK

  Best Answer

try

timer.performWithDelay(1000, function() shipManage.restoreShip(ship) end)

also use : notation instead of . notation as this will reference your object by default.  i.e.

ship:restoreShip()

You will need to restructure your functions accordingly.  But generally this is the preferred way.  

 

You then reference self within those functions and that will give you a direct reference to ship.



[TOPIC: post.html]
#5

robertom.ranieri

[GLOBAL: userInfoPane.html]
robertom.ranieri
  • Observer

  • 5 posts
  • Corona SDK

 

timer.performWithDelay(1000, function() shipManage.restoreShip(ship) end)

This worked. Is there a particular reason or is it just some quirk?

 

 

also use : notation instead of . notation as this will reference your object by default.  i.e.

Could you tell me more about this. So far I've built all the modules by putting functions in a table (including a create function when needed) with the dot. What's the difference?



[TOPIC: post.html]
#6

SGS

[GLOBAL: userInfoPane.html]
SGS
  • Corona Geek

  • 2,120 posts
  • Corona SDK

When you have (param) on a function call (within a timer and other places) it will get executed immediately.  Wrapping it with function() .... end turns it into a closure.

 

 

Using : means your functions will automatically have a reference to self and keeps everything clean. (more info https://www.lua.org/pil/16.html).  

ship = {}

function ship:restore()
    //reset ship
    self.x = 0
    self.y = 0
end

return ship

So using : notation means (with a slight mod) your original code would of worked

timer.performWithDelay(1000, ship:restoreShip)

  • sporkfin likes this

[TOPIC: post.html]
#7

robertom.ranieri

[GLOBAL: userInfoPane.html]
robertom.ranieri
  • Observer

  • 5 posts
  • Corona SDK

I know this is going off-topic, but I don't fully understand how I'd change my code to use the : notation as you described.
For instance, this is how I currently create the ship

local shipManage = {}

shipManage.create = function()
    local ship = {}
    ship = display.newSprite(mainGroup, sprites.spriteSheet, sprites.sequences_Ship) -- constants.sizingTable["ship"][1], constants.sizingTable["ship"][2]  _TODO_
    -- 4 is the frame number (declared in order earlier from the image sheet)
    physics.addBody(ship, {radius = display.contentWidth / 12, isSensor = true}) -- Defines 'physical box' of object and is set as object that can sense collisions but not bounce off
    ship.myName = "ship" -- Property used for collisions
    ship:scale(
        constants.sizingTable["ship"][1] / ship.contentWidth,
        constants.sizingTable["ship"][2] / ship.contentHeight
    )
    return ship
end

How would I change this portion of the code to accomodate the changes you've suggested making?



[TOPIC: post.html]
#8

SGS

[GLOBAL: userInfoPane.html]
SGS
  • Corona Geek

  • 2,120 posts
  • Corona SDK

. notation would be fine for create() as that creates the instance of ship.  You would then use : notation for anything else in the ship class (like moving, etc.)




[topic_controls]
[/topic_controls]