Articles Archive
Articles Search
Director Wiki

Lists for Item collection in a Game

August 15, 1999
by Pat McClellan

Dear Multimedia Handyman,

I'm making a game that allows you to pick up objects as you walk around. The objects are automatically placed in your inventory when you click on them.

What I need is some help with the lingo that keeps track of all these objects. If I happen to go back to the same room that I already picked up an object, I need the lingo to say that the object is not there anymore and not reveal it again...

And If somehow I can work that out, then I need to be able to save a user's game.

Gavin Rossow

Dear Gavin,

This sounds like a job for...lists! Lists are wonderful things, so versatile and truly indispensible for almost any game I can think of. There are two types of lists: linear and property. A linear list can hold a series of almost anything you want: integers, symbols, float values, strings, even other lists. You can add and delete things from the list easily, and you can access the value of items in the list by referencing the item's order in the list. For example...

set myList = ["key", "gold", "flask", "potion"]
put myList
-- ["key", "gold", "flask", "potion"]
add myList, "cloak"
put myList
-- ["key", "gold", "flask", "potion", "cloak"]
deleteOne myList, "flask"
put myList
-- ["key", "gold", "potion", "cloak"]
whichItem = myList[3]
put whichItem
-- "potion"

Note in that last example, that the third item in myList was accessed with the syntax of naming the list, followed by bracketing the item we want.

Linear lists are very handy for lots of applications, but in your situation, I think a property list is more appropriate. A property list keeps track of items by category (by property) rather than by order. All property lists are a series of property:value pairs. In your game, the order of the items in the list is irrelevant. In fact, it would be very difficult for you to keep track of the items in the list using a simple linear list. In your game, you have a finite set of objects which can be picked up. So let's initialize a property list that includes all of those items as properties, and each will have a value of either 1 (if it has been picked up) or 0.

set myList = [#key:0, #flask:0, #potion:0, #cloak:0, #gold:0]
put myList
-- [#key: 0, #flask: 0, #potion: 0, #cloak: 0, #gold: 0]

Now, when an item is clicked on (picked up), we'll simply need to set the corresponding value in myList to 1.

myList.flask = 1
put myList
-- [#key: 0, #flask: 1, #potion: 0, #cloak: 0, #gold: 0]

Since these items need to disappear once they've been picked up, the sprites representing the items will need to have a behavior which checks the list. If the value for its particular item is 1, then it "knows" that it has been picked up and therefore should disappear offscreen. Obviously, the list needs to persist throughout the game and be accessible to these sprites, so be sure to declare the list as a global variable.

One variation on this plan is that some things might not be finite. For example, you might want to have gold be something that can continue to be accumulated. So instead of gold having a 1 or 0 value, it could increase by some increment. Here's a demo movie.

This movie is available for download in Mac or PC format.

For your Lingo scripts, start by initializing myList. I'll do it in the startMovie script. One note about initializing variables (including lists) in startMovie scripts: if your program jumps from movie to movie then the startMovie handler in any particular movie executes each time you enter that movie. That means that your variables will be re-initialized -- losing your user's status. So, take a look at what I do in this startMovie script.

on startMovie
  global myList
  if voidP(myList) then
  end if
end startMovie
on initializeList
   myList = [#key:0, #flask:0, #potion:0, ¬
     #cloak:0, #gold:0]
end initializeList
on stopMovie
end stopMovie

I check to see if the variable myList is void. If it is, then I initialize it. But if it is not, then I know that we must have initialized it elsewhere and I don't want to change it. One other item to note... in authoring, it's very helpful to have a stopMovie script to clearGlobals. Otherwise, myList would not be void as it should be when we start the movie again. This clearGlobals thing is really only an issue in authoring.

We'll need a "collectItem" behavior for each item. I'll make it so that when we drop it on an item, there will be a pulldown menu that allows us to select which item it is.

That functionality is created in the getPropertyDescriptionList handler by adding a range. First I create a list (linear) of all the items I want to choose from. Then, I specify #range: itemList just below. If you have different items, you'll want to change the items listed in itemList. This is a very handy skill to have, so if you've never played around with a getPropertyDescriptionList ghandler, take the time to learn it. (Gold is not listed in itemList because we'll use a different behavior for that.)

-- collectItem behavior
-- copyright © 1999, ZZP Online, LLC
-- free use for DOUG readers
property spriteNum, pItem
global myList
on getPropertyDescriptionList me
  itemList = [#cloak, #key, #flask, #potion]
  pdlist to [:]
  addprop pdlist, #pItem, [#comment:"Which item?", ¬
    #format:#symbol, #default:#cloak, #range: itemList]
  return pdlist
end getPropertyDescriptionList
on beginSprite me
  if myList[pItem] = 1 then
    sprite(spriteNum).locH = 1000
  end if
end beginSprite
on mouseUp me
  myList[pItem] = 1
  sprite(spriteNum).locH = 1000
end mouseUp

This is a very easy behavior. When the sprite first appears (beginSprite), it checks to see if its value in myList is 1. If so, it knows that it has been collected already, so it moves itself offstage to a locH of 1000. Otherwise, it does nothing and appears on the stage. When the user clicks on it, it sets its own value in myList to 1 and moves itself offstage.

For the gold behavior, we want it to act a bit differently. If you click on the gold, it will add some preset value to your gold tally in myList and disappear offstage. However, if you return to the room later, the gold reappears -- allowing you to collect more of it. Here's the collectGold behavior.

-- collectGold behavior
-- copyright © 1999, ZZP Online, LLC
-- free use for DOUG readers
property spriteNum, pValue
global myList
on getPropertyDescriptionList me
  set pdlist to [:]
  addprop pdlist, #pValue, [#comment:"Value?", ¬
    #format:#integer, #default:10]
  return pdlist
end getPropertyDescriptionList
on mouseUp me
  myList[#gold] = myList[#gold] + pValue
  sprite(spriteNum).locH = 1000
end mouseUp

This behavior's getPropertyDescriptionList handler doesn't need to have the pulldown for other items; just a field to allow you to specify the value of the gold.

It also doesn't have a beginSprite handler. Although the gold disappears when you click it (mouseUp handler), when you return to the room, there's no beginSprite handler to check to see if it has been clicked before. Therefore you can collect the gold each time you pass through this room.

Saving the user's game is as easy as saving myList. You'll simply need a way for the user to identify himself/herself. Perhaps you can have an editable field as a login, and use that ID as the prefs name. For more information on saving the user's game, see this article.

Good luck with your game!

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-2019, Director Online. Article content copyright by respective authors.