Home 0 SoundRaider 0 Director 0 Faust 0 Nectarine 9 0 Personal 0
 
 XObjects
 Shockwave Gallery
 Technical Guide for Director Developers
 Director Tips and Tricks
 
 Director Users Group
 DUG Members List

© Andy Wilson, 1998

Tips and Tricks: Pop and Push

This month I’ll be looking at a simple technique you can use to manage your data in a Director application. This technique involves managing a data stack. The concept of a data stack is very simple. It means that you think of your data as being arranged in a stack so that when you add data it goes to the top of the stack, and when you retrieve data it is taken from the top. This is know as ‘pushing and popping’: you ‘push’ data onto the top of the stack when you want to store it and ‘pop’ it when you want it back.

The idea is that data is piled up on the stack one item at a time and then popped back out in reverse order. This can be a very handy way to think about your data in some circumstances. For example, assume you have built a game that involves the user navigating their way around a maze of some sort. Assume that each choice the user makes takes them to a new frame in your movie. At any point you want to allow the user to be able to step back to their previous position before moving forward again. A stack would come in very handy here – simply ‘push’ the frame number onto the stack each time the user makes a decision then, when they choose to step back, pop their last position off the top of the stack and take them to that frame. This way, even if the user had been playing the game for hours, visiting hundreds of frames, they would be able to step back through every decision they had made in reverse order.

There are lots of other situations where the same technique would come in handy. For example, let’s say that you build a ‘browser’ that allows users to look at different web pages in your Director application. As long as you pushed the users new URL onto the stack each time they moved to a new location you could build a back button that returned the user to their previous positions just by popping them back off the stack. They would then be able to step back through every page they had visited in that session.

The way we are going to implement this in Director is really very simple, since it only really involves using a combination of parent scripts and lists. To kick off we’ll write a simple parent script to hold the stack data. To do this, open a new script window and type in the following lingo;

property stackList

on new me
  set stackList = []
  return me
end

Remember to click on the properties button for the script and change it’s type to ‘Parent’ since we are going to use this as a parent script to create multiple stack objects. Remember also to give the script a name when you have entered the code, since you have to call the script by name whenever you create a new object. In this example I’m going to call my script ‘Stack’. If you do this, your cast window should look something like:

All we’ve done so far is create the core of the stack object – just enough to allow us to create a stack without giving it any real functionality. Nevertheless, it allows us to create stacks as follows;

set stack1 = new (script "Stack")
set stack2 = new (script "Stack")

put stack1
-- <offspring "Stack" 2 2321c56>
put stack2
-- <offspring "Stack" 2 2321cb0>

set stack1 = EMPTY
set stack2 = EMPTY

The two objects we create here actually do nothing of any use. The parent script does just enough to allow us to create objects in this way. Let’s take the next step and write the code that allows us to push data up onto the stack. Obviously you will be adding this code to the Stack parent script, thus adding a new method to the objects that are created from this script;

on push me,  val
  append (stackList, val)
end

Notice that the parent script declares a property stackList, and also that the on new handler that we call when we create a child object initializes this property to [ ], an empty list. This means that each time a new stack is created from the parent script it starts of with a list property which we initialize to [ ]. The push handler we have just added to the object allows us to add a new value to this list. When we call the push handler we pass to it a value, val, which is simply appended to the end of the objects’ stackList property.

The other half of our objects’ functionality involves writing a pop handler that allows us to retrieve any values we have already pushed up on to the stack. The code for the pop handler is as follows;

on pop me
  if not count (stackList) then return #error
  set var = getLast (stackList)
  deleteAt (stackList, count (stackList))
  return var
end

This code checks to see if there are any values up on the stack. If not, it returns an error signal. Otherwise it returns the last value pushed on to the stack and deletes that item from the stack. To push a value up on to the stack and then pop it back out we would do something like this;

set myStack = new (script "Stack")
push (myStack, 100)
put pop (myStack)
-- 100

All I’ve done here is create a new stack object, myStack, pushed up an arbitrary value, the integer 100, then popped it back off the list. Note that each time a value is popped off the stack it is actually removed from the top of the stack completely – that is the whole point of a stack. That means that if, as in this example, we have only pushed one item up onto the stack then we can only pop one item back off before receiving an error;

put pop (myStack)
-- #error

To get a better idea of how our stack works, lets kill off our existing object create a new one, push a series of values onto it then pop them all back out again. In the previous example I pushed an integer onto the stack. In fact, since the stack is implemented as a lingo list, you can push up any type of data supported by lingo;

set myStack = EMPTY

set newStack = new (script "Stack")
push (newStack, 100)
push (newStack, "Lingo")
push (newStack, 2.4023)
push (newStack, [2, "Andy", 4.2])
push (newStack, [#name:"Andy", ¬
	#address:"andyw@dircon.co.uk"])
push (newStack, the script of ¬
	member "Stack")

 
put pop (newStack)
-- (script "Stack")
put pop (newStack)
-- [#name: "Andy", ¬
	#address: "andyw@dircon.co.uk"]
put pop (newStack)
-- [2, "Andy", 4.2000]
put pop (newStack)
-- 2.4023
put pop (newStack)
-- "Lingo"
put pop (newStack)
-- 100
put pop (newStack)
-- #error

Remember that the code we've written is in the form of a parent script, which means we can use it to create as many child objects as we like. Each child will have it’s own stackList property, which means that each can be used to manage and maintain a separate stack. And that’s really all there is to it. We’ve developed what is potentially a very powerful tool from just a few lines of lingo. Just to remind you, the entire Stack script looks like this;

- - "Stack" parent script
property stackList

on new me
  set stackList = []
  return me
end

on pop me
  if not count (stackList) then return #error
  set var = getLast (stackList)
  deleteAt (stackList, count (stackList))
  return var
end

on push me,  val
  append (stackList, val)
end

Having explained the core techniques involved in writing a stack object I want to finish by making a few modifications to allow us to use this technique to implement the back button I talked about at the start of the article. To do this you will first need to create a new parent script – call it 'Navigator', with code as follows;

-- "Navigator" parent script
property stackList

on new me, startFrame
  set stackList = []
  navigateTo me, startFrame
  return me
end

on backTo me
  if count (stackList) then
    set newFrame = getLast (stackList)
    if (count (stackList) > 1) then 
      deleteAt (stackList, count (stackList))
    end if
    go to frame newFrame
  end if
end

on navigateTo me, newFrame
  append (stackList, newFrame)
  go to frame newFrame 
end

You will need to do a few other things too. First, create a movie script as follows;

global navObject

on startMovie
  set navObject = new (script "Navigator", 1)
end

on enterFrame
  put the frame into field "frameNum"
end

on exitFrame
  go to the frame
end

Now, create two buttons, Navigate and Back, and attach cast member scripts to them as follows;

- -  code for ‘Navigate’ button
global navObject

on mouseUp
  navigateTo (navObject, random(60))
end

- -  code for ‘Back’ button
global navObject

on mouseUp
  backTo (navObject)
end

Finally, create a field member ‘frameNum’ and place it, along with the Navigate and Back buttons on all frames from 1 to 60 in your movie. What happens here is that the startMovie handler creates a Navigation object which is basically a slightly modified Stack object – the main difference is that it not only pops and pushes the stack but also navigates to a new frame every time it does so. When the Navigate object is created it takes the movie to a frame, in this case frame 1. Each time the Navigate button is clicked the user is taken to a new frame at random. When the Back button is clicked the user is returned to the last frame they visited. I also modified the code so that if the user tries to step back from the first frame nothing happens. Now you have all the elements you’ll need to create a game that allows the user to step back through all the steps they’ve made.

As usual I’ve put this article on the web along with all the previous articles in this series. I’ve also included a version of the code I’ve described here as a zipped file for you to download.

 
There are currently users connected. You have viewed 1 pages. Unless otherwise stated, all content is ©1996-2003 Andy Wilson. If you have any questions or suggestions you can mail me: andyw at dircon dot co dot uk. This site is hosted by LShift Ltd.