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...

How to write an adventure game in ActionScript

Fun with Flash!
Tuesday 15 April 2014.
 

Huw Collingbourne goes back to the ’80s to show how to bring adventure games up to date in ActionScript and Flash

Let me take you to a time way before the advent of PlayStation and XBox, when Assassin’s Creed and Grand Theft Auto hadn’t even been dreamt of. We’re going back to the late 1970s and early ‘80s when most computers didn’t even have graphics, let alone multimedia!

This video gives an overview of how I wrote my simple ActionScript Adventure Game project

This was the era of black screens and glowing green text. But even though there were no graphics, there were games – some very good ones too! These were games such as Colossal Castle and Zork. They were called adventure games or “interactive fiction” and they allowed the player to travel around hugely complex worlds, collecting treasures, fighting monsters, breaking into houses or wandering into dark corners and getting eaten by grues...

And it was all done in text. Each location was described in text. Each command was written in text: “Take the ring” the game-player would write; and the game might respond, “Which ring do you mean – the golden ring or the emerald ring?” There was a certain magic to those games which, to my mind, is missing from modern games. Just like books, they sucked the reader or player into worlds of the imagination in a way that graphical games – with all their fully formed 3D reality - simply don’t.

From the programmer’s point of view, writing an adventure posed all kinds of technical challenges: how to parse the user input into meaningful commands; how to create a data-structure capable of representing a ‘map’ of linked locations and move the player around on that map; how to populate locations with objects and permit the player to take those objects or drop them in new locations; how to save and restore the game state - and so on.

It turns out that ActionScript is a great language for writing text adventures. Don’t be fooled into thinking that it’s just a scripting language for Flash graphics. On the contrary, it is a deeply object-oriented language that can provide everything we need to create complex object hierarchies, design a user interface and save and restore game data. So, without more ado, let’s begin the adventure...

Maps By Numbers

I am going to begin by writing a very short program to illustrate one way in which we can create a map of linked locations. There are many possible ways of doing this. The simplest way – and one that has been used in countless thousands of games – is to create a sequential array of Room objects. Each Room object might contain four variables, N, S, W and E to store the number of the adjacent Room at each of four compass directions. Each of these four variables would be an integer giving an index into the array (the ‘map’) of Rooms. So, having created Room objects called Cave, TreasureRoom, TrollRoom, CrystalDome, SmallHouse and DragonsLair, I would put them into the ‘slots’ of a Map array like this:

Map = [Cave,TreasureRoom,TrollRoom,CrystalDome,SmallHouse,DragonsLair];

NOTE: I explain this method of map creation more fully in this video…

An array such as this works fine but it is not very descriptive. The exits in each Room would be shown as integer s(representing the ‘adjoining’ Room’s index in the Map array). Even in a very simple adventure game, it soon becomes quite hard to see which exits lead to which room objects (the integer doesn’t tell you – instead, you have to count through the items to find which Room object is stored at that index in the Map array). The example below, illustrates this point. I create six Room objects (the Room class is defined elsewhere – and I’ll come back to that shortly). I then initialize the name and ‘exits’ of each object, like this:

Cave.init( "Cave",-1,3,1,5 );

Finally, I put all the Room objects into the Map array. Look at the code. Each integer represents an index into the Map, and -1 means ‘No Exit’. So the Cave has No Exit to the North, it goes to the Room at index 3 in the map on the South, and the Rooms as indexes 1 and 5 on the West and East. As you can see, figuring out the actual connections between Rooms in this map array is not easy!

private var NoExit : int = -1;

private var Cave : Room = new Room( );
private var TreasureRoom : Room = new Room( );
private var TrollRoom : Room = new Room( );
private var CrystalDome : Room = new Room( );
private var SmallHouse : Room = new Room( );
private var DragonsLair : Room = new Room( );

private var Map : Array = [];

private var here : int;

private function init( ) : void {
  // Init Rooms, name: N, S, W, E
  // The 4 ints show the Map index of adjoining rooms
Cave.init( "Cave",-1,3,1,5 );
TreasureRoom.init( "Treasure Room", -1,2,-1,0 );
TrollRoom.init( "Troll Room",1,-1,-1,3 );
CrystalDome.init( "Crystal Dome",0,-1,2,4 );
SmallHouse.init( "Small House",-1,-1,3,-1 );
DragonsLair.init( "Dragon's Lair",-1,-1,0,-1 );
Map = [Cave,TreasureRoom,TrollRoom,CrystalDome,SmallHouse,DragonsLair];
here = 0;
}

In a big adventure you could easily have hundreds of Room objects a Room might be initialised with very large array indexes like this: Cave.init( "Cave", 20, 234, 125, 57 ). The only way to figure out which room each integer represents would be to count along the items in the Map array to the specific index. In ActionScript (and many other object-oriented languages) we can do much better than that. In fact, we can create Rooms whose exits are defined by name, rather than number, like this:

Cave.init( "Cave",  NoExit, CrystalDome, TreasureRoom, DragonsLair );

Maps By Reference

In ActionScript, when you refer to an object using a variable name, you actually have a direct reference to the object itself. If one Room object wants to indicate another Room object in is N, S, W or E directions, it can be initialized using the variable name of an object. This is the approach I’ve taken in the project described in the video at the start of this article.

Take a look at the Room class (the code is in listing 1 at the end of this article). Each of the ‘direction’ variables in the new version of the Room class is defined to be a Room rather than an int:

private var _n:Room;

Each private variable comes with a pair of getter and setter accessor methods to allow its value to be assigned or read from other code:

public function set n(aN:Room):void {
   _n = aN;
}
       
public function get s():Room {
   return _s;
}

In order to link a network of Rooms together I first create some empty Room objects and then, once all Rooms have been created, I ‘wire them up’ by assigning other Room objects to each exit in the initGame() function. I’ve done this in the Game class (see listing 2 below). I can’t do this assignment in the constructor since not all the objects will be created at this time. For example, Cave is the first Room I create. Its S direction references the CrystalDome object. But the CrystalDome object hasn’t been created yet so I can’t yet refer to it. My solution to this problem is to create all Room objects with null assigned to their internal Room variables and only then assign the actual Rooms to those variables in the initGame() function. By the time initGame() executes, all the Room objects exist so there is no problem.

Moving around from one Room to another is easy. In my sample code, I’ve created a simple user interface with four buttons – one for each direction. When a button is clicked it passes a character, such as “s” to my moveTo() function. This function looks for a reference to a Room object returned by the current Room (here) object’s s accessor method. It assigns this Room to the local Room variable, newroom:

newroom = here.s;

For example, if the current Room is Cave, the Room object returned by its s accessor will be CrystalDome. The moveTo() function now assigns CrystalDome to the here variable which stores the player’s current position. And on screen, a message tells the player that he or she has moved into the Crystal Dome. If there is no room in the specified direction (that is, if null is assigned to the direction variable) then the player is not moved and a “No Exit” message is shown.

For more ideas on how to write your own adventure games in a programming language of your choice, see my YouTube series ‘How To Program an Adventure Game’. And, to be sure never to miss a new video tutorial whenever one is published, be sure to Subscribe to the Bitwise Courses YouTube channel.


Listings

Listing 1: The Room class…

package gameclasses {
   
   public class Room {
       private var _name:String;
       private var _n:Room;
       private var _s:Room;
       private var _w:Room;
       private var _e:Room;
       
       public function Room() {
           _name = "A Room";
           _n = null;
           _s = null;
           _w = null;
           _e = null;
       }
       
       public function init(aName:String, aN:Room, aS:Room, aW:Room, aE:Room) {
           _name = aName;
           _n = aN;
           _s = aS;
           _w = aW;
           _e = aE;
       }
       
       public function get name():String {
           return _name;
       }
       
       public function get n():Room {
           return _n;
       }
       
       public function set n(aN:Room):void {
           _n = aN;
       }
       
       public function get s():Room {
           return _s;
       }
       
       public function set s(aS:Room):void {
           _s = aS;
       }
       
       public function get w():Room {
           return _w;
       }
       
       public function set w(aW:Room):void {
           _w = aW;
       }
       
       public function get e():Room {
           return _e;
       }
       
       public function set e(aE:Room):void {
           _e = aE;
       }
       
   }    
}

Listing 2: The Game class…

package gamedata {
   
   import gameclasses.Room;
   
   public class Game {
       
       public function Game() {
       }
       
       private var NoExit:Room = null;
       private var Cave:Room = new Room();
       private var TreasureRoom:Room = new Room();
       private var TrollRoom:Room = new Room();
       private var CrystalDome:Room = new Room();
       private var SmallHouse:Room = new Room();
       private var DragonsLair:Room = new Room();
       
       private var here:Room;
       
       //    THE MAP
       //
       //    Treasure Room     ----     Cave        --   Dragon's Lair
       //        |                      |
       //    Troll Room        ----    Crystal Dome  --  Small House
       public function initGame():void {        
                            // 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 );
          CrystalDome.init( "Crystal Dome", Cave, NoExit, TrollRoom, SmallHouse );
          SmallHouse.init( "Small House", NoExit, NoExit, CrystalDome, NoExit );
          DragonsLair.init( "Dragon's Lair", NoExit, NoExit, Cave, NoExit );
          here = Cave;
       }
       
       public function moveTo(aDir:String):String {
           var str:String = "";
           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) {
               str += "No Exit in that direction!\n";
           } else {
               here = newroom;
               str += "You have moved into the " + here.name + "\n";
           }
           return str;
       }
       
   }
   
}
AddThis Social Bookmark Button


Home