Seemingly strange nil function problem with Lua

I’m just writing some helper stuff so that it can be reused across my games, one of these things is a very simple sound manager with a simple playlist. However I’m getting a very strange (at least to me, it’s probably a simple foolish thing that I have done) problem.

I have uploaded the code (and some small free .mp3s just for testing) to here - http://dl.dropbox.com/u/571145/Media.zip

Basically what happens is that when a song finishes it calls the onComplete event and then in the listener for this I am trying to call the next function yet it is saying that the method is nil yet as a test I’ve put in a print function that uses the getName function and that works fine. It’s easier to just look at the code though.

The offending lines are in sound.lua at line 49 (in the listener) and 134 (the next function). If anyone could have a look that would be great as I’m pulling my hair out to try to work out what I have done wrong.

Graham

[import]uid: 5833 topic_id: 1371 reply_id: 301371[/import]

Graham,

I briefly looked at the code and found the problem has to do with the value of “self” in the onSongComplete method. If you remove “self:” from the next() method and from the call, the call to next() works but the call to self:play() fails. I’m not sure why the call the self:getName() works but self:next() fails.

I’ll look at it later if I have time.

-Tom [import]uid: 6119 topic_id: 1371 reply_id: 3821[/import]

It is pretty easy to spot what you are doing wrong if you run into this problem before.

You are using a function as target for onComplete and expect it to carry over the object “magically”

I think this is something people do not easily grasp… and there are few if none examples in the sdk how to work with objects! Which is what everybody does in a bigger project (hopefully).

The basic fact is: A function call does not have any magical “self”.

You need to use the object (a table) as target for onComplete and use the table listener named “completion” for this to work.

This means that you need to implement a method named “completion” for this kind of event. It will be called when the song is over and you specified “self” (a table / aka object) for onCompletion.

Look at this example Code:

function object:completion(event)  
 print("song has completed")  
 -- restart with the same song  
 self.playSound(self.songname, self)  
end  
  
function object:playSong(name)  
 self.songname=name  
 media.playSound(name, self)  
  
end  
  
local o=myNewObject() -- creates an "o" object with above methods  
  
o:playSong("test.mp3")  
  

This example will call the completion() method of “o”

Which would be “object:completion()” and self would be available … and here used to find the name which restarts the song with the same name… and uses self again…

So it is infinitely calling itself on the song endings.

Hope that helps to fix your code!

BTW: A Problem can be that the same event is generated for other stuff… like choosing media from the device photo gallery. Those two events could not be distinguished in the case the user cancels the request (because if not the event contains a target which would make it distinguishable)
[import]uid: 6928 topic_id: 1371 reply_id: 3822[/import]

That is brilliant, it’s fixed it! Such a simple fix, I will certainly remember this :slight_smile:

Also some people don’t use objects? That could get messy fast I’m guessing. [import]uid: 5833 topic_id: 1371 reply_id: 3826[/import]