logo

 

     
 
Home
Site Map
Search
 
:: Bitwise Courses ::
 
Bitwise Dusty Archives
 
 
 

rss

 
 

ruby in steel

learn aikido in north devon

Learn Aikido in North Devon

 


Section :: ActionScript
- Format For Printing...

Adventures in ActionScript - part two

Connecting up the Rooms
Wednesday 11 March 2009.
 

This series explains how to use ActionScript - the language behind Adobe’s Flash graphics and Flex framework - to program an adventure game. In part one, I created a simple ‘map’ which was an ‘associative array’ (a ‘hash’ or ‘dictionary’ of key-value pairs) containing user-defined Room objects. Each room had ‘exits’ which took the form of strings (each string being the name of an ‘adjoining’ room). This string was used as a key into the ‘map’ to locate a room with the matching name.

In principle, I might just as easily have used a simple array or rooms indexed from 0 to 9 (say) to represent a map of ten rooms). Each ‘exit’ could then have been an integer - so if the North exit were 1 that would mean it leads into the room at index 1 in the array. Using string keys instead of integers made the map a bit more easily readable but, essentially, moving from one location to another still required me to obtain a value (e.g. the string at exit N) and then use that value to ‘look up’ a room. In short, whether you use a simple array or an associative array as your ‘map’, it is really nothing more than a ‘lookup list’. It does not really and truly represent a multi-connected ‘map-like’ structure since the rooms themselves aren’t really and truly connected to other rooms.

The screenshots accompanying this article show the Amethyst Flex IDE. But you may load the code into an ActionScript or Flex IDE or editor of your choice
Download source code: adventure2.zip

This month we’ll take a far more radical approach to world building. We’ll get rid of the map completely. From now on, each exit in each room will lead directly into an adjoining room. Before we can do that, we first need to redefine the Room class. Up to now, each Room object contained four string variables to indicate the adjoining rooms (or ‘No Exit) and these variables were initialized in the Room’s constructor:

private var _n:String;
private var _s:String;
private var _w:String;
private var _e:String;
               
public function Room(aN:String,aS:String,aW:String,aE:String){                       
        _n = aN;
        _s = aS;
        _w = aW;
        _e = aE;
}

In my new version, each exit won’t be a string, it will be a Room object. So these are now the four direction variables plus an extra string variable to store the Room’s name:

private var _name:String;
private var _n:Room;
private var _s:Room;
private var _w:Room;
private var _e:Room;

Now, a problem arises with the constructor. Since each exit now leads to a Room object we must ensure that all the Room objects have been created before assigning them to the direction variables. This constructor won’t work:

// This is incorrect!
public function Room(aName:String, aN:Room, aS:Room, aW:Room, aE:Room) {
        _name = aName;
        _n = aN;
        _s = aS;
        _w = aW;
        _e = aE;
}

If we used the above constructor, consider what would happen if we created the first room and set its south exit, _s, to the second room. The trouble is that the second room hasn’t been created yet so it cannot be assigned to the _s variable. If we try to do so, the program will crash unceremoniously.

There is a pretty simple way around this, however. Use the constructor to create a simple room with no exists (each variable is assigned ‘null’):

public function Room( ) {
        _name = "A Room";
        _n = null;
        _s = null;
        _w = null;
        _e = null;
}

Only once all the rooms in the game have been created, start to ‘wire’ up their exits. We do this by creating an init() method to initialize each room object with its data (here its name and the adjoining Room objects at each of the four compass points):

public function init( aName:String, aN:Room, aS:Room, aW:Room, aE:Room ) {
        _name = aName;
        _n = aN;
        _s = aS;
        _w = aW;
        _e = aE;
}

The main file of the application (Wombat.mxml) starts by creating all the rooms in the game (with no exits), including one ‘special’ Room called NoExit which is assigned the value null to indicate that no room exists in any direction that ‘leads to’ the NoExit object...

private var NoExit:Room = null;
private var Cave:Room = new Room( );
private var TreasureRoom:Room = new Room( );
private var TrollRoom:Room = new Room( );
// and so on...

In the Application tag at the top of the file I have added this:

applicationComplete="init()"

This causes my application’s init() function to execute once the application itself has been created. The init() function now calls my Room.init() method on each Room object, assigning to it some actual Room objects (the Room variables which I have already defined) at each exit:

                  // N,            S,            W,            E
Cave.init("Cave", NoExit, CrystalDome, TreasureRoom, DragonsLair );
TreasureRoom.init("Treasure Room", NoExit, TrollRoom, NoExit, Cave );
TrollRoom.init( "Troll Room", TreasureRoom, NoExit, NoExit, CrystalDome );
/// etc.

Since each room now contains direct links, at its exits, to other rooms, I no longer need a lookup list (an array or associative array) to determine which room is found at a given exit. As a consequence, I can dispense with the ‘map’.

Note that when a room is passed as an argument, this is not a new copy of the room but a reference (a pointer) to the original Room object. In the example above, you’ll see that the TrollRoom leads to the TreasureRoom in its North direction while the Cave leads to the TreasureRoom in its Eastern direction. In both cases this is a reference to the same Room object identified by the TreasureRoom variable.

The end result is that the Rooms are really wired up to one another; their exists really lead into other room objects rather than, as before, providing keys into a lookup list. Now all I have to do is rewrite the moveTo() method. This method moves the player from the current location (here) into the new location (newroom) or else display a message saying that there is no exit in that direction. Rewriting the method to operate on Room objects is incredibly easy to do. All I have to do is create here and newroom Room objects, check whether there is a room in the specified direction and, if so, assign that room to the current Room variable, here:

private function moveTo( aDir:String ):void {
        var newroom:Room;
        switch( aDir.toLowerCase( ) ) {
                case "n":
                        newroom = here.n;
                        break;
                case "s":
                        newroom = here.s;
                        break;
                case "w":
                        newroom = here.w;
                        break;
                case "e":
                        newroom = here.e;
                        break;
        }
        if( newroom == NoExit ) {
                ta.text += "No Exit in that direction!\n";
        } else {
                here = newroom;
                ta.text += "You have moved into the " + here.name + "\n";
        }
}

If you want to play around with this, download all the source code in a Zip archive. This can be loaded into any IDE or editor of your choice. If you are using Amethyst you can load up the Wombat2.sln solution file.

The proof of the pudding is in the debugging! Here I have placed a breakpoint using the Amethyst IDE . In the moveTo() method I have hovered over the newroom variable. As you can see, this has opened up some serious drilldown possibilities. Since the exits of each room object point to other room objects I can drill down into a second room at one of the first room’s exits and then drill down into a third room at one of the second room’s exits - and so on. In fact, since all the rooms are linked to one another, there is, in principle, no limit to the number of times I can drill down as I move from one linked room to the next

In the next part of this series the adventure I’ll add some treasures to the rooms and let the adventurer take them when he (or she) finds them...

AddThis Social Bookmark Button

source code


290 kb


Home