Java-Gaming.org Hi !
Featured games (81)
games approved by the League of Dukes
Games in Showcase (513)
Games in Android Showcase (119)
games submitted by our members
Games in WIP (576)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Best set up of Areas in text based RPG?  (Read 520 times)
0 Members and 1 Guest are viewing this topic.
Offline Palocles

Junior Newbie





« Posted 2013-11-27 04:00:23 »

So I'll jump right in with a question as my first post here...

Right after the short explanation:  I'm trying to write a fairly simple mostly text RPG in the style of the old Fighting Fantasy game books.  (http://en.wikipedia.org/wiki/Fighting_Fantasy for the unfamiliar.)  And my current hurdle is setting up and running the areas .

So far I'm planning to have an Area class, of course, which will looks something like this:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
public class Area{
   private int areaNum;
   private String descShort;
   private String descLong;
   private int[] exitDir;
   private int[] exitNum;
   private Creature mobType;
   private int mobSize;
etc.
}

And getters for everything that is needed.

Next I think I need another class which consists of one big Object[][] and has all the data hard coded.  That data is then accessed with getters that are called by the Area() constructor or the game loop when needed (unsure which yet). So each Area would initially be instantiated with only the areaNum(ber), ie.
1  
Area areaOne = new Area(1); 
and the constructor would do:
1  
2  
3  
4  
5  
6  
7  
8  
9  
Area(int areaNum){
   this.areaNum = areaNum;
   this.getData(areaNum);
}
getData(int areaNum){
   this.descShort = areaData.getDescShort(ereaNum);
   this.descLong = areaDataa.getDescLong(areaNum);
   etc.
}
And the Object[][] in areaData looks like this:
1  
2  
3  
4  
5  
6  
7  
8  
class AreaData {
     Object[][] data = {
         //there would be another area at index 0
         {1, "Main Gate", "You approach the forbidding gate...", {2, 4}, {2, 0}, Goblin, 3},
         {2, "Entrance Hall", "The air is thick with dust long undisturbed until...", {1, 2, 3, 4}, {3, 4, ,5 ,1}, null, 0},
         {3, "North Hall", "You pass through a door leading north...", {1, 3}, {6, 2}, Orc, 2},
         //continue for all areas
        };


Does this make sense and am I coming at this from the right angle?
A lot of this is like me thinking out loud...

Any questions fire away.  I don't want to give unnecessary detail straight away.
Offline opiop65

JGO Kernel


Medals: 156
Projects: 7
Exp: 3 years


JumpButton Studios


« Reply #1 - Posted 2013-11-27 04:14:02 »

Whoa, why do you have an array of the Object type? Don't do that, just have seperate arrays for the text and positions of the enemies should be stored in the creature class.

Offline Palocles

Junior Newbie





« Reply #2 - Posted 2013-11-27 04:39:11 »

It's an object array because the data are all sorts of different object types so I need to encapsulate them all.

I'm not instantiating monsters until the areas are entered so can't have them holding a location variable.

Are you suggesting that I have multiple arrays and store different parts of the data in each?  Ie. String[][], int[][], etc.?
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Damocles
« Reply #3 - Posted 2013-11-27 06:49:19 »

If you can read your Data correctly from the Array and construct your Area-Object

AND

The visualization in code is easy to keep an overview, then you approach is fine.

(if it works, and is not confusing, stick to it)

For a larger game, I would import the area-data from a textfile, using a selfdefined script.
This requires some fizzeling with String, but its ot hard to write a simple parser.

Example of a pseudoscript:


areas.txt:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
//my entrance area

DEF_AREA 1,"Entrance to Goblin Pit"
//comments, use C like syntax highighting for nice representation in a text editor
  MAKE_ITEM item#1,"golden key",typeKEY
  MAKE_ITEM item#2,"health portion",typePotion#5

  ADD_EXIT portal#1,north,"a doorway"
  DEF_EXIT_KEY portal#1,item#1,"the door is locked, looks like it needs a key."

  ADD_MOB typeGoblin,5
  ADD_MOB typeGoblin,5
  ADD_MOB typeBossGoblin,"overlord goblin",30

  ADD_CONTAINER container#1,"chest"
  ADD_TO_CONTAINER container#1,item#1
  ADD_TO_CONTAINER container#1,item#2

//etc,

END_DEF_AREA


//first hallway
DEF_AREA 2,"Hallway"

  ADD_EXIT portal#1,north,"a staircase"
  ADD_EXIT portal#1,south,"a doorway"

  ADD_MOB typeGoblinWizard,8

END_DEF_AREA


Not too complex writing a parser that can dynamically create
your objext from this custom text-script.

Its good to seperate logic and content.
Debugging / patching the script is quicker than having to work in code.
Also, when working in a team, this approch lets you work in paralel with a leveldesigner
that con conentrate on contens, while you debug your code.

Offline Jimmt
« League of Dukes »

JGO Kernel


Medals: 136
Projects: 4
Exp: 3 years



« Reply #4 - Posted 2013-11-27 06:53:39 »

It's an object array because the data are all sorts of different object types so I need to encapsulate them all.

I'm not instantiating monsters until the areas are entered so can't have them holding a location variable.

Are you suggesting that I have multiple arrays and store different parts of the data in each?  Ie. String[][], int[][], etc.?
Using OOP design, you have a superclass that encapsulates the types you need. Object is waaay too broad for use in your game; it can encapsulate every single type of object in java, the vast majority of which have nothing to do with your game. Of course, this is in theory, but in your app you will eventually have to separate each type of object into groups - maybe differentiating between questline text and dialogue text (just my bs example, hopefully you get what I mean).
Offline StrideColossus
« Reply #5 - Posted 2013-11-27 14:43:49 »

Using a big object array to store arbitrary data is definitely not the way to go IMHO, you would be sort of turning the OO principle of data encapsulation inside out.

You've already defined the notion of an Area with all the properties it requires, why would that need to refer to another class which holds its data?

The constructor for Area ought to be something like this:

1  
2  
3  
4  
public Area( String shortDesc, String longDesc, Creature mob, ... ) {
    this.shortDesc = shortDesc;
    ....
}


(or use setters is you want Area to be mutable)

Then the setup code becomes:

1  
2  
3  
4  
final Area[] areas = {
    new Area( "short", "long", ... ),
    ...
};


No need for a separate array of object data.  No need to copy data from the array to the Area instances.

Also has the advantage that your design will support loading the data from a file with little or no change to the game code.

As an aside, I assume the exitDir field is a compass direction and exitNum 'points' to the area it leads to?  If so then you might also want to consider encapsulating that into it's own enumeration and use a map to associate possible directions and destinations, e.g.

1  
2  
3  
4  
5  
6  
7  
8  
9  
enum Direction {
    NORTH,
    SOUTH,
    ...
}

final Map<Direction, Integer> exits = new HashMap<>();
exits.put( Direction.EAST, 42 );
...


and then pass that into the Area constructor, or have a setter for the exits, or an add( Direction, destination ) method.

Hope this makes sense and helps a little.

- stride
Offline HeroesGraveDev

JGO Kernel


Medals: 269
Projects: 11
Exp: 2 years


┬─┬ノ(ಠ_ಠノ)(╯°□°)╯︵ ┻━┻


« Reply #6 - Posted 2013-11-27 18:52:18 »

I found XML quite useful for this task.

If you do it right, you can even have areas as objects (eg: a house)

Some neccessary properties include:

Short description.
Long description.
List of available actions.
List of objects (including enemies).
List of areas to link to.

Offline Palocles

Junior Newbie





« Reply #7 - Posted 2013-11-27 21:13:25 »

Thank you everyone.  This is the kind of feedback I was after and was unable to get on my previous Java forum.  (The "one specific question" per thread limitation was unhelpful for things like this where I don't have a clearly defined question.)

Damocles (could we be related, hehe), "it works and is not confusing" for me.  I was working this way because it's something I can get my head around with what I've already learnt.  But what I learnt was fairly general and not at all gaming focused.

I can see how your suggestion should work too, though, but I don't know how to write a parser or how the parser should work.  Does it use loops which look for things like DEF_AREA and MAKE_ITEM then run a constructor as it finds them?  I think learning that might be a project for a little later.

Jimmt, yes, Objects are very broad but I'm not aware of something that can hold an int, a String and an Enum (and Creatures, Weapons and Armour), plus what ever else I might add, which isn't that broad.  Is there any liability to being too broad?

Stride.  (After a quick brush up on data encapsulation)  Would a better approach be to include that Object[][] within the Area class then define the values of the members with a method after the area is instantiated?

It seems to me that there are two ways to instantiate the Areas and set the values and I can't think of something in between.  The first is to have a constructor which receives all the needed values, ie:
1  
2  
3  
4  
5  
Area(int areaNum, String descShort, String descLong, etc.){
   this.areaNum = areaNum;
   this.descShort = descShort
   //etc
}
And then use a call to that constructor as usual,
1  
Area(1, "Main Entrance", "You enter a dirty room...", etc);

And the alternative to use a simple constructor with only a single value (or no values) then get the data from somewhere and set the members values with it;
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
Area(int areaNum){
   this.areaNum = areaNum;
   this.getData(areaNum);
}

getData(Area area, int areaNum){
   index = areaNum;
   area.setDescShort(areaData[1][index]);
   area.setDescLong(areaData[2][index]);
   area.setExitDir(areaData[3][index]);
   ///etc.
}
Sorry, it's a bit repetitive of my first post.

So I can understand how these both work but don't know where all the data will come from with the first one.  Would I include a prewritten constructor call for each area with the first?

If I just treat the AreaData class as an extension of the Area class wouldn't still be fairly well encapsulated?

The aside assumption was correct.  exitDir(ection) is a compass point, starting with one at North and going clockwise but allowing for Up and Down at 5 and 6.  It does seem like an Enum and Map would work but I'll need to do more work with Maps first.

HeroesGD.  I had a quick look at XML too.  It looks like I would work in a similar way to the text file and parser that Damocles suggested.  It's something else I'll have to look into more and learn how to use though...

Thanks again everyone.  Sorry if some of this reply was stupid, I'm in a rush now and have no time to review or edit.
Offline StrideColossus
« Reply #8 - Posted 2013-11-28 10:11:21 »

I think using XML to specify your data is perfect for your game, and that was part of the reason for my suggestion about encapsulating all the data for an area in a single class rather than having the data elsewhere - it means its much easier to write a loader because the area class is 'self contained', e.g.

Your XML could look something like this:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
<map>
    <area name="Main Entrance" mob="goblin">
        <description>You enter a dirty room...</description>
        <exits>
            <exit dir="NORTH" dest="Entrance Hall" />
            <exit dir="EAST" dest="North Hall" />
        </exits>
    </area>
   
    <area name="Entrance Hall"...>
    ...
</map>


The area class would be something along these lines:

1  
2  
3  
4  
5  
6  
class Area {
    private final String name;
    private final String description;
    private final Map<Direction, Area> exits = new HashMap<>();
    ...
}


The loader could be like this:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
// Load XML using whatever parser you prefer (built-in javax.xml.parsers, JDOM, etc)
final Element root = ...

// Load map
final Map<String, Area> world = new HashMap<>();
for( Element areaElement : root.getChildren() ) {
    // Load area
    final Area area = new Area();
    area.setName( areaElement.getAttribute( "name" ) );
    area.setDescription( areaElement.getChildText( "description" ) );

    // Lookup mob and add to area
    final String mobName = areaElement.getAttribute( "mob" );
    ...

    // Load exits
    for( Element exitElement : areaElement.getChild( "exits" ).getChildren() ) {
        final Direction dir = Direction.valueOf( exitElement.getAttribute( "dir" ) );
        final Area dest = areas.get( exitElement.getAttribute( "dest" ) );
        area.getExits().put( dir, dest );
    }

    // Add to map
    world.put( area.getName(), area );
}


Couple of things to consider:

1. The above is a 'sunny day' implementation, i.e. it doesn't do any checks to validate the XML.  You would probably want to add your own helper methods that get stuff out of the XML document and perform whatever checks you need, e.g. make sure the area name is not empty, ditto description, make sure each area has at least one exit, check for duplicate exits, etc.

2. The way the above loads the exits means that an area can only refer to an area that has already been loaded, i.e. you would have to specify your map 'upside down', and you couldn't have cyclic exits, i.e. area A with exit to area B and vice versa.  You could do a two-pass approach: load all the area data, then load all the exits.  Or use numeric indices but that could be error-prone.

3. If you intend to have lots of area in your game you might want to consider splitting the XML into multiple 'zones' and/or have some sort of #include type approach.

4. The results are stored in the world as a map of areas ordered by name.  If you needed to get hold of the starting location you would have to do world.get( "Main Entrance" );  You might want to put the name of the starting location into the root of the XML document, might be handy for testing.

5. It's a lot easier to edit an XML file than it is to code a damn great array of objects Wink

This is pretty much the approach I have used to create text-based RPGs.

- stride
Offline Palocles

Junior Newbie





« Reply #9 - Posted 2013-11-28 22:38:19 »

I guess I should learn how to use XML then!

It looks like it works in a similar way to what I had planned but a bunch of you with more experience say it's better, so it probably is.

I think I'll have to use the two passes to load all the data as I DO want two way exits.  One of the advantages of doing this as a computer game instead of a book is this flexibility, so I want to take advantage of that.

I was also thinking of doing zones or groups of locations and loading them as needed.  From a game play perspective they might also be connected by one way exits from previous locations to force the player forwards, which is something the books do too.'

As to actual numbers of areas... I'd like to go up to maybe 100 for a really large dungeon but will probably aim for about 20 initially.  And only about 6 to get the thing working.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline opiop65

JGO Kernel


Medals: 156
Projects: 7
Exp: 3 years


JumpButton Studios


« Reply #10 - Posted 2013-11-28 22:40:50 »

If you have to pause the game and load the area, then I really wouldn't recommend having too many of your areas. I personally hate when the game freezes and loads a new level, especially because with the amount of memory we have now, keeping large areas loaded isn't really a problem.

Offline Palocles

Junior Newbie





« Reply #11 - Posted 2013-11-28 23:06:59 »

Oh, good point.  Mostly text data should take up very little memory.  I don't think it would have been noticeable though.  The new areas would have loaded by the time you finished reading the current area description and looked at the picture.  But yeah, no need to scrimp on memory when there's so much available.
Offline opiop65

JGO Kernel


Medals: 156
Projects: 7
Exp: 3 years


JumpButton Studios


« Reply #12 - Posted 2013-11-28 23:18:31 »

Ah yes, that's fine if you preload them so when you reach a new area its just a smooth transition.

Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Longarmx (46 views)
2014-10-17 03:59:02

Norakomi (37 views)
2014-10-16 15:22:06

Norakomi (28 views)
2014-10-16 15:20:20

lcass (32 views)
2014-10-15 16:18:58

TehJavaDev (62 views)
2014-10-14 00:39:48

TehJavaDev (62 views)
2014-10-14 00:35:47

TehJavaDev (52 views)
2014-10-14 00:32:37

BurntPizza (70 views)
2014-10-11 23:24:42

BurntPizza (40 views)
2014-10-11 23:10:45

BurntPizza (82 views)
2014-10-11 22:30:10
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!