Interacting with tiles and props
In the data model supporting my engine, I distinguish three base classes:
- Cells – cells are ’tiles’ on the game board. A cell defines a terrain (an id representing grass, sand, etc…), the solid property which determines whether an actor can go through the cell, a prop
- Props. A prop is an accessory associated with a cell. This could be use for trees, walls, etc…
For performance reasons, it might be better for actors not to interact with cells and props. Also we could work around the problem using actors. I leave this question as an implementation detail. For now, I want to consider a few scenarios which might require interacting with the stage and props:
- There used to be games based on a ‘color all tiles’ concept. We’d like to change the environment property of a tile given preconditions.
- Suppose an actor picks a key and uses it to open a door. I would tend to define the door as a prop, and the key as either a prop or an actor.
- Now suppose an actor activates a lever, this might open a door as well, or change something else
a. Specifying tile and prop interactions
Let’s see how this can be specified using our pseudo-scripting. I add the following methods to the Script class:
-(void)let:(act)reaction when:(tag)kind doing:(act)action within:(float)range has:(tag)object;
-(void)let:(act)reaction when:(tag)kind within:(float)range has:(tag)object;
-(void)let:(act)reaction when:(tag)kind is:(tag)status;
-(void)let:(act)reaction when:(tag)kind within:(float)range is:(tag)status;
This doesn’t require redefining the statement class, all that is new so far is that we can add conditions over the target that triggers an action – carrying an item or bearing a given status. So I extend the Statement class accordingly.
I have added methods checking for statuses and items to the Actor class; the actor class forwards hasStatus:(tag)status and hasItem:(tag)item to the hasTag:(tag)tg method; I don’t allocate new pointers at this point – I’ll be relying on an actor subclass if I need more flexibility.
b. Enabling tile and prop interaction
At this point, scripts using the new statement could work, but they would only work with actors:
- The Interpreter doesn’t recognize tiles and props as type-binding targets
- Tiles and props don’t have tags associated to them anyway
I modify Interpreter to allow type-binding using tiles. I won’t define per-tile tags. Each tile has an integer coding the kind of terrain used for the tile. I map these ids to tags in the Board class. Maybe later I can extend board to tag special tiles irrespective of terrain if needed.
The interpreter works by associating a TargetSelector to a Decision. Decision is tightly bound to the Actor class, so I define a BoardDecision class for tiles. TargetSelector only requires an actor’s location, so I updated this class to support tiles as well.
For now BoardDecision only recognizes changes to the solid/empty state of a tile (can actors pass through?) and wholesale changes to terrain type.
Finally, I decide I won’t support prop interactions after all. using an Actor as substitute for a prop is much easier.
Picking, dropping, exchanging and snatching objects
I still don’t have anything to support picking and dropping objects. Maybe a good place to implement picking is within BasicActorUpdates:
- If an actor is on a tile with a pickable object, they can automatically pick an object with a suitable ‘auto-pick’ tag
- If an actor is on a tile with a pickable, and they use a PICK action, they will also pick that object.
There are many issues related to picking, dropping, exchanging and snatching (forcefully acquiring) objects. To get started, however, I will only use the following statements, adding them to the script class:
This allows a game designer to specify basic flows for goods collection, storage and exchange. Note that all of these are high level actions compared to what I have defined so far – given the opportunity, a character is expected to effect these actions, moving to reach the target when detected.
These actions all break down into a couple of actions, one to reach the target and one to effect the corresponding ‘material transfer’ (give/take/pick an object). This is reflected in my implementation of the new Script methods:
- Each of the above functions generates an approach: statement as already defined by the Script class.
- A required/desired item condition is attached to the generated statement.
- A lower priority statement is added to specify the actual transfer.
I have tied up a quick implementation – for now the items to give/take and the intended target are bound to the target actor as a side effect of selecting target actors/locations. I’ll try to put together something more adequate later, but for now, let’s see if that works.
There is an incidental difference between picking and other behaviors I worked with so far: the pick methods defined in Script may imply moving to a location defined by a cell on the board.
So far, all my tests only required actors to move towards/away from other actors. However, because I decided to rely on existing script statements to implement picking, the requirement that a target tag may refer either to a tagged tile or a tagged actor propagated.
I’ve stubbornly followed suit, for the simple reason that it was legitimate to want to move towards/away from a given tile rather than a given actor. Meanwhile…
- I have a serious performance issue to take care of, because cells in the data model don’t define a location vector. I have a method that generates a location vector every time, but it is unthinkable to have this run for many tiles at every frame, as it would kill runtime memory in a very, very short time.
- While it is legitimate to attempt reaching an item on a tagged tile, the algorithm for selecting a tagged tile containing an item is also a concern.
Next time I might look into this in some detail – probably we can improve all this a lot by defining a base class for tiles and actors; also, I surely need to run a fun script to test picking, giving and snatching.