Articles Archive
Articles Search
Director Wiki
 

Memory

August 24, 1998
by Pat McClellan

Dear Multimedia Handyman,

I'm trying to create a memogame -- like the old Concentration game show -- with three columns and four lines. Everytime you click on a square, an image appears, if you click on another, if it's the same one, both will stay, otherwise they'll disappear. The game is won when all pairs are matched. So I guess I should use variables, but as I'm a beginner I'm really stuck with the lingo...

I would appreciate your help.
Thanx

Tonard

Dear Tonard,

There are a lot of variations on this game. I'm going to stick to your specifications in creating some Lingo that you can apply to all the sprites in a matching game. You could do what you describe with global variables, but I much prefer the behavior approach. It's much more reusable. The only global I'm going to use is gSpritesMatched, which will keep track of how many sprites have disappeared. This will tell us when the game is over.

In a movie script, let's set up a resetGame handler and an on idle handler to monitor whether the game has been won.


on startMovie
  resetGame
end
on resetGame
  global gSpritesMatched
  set gSpritesMatched = 0
  sendAllSprites (#reset)
end
on idle
  global gSpritesMatched
  if gSpritesMatched = 12 then
    alert "You win!"
    resetGame
  end if
end

Note that in the resetGame handler, I used a sendAllSprites() command. This is a very useful way to send a message to the behavior scripts attached to all sprites. In this case, all sprites will get the message to execute their reset handler (if they have that handler). In fact, as you'll see below, I'm going to use the sendAllSprites() command in the behavior itself to send messages to the other sprites. If you've never used sendAllSprites(), I suggest you check it out in the Lingo dictionary. Also read up on the sendSprite()command, which we'll also be using.

OK, now we need to figure out what properties the behavior is going to need. First, when we drag it onto the sprite, we need to be able to specify which cast member will be the "front" or unique member. All of the "backs" in my example are the same cast member, though this is not needed. I've set up this behavior so that you put the "backs" in the score, rather than the "fronts". We'll also need to give each sprite an ID, so that this ID can be compared with the ID of the other selected card. So, we'll start with properties called pFront and pMyID. I'm going to store the original cast member of the sprite in pBack.

We'll also want to keep track of whether the sprite is selected (flipped over) or not. For this, I'll use a simple flag property called pSelected, which will be set to FALSE or TRUE.

In order to make the card "disappear", I'm simply going to set the locH of the sprite to a number which is offstage. However, when we reset the game, we'll want the sprite to return to its original locH, so we'll need to capture this information and store it in a property called pLocH.

Finally, I like to use pMySpriteNum instead of writing out sprite the spriteNum of me everytime.

Now that we've got all our properties, let's figure out all the handlers we'll need. The on getPropertyDescriptionList handler will let the author specify pFront and pMyID. We'll set the other properties in the on beginSprite me handler.

We'll need a mouseUp (or mouseDown) handler to set the pSelected to TRUE, swap in the pFront member, and send out the message to check for a match. If a match is found, we'll need a makeMatch handler to move the sprites offstage and increment gPairsMatched. And if a match is not made, then we'll want a handler to flip the sprites back to pBack. Finally, we'll need a reset handler to set the sprite back to its original locH and cast member.

I think that's everything, so let's give it a crack, Nigel!


-- MatchGame behavior
-- Used to set up pairs of matching sprites
property pFront 
-- the "front" of the card
property pBack
-- the "back" of the card
property pMyID
-- matching pairs will have the same ID
property pSelected
-- state of the card, selected/not
property pLocH
property pMySpriteNum
global gSpritesMatched
on getPropertyDescriptionList
  set pmySpriteNum = the currentSpriteNum
  if pMySpriteNum = 0 then 
    set memdefault = 0 
  else
    set memref = the member of sprite pMySpriteNum
    set castlibnum = the castlibnum of memref
    set memDefault = member (the membernum of ¬
      member memref + 1) of castlib castlibnum
  end if
  set p_list = [#pMyID: [ #comment:"ID:",#format:¬
    #symbol,#default: #item1 ], #pFront:[ #comment:¬
    "Member:",#format: #graphic,#default: memDefault]]
  return p_list  
end
on beginSprite me
  set pMySpriteNum = the spriteNum of me
  --  put "Sprite" && pMySpriteNum && "is" &&¬
     pMyID && pFront
  set pSelected = FALSE
  set pBack = the member of sprite pMySpriteNum
  set pLocH = the locH of sprite pMySpriteNum
end
on mouseUp me
  set pSelected = TRUE
  set the member of sprite pMySpriteNum to pFront
  updateStage
  sendAllSprites(#checkMatch, pMyID, pMySpriteNum)
end
on checkMatch me, testID, testSpriteNum
  if pSelected = TRUE AND testSpriteNum <> ¬
    pMySpriteNum then
    if testID = pMyID then
      beep
      startTimer
      repeat while the timer < 60 -- delay
      end repeat
      makeMatch me
      sendSprite(testSpriteNum, #makeMatch)
    else
      beep
      startTimer
      repeat while the timer < 60 -- delay
      end repeat
      flipBack me
      sendSprite(testSpriteNum, #flipBack)
    end if
  end if
end
on makeMatch me
    -- do whatever you want
    set the locH of sprite pMySpriteNum to 800
    set pSelected = FALSE
    set gSpritesMatched = gSpritesMatched + 1
end
on flipBack me
    -- play annoying sfx if desired
    set the member of sprite pMySpriteNum to pBack
    set pSelected = FALSE
end
on reset me
  set the member of sprite pMySpriteNum to pBack
  set the locH of sprite pMySpriteNum to pLocH
end

Let's take a look at the way this behavior sends and receives messages from the other sprites' behaviors. In the mouseUp handler, a message is sent to all other sprites to execute their checkMatch handler. We go on to specify the ID and spriteNum of the sprite that is sending the message.

This message is received by all sprites -- including the sprite that sent the message. This is important, because the sprite that sent the message will ALWAYS have a matching ID, so we have to screen this sprite out by checking the spriteNum. Let's walk through an example. You click on sprite A. A sends out a message to sprites A through L -- remember, only A has been selected. In sprites A through L, the first line of the checkMatch handler runs an if statement that checks on 2 things. First, if the receiving sprite is NOT already selected, nothing else happens. So, that means that sprites B - L immediately exit the handler while sprite A proceeds. The second condition of the if statement checks to see if the spriteNum of the sending sprite is the same as the receiving sprite. In our case, A sent the message and A is also the receiving sprite, so A now exits and nothing else happens.

Now you select the second sprite in your pair, let's say D for example, and let's assume that it is not the correct match. D now sends out the message to A through L to checkMatch. Only A and D will make it past the first condition of the if statement, because they're the only ones with pSelected set to TRUE. Now, A and D will compare their own spriteNum to the spriteNum of the sending sprite. Since D matches, it will exit the handler and only A will continue. Now, sprite A will compare its pMyID to the sending sprite's pMyID. Since it doesn't match, A will delay for a moment (so the user can contemplate their mistake), then issue the flipBack command to itself. It also sends the flipBack message to the other selected sprite.

If the two selected sprites have matching IDs, the checkMatch handler will beep, pause a second, then send the makeMatch command to itself and the other selected sprite.

We can use the sendSprite command in the checkMatch handler (instead of the sendAllSprites) because we happen to know exactly which sprite to send the message to. That information was sent out as pMySpriteNum... and received as testSpriteNum.

This behavior serves as a great example of how powerful inter-sprite communications can be. I hope you can apply these principles in many other applications.

Patrick McClellan is Director Online's co-founder. Pat is Vice President, Managing Director for Jack Morton Worldwide, a global experiential marketing company. He is responsible for the San Francisco office, which helps major technology clients to develop marketing communications programs to reach enterprise and consumer audiences.

Copyright 1997-2024, Director Online. Article content copyright by respective authors.