Wednesday, July 4, 2012

EPI #10: MapEntitys

In order to finalize my concept for MapEntitys, I need to figure out how MapEntitys, player characters (PCs), and non-player characters (NPCs) are related to each other.  Since a MapEntity (per my definition from last post) is anything the player can interact with, PCs and NPCs must both be related to them in some way.

My original idea was to write a class Character(MapEntity) to define extra resources needed to differentiate a Character from a MapEntity, and then write a class PlayerCharacter(Character), to differentiate player characters from other characters.  (For those of you who aren't fluent in Python syntax, Character extends MapEntity, and PlayerCharacter extends Character.)  This is a textbook example of why it's important to understand inheritance.

While this approach is neat, logical, and takes advantage of the object-oriented paradigm, it's problematic in a couple of ways.  If you look back to the definition for class Map, you'll notice that Maps have an actors property.  actors is a list of all the MapEntitys on the Map, and it's how the MapWidget knows what to draw other than the Map's MapTiles.  The MGEET also asks each entry in the actors list every so often if it wants to move somewhere.  This is how NPC movement is implemented.  What I'm getting at is that if I have a mix of Characters and MapEntitys in my actors list, I have to handle each one differently.  This is a little messy, but not a huge problem.

The real problem comes in the XML definitions.  What's the best way to distinguish MapEntitys from Characters in entities.xml?  And then what's the best way to parse them differently?  I thought about this for awhile, and came up with several more or less elegant ways to do this, but I wasn't really happy with any of them.  There had to be a better way.

And there is.  I made an assumption at the beginning of this post that it is necessary for NPCs to be logically distinct from MapEntitys.  Thinking harder about it, this assumption isn't valid.  There's nothing an NPC needs to be able to do that a MapEntity shouldn't also be able to do.  So I threw out class Character(MapEntity), and changed PlayerCharacter to class PlayerCharacter(MapEntity).  This decision means that the distinction between, say, a treasure chest and a shopkeeper rests in the definition for their respective behaviors.

A sample MapEntity definition in entities.xml might look like this:

<mapentity id='1' name='treasure_chest'>
     <default state='0' direction='SOUTH'/>
     <path type='map_sprite' direction='ALL'>./content/test/sprites/chest_01.png</path>
     <event type='use' state='0'>(GRANT ITEMS 1,2,3 AND CHANGE STATE id=1 TO 1) ELSE SHOW TEXT "You can't carry all the items!"</event>
     <event type='use' state='1'>SHOW TEXT "It's empty!"</event>
</mapentity>

(I apologize for the line wrapping.)  This is pretty simple.  direction indicates the direction the MapEntity is facing.  This is used in conjunction with the map_sprite definitions.  Designers can specify up to four sprites to display when the MapEntity is facing NORTH, SOUTH, EAST, or WEST.  Designers can also use the special keyword "ALL" to assign all four directions at once.  Events, for the time being, are specified in event elements.  The type and state attributes indicate which event to listen for and which state the MapEntity must be in for the event logic to be interpreted.  I'm still thinking about how I'm going to define event logic, but for the moment I'm thinking about a system that looks a little bit like SQL.

No comments:

Post a Comment