Design issues for Adventure Games

Previous topic - Next topic

doimus

I'm trying to make a framework for point'n'click adventure games, like the old classics from Lucas Arts. Just like Monkey Island, Indiana Jones, Day Of The Tentacle, etc.

Structure of these games revolves around "Rooms" (locations, what you walk around) and "Objects" (stuff you interact with, like items that you can pick up and characters you can talk to).
I'm wandering what is the best way to organize this?

My current plan is to use arrays that store all objects and all characters in the game. Let's call them "game arrays".
There really isn't much raw data to store in these anyway. Let's say that I could have up to 50 rooms with about 20 objects max. per room - that's array[1000]. Not that big.
These "game arrays" are useful as they provide instant game-save feature. Write them to file and you're done.

Code (glbasic) Select

TYPE TObject
roomNr
positionX
positionY
sprite[] as TSprite
sound[] as TSound
//..... other stuff
ENDTYPE

LOCAL gameObject[] as TObject
LOCAL gameCharacter[] as TCharacter

gameObject[34].roomNr = 12
gameCharacter[23].roomNr = 12


When the player enters certain room, all relevant "game" objects will be copied into "Room" array for easier handling, sorting and drawing. At this time, all graphics and sound is loaded as well. "Game array" just stores references to files, etc.

Code (glbasic) Select

LOCAL object[] AS TObject  // this is the "Room" array
FOREACH n IN gameObject[]
IF n.roomNr = currentRoom
DIMPUSH object[], n
ENDIF
NEXT

FOREACH n IN object[]
// load all sprites, sounds
// draw it on screen, do other exciting stuff
NEXT

Upon player exiting the Room, all data from local room array should be copied back to game array.
This is the tricky & untidy part - now I need another reference to know exactly *where* I should copy back the data.
Maybe I could use object "names" for reference:
Code (glbasic) Select

IF gameObject[j].name = object[i].name THEN gameObject[j] = object[i]


Or maybe I should store array index when copying from game to room array:
   
Code (glbasic) Select


gameObject[42].arrIndex = 42  // extreme potential for fcuk-up here!

DIMPUSH object[], gameObject[42]

FOREACH n IN object[]
gameObject[n.arrIndex] = n
NEXT


This method is faster, and seems to be more sensible.

I considered putting everything into multi-dimensional array but then I could have something like:
object[currentRoom][LAMP].sound[FIRE].volume = 12
Ouch! :)
And I don't need to have all of that in memory anyway - gameObject[] could be deleted before loading graphics and sounds to free some memory.

I also considered having all Rooms in their separate files. That would make run-time loading very easy, but would complicate save-game routines.

Then again, I'm sure I'm over-complicating stuff here. Twenty-some years ago these games came on a single floppy. There must be a quick & dirty solution to this.

ampos

I did one of this completly back in 1992...

In fact it was a working 2 screens demo of a adventure for a Spanish game company.

The game title was... BLADE RUNNER.

Yes, it was for getting a license they didn't get in the end.
check my web and/or my blog :D
http://diniplay.blogspot.com (devblog)
http://www.ampostata.org
http://ampostata.blogspot.com
I own PC-Win, MacBook 13", iPhone 3G/3GS/4G and iPAC-WinCE

Ian Price

#2
I did one in BlitzMax a few years back -







Grab it from HERE

Warning:  This game is not suitable for children as it contains adult humour, language that some may find offensive and scenes of violence.

I stored all rooms, objects, speech etc. in their own arrays and referenced them only if they were in the room the character was standing in.

I made up each screen with separate images, rather than a whole drawn scene - this allowed me to play around with positioning of objects, characters etc.
I came. I saw. I played.

XanthorXIII

Fun game Ian, played through it and got some pretty good laughs out of it.
Thanks!
Owlcat has wise

Slydog

I've never done anything like this before, but it sounds interesting.
I think it may be easier to keep your rooms separate instead of clumped into one array, such as:

Code (glbasic) Select
TYPE TObject
  objectType%
  special%   // hold door room numbers, or any custom value for various object types
  positionX
  positionY
  sprite[] as TSprite
  sound[] as TSound
  //..... other stuff
ENDTYPE

TYPE TRoom
  number%
  name$
  objects[] as TObject
ENDTYPE

LOCAL rooms[] AS TRoom
LOCAL gameCharacter[] as TCharacter
LOCAL roomCurrent%
rooms[roomCurrent].gameObject[34].positionX = 10
gameCharacter[23].roomNumber = rooms[roomCurrent].number

FOREACH room IN rooms[]
...
FOREACH object IN rooms[roomCurrent].objects[]
...
LOCAL roomTemp AS TRoom
// Copy current room
roomTemp = rooms[roomCurrent]
// Restore current room
rooms[roomCurrent] = roomTemp


You could use 'rooms' to specify what paths / doors lead to other specific rooms, such as:
Code (glbasic) Select
IF room.objects[objectActivated].objectType = OBJECT_DOOR
  // Change current room to object's 'special' value
  roomCurrent = room.objects[objectActivated].special
ENDIF
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]

doimus

#5
@ ampos - As a huge fan of adventure games and Bladerunner being one of my favourite movies, I'm slightly envious.  ;)

@ Ian - Great game! :good: I LOLed at Hunchback C64 reference.  "Face rings a bell" - hehe! :D

@ Slydog - I like your ideas, I might utilize something like that.

I really have to bang my head against this for some more time to find the most efficient solution.
I plan to "script" the game in GLB as well. My first idea is to place the "scripts" in SUBs that will be called with CALLBYNAME, with  IF-THENs & Co. that will take care of the game-flow.

Since the major action takes place there, I would like to keep the syntax as concise as possible.
Here's a mock-up.... I use a lot of constants as references, which kind of defies the DRY principle, but I think it's better than using numbers or strings for that (lots of opportunity for nasty bugs that way!).

Code (glbasic) Select

LOCAL callRoom$ = "Room" + currentRoom
CALLBYNAME callRoom$

SUB Room42: object[] AS TObject, player AS TCharacter //blah......

player.setRoomVisited(currentRoom)

IF player.questCompleted(QUEST_WAIT_GODOT)
   player.dance(LIMBO, VERY_FAST)
      IF somethingElse >= exactlyThat
           object[OBJ_LAMP].destroyCharacter(PINK_SQUIRREL)
      ENDIF
ENDIF

ENDSUB
[\code]



ampos

I designed a script language for the game, basically prints, let, if/then, goto, drawsprite, music, sample.

The script was composed of a main code to be executed everytime you enter a room and subroutines.

Everytime you did choose a verb+object, they were translated to verb number+object number.

Then, the subrutines, named as VERB+OBJECT+OBJECT (for use this on this, 2 objects), listed in this script (every room has his own script) where checkeck. If they exist, it was executed. If not, it did show "I dont know how to 'verb' this 'object'"

To show objects in screen when you moved the mouse, my screen was divided in 8x8 pixels blocks (remember, it was an amiga and memory was limited. Also commands where limited in Amos). Every block had a number, the number of the object. Yes, my game was limited to 255 objects.

So, it was really like

Code (glbasic) Select
object_under_mouse=room_zones_or_objects[xmouse/8][ymouse/8]

As a side note, I created and enhaced graphic system, able to display tons of colors on screen. Basically, it was 20 colors fixed for screen, and 12 variables per scanline. I got 256 color images in PC DPaint format from Dinamic (the game company), and they almost look identicals in the Amiga and the PC.
check my web and/or my blog :D
http://diniplay.blogspot.com (devblog)
http://www.ampostata.org
http://ampostata.blogspot.com
I own PC-Win, MacBook 13", iPhone 3G/3GS/4G and iPAC-WinCE

okee

the most memorable line i've seen in an adventure game, i think it's 7 days a stranger
you're walking through a field and you come across a haystack, when you click on it
The charachter says " that hay reminds me of a warm safe place where as a child l'd hide" :)
Android: Samsung Galaxy S2 -  ZTE Blade (Orange San Francisco) - Ainol Novo 7 Aurora 2
IOS: 2 x Ipod Touch (1G)