Author Topic: OO roguelike design  (Read 21981 times)

programmerlike

  • Newcomer
  • Posts: 11
  • Karma: +0/-0
    • View Profile
    • Email
OO roguelike design
« on: March 27, 2011, 05:03:42 PM »
Hello there,

i discovered this community when i decided to start my first roguelike project and immediately registered in order to share my ideas with you experienced roguelike programmers...
I'm NOT new to game programming, this is just my first roguelike game.
I intend to use c# with no additional library (i know most people use some version of the curses lib). I know that a large part of you think that many aspects of roguelikes are not to be designed in advance but i think it would be wise to design the major framework at least...

I want to share with you the data structures i had in mind (pseudo-code, of course):
 
  // entities represents anything in the dungeon
  //
  class Entity
  {
    Char glyph;
    Color Background;
    Color Foreground;
    int X, Y;
  }

  // hero and monsters are actors
  //
  class Actor subclass of Entity
  {
    abstract Action Think();
  }
 
  // an object that tells you the next actor that has to make
  // a move
  //
  class ActorScheduler
  {
    Actor Current;
    void GoNext() { ... }
  }
 
  // an action is anything that an actor can do
  // examples are:
  //   MoveAction
  //   UseItemAction
  //   AttackAction
  //   etc
  //
  class Action
  {
    abstract void Execute();
  }

  class Dungeon
  {
    grid of tiles (empty, wall, corridor, room, door etc)
    list of entities
  }

The main loop should look like this:

  Action action = actorScheduler.Current.Think();
  action.Execute();
  actorScheduler.GoNext();
  // maybe update fov, stats display etc...
  repeat untill gameover

That's all about the framework. Another thing i had in mind was the following:

  class Entity
  {
    everything like before

    // This method has the following meaning:
    // if the hero touches this entity, what happens?
    // for example an ItemEntity should return the PickUpItemAction
    // I'd really appreciate suggestion for the name of this method...
    // I know that ProvidedInteraction is not very clear...
    //
    Action ProvidedInteraction(Actor actor);
  }

WELL... i know it's a long post but i hope someone reads it all and shares his opinion with me...

Bye

kipar

  • Rogueliker
  • ***
  • Posts: 105
  • Karma: +0/-0
    • View Profile
    • Email
Re: OO roguelike design
« Reply #1 on: March 27, 2011, 06:55:15 PM »
I'm not experience developer, but my noobish opinion:
1. Imho you can split class Dungeon to Branches and branches to the levels (maps) which contain grid of cells. Of course this is useless if there will be no persistant maps in your project.
2. ProvidedInteraction -> Touched or WhenTouched, but you will have more troubles with distance combat or using spells&skills to the object.
3. Approach with Action objects can be more complex than just making all actions a methods of the Actor, but will give you additional flexibility if you will use an advanced timing-system (where actions are processed asynchronously from actors).

Ancient

  • Rogueliker
  • ***
  • Posts: 453
  • Karma: +0/-0
    • View Profile
Re: OO roguelike design
« Reply #2 on: March 27, 2011, 08:06:31 PM »
Welcome.

i discovered this community when i decided to start my first roguelike project and immediately registered in order to share my ideas with you experienced roguelike programmers...
There are much more seasoned veteran rogue developers at rec.games.roguelike.development newsgroup if you wish to jump through the hoops to access that.

I know that a large part of you think that many aspects of roguelikes are not to be designed in advance
Wow! This is news to me. Where you get that from? I know that in times when Thomas Biskup himself still walked the rgrd threads some people really were like that but it was years ago. Seems you have not had a look at Roguelike Dev FAQ. This section is very old but still reflects the it is better to make some design before standpoint.

  // entities represents anything in the dungeon
  //
  class Entity
  {
    Char glyph;
    Color Background;
    Color Foreground;
    int X, Y;
  }
Do you need glyph and colors for every single entity or just for a class of entities? I have appearance data stored in static table. Color-shifting is solved by assigning special value to foreground. Drawing routine then checks for this special constant and randomly selects displayed hue. Added bonus is multicolored monsters glitter every screen refresh and you need not to worry when to change their appearance.

  // hero and monsters are actors
Why not items too? Unless you wish to close yourself way to intelligent artifacts or self-acting equipment I would include those too.
 
  class Dungeon
  {
    grid of tiles (empty, wall, corridor, room, door etc)
    list of entities
  }
I am slightly uneasy about stuffing list of Entities in the Dungeon. However to really comment on it I would need to know how you plan to solve going to another level.

  class Entity
  {
    // This method has the following meaning:
    // if the hero touches this entity, what happens?
    // for example an ItemEntity should return the PickUpItemAction
    // I'd really appreciate suggestion for the name of this method...
    // I know that ProvidedInteraction is not very clear...
    //
    Action ProvidedInteraction(Actor actor);
  }
"Default Action", "Default Behavior", "Auto Interaction". I prefer to have that logic in Hero class though. Decentralized organization makes this harder for me to maintain. When I dislike something in stumble, autopickup or bump behavior I do not need to change it in several places but in merely one.
Michał Bieliński, reviewer for Temple of the Roguelike

languard

  • Newcomer
  • Posts: 41
  • Karma: +0/-0
    • View Profile
    • Email
Re: OO roguelike design
« Reply #3 on: March 27, 2011, 08:27:22 PM »
Providing a UML document would make it a little easier to read :)  Given that you are going for an OOP design, I'd drop the monolithic 'ProvidedInteraction' and instead go for an event driven system instead.  One way of doing this is to create a series of Interfaces, such as ITouch, IHit, IPickUp, so on.  This way an object only implements the interfaces that make sense for it.  So for a floor trap you might just have the ITouch, but a monster might have ITouch and IHit.  

To back up what Ancient said, I would have an EntityBase class, and then a EntityInstance class.  The instance would only track the X,Y of the instance, hp, and any other dynamic attributes, and pull from the Base all the static stuff such as glyph and color.

programmerlike

  • Newcomer
  • Posts: 11
  • Karma: +0/-0
    • View Profile
    • Email
Re: OO roguelike design
« Reply #4 on: March 27, 2011, 09:45:46 PM »
Tnx for all of your replies!

i'm already storing "appearence" of entities in a static table... that was only to make it simpler to understand in my previous post.
It's like this:

class Icon
{
   glyph and colors
}

class IconSets
{
  // if visible is false i use grayed-out colors (for fog of war)
  static Icon[] GetDungeonCellsSet(bool visible) { ... }

  // hero, monsters, weapon, armour, potion etc
  static Icon[] GetEntitiesSet() { ... }
}

class Entity
{
   Icon Icon;
   and the rest...
}

I'm thinking about the following interface:
Numpad to move
Spacebar to pop up a menu (text lines with a frame around it)
Entries of this menu are:
  Rest
  Ranged Attack (only if you have a ranged weapon equipped)
  Inventory
  Spells

Inventory and Spells will display submenus.
ItemEntity class has a method that returns a list of actions that you can do with it.
Example:

class Weapon subclass of ItemEntity
{
   ActionList WhenSelected(Actor actor)
   {
      ActionList A;
 
      if (!actor.Equips(this))
        A.Add( WieldAction(this) );
      A.Add( DropItemAction(this) );

      return A;
   }
}

So if you select Inventory and then a weapon, you'll see two possible actions, wield and drop.
For spells, instead, after you choose one you will be prompted to select target square.

Please let me know what you think... i'm starting to code the framework right now to see if it works...
« Last Edit: March 27, 2011, 09:51:10 PM by programmerlike »

willraman

  • Newcomer
  • Posts: 24
  • Karma: +0/-0
    • View Profile
Re: OO roguelike design
« Reply #5 on: March 27, 2011, 10:08:14 PM »
For your project would it be easier to assign 1 color variable to the entity? This way the background can be printed by your rendering engine by whatever color tile the entity is sitting upon. Blue water, brown ground or green grass, with a white @ sitting on it?


programmerlike

  • Newcomer
  • Posts: 11
  • Karma: +0/-0
    • View Profile
    • Email
Re: OO roguelike design
« Reply #6 on: March 27, 2011, 10:14:03 PM »
For your project would it be easier to assign 1 color variable to the entity? This way the background can be printed by your rendering engine by whatever color tile the entity is sitting upon. Blue water, brown ground or green grass, with a white @ sitting on it?

It's possible, of course, but it's something i can change later since now i'm more concerned with the basic processing framework (and not with rendering).

Krice

  • (Banned)
  • Rogueliker
  • ***
  • Posts: 2316
  • Karma: +0/-2
    • View Profile
    • Email
Re: OO roguelike design
« Reply #7 on: March 28, 2011, 06:41:59 AM »
There are many ways to structure the class hierarchy and the way data is handled. I think this will be a good learning process for you, because roguelikes are a bit more complicated than average game types.

purestrain

  • Rogueliker
  • ***
  • Posts: 172
  • Karma: +0/-0
    • View Profile
Re: OO roguelike design
« Reply #8 on: March 28, 2011, 10:40:12 AM »
If you now use components for the entities instead of inheritance it could almost look like my framework  ;D Seems to be solid enough for starting.

programmerlike

  • Newcomer
  • Posts: 11
  • Karma: +0/-0
    • View Profile
    • Email
Re: OO roguelike design
« Reply #9 on: March 28, 2011, 12:34:22 PM »
OK... i received a lot of feedback and i'm happy with your suggestions/comments.
I'm actually coding a test-bed for this "framework".
When i get it working i'll be posting a download link here to show you what i have achieved.

Bye

Ancient

  • Rogueliker
  • ***
  • Posts: 453
  • Karma: +0/-0
    • View Profile
Re: OO roguelike design
« Reply #10 on: March 28, 2011, 08:24:24 PM »
class Weapon subclass of ItemEntity
This is often taken path but often brings many problems with itself. Roguelikes lend themselves better to data-driven paradigm. Making weapon a subclass of item you either:

1. Will not include block value since this should be member of shield class and forbid yourself to create swords of parrying.
2. Will include block value to make implementing swords of parrying possible and have a lot of nearly identical code in weapon and shield classes.

You are abusing inheritance and it has high probability of backfiring at you. I suggest you make information that makes an item into weapon or shield fields of ItemEntity class.

You may wish to read a thread touching on similar subject on rgrd: link
Michał Bieliński, reviewer for Temple of the Roguelike

programmerlike

  • Newcomer
  • Posts: 11
  • Karma: +0/-0
    • View Profile
    • Email
Re: OO roguelike design
« Reply #11 on: March 28, 2011, 09:25:26 PM »
Your approach seems good to me... but, if you read my class hierarchy, you'll notice that ItemEntity objects tell you the actions an actor can do with them. For example the Weapon class will return the following actions:
  -WieldWeapon (if not weld already)
  -DropItem (if not weld)
  -PutAwayWeapon (if weld)
With your approach i'd need a big switch statement on the "ItemType" field of ItemEntity and i don't like it.
For my simple first roguelike project i'm sticking with my pattern but i clearly understand your point and probably doing things your way leads to more flexibility... tnx anyway.

Ancient

  • Rogueliker
  • ***
  • Posts: 453
  • Karma: +0/-0
    • View Profile
Re: OO roguelike design
« Reply #12 on: March 29, 2011, 05:58:54 PM »
With your approach i'd need a big switch statement on the "ItemType" field of ItemEntity and i don't like it.
Nothing more wrong. All ItemEntities could return general actions WieldItem, DropItem and PutAwayItem. WieldItem only modifies your damage if item has damage property. No need to check ItemType in a place other than UI.

The other question to ask oneself is why have "ItemType" field at all? This opens more design issues but since you decided to make simple roguelike I will not go into that.

Whatever path you choose good luck and may your code never have a bug!
Michał Bieliński, reviewer for Temple of the Roguelike

programmerlike

  • Newcomer
  • Posts: 11
  • Karma: +0/-0
    • View Profile
    • Email
Re: OO roguelike design
« Reply #13 on: March 30, 2011, 01:38:13 PM »
I love when i have to admit i was wrong because it means i learned/understand something new...
I switched to the single ItemEntity class design.
The "big swith statement" is currently only in the UI code (as Ancient already correctly pointed out)...
ItemType could be removed?
You mean that removing it i could weld a shield, an armor, a scroll? Is that correct? Looks interesting infact...
This way i could also remove the big switch in the UI and always return the same set of actions for all items... well maybe i could add just some properties (as flags) such: wearable, quaffable etc... otherwise you will have strange things like "wear potion of healing" or "quaff leather armor"...
So my UI code could look like this:
Code: [Select]
ActionList GetItemActions(Item item)
{
  ActionList actions;

  if (item.IsWearable())
    actions.Add(new WearItem(item));
  if (item.IsQuaffable())
    actions.Add(new QuaffItem(item));
  // etc...

  return actions;
}

What do you think about the Decorator pattern for items? You have one big interface IItem with all item properties. You have one big ConcreteItem class that implements the interface returning all default zeros/false values. You then have an ItemDecorator class that implements the IItem interface delegating all methods implementation to an object implementing the IItem interface given in the constructor. So to have a quaffable/throwable/weldable item you do the following:
Code: [Select]
  IItem coolItem = new Quaffable(EFFECT_HEALING, new Throwable(RANGE_POTION, new Weldable(DAMAGE_POTION, new ConcreteItem())));

Each Decorator implementation overrides only relevant methods of the ItemDecorator class.
For example:
Code: [Select]
  //
  // VERY C# LIKE CODE
  //
  class Quaffable subclass of ItemDecorator
  {
    int potionType; // set in the constructor

    public Quaffable(int potionType, IItem baseItem)   
    {
       baseClassConstructor(baseItem);
       this.potionType = potionType;
    }

    public int overrides GetPotionType()
    {
       return potionType;
    }

    public bool overrides IsQuaffable()
    {
       return true;
    }
  }

A datafile for that item could look like the following:
Code: [Select]
ITEM
  NAME=Potion of Healing
  UsabilityFlags=QUAFFABLE | THROWABLE | WELDABLE
  // Reading those flags the parser is smart enough to ignore useless values (for instance ArmorClass)
  Effect=EFFECT_HEALING
  Range=RANGE_POTION
  Damage=DAMAGE_POTION
END ITEM

OK... another huge post... hope someone reads it!
Regards!
« Last Edit: March 30, 2011, 01:40:40 PM by programmerlike »

purestrain

  • Rogueliker
  • ***
  • Posts: 172
  • Karma: +0/-0
    • View Profile
Re: OO roguelike design
« Reply #14 on: March 30, 2011, 04:40:12 PM »
Well, thats a good way to go i guess :-) I'm not using a decorator pattern though but i ask for specific components or let the method (e.g. Entity.getActions(Entity inflictor)) loop through each available component.

I'm also delegating the actions to the specific components, e.g:

Code: [Select]
PickupComponent() : AbstractComponent()
{
  Entity host;

  private int weight;
  private int volume;

 ....

  List<EntityAction> getActions(Entity inflictor) {
    List<EntityAction> result = new ArrayList<EntityAction>();
    if (host.getParent().IsCreature())
      result.add(new StealAction(host));
    if (host.getParent() == null)
      result.add(new PickupAction(host));
  }  
}

So basically if the parent of "sword" is a orc, you could steal it.... if it doesn't have a parent you could pick it up. Its way more complex then this simple example.

Edit:
That example is not that good and i did't implement stealing that way... and i modified the first sentence to avoid discussions about the ultimate way
« Last Edit: March 30, 2011, 06:03:03 PM by purestrain »