Slow progress

The game editor is coming along fine. I gutted the first version and started over with a clear idea of what I wanted to achieve. My focus is now on being able to create a game scenario.

A game scenario would include all customisable elements of the game such as terrain, races, equipment, classes etc. As a start I am going to use the data from Angband to get some content into the scenario. My hope is that once I’ve got Angband set up as a scenario that I will have a good feel of what it takes to create a custom scenario.

The game editor has the added benefit of having me think more about the engine design. Originally I had the concept of a TerrainObject and this object was hard-coded within the engine. Not really ideal if you want to have multiple scenarios that could have different terrain types. The editor now caters for this allowing me to specify the composition of a certain terrain type and its texture (or image).

Of course the logic for handling different terrain types now needs to be removed from the engine and passed on to the scenario. This is where I see some form of scripting requirement emerge whereby a scenario designer can script what happens when an actor bumps into a closed door terrain for example. The engine would expose functionality to allow the script to change a closed door terrain object into an open door terrain object. (well that’s the theory anyway)

Now all I need is more time to code so that I can actually implement all of this.

Advertisements

A Game Editor

I whipped up the beginnings of a game editor today. I know its not traditional for roguelikes to have editors, but I have felt the requirement in terms of building special rooms (prefabs), testing layouts, lighting, etc.

It’s not much yet. All I can do is draw tiles on the map, but it’s a start.

Game Editor

I envisage the editor to allow me to configure dungeon layouts, light sources, skills, races, etc. Basically it should become the editor for all the customisable content in my game.

I had to jump through some hoops to get it to work with XNA, but in the end it wasn’t too hard. There are some nice articles on rendering XNA output onto a panel as seen above. The grid lines were also quite tricky. I basically ended up drawing a 1×1 pixel texture across the render window to form the grid lines. (yes there is no native 2D line drawing support).

I envisage the design to use a Model-View Presenter architecture (MVP) with the actual editor form making updates to the model through a presenter class. My XNA main loop will render the model in whatever state it is. No decisions will be made in the XNA portion of the code. I find it helps me to separate the rendering of game graphics from the actual game data.

I need more hindsight

I started rewriting the entire project yesterday and so far I’m really pleased with the results. I find it helps me to implement something, analyze it, and then scrap it completely. That way I gain the experience of why certain decisions where good and why others were bad.

Some changes I made in the new design are as follows:

  • I got rid of the IDungeonTile metaphor. IDungeonTile constrained me to dungeons and contained logic related to movement. I now use an ITerrainType interface which contains one property describing the terrain composition. This change brings about the Terrain metaphor allowing me to use the same construct for towns, wilderness and dungeons. Each ITerrainType instance defines its own composition based on a set of flags for example Acid, Granite, Lava, etc.
  • I shifted the focus to from a player to actors. No longer do I have hard coded logic based on the player, but rather handle anything from the perspective of an actor. Monsters, NPCs and players are all actors. For testing purposes I take out the player and just have monsters playing the game.
  • Ok, I don’t really have monsters or NPCs either, but rather an actor with an intellect. The intellect is defined by the IIntellect interface and allows me to give an actor a specific IIntellect implementation. Currently I make use of a ComputerAI and PlayerAI. The ComputerAI implementation will make decisions based on it’s needs at the time. Decisions are translated into Commands and then executed by the game engine. PlayerAI is under the control of the player and does nothing until it receives an input command from the player which is then translated into a Command.
  • From the above you will realize that I’ve added a generic command structure using the Command design pattern. All actions within the game get translated into a ICommand object and are executed in turn by the engine.
  • IMovementBehaviour has become IMovementProfile. I just like the terminology better. I changed the handle bump functionality somewhat. The movement profile now provides a default action to perform when an actor collides with something. This is useful if I have an actor that can dig through walls versus an actor that moves like a humanoid. The default action for a digging actor when colliding with rock would be to dig versus a humanoid actor who would do nothing.
  • I added a new IFovProfile to my field of view code. The field of view profile describes how something “sees” in the game. This includes the field of view shape, sight range, and some functionality to determine if something is visible based on the amount of light it receives. The last bit of functionality is useful to implement blindness, infravision, etc.
  • I created a GameLevel object that will manage the aspects of the particular game level. This could be a town, wilderness area or a dungeon. The GameLevel has a TerrainMap (which is a bunch of ITerrainType instances), a list of actors, and a lightmap (which describes the lighting information for the level). In the future I will add a list of level objects i.e. treasure to the game level.

The above changes are a big departure from the original design, but feel a lot more like a game design (from a software design perspective) rather than a dungeon generator with stuff hacked onto it. I am thinking that the IMovementProfile and IFovProfile interfaces will probably move from the Actor class to some kind of Race class. That way the actor’s race would define its movement and field of view characteristics.

My new implementation has already raised some more questions. When I check for a collision I ask my GameLevel object for the composition properties of the terrain at the location I want to move to. Then I ask my GameLevel object for the composition properties of any actors at that location. An actor has a collision when the union of the terrain and actor composition properties is impassable for the IMovementProfile at the target location.

The question is whether I should leave the check as two separate calls, one for terrain and one for actors? This seems a bit clumsy. To change it to a single method call would necessitate the ITerrainType and Actor classes to inherit from the same base class. The base class would define a common Composition property which is used during collision checks. As a rule I am not keen on inheritance hierarchies and never imagined all my “game” objects inheriting from some super class.

Hence the need for more hindsight.

My Tiles are Evil

As mentioned in my Refactoring for AI post, things are starting to get a bit complicated. The fundamental problem lies in the fact that my code is based on a dungeon generator design and not on a game design.

I make use of a generic map class that encapsulates an array of tiles. For dungeon generation I use an interface IDungeonTile to describe my dungeon tile behaviour.

    public interface IDungeonTile

    {

        bool IsObstacle { get; }

        bool IsWalkable { get; }

    }

The dungeon tiles know if they are obstacles and if they are walkable. My dungeon generator would start with a map filled with tiles full of rock (i.e. where IsObstable is true and IsWalkable is false) and then start to carve out corridors, place rooms and add doors.

My tiles also handled the logic for when a player would bump into them. Closed door tiles would know to open themselves, walls would repel the player etc. Notice that I only talk about the player, this was due to the fact that it was all I was thinking about at the time. The following code shows the logic of the ClosedDoorTile class for when something bumps into it.

        public bool HandleBump(DungeonMap dungeon, Point location)

        {

            if (IsObstacle)

            {

                dungeon[location] = new OpenDoorTile();

                return false;

            }

 

            return true;

        }

My path finding implementation started to raise the first real issues of this design. For the A* algorithm you need to provide a movement cost for the various terrain features. The question I had to ask myself was, what determined the movement cost of over a specific type of terrain? You could simplify this to whether a certain terrain type is an obstacle or not. My current design, where the IDungeonTile objects determined if they were obstacles or not, meant that I cold only support one type of movement cost for all entities (or actors).

My A* implementation required some further information that needed to be abstracted into some kind of common behaviour. For this I created the IMovementBehaviour interface listed below.

    public interface IMovementBehaviour

    {

        /// <summary>

        /// The directions available for movement. Use this to constrain the movement behaviour to certain directions when moving.

        /// </summary>

        Direction[] DirectionsAvailable { get; }

        /// <summary>

        /// Retrieves the movement cost for this behaviour based on the terrain type.

        /// </summary>

        /// <param name=”dungeonTile”>The dungeon terrain type to evaluate</param>

        /// <returns>The movement cost calculated for the dungeon terrain type</returns>

        double GetTerrainMovementCost(IDungeonTile dungeonTile);

        /// <summary>

        /// Determines if this movement behaviour can walk on a specific terrain type

        /// </summary>

        /// <param name=”dungeonTile”>The dungeon terrain type to evaluate</param>

        /// <returns>Returns true if the behaviour can walk on the terrain type</returns>

        bool CanWalkOnTerrain(IDungeonTile dungeonTile);

        /// <summary>

        /// Handles the interaction with a dungeon terrain type at a specific location

        /// </summary>

        /// <param name=”dungeon”>The dungeon representing the terrain</param>

        /// <param name=”location”>The location to bump into</param>

        /// <returns>Return true if the bump was successful</returns>

        bool HandleBump(DungeonMap dungeon, Point location);

    }

The idea behind the movement behaviours was to abstract how something moves around the dungeon away from the terrain itself. I envisaged that a PlayerMovementBehaviour would react completely different to a GhostMovementBehaviour for example. With the IMovementBehaviour interface I was able to do this by

  • limiting the directions available for movement,
  • terrain movement cost based on terrain type,
  • determining if a particular terrain type was movable,
  • and handling what happened if a particular “movement behaviour” bumped into something.

(I am not completely convinced that HandleBump should belong with movement behaviour.)

My IDungeonTiles now no longer define if they are obstacles or not. Rather I envisage them to define some kind of property such as whether they are solid rock, water, fire, etc. The movement behaviour would use these properties to determine if an actor can walk (or move) on the terrain and the associated movement cost for the terrain type.

Of course I now have to refactor all my original code to make use of movement behaviours. The end result will be a more flexible system which is no longer tied to a specific type of actor.

Speed Issues Resolved

I made use of a profiling tool to identify the major bottlenecks in my code. Two sections were causing most of my problems. The first has to do with my generic Map class.

The Map<T> class is used to represent all the 2-D structures in the game for example the dungeon, visibility map and light maps. For ease of use I had the following code to fill a map structure with an instance of a specific type.

        public void FillMap(Type tileType)

        {

            // Set each tile to the instance of the default tile

            foreach (var location in Locations)

                this[location] = (T)Activator.CreateInstance(tileType);

        }

Now the above code worked nicely, but is dog slow due to the reflection. As a rule I don’t do any premature optimisation, but the general slowness of my AI required me to address this slowness.

The solution was to use an anonymous delegate to pass in the actual new statement of the type to the function. The new code looks as follows

        public void FillMap(Func<T> cellFactory)

        {

            // Set each tile to the instance of the default tile

            foreach (var location in Locations)

                this[location] = cellFactory();

        }

The new function is used as follows

            // Fill the lightmap with black tiles

            FillMap(() => new LightMapTile());

This change gained a 50% speed improvement over the old code. Not too bad.

The next real bottleneck was in the actual AI logic. I have a piece of code that is responsible for identifying threats. The original code made use of a LINQ statement which was incorrect to begin with (the actual logic not the LINQ). The new code simplifies the threat logic into the following.

            // Find all actors that are visible threats

            return (from actor in Dungeon.Actors where IsThreat(actor) && VisibilityMap[actor.Location].IsVisible select actor)

                .ToList();

The new code flies and I now have multiple actors running around the dungeon finding each other. Pretty cool.

The next step is to add some evasion logic which should yield actors chasing each other around the map. Thereafter I should look at some simple combat and tweaking the main loop to defer decision making to the player when it’s his turn.

Refactoring for AI

Initially I started this project as a set of technologies such as dungeon generation, field of view, lighting, pathfinding, etc. My code was always from the perspective of the player and I made no provision for monsters and other gameplay elements. That’s why previous releases have always been in the form of tech-demo’s, because that is all the were.

For AI I have to rethink the whole thing. I don’t want to have the concept of a player and then some monsters, but would like the engine/game to deal with both in the same way. This adds some complexity, but also opens up a lot of possibilities.

The main update loop would be something along the lines of, for each actor, act. The AI controlled actors would act immediately and the player actor would do nothing until input (which is translated into an action) was received. All actors after the player would wait until the player completed his action. Rinse and repeat.

So far so good. I implemented a basic wandering monster with chase AI and let it loose in the dungeon. It looked cool with two little critters running around the dungeon and then converging on each other when they entered each other’s Fov. I added some more critters which promptly sent my framerate to 1Fps.

I guess it’s time to optimize.