Sending Messages

Objects communicate with each other by 'sending messages'. Objects respond to messages using their 'methods', which are like 'handlers'. Sending a message is like 'calling a function' or 'evoking a handler'. The syntax for sending a message directly to an object is like this:

  anObject = script("Classname").new()

  -- store the reference in a variable - we will use this 

  -- reference to send messages to the object

  -- using any of the following syntax

  MessageName(anObject, arguments) -- 'Old style'

  anObject.MessageName(arguments) -- 'Dot style'

  Call (#MessageName, anObject, arguments) -- 'Call style'

And to receive the message, the object needs to have an "on MessageName" method.

With each different syntax, you will notice that the message is directed to a variable holding a reference to the object. To send a message directly to an object, you need to know the 'address' of the recipient object. This reference acts as such an 'address' to the object.

It is also possible to send messages to sprites. Messages addressed to sprites get forwarded to the objects contained in the sprite scriptInstanceList:

sendSprite(1, #MessageName, arguments)

You can also shout the message to all sprites:

sendAllSprites(#MessageName, arguments)

The disadvantage of shouting is that you cannot be sure who is listening - the wrong object may receive the message. It is also slower that sending messages directly since Director will need to check each and every sprite.

Receiving Messages

When Director sends a message to an object, it always passes a reference to the receiving object as the first parameter. By convention, this is called the 'me' parameter.

 on MessageName (me, args)

   put me.string && "received the message"

end

This parameter is important because it gives us a reference to the particular object that received the message. We can use this parameter to access the object's properties and methods:

on MessageName (me, args)

  me.AnotherMethod() -- access other methods of this particular object

  put me.SomeProp -- access the properties of this object

end

In other programming environments, this reference is usually labelled "this" and is implicit - you do not need to explicitly list it as a parameter. Thus, a similar method an a more orthodox language class might look like this

function MessageName (args) {

	this.AnotherMethod();// access other methods of this particular object

	trace this.SomeProp; //access the properties of this object

	}

It is important to remember that this instance parameter is always the object that receives the message. For example, if you create this behaviour called "Class.HelloWorld" and add it to sprite 1

[Behaviour called "Class.HelloWorld"]



on SayHi (me)

  put me.string & " says hi"

end

Now the object referenced by "me" can be different depending on which object you send the message to:

sendSprite(1, #SayHi)

-- "<offspring "Class.HelloWorld" 6 7a19bc0> says hi"



sprite(1).sayHi()

-- "(sprite 1) says hi"



call(#SayHi, script("Class.HelloWorld"))

-- "(script "Class.HelloWorld") says hi"

In this example, we have sent the #sayHi message to three completely different objects. All three objects were created using the same script, but are all independant of each other and can have their own properties.

Another important point to remember is that this "me" parameter is sent regardless of whether you list it as a parameter in the receiving method. To see this, add a behaviour to a sprite like this:

on mouseUp

  repeat with i = 1 to the paramCount

    put "Parameter" && i && param(i)

  end repeat

end

You will see that instance of the behaviour is still there.

Sending messages without an address

If you ever send a message without specifying where to send it to, Director tries its hardest to send it anyway (before giving up and generating a 'handler not defined error'). The first place it sends the message is the current script object. If there is no handler for this message, then Director looks in all the movie scripts. In either case, Director does not pass a reference to the recipient object as a parameter. Thus, if you have a behaviour like this

[A Behaviour]



on mouseUp (me)

  foo()

end



on foo (me)

  put me.string & " GOT THE FOO"

end

Clicking the sprite would send a #MouseUp message to the instance. However, when that method calls the #Foo handler, the 'me' parameter will be void since we did not specify which object to send #Foo to.

Common Issues and Scenarios

It is common to have a couple of sprites wanting to send messages to each other. For example, imagine sprite 1 contained a Quicktime movie with a behaviour that handled preloading and playing the media, and sprite 2 contained a play/pause button with a 'button' behaviour, sprite 3 contains a fast-forward button (etc, etc). Now, the obvious way sprite 2 can send a message to sprite 1 (such as "play") is like this:

sendSprite(2, #StartPlayingTheMovie)

However, the problem with this is that if you need to move the sprites around, you would need to search through all your lingo looking for where you specified which sprite channels were used for what. A better way might be to have the sprites look for each other, and then exchange addresses. For example, the play button might do something like this:

on beginSprite (me)

	addressBook=[:]

	sendAllSprites(#CollectQTPlayerAddress, addressBook)

end

... and the playerSprite might have a method like this

on CollectQTPlayerAddress (me, addressBook)

	addressBook.addProp(#QTPlayer, me)

end

Now, when the play button wants to send a message to the Player, it can do it directly like this:

QTPlayerObj = me.addressBook[#QTPlayer]

if QTPlayerObj.ilk = #instance then 

   QTPlayerObj.StartPlayingTheMovie()

end if
First published 02/09/2005