It’s no secret that I am a keen adventure gamer. I love playing them. I love programming them. The traditional type of text adventure (sometimes called ‘Interactive Fiction’) is a bit like a book in which the game-player is a character. You walk around the world entering human language commands to “Look at” objects, “Take” and “Drop” them, move around the world to North, South, East and West (and maybe Up and Down too). Unlike modern graphics games, an adventure game can realistically be coded from start to finish by a single programmer with no need to use complicated ‘game frameworks’ to help out.
While my Delphi adventure game has a graphical user interface it is, in essence, a text adventure just like the 70s and 80s originals |
Programming a game is not a trivial task. If you are using an object oriented language, you need to create class hierarchies in order to create treasures, rooms, a map and a moveable player. You need good list-management to let the player take objects from rooms and add them to the player’s inventory. And you need to have robust File/IO routines to let you save and reload the entire ‘game state’.
If you really want to understand all the techniques of adventure game programming, I have an in depth course that will guide you through every step of the way using the C# language in Visual Studio.
But you don’t have to use C#. I’ve written similar games in a variety of languages: Ruby, Java, ActionScript, Prolog and Smalltalk to name just a few. Recently one of the students of my C# game programming course asked for some help with writing a game in Object Pascal (the native language of Delphi, and also of Lazarus). OK, so here goes…
Delphi lets you design, compile and debug Object Pascal applications |
This is not a tutorial on how to use Delphi. I am therefore assuming that you already know how to create a new VCL application, design a user interface and do basic coding. If you don’t, Embarcadero has some tutorials here: http://www.delphibasics.co.uk/
If you prefer an online video-based tutorial with all the source code, you can get a special deal on my Delphi & Object Pascal Course by clicking this link.
The Adventure Begins
First I designed a simple user interface with buttons and a text field to let me enter the name of an object that I want to take or drop. The main game output is displayed in a TRichEdit box which I’ve named DisplayBox.Now, I want to create the basic objects for my game. I want a base Thing class which has a name and a description. All other classes in my game derive from Thing. Then I want a Room class to define a location and an Actor class for interactive characters – notably the player. I could put all these classes into a single code file. In fact, I prefer to put them into their own code files, so I’ve created the three files: ThingUnit.pas, RoomUnit.pas and ActorUnit.pas.
Here are the contents of those files:
unit ThingUnit;
interface
type
Thing = class(TObject)
private // hide data
_name: shortstring;
_description: shortstring;
public
constructor Create(aName, aDescription: shortstring);
destructor Destroy; override;
property Name: shortstring read _name write _name;
property Description: shortstring read _description write _description;
end;
implementation
constructor Thing.Create(aName, aDescription: shortstring);
begin
inherited Create;
_name := aName;
_description := aDescription;
end;
destructor Thing.Destroy;
begin
inherited Destroy;
end;
end.
unit ActorUnit;
interface
uses ThingUnit, RoomUnit;
type
Actor = class(Thing)
private
_location: Room;
public
constructor Create(aName, aDescription: shortstring; aLocation: Room);
destructor Destroy; override;
property Location: Room read _location write _location;
end;
implementation
constructor Actor.Create(aName, aDescription: shortstring; aLocation: Room);
begin
inherited Create(aName, aDescription);
_location := aLocation;
end;
destructor Actor.Destroy;
begin
inherited Destroy;
end;
end.
unit RoomUnit;
interface
uses ThingUnit;
type
Room = class(Thing)
private
_n, _s, _w, _e: integer;
public
constructor Create(aName, aDescription: shortstring;
aNorth, aSouth, aWest, anEast: integer);
destructor Destroy; override;
property N: integer read _n write _n;
property S: integer read _s write _s;
property W: integer read _w write _w;
property E: integer read _e write _e;
end;
implementation
{ === ROOM === }
constructor Room.Create(aName, aDescription: shortstring;
aNorth, aSouth, aWest, anEast: integer);
begin
inherited Create(aName, aDescription);
_n := aNorth;
_s := aSouth;
_w := aWest;
_e := anEast;
end;
destructor Room.Destroy;
begin
inherited Destroy;
end;
end.
And this is the code in the main file, gameform,pas. Note that the button event-handlers such as TMainForm.NorthBtnClick were created using the Delphi events panel prior to adding code to those methods:
unit gameform;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls,
Vcl.ComCtrls,
ThingUnit, RoomUnit, ActorUnit;
type
TMainForm = class(TForm)
DisplayBox: TRichEdit;
NorthBtn: TButton;
SouthBtn: TButton;
WestBtn: TButton;
EastBtn: TButton;
LookBtn: TButton;
CheckObBtn: TButton;
TestSaveBtn: TButton;
TestLoadBtn: TButton;
Panel1: TPanel;
DropBtn: TButton;
TakeBtn: TButton;
inputEdit: TEdit;
InvBtn: TButton;
procedure FormCreate(Sender: TObject);
procedure LookBtnClick(Sender: TObject);
procedure SouthBtnClick(Sender: TObject);
procedure NorthBtnClick(Sender: TObject);
procedure WestBtnClick(Sender: TObject);
procedure EastBtnClick(Sender: TObject);
private
{ Private declarations }
procedure CreateMap;
public
procedure Display(msg: string);
procedure MovePlayer(newpos: Integer);
{ Public declarations }
end;
var
MainForm: TMainForm;
room1, room2, room3, room4: Room;
map: array [0 .. 3] of Room;
player: Actor;
implementation
{$R *.dfm}
procedure TMainForm.Display(msg: string);
begin
DisplayBox.lines.add(msg);
end;
procedure TMainForm.CreateMap;
begin
room1 := Room.Create('Troll Room', 'a dank, dark room that smells of troll',
-1, 2, -1, 1);
room2 := Room.Create('Forest',
'a light, airy forest shimmering with sunlight', -1, -1, 0, -1);
room3 := Room.Create('Cave',
'a vast cave with walls covered by luminous moss', 0, -1, -1, 3);
room4 := Room.Create('Dungeon',
'a gloomy dungeon. Rats scurry across its floor', -1, -1, 2, -1);
map[0] := room1;
map[1] := room2;
map[2] := room3;
map[3] := room4;
player := Actor.Create('You', 'The Player', room1);
end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
CreateMap;
end;
procedure TMainForm.LookBtnClick(Sender: TObject);
begin
Display('You are in ' + player.Location.Name);
Display('It is ' + player.Location.Description);
end;
procedure TMainForm.MovePlayer(newpos: Integer);
begin
if (newpos = -1) then
Display('There is no exit in that direction')
else
begin
player.Location := map[newpos];
Display('You are now in the ' + player.Location.Name);
end;
end;
procedure TMainForm.NorthBtnClick(Sender: TObject);
begin
MovePlayer(player.Location.N);
end;
procedure TMainForm.SouthBtnClick(Sender: TObject);
begin
MovePlayer(player.Location.S);
end;
procedure TMainForm.WestBtnClick(Sender: TObject);
begin
MovePlayer(player.Location.W);
end;
procedure TMainForm.EastBtnClick(Sender: TObject);
begin
MovePlayer(player.Location.E);
end;
end.
So this is already a good basis for the development of an adventure game in Delphi. I have a map (an array) or rooms and a player (an Actor object) capable of moving around. There’s still much to do, however – for example, I need some way of taking and dropping objects and saving and restoring a game. I’ll look at those problems in a future article.
If you are seriously interested in programming text adventure games or learning Delphi, here are special deals on two of my programming courses.
Learn To Program an Adventure Game In C#
- Write a retro-style adventure game like ‘Zork’ or ‘Colossal Cave’
- Master object orientation by creating hierarchies of treasure objects
- Create rooms and maps using .NET collections, arrays and Dictionaries
- Create objects with overloaded and overridden methods
- Serialize networks of data to save and restore games
- Write modular code using classes, partial classes and subclasses
- Program user interaction with a ‘natural language’ interface
- Plus: encapsulation, inheritance, constructors, enums, properties, hidden methods and much more…
https://bitwisecourses.com/p/adventures-in-c-sharp-programming/?product_id=943143&coupon_code=BWADVDEAL
Learn To Program Delphi
- 40+ lectures, over 6 hours of video instruction teaching Object Oriented programming with Pascal
- Downloadable source code
- A 124-page eBook, The Little Book Of Pascal, explains all the topics in depth