Trouble with sprite in modular class

This the the class code:

-------------------- -- REQUIRE -------------------- -- STORYBOARD local sb = require "storyboard" -------------------- -- ENUM -------------------- local state = { idle = "idle", move = "move", eat = "eat", play = "play", sleep= "sleep" } -------------------- -- FISH CLASS -------------------- local fish = {} local fish\_mt = { \_\_index = fish } -- CONSTRUCTOR function fish.new( fishData ) -- Create the instance of the fish (sprite) local fishSheet = graphics.newImageSheet( fishData.sheetPath, fishData.sheetSetting ) local instance = display.newSprite( fishSheet, fishData.spriteSequence ) instance.state = state.idle -- Cant play animation here will crash randomly as this is a local copy instance.x = display.contentWidth \* 0.5 instance.y = display.contentHeight \* 0.5 return setmetatable( instance, fish\_mt ) end -- MEMBER FUNCTIONS function fish:playAnim() self:setSequence( self.state ) self:play() end function fish:changeState( newState ) if ( self.state ~= newState ) then self.state = newState -- NYI end end -- RETURN return fish

My problem:

  1. I can’t call setSequence or play outside or inside the class. Example:

    local obj = require “objclass” local function game() --local fishData = {Some data here} local fish = obj.new( fishData ) – fish:setSequence( “idle” ) – fish:play() – OR – fish:playAnim() end

Either uncommenting line 5 and 6, or uncommenting 8 will crash. Is there a way I can play animation of a sprite created inside a class? Any help would be appreciated.

Why can’t you just return the fish, instead of returning setmetatable?

I’m not well versed in metatables, but that’s what I get off the top of my head.

Something like this:

[lua]


  1. – REQUIRE

  2. – STORYBOARD
  3. local sb = require “storyboard”
  4.  

  5. – ENUM

  6. local state = {
  7.     idle = “idle”,
  8.     move = “move”,
  9.     eat = “eat”,
  10.     play = “play”,
  11.     sleep= “sleep”
  12. }
  13.  

  14. – FISH CLASS

  15. local fish = {}
  16. local fish_mt = { __index = fish }
  17.  
  18. – CONSTRUCTOR
  19. function fish.new( fishData )
  20.     – Create the instance of the fish (sprite)
  21.     local fishSheet = graphics.newImageSheet( fishData.sheetPath, fishData.sheetSetting )
  22.     local instance = display.newSprite( fishSheet, fishData.spriteSequence )
  23.  
  24.     instance.state = state.idle
  25.     – Cant play animation here will crash randomly as this is a local copy
  26.     instance.x = display.contentWidth * 0.5
  27.     instance.y = display.contentHeight * 0.5
  28.   setmetatable( instance, fish_mt )
  29.     return instance
  30. end
  31.  
  32. – MEMBER FUNCTIONS
  33. function fish:playAnim()
  34. self:setSequence( self.state )
  35. self:play()
  36. end
  37.  
  38. function fish:changeState( newState )
  39.     if ( self.state ~= newState ) then
  40.         self.state = newState
  41. – NYI
  42.     end
  43. end
  44.  
  45. – RETURN
  46. return fish

[/lua]

Why can’t you just return the fish, instead of returning setmetatable?

I’m not well versed in metatables, but that’s what I get off the top of my head.

Something like this:

[lua]


  1. – REQUIRE

  2. – STORYBOARD
  3. local sb = require “storyboard”
  4.  

  5. – ENUM

  6. local state = {
  7.     idle = “idle”,
  8.     move = “move”,
  9.     eat = “eat”,
  10.     play = “play”,
  11.     sleep= “sleep”
  12. }
  13.  

  14. – FISH CLASS

  15. local fish = {}
  16. local fish_mt = { __index = fish }
  17.  
  18. – CONSTRUCTOR
  19. function fish.new( fishData )
  20.     – Create the instance of the fish (sprite)
  21.     local fishSheet = graphics.newImageSheet( fishData.sheetPath, fishData.sheetSetting )
  22.     local instance = display.newSprite( fishSheet, fishData.spriteSequence )
  23.  
  24.     instance.state = state.idle
  25.     – Cant play animation here will crash randomly as this is a local copy
  26.     instance.x = display.contentWidth * 0.5
  27.     instance.y = display.contentHeight * 0.5
  28.   setmetatable( instance, fish_mt )
  29.     return instance
  30. end
  31.  
  32. – MEMBER FUNCTIONS
  33. function fish:playAnim()
  34. self:setSequence( self.state )
  35. self:play()
  36. end
  37.  
  38. function fish:changeState( newState )
  39.     if ( self.state ~= newState ) then
  40.         self.state = newState
  41. – NYI
  42.     end
  43. end
  44.  
  45. – RETURN
  46. return fish

[/lua]

@JeffreyQjr: I’ve ever seen metatables before, but I would think that’s the source of your problem. Could you post the error you’re receiving? Another way to do this would be to attach the member functions to the spriteObject, and return the spriteObject when .new is called. That’s how I’m handling this situation in my game.

Good luck!

  • David

Hello, thanks for the reply.

This was quite long ago when I was trying to test out how modular classes work as shown here: http://www.coronalabs.com/blog/2011/09/29/tutorial-modular-classes-in-corona/

I’ve changed my approach to this without using meta table, so I no longer have the code to reproduce this unfortunately. However I think the main problem is that the instance isn’t a table like what is shown on the above link. But I can’t be 100% sure because I am not really good with meta tables and not sure how they work.

Just in case you needed an answer to the original question; I suspect it’s because you can’t setmetatable on a Corona display object - as they already have metatables attached.

The solution is often to hold a proxy to the display object as part of the object: i.e:

[lua]

function fish.new( fishData )
     – Create the instance of the fish (sprite)
     local fishSheet = graphics.newImageSheet( fishData.sheetPath, fishData.sheetSetting )
     local instance = {}

     instance.sprite = display.newSprite( fishSheet, fishData.spriteSequence )
 
     instance.state = state.idle
     – Cant play animation here will crash randomly as this is a local copy
     instance.x = display.contentWidth * 0.5
     instance.y = display.contentHeight * 0.5
   setmetatable( instance, fish_mt )
 
     return instance
end

[/lua]

Then makes the calls that are currently failing on the proxy: self.sprite:setSequence()

@JeffreyQjr: I’ve ever seen metatables before, but I would think that’s the source of your problem. Could you post the error you’re receiving? Another way to do this would be to attach the member functions to the spriteObject, and return the spriteObject when .new is called. That’s how I’m handling this situation in my game.

Good luck!

  • David

Hello, thanks for the reply.

This was quite long ago when I was trying to test out how modular classes work as shown here: http://www.coronalabs.com/blog/2011/09/29/tutorial-modular-classes-in-corona/

I’ve changed my approach to this without using meta table, so I no longer have the code to reproduce this unfortunately. However I think the main problem is that the instance isn’t a table like what is shown on the above link. But I can’t be 100% sure because I am not really good with meta tables and not sure how they work.

Just in case you needed an answer to the original question; I suspect it’s because you can’t setmetatable on a Corona display object - as they already have metatables attached.

The solution is often to hold a proxy to the display object as part of the object: i.e:

[lua]

function fish.new( fishData )
     – Create the instance of the fish (sprite)
     local fishSheet = graphics.newImageSheet( fishData.sheetPath, fishData.sheetSetting )
     local instance = {}

     instance.sprite = display.newSprite( fishSheet, fishData.spriteSequence )
 
     instance.state = state.idle
     – Cant play animation here will crash randomly as this is a local copy
     instance.x = display.contentWidth * 0.5
     instance.y = display.contentHeight * 0.5
   setmetatable( instance, fish_mt )
 
     return instance
end

[/lua]

Then makes the calls that are currently failing on the proxy: self.sprite:setSequence()