Entity-Component-System Part 1

by Call me dave... 13. October 2018 20:07

The Entity-Component-System pattern is utilised in many modern computer game engines so that game entities such a players, enemies, weapons, buildings, etc. are not built from specific classes within an inheritance hierarchy but are implemented as a collection of pluggable behaviours and state that can be added and removed at runtime.

Dynamic behaviour is hard

Dynamic languages like JavaScript are able to modify their class definition at runtime. Methods and fields can be added or removed with ease. By replacing, a method with a wrapper that calls the original method it is trivial to implement cross cutting concerns such as logging or firing data changed events. In contrast, statically typed languages objects are constrained by their compile time type.

I have used the complexity of modelling Bank Accounts in a number of posts over the years.  They are complex as Banks often market a diverse set of interest bearing accounts to their customers.  As part of the product definition the interest calculations can be defined based on on a large number of variables such as account type, the customer type, number of deposits or withdrawals during the month, the balance, fixed or variable terms and whether the account is linked to a credit card or mortgage.  Assuming that you model each type of Bank account as a separate class a factory is needed to choose the correct instance type by first looking up the customer’s configuration and account transactions change over time the type of class that should be instantiated can only be determined at run time.

Extensions points for Dynamic behaviour

Choosing the correct class at runtime using a Factory or Abstract Factory  is not a scalable solution as the process to “lookup” the the correct class can lead to scans of dozens of different tables.

A better approach is to have a single slimmed down generic Bank Account that has been built with a suite of extensions points where capabilities such as interest calculations are plugged into it at runtime.

Similarly, there can be a huge amount of variability in computer games with players, enemies, weapons, buildings, trees, potions all sharing common characteristics but each ultimately being unique.

Decomposing an Game Entity

Imagine a 80s style top down scroller where the player either runs on the ground or flies a helicopter. In the game you move around picking up power ups, replenishing ammunition and gaining different weapons. Trees block the player when they are on the ground but they can be flown over in the helicopter. Similarly, buildings are can only be entered when the player is on the ground.

Here is a table of Game Entities with some common attributes.

Environment Position

Velocity/Movement

Life points

Damage Points

Can open building

Can fly

Player

Y

Y

Y

Y

Y

N

Player Helicopter

Y

Y

Y

Y

N

Y

Tree, Building

Y

N

N

N

N

N

Ground Power Up

Y

N

N

N

N

N

Flying Power Up

Y

N

N

N

N

Y

Player Machine Gun

N

N

N

Y

N

N

Head Up Display

N

N

N

N

N

N

By going through the table it’s clear that there aren’t ANY attributes that are shared by all elements but it may be possible to create two or three groups of similar entities and each group could have its own base class. Problems also arise from when entities go through state changes such as a player moving from walking to flying or when a player gains a power up. These transitions change the behaviour and state of the entity.

The Entity-Component-System pattern takes a very different approach. The Entity is reduced to a single identity field with a dynamic collection of attributes and behaviours (called components) logically attached to it. When the player walks up to the helicopter the visual and behavioural components for a walking person are replaced with the helicopter. The damage and hit points are similarly modified with ease. The last role in the pattern is called the System, which are the algorithms that span across entities and provide collision detection, rendering etc.

Tags:

My favourite design tools - part 1

by Call me dave... 11. February 2014 19:56

I work in an agile environment where the majority of our design and requirement artefacts are photographs of whiteboard sessions with our users and colleagues. These uploaded into our requirement tracking tool and attached to the relevant user story.

The two diagrams that we use on a daily basis are:

· Output to Input diagrams which we utilise for requirements gathering

· Color-UML which overlays UML with design rules

Recently I have been training some business analysts and dev leads that have joined the team and I will be posting the training material here.

Tags:

C++ Accelerate Massive Parallelism

by Call me dave... 25. June 2011 22:43

I have been an avid follower of Herb Sutter’s writings for years, from his magazine articles in the C++ Report and the C/C++ Users Journal, his books on C++ development and recently his series of posts on parallel programming and concurrency for Dr Dobbs.  Herb is the chair of the C++ standards committee where he and others are near to finalising C++0x standard.  In essence Herb knows his stuff.

Herb recently announced C++ AMP at the AMD Fusion conference and I was blown away.  Microsoft have modified their C++ compiler so that it can target both the CPU and a DirectX compatible graphics card within the same program.  This enables a developer to write code that utilises the hundreds of cores available on graphics cards, to perform blazingly fast parallel computations, without resorting to the current practice of writing code in a language designed for graphics processing (High Level Shader Language [HLSL] or GL Shading Language [GLSL]) or within a C like language (CUDA or OpenCL) where the OO benefits of C++ are missing.

Instead the keyword restrict is used to mark a method as being able to be executed on the graphics card.  The developer then uses a subset of the C++ language (enforced by the compiler) to implement the computation.  The complexity of moving data between the CPU, RAM and the GPU is also simplified by the introduction of a set of classes that automatically handle the marshalling of data between the devices.  The compiler converts the C++ code into HLSL code which is then embedded into the executable.  At runtime the HLSL code is sent to the DirectX driver which in turn converts it into the appropriate machine code (for a particular device) and executes it on the graphics card.

The example below (from Daniel Moth’s presentation - URL below) is a simple matrix by matrix multiplication.  Its clear that the outer for loop can be parallelised.  An interesting point is the complex indexing to pull out values from vA and vb which are both one dimensional arrays but actually store a two dimensional structure.

void MatrixMultiply( vector<float>& C,
const vector<float>& vA,
const vector<float>& vB, int M, int N, int W )
{
  for (int y = 0; y < M; y++) {
    for (int x = 0; x < N; x++) {
      float sum = 0;
      for(int i = 0; i < W; i++)
      sum += vA[y * W + i] * vB[i * N + x];
      vC[y * N + x] = sum;
    }
  }
}
Using C++ AMP the matrices are marshalled across to the GPU by wrapping the vectors in array_views.  Further the array_views are used to project the two dimensional matrix onto the one dimensional vector and so the complex indexing code isn’t present in the C++ AMP version.  The code that executes on the GPGPU are the lines within the lambda expression that marked with the restrict(direct3d) keyword.  On the graphics card the texture that is getting the result of computation is write only hence variable c is of type array_view<writeonly<>>.
void MatrixMultiply( vector<float>& vC,
const vector<float>& vA,
const vector<float>& vB, int M, int N, int W )
{
  array_view<const float,2> a(M,W,vA),b(W,N,vB);
  array_view<writeonly<float>,2> c(M,N,vC);
  parallel_for_each(c.grid, [=](index<2> idx) restrict(direct3d) {
   float sum = 0;
   for(int i = 0; i < a.extent.x; i++)
     sum += a(idx.y, i) * b(i, idx.x);
     c[idx] = sum;
   }
  );
}

There are millions of lines of C++ code used in finance industry for modelling derivatives and many of the larger institutions are now looking at GPGPU technology to give them an edge in the competitive world of algorithmic trading.  CUDA is currently the default choice for GPGPU development it will be very interesting in twelve months to see if this trend reverses due to both the simplicity of parallelising a function using AMP C++.

Herb’s keynote.

Daniel Moth: Blazing-fast code using GPUs and more, with C++ AMP

NVidia will also support C++ AMP but points out CUDA is available for Linux and Mac as well as Windows

Finally Microsoft have indicated that they will take their C++ extensions to a standards board thus enabling other compiler vendors to implement the restrict keyword in their products.  Hopefully this will mean that in a couple of years it will be possible to have C++ code target other devices such as FPGAs, PS3’s cell processor and Intel’s Many Integrated Cores (MIC) daughter board.

 

Side Note: 

Eventually all good ideas come back again. When C with Classes was being created it had a readonly and a writeonly keyword and when C++ was created the C standard committee liked the concept so much they asked that the readonly keyword by renamed to const and added it to the language. Meanwhile writeonly was dropped entirely. Instead of adding writeonly as a keyword Microsoft have gone down the library root i.e. writeonly<T> instead of writeonly T. Personally I think a keyword would have been far cleaner but then again I don’t work on the standards committee and have no idea how complex it would be to add into the official ISO C++ standard…  But considering how long its taken to complete this version of the standard I cant say I am terribly surprised...

Tags:

Coding Dojos at the workplace

by Call me dave... 25. June 2011 20:58

Your an IT manager at a small manufacturing company and have a staff of 5.  In two months time your team is slated to replace the internal HR web site that is currently running on Classic ASP. The Architect and lead developer have selected the following software stack:

  • ASP.NET MVC
  • Entity Framework
  • .NET 4.0

The team is very experienced however for the last 2 years they have been maintaining the sales web site which runs on ASP.NET and .NET 2.0.  Due to production support constraints you are unable to send the team on an externally run training course… 

Over my career I have seen this situation played out far too many times.  Teams spend the first couple of weeks or months learning on the job and end up having to replace most of the code that was written at the project’s commencement.

A Coding Dojo is a meeting where a bunch of coders get together to work on a programming challenge. They are there have fun and to engage in DeliberatePractice in order to improve their skills. (ref Coding  Dojo)

What’s the best way to learn a new technology, pattern or programming language?  By playing, doing, prototyping, fiddling and experimenting with it.  What’s the best way for a team to learn a new technology, pattern or programming language? By doing it together!!

Coding Dojos rules:

  • A challenge isn’t solved or challenge beaten without code i.e. A paper design doesn’t cut it
  • Code doesn’t exists unless there are tests
  • Work as a team/hook up with an expert

Formats:

  • Prepared Kata – Presenter solves the problem in front of an audience but can/should/will change his solution based on ideas/enhancements/feedback from the audience
  • Randori Kata – A pair of developers are selected from the audience.  The pair work together together to solve the problem and every 15 or 20 minutes one of the pair is swapped with another audience member.  Preferably everyone in the audience should have an opportunity to sit at the computer and bang out some code.

In a Coding Dojo “meet up” the Randori Kata can be intimidating for a new comer – No one wants to get a mental blank in front of a group of people or have a group commenting of their coding style.  This should be less of an issue in a work environment where the developers already know each other.  In fact the format ensures that everyone participates in the learning experience.

Workplace <Insert Technology here> Coding Dojo:

  1. Prep work
    1. Find the most experienced person in the team who has already used the technology
    2. Ask them to create a 30 minute demo (PowerPoint is fine) where the technology is used
    3. Ask them to create a “Cheat sheet” that consists of 3 or 4 pages of generic code snippets that show how the technology is used for different situations
    4. Create a coding problem (don’t tell the team or the person that wrote the Cheat Sheet) that can be solved reasonably easily using the technology and ensure that the solution to the problem utilises items within the Cheat Sheet
  2. Kata
    1. Have the team member present the 30 minute introduction demo
    2. Provide everyone with a copy of the “Cheat Sheet”
    3. Spend 10 minutes discussing the technology and the contents of the Cheat Sheet
    4. Explain the coding problem
    5. Randomly chose a developer to join the presenter – Coding in a pair is less stressful
    6. Have the presenter/colleague pair start solving the problem (make sure they write tests)
    7. Following Randori Kata rotate through the developers every 15 to 20 minutes
    8. After two hours of coding stop the clock
    9. Spend 10 minutes in a discussion
      1. What was hard?
      2. What was easy?
      3. How confident do people feel?
      4. What else do we need to learn?

Tags:

WPF, Silverlight and MVVM presentation slide deck

by Call me dave... 27. May 2011 20:03

During the week I presented an introduction to WPF & Silverlight using the Model View ViewModel pattern.  The audience was a group of developers that had been working on a .NET 2.0 based application for the last 5 years and were going to transition to .NET 4.0.  Hence the session material was designed to briefly touch on the main WPF concepts and allow them to drill into the topics in more detail at their own leisure.

Enjoy…

WPF & Silverlight Development using Model View ViewModel.pptx (164.07 kb)

Tags:

Back in Australia

by Call me dave... 27. May 2011 19:52

After living in the UK since mid 2008 my wife and I have moved back to Sydney Australia.  We are also bringing back our baby boy Logan who is the reason I haven’t blogged in almost a year.  I’m looking forward to learning about the Open Source, Alt.NET and Agile community in Sydney. 

Tags:

BattleLang – A Domain Specific Language in .NET – Part III

by Call me dave... 23. December 2009 06:45

In this series of blog posts I am exploring the creation of a DSL for a mythical Role Playing Game called “Dragons of Kin” at the Puzzle Guzzler software house.  The language will allow the game designers to interact with the underlying game engine.  All the business logic and heavy lifting is performed by the engine meanwhile the language will be used a conduit into the engine.  Characters, layout and animations will be configured using the language.  In this post I will show the first implementation of the DSL.

In the last post Douglas (the development lead) and Jasmine (the level designer) had created the following example of the first cut of the language they had developed.

 Creature Crocodile {
    Life := random_select [30..40] LP
    Magic := 15 MP
    LifeHealingSpeed   := 3 LP/sec
    MagicHealingSpeed   := 1 MP/min
    Weapons
    {
      Bite:
        Inflicts:= random_select [5..10] LP
      PoisonBite:
        Inflicts:= random_select [5..10] LP + 3 LP/sec
        Costs:= 5 MP
    }
  }

Douglas takes the language fragment to Jimmy a developer on his team.

Jimmy So this is the infamous BattleLang
Douglas Yep.  As we discussed in the Stand Up.  We have three weeks to implement a text mode engine that will allow Christoph to move from the town to the spring.  There he will kill the crocodiles and save the town.
Jimmy Everything hard coded then.  So we will have three Creature types – Jimmy, Crocodile and Boss Crocodile.  Lets not do spawning either.  The Crocodiles will be created as soon as the engine starts.  There really should be an Area type in the language so that Jasmine can assign the Crocs to a location.
Douglas Definitely.  Lets put that up onto the Product backlog.  So can you do the first cut of the parser over the next couple of days?
Jimmy I think so.  I was looking at F# Lex support, ANTLR, Bison but if I only have 2 days I don’t want to learn a new library or toolset.  I’ll just crank out something quickly and we’ll throw it away bit further down the track. It looks pretty easy to parse.
Douglas Lets go to the white board and draw out a transition diagram.

image  

Each line represents a token that the scanner is reading from the input.  We start with “Creature” read in the name of the name Creature then we have an open and close bracket and then we reach the end. In this case we are saying its legal to have a Creature with no attributes defined at all.
Jimmy And what we assume that during each transition all the whitespace is thrown away?  It doesn’t make sense for that to be legal does it?
Douglas For now lets assume that around every token there is whitespace.  When the code is rewritten we can throw that assumption away.  So the code should actually look like this.
  Creature Crocodile {
    Life := random_select [ 30 .. 40 ] LP
    Magic := 15 MP
    LifeHealingSpeed   := 3 LP / sec
    MagicHealingSpeed   := 1 MP / min
    Weapons
    {
      Bite :
        Inflicts := random_select [ 5 .. 10 ] LP
      PoisonBite :
        Inflicts := random_select [ 5 .. 10 ] LP + 3 LP / sec
        Costs := 5 MP
    }
  }

What is I mean by it being legal is that the checking if the Creature is valid is a different step in the process. 
image 
By shifting the complex validation out of the Syntax Analyser it makes the code a lot simpler. 
Jimmy Ok.  Let me see so to do the parsing of the character attributes there is another string literal and then we parse the function itself.
 image  

And the function parser is as follows.
image
Douglas I’ll add in the Weapons
 image

 

Building the Proof of Concept BattleLang DSL

As described above there are a couple of stages to process a language:

  • Lexical Analyser which converts the input stream into into Tokens
  • Syntax Analyser which implements the transition diagram
  • Semantic Analyser validates the business rules

 

Lexical Analyser

By simplifying the language definition so that all Tokens are separated by whitespace the scanner is very simple.

public static TokenAndStringIndex GetNextToken(string text, int currentIndex)
{
    string token;
    if (HaveReachedEndOfInput(currentIndex, text))
        return new TokenAndStringIndex("", text.Length);

    currentIndex = RemoveWhitespace(currentIndex, text);
    currentIndex = GetToken(currentIndex, text, out token);
    return new TokenAndStringIndex(token, currentIndex);
}

The TokenAndStringIndex is a tuple that stores the current Index into the array and the Token that was found.  Retrieving a list of all the tokens is a simple matter of looping through the input.  While we could return an IEnumberable<string> in a more complete solution the TokenAndStringIndex would be renamed and extended to to include information such as the line number within the string the token was extract from.  This information is invaluable when it comes to creating useful error messages when problem are found during the Syntax and Semantic Analyser steps.

 

public static IEnumerable<TokenAndStringIndex> GetAllTokens(string text)
{
    int currentIndex = 0;
    while (currentIndex < text.Length)
    {
        var result = GetNextToken(text, currentIndex);
        currentIndex = result.IndexIntoInputString;
        if (!string.IsNullOrEmpty(result.Token))
            yield return result;
    }
}

 

Syntax Analyser

The syntax analyser eats through the streams of tokens moving through the transition diagram.  On nodes such as the Open Bracket it needs to grab the next token and determine which of the three subsequent nodes should be selected (Close Bracket, retrieve Creature attribute or Enter Weapons scope).  There are lots of different ways to model the nodes and transitions.  One very clean way is to have a class per node and implementing the state pattern.  All classes implement an interface INode and member INode ProcessToken(Token t)

However this time I decided to use an even simpler (although far less scalable) approach.

First three enums were created:

  • Keywords – Include nodes for Creature,  Weapons, Inflicts, Costs,  MagicPoints, LifePoints, Seconds, Minutes, RandomSelect and Colon
  • Operators – Includes nodes for Assign, Add, Subtract, Multiply, Divide, Range
  • Scope – Includes nodes for OpenCreateScope, CloseCreateScope, OpenWeaponScope, CloseWeaponScope, OpenRangeScope, CloseRangeScope

I then created the TokenAction class which links the Token string, to the enum and to a delegate that will manage the transition logic and the retrieval of the information about the Creature.

internal class TokenAction<T>
{
    private readonly T _tokenType;
    private readonly string _token;
    private readonly Action _action;

    public TokenAction(T tokenType, string token, Action action)
    {
        _tokenType = tokenType;
        _action = action;
        _token = token;
    }

    public Action Action
    {
        get { return _action; }
    }

    public string Token
    {
        get { return _token; }
    }

    public T TokenType
    {
        get { return _tokenType; }
    }
}

If we are at Node “Creature” the next token will be the Creature’s name then the following node should be a “{“.  The “{“ node includes its own transition logic that we can access by calling execute on its Action.  Hence:

new TokenAction<KeyWords> (KeyWords.Creature, "Creature", () =>

  {
    _creature.Name = GetLiteral(); 
    TransitionToScopeToken(new[] { Scope.OpenCreateScope });
  }

)

The following code searches for either “MP” or “LP” and sets the _dimension to the required value:

TransitionToKeywordToken(new[] { KeyWords.MagicPoints, KeyWords.LifePoints });

new TokenAction<KeyWords>(KeyWords.MagicPoints, "MP", () => _dimension = DimensionType.Magic)

new TokenAction<KeyWords>(KeyWords.LifePoints, "LP",  () => _dimension = DimensionType.Life)

As you can see the code “collects” values such as the DimesionType as it parsers the tree.  All of the Tokens and their relevant Actions were placed into three symbol tables using the TokenActions class which manages the moving executing of the Actions.

internal class TokenActions<T> 
{
      private readonly Dictionary<T, TokenAction<T>> _symbolTable = new Dictionary<T, TokenAction<T>>();
      public void Add(TokenAction<T> tokenAction)
      {
          _symbolTable.Add(tokenAction.TokenType,tokenAction);
      }

      private TokenAction<T> GetTokenAction(string token)
      {
          return _symbolTable.Values.First(x => x.Token == token);
      }

      private TokenAction<T> GetTokenAction(T tokenType)
      {
          return _symbolTable[tokenType];
      }

      public void InvokeAction(string token)
      {
          GetTokenAction(token).Action();
      }

      public void InvokeAction(T tokenType)
      {
          GetTokenAction(tokenType).Action();
      }

      public bool IsTokenFor(string s, T tokenType)
      {
          return GetTokenAction(tokenType).Token == s;
      }

      public bool TokenSymbolExists(string token)
      {
          return _symbolTable.Values.Count(x => x.Token == token) > 0;
      }
  }

The parser populates the following objects:

  • Unit which models the following “10 MP / sec”
  • UnitsType a collection of Unit objects and automatically reduces “10 MP / sec + 11 MP / sec” to “21 MP / sec”
  • Weapon which includes the damage that is inflicted and the cost to the user
  • Creature which will be passed to the engine – Currently implemented as a fake shell to demonstrate the parser
using System.Collections.Generic;
using System.Linq;

namespace BattleLangParser
{
    public enum DimensionType
    {
        Magic,
        Life
    }

    public enum TimespanType
    {
        Now,
        Second,
        Minute
    }

    public class Unit
    {
        public float Amount { get; set; }
        public DimensionType Dimension { get; set; }
        public TimespanType Timespan { get; set; }
    }

    public class UnitsType
    {
        private readonly List<Unit> _units = new List<Unit>();
        public IList<Unit> Units { get { return _units; } }
        
        public void Add(Unit u, Operator @operator)
        {
            if(_units.Where(x => x.Dimension == u.Dimension && x.Timespan == u.Timespan).Count()>0)
            {
                var result = _units.First(x => x.Dimension == u.Dimension && x.Timespan == u.Timespan);
                switch(@operator)
                {
                    case Operator.Add:
                        result.Amount += u.Amount;
                        break;
                    case Operator.Subtract:
                        result.Amount -= u.Amount;
                        break;
                }                
            }
            else
            {
                _units.Add(u);
            }
        }
    }

    public class Weapon
    {
        public Weapon()
        {
            Inflicts = new UnitsType();
            Costs = new UnitsType();
        }

        public UnitsType Inflicts { get; private set; }
        public UnitsType Costs { get; private set; }
    }

    public class Creature
    {
        public Creature()
        {
            Stats = new Dictionary<string, UnitsType>();
            Weapons = new Dictionary<string, Weapon>();
        }

        public string Name { get; set; }
        public Dictionary<string, UnitsType> Stats { get; private set; }
        public Dictionary<string, Weapon> Weapons { get; private set; }
    }
}

Semantic Analyser

In this version of the software it does not include a semantic Analyser.

 

 

Unit Tests

An example of one of the Unit tests:

[Test]
public void ParseCreature_MultipleDimensions_EachDifferent()
{
    const string emptyCreature = @"
Creature TestMonster
{
    RingOfhealing := 3 MP / min + 8 LP / min
}";
    var b = new Parser(emptyCreature);
    Creature result = b.Parse();
    Assert.AreEqual("TestMonster", result.Name);

    Assert.IsNotNull(result.Stats["RingOfhealing"]);
    Assert.AreEqual(3.0, result.Stats["RingOfhealing"].Units[0].Amount);
    Assert.AreEqual(DimensionType.Magic, result.Stats["RingOfhealing"].Units[0].Dimension);
    Assert.AreEqual(TimespanType.Minute, result.Stats["RingOfhealing"].Units[0].Timespan);
    Assert.AreEqual(8.0, result.Stats["RingOfhealing"].Units[1].Amount);
    Assert.AreEqual(DimensionType.Life, result.Stats["RingOfhealing"].Units[1].Dimension);
    Assert.AreEqual(TimespanType.Minute, result.Stats["RingOfhealing"].Units[1].Timespan);
}

Verifying the Creature has been created correctly involves:

  • Checking that expected attributes have been loaded
  • Checking that attributes have the correct Units of Measure
  • Providing the user with appropriate error messages

 

Summary

This post has shown how to very easily write a simple DSL (less than 500 lines of code in total) that can be used to populate a relatively complex object. 

There are problems with the approach I’ve taken:

  • The Lexical Analyser was written by hand – There are some great libraries and frameworks that can do the heavy lifting for us on this one
  • Logic for populating the Creature was intermingled with logic for verifying the grammar – An Abstract Syntax Tree and the Visitor pattern is the answer for decoupling those two domains
  • Currently very poor error messages for badly formed user code

 

Source code

BattleLang.SimpleImplementation.7z (91.06 kb)

Tags:

BattleLang – A Domain Specific Language in .NET – Part II

by Call me dave... 20. December 2009 00:24

At Puzzle Guzzler, a small games software company, the development team are starting design work on their new game “Dragons of Kin”.  They are sitting around a table covered with toy dragons, dwarfs and concept drawings. 

The group consists of:

  • Brett the writer – He will be creating the overriding theme for the game, the quests, dialog and boss character personalities
  • Jasmine the environment and level lead – She owns the look of the game and the placement of monsters and items
  • Jen the Animation lead – She owns all CG assets in the game including modelling, lighting and animation
  • Douglas the Engine lead – The programmer geek

 

Brett Just to recap Kin is telling the story of a society falling apart.  Kin was vibrant farming country that stretched from fishing villages in the east, to mines to the north.  There was no King instead each small village was run by a council of elders.  Basically very idyllic with elements of Greek culture but unable to handle a big crisis or invasion. 
Jasmine So no massive cities…  Lots of little towns surrounded by farms fairly clear roads between each area.  The forests will be where all the creatures are then.
Brett Yah that’s right…
Thirty years ago the “Scrolls of Elioch” were discovered and taken to the Mage Guild.  They contained new spells for weather control, a minor fireball and the ability to calm animals.  Its the last one that has caused the trouble.  Relatively quickly the master mages discovered that its a small leap from calming to control.
Now many of the towns folk are slaves to the strongest mage in the area. They use them for their own amusement and live like Gods.  We will get to delve into some pretty dark human vices.  Some will have harems, others will feed off the population to “live forever”.  We will also have a few towns where the local Mage is good but is in constant fear that another stronger Mage will “steal his town”.  So they need to either constantly make potions to give their community immunity or put a minor control spell on everyone.
Jasmine And our hero is?
Brett

Christoph is a member of “Dragons” a resistance movement.  French resistance with fire balls instead of bombs. They go into each town, assassinating the weaker mages, putting potions into the water supply to disrupt the magical control of the towns etc.  The Dragons maybe heroes but since all the militia and armies are controlled by the mages they are public enemy number one.  I’m still working on the back story but his family were refugees fleeing their village. He became separated from the rest of his family and is now trying to find them. 

He has natural immunity to all magic and can’t be controlled but makes his own magical abilities pretty poor.  I think its important that by the end of the game he isn’t walking around with his own slave army.  Kinda defeats the purpose of him being a hero…

Douglas I’m really excited about this game its really going to kick ass.  But we really have to make sure that the coders don’t become a bottleneck like last time.
I want to start working on the AI for fighting.  Do we have an idea yet on what character stats we are going to use?  At least an outline so that I can start creating some of the core classes?
Jen Yah I would like to know as well so that my team can look at mocking up the character setup screens.
Jasmine Steady on.  We aren’t even close to that yet.  Isn’t there a way you can start on the engine without knowing all the details.  It sounds like you want to lock in the design but I think we should delay it as late as possible at least until we have created a completed dungeon and have play tested it for a couple of weeks.
Douglas Umm I’m not sure.  I suppose but I still need a starting point.
Brett How about…  Let me see…
Ok Christoph is with three other members of the resistance.  The town mage is very weak and only just hangs onto power.  But his brother who is now running the town militia has his palace completely locked down.  So the normal dash and stab is out.  The Dragon cleric sends Christoph out of town to find some ingredients for the immunity potion.  Battle, blah, blah hunt/gather blah, blah.   
When he returns to the town there are gallows setup and the Dragon’s have been found guilty of treason.  They will be killed in 2 hours.  Camera zooms in and Christoph’s hands start glowing a large tattoo of a Dragon is seen pulsing on his forearm.  The cleric mouth is moving in the distance but he can hear every word.  “There is a spring above the town go quickly pour the elixir into it.  It runs below the square it might just be enough to save us.”
Later our hero stands looking down on the spring.  There is a large crocodiles chained to an enormous statue. Magical energy vibrates across it.  Of course! This is how the mage controls the town.  Destroy the statue.  Use the elixir and the town will be free.
Douglas Brett you really are full of (*^(*&^
Brett Thanks…  Lets make this interesting. 
There are 10 baby crocs each dealing health damage.  The big one has a poisonous bite.  It drains health away each second after you have been bitten.  By being close to the statue  Christoph is being confounded so he cant move as fast.  He also has a ring on that is slowly healing him ever few seconds.
Douglas Ok so we have a number of effects that are time dependent.  We have effects that are dependent on the distance between objects and of course we have the run of the mill hit points and magic points.
Jen Funny it sounds a lot like a Mel script in Maya.  Some stuff can be done on the timeline and some can be done through triggers.
Douglas Of course, of course that’s all easy to do in Mel as the language is designed around animating.  It knows a lot about polygons, timelines etc.  Maybe we should create a language for “Dragons of Kin”.  At the start it will be very simple and generic just to get us going.  But it will know about spells and damage and weapons. 
Wow that could be great.  If Brett and Jasmine write the story using the language my team can create an Engine that will “play the game”.  Awesome…  And the best bit, my engine and the language and decoupled.  When we start optimising or refactoring it wont break the language as they are completely separate. 
Bring it on…
Jasmine Douglas I don’t want to rain on your parade but I’m not a programmer and sometimes I wonder if Brett can even type.
Douglas Don’t worry about that.  It will be designed for you guys from scratch.  It should be almost identical to how you create the levels in Word now.  But instead of my team having to translate the design into code the document will be the code.

 

BattleLang first draft…

The next day Douglas and Jasmine start on designing the language

Douglas Lets start with the crocodiles setup

  class Crocodile {
    int magicPoints;
    int healthPoints;
    float healthHealingSpeed;
    float magicHealingSpeed;

    Crocodile(…)
  }

Ok so we have this class and stats…
Jasmine Sorry, I thought you said the language would be text like.  Kinda looks like normal code to me.  Why are there int and floats in there.  How do I set the amounts?  What is a class how do I do different types for crocodiles for instance like the boss crocodile?
Douglas Dam your right.  Ok lets start again.  What you need to be able to do is setup the values for the different stats directly in here…  Maybe something closer to Pascal and I’ll kill the semicolon.

  Creature Crocodile {
    Life := 40
    Magic := 50
    LifeHealingSpeed   := 5
    MagicHealingSpeed   := 5
  }
Jasmine That makes more sense.  How fast is the healing speed.  Is it per minute per second.
Douglas Right, maybe we should be using Ada’s and F# Units of Measure. 
Sorry, in a normal programming language everything is a number.  The problem is that it means you can add values that aren’t properly related.  So if you add 3 oranges and 2 apples, instead of getting 5 fruit you get either 5 oranges or 5 apples.  As far as the computer is concerned its just two numbers.  The knowledge about what the number represents in a problem for the programmer.  Units of Measure allows you to stamp each numeric value with the actual item type it represents.  Most examples use gravity, speed, velocity, money that kinda thing.
So…
  Creature Crocodile {
    Life := 40 LP
    Magic := 50 MP
    LifeHealingSpeed   := 1 LP/sec
    MagicHealingSpeed   := 10 MP/min
  }
Jasmine Cool so does that mean we can represent damage this way.
  LizardPoison  := 15 LP + 3 LP/sec
Douglas Wow yes you could.  That is really compact.  Lets extend this to spells
  FireBall :
    Inflicts:= 20 LP
    Costs:= 5 MP
Jasmine I see so the firewall has an amount of damage that inflicts but to use the spell it has a cost of 5.  I suppose all that is really missing is that every crocodile shouldn’t have just 50 LP but it should random from a range of values.
Douglas Ok lets do the Crocodile properly then
  Creature Crocodile {
    Life := random_select [30..40] LP
    Magic := 15 MP
    LifeHealingSpeed   := 3 LP/sec
    MagicHealingSpeed   := 1 MP/min
    Weapons
    {
      Bite:
        Inflicts:= random_select [5..10] LP
      PoisonBite:
        Inflicts:= random_select [5..10] LP + 3 LP/sec
        Costs:= 5 MP
    }
  }

This a good start.  Eventually we will need to extend it to contain all the animation and sounds effects that Jen needs and currently there is no concept of the distance weapons.  Before we go any further I would like to spend a couple of days writing a parser that can load the language into a form an engine can use.

Tags:

BattleLang – A Domain Specific Language in .NET

by Call me dave... 19. December 2009 06:56

Over the next couple of blog posts I will be creating a simple DSL for a Role Playing Game (RPG).   DSLs are often used in the games industry to combat the huge amounts of complex data within AAA titles.  A RPG will often have thousands of different characters spread throughout the environment each having different:

  • Animation cycles and sound effects
  • Characteristics such as hit points and strength
  • Armour and weapons

All of this information eventually gets fed into a C++ engine that actually runs the game.  This means either all of the members of the team need to be professional programmers or the game’s data needs to be managed and manipulated elsewhere.  While a CSV or XML file can provide some assistance eventually the designer will need to be input state based behaviour:

If HiPoints > 20

  Attack closest player

Else

  Run away

This type of logic is extremely difficult to embed into a CSV file.  However it is relatively simple to create a DSL allows the Game Designer to define each creature’s characteristics and the effects of items and spells.

DSL Background - Ubiquitous Language

A core tenet of Domain Driven Design is the Ubiquitous Language where business users and developers, use a shared language and terminology to define each concept, within the domain.  Instead of leaving this information in a document they are embedded into the domain objects within the system that is being built.  By both groups using the same terminology the opportunities for miscommunication are greatly reduced.  Further as the business and developers come to understand and respect the other group’s expertise the language becomes richer and the definition’s gain greater clarity resulting in the the domain objects being updated to replicate the new richer model.

DDD and Acceptance testing are a perfect fit.  By having tests written using terminology from the Ubiquitous Language allows the business to create test cases early in the development process.  These tests can form the basis of the project’s detailed requirements and allows the development team to build the meaty parts of the application extremely quickly and to a very high quality.

Business writing the software

The natural question to ask is “If the business can write the tests can they also write the software”?  The answer is a resounding NO.  Software development is very complex.  Modern generic programming languages are designed to execute an infinite number of different programs.  They do this by having a type system that maps to the architecture of the underlying computer.  We use ints, floats and strings in our programs to represent concepts such as age, weight and names.  Programmers are easily able to do the mental jump between built in types and the abstract concepts that are being simulated by the program and are described in the Ubiquitous Language.  Further developers are able to look at control structures such as for loops and instantly recognise that some action is occurring on each element within an array.  These skills are not universal and without them it is very difficult to understand any non-trivial piece of software.

The problem space that the DSL solves is making a programming language that allows a user to explain a business activity or business data using concepts from the Ubiquitous Language directly.  So instead of having to understand an entire application with five hundred files, tens of thousands of lines of code and concepts such as component layering and patterns.  They can either write or approve a small code fragment that looks surprising close to the Acceptance tests that they may are already actively creating.

Examples of useful DSLs:

DSL Requirements

If we treat our DSL as a tool to allow a business analyst or fairly technical business user to interact with our application we can quickly come up with some high level requirements:

  • The language should use business or problem space terminology – Its pointless creating a DSL that isn’t intermit with the domain
  • The language should include the smallest number of control structures as possible – The more complex the language the more difficult it is to learn and maintain.  If statements and assignment should be adequate for the majority of problems.
  • The DSL user code should be treated as any other development artefact
    • Should be in source control
    • Build server should validate any user generated code on check in – Very important since DSL syntax will change over time hence its vital to know when a script is no longer valid
  • DSL should be very focussed – There is no reason not to have a couple of complementary DSLs on a single project each solving a single problem is a clear and simple manner

Tags:

Introduction to Immutability in C#

by Call me dave... 7. November 2009 07:43

Value Objects from Domain Driven Design, Functional programming and “Many Cores” have made immutability sexy.  However being immutable only means that the code is question is side effect free.  What is more important is how the immutable object will be used.

 

Immutability – I don’t change

In Domain Driven Design Money often given as an example of a Value Object.

public class Money
{
    public decimal Amount { get; set; }
    public string CurrencyCode { get; set; }
}

 

Here the Money class in clearly mutable.  The class includes public methods that can be used by external consumers to modify the Amount and the CurrencyCode. 

var tenDollars = new Money {Amount = 10, CurrencyCode = “AUD”};

tenDollars.Amount = 20; 

 

We can ensure that type is not modifiable by making the the property setters private. 

 

public class Money
{
    public Money(decimal amount, string currencyCode)
    {
        Amount = amount;
        CurrencyCode = currencyCode;
    }

    public decimal Amount { get; private set; }
    public string CurrencyCode { get; private set; }
}

While private setters make the class immutable from external change both Amount and CurrencyCode can both be modified within the class or from a derived class.  Using a read only backing field allows the compiler to enforce the immutability of the type.

public class Money
{
    private readonly decimal _amount;
    private readonly string _currencyCode;

    public Money(decimal amount, string currecyCode)
    {
        _amount = amount;
        _currecyCode = currencyCode;
    }

    public decimal Amount
    {
        get { return _amount; }
    }
    public string CurrencyCode
    {
        get { return _currencyCode; }
    }
}

 

While Value Objects like Money are immutable Domain Entities are not.  Hence the Bank Account or Person’s Wallet Domain Entity will have a public setter on a property of type Money.  Changing the value involves creating a new instance of the Money class.

 

Immutability – I don’t change and am interchangeable

Once an immutable type has been created we need to decide whether instances on the type are interchangeable.  Consider an Audit log entry that is created each time a web page is accessed on a server.  Logically each entry is globally unique since the entry is created for a particular web page request, from a particular IP address at an instant in time.  The Log entry is immutable however  Log Entries are NOT interchangeable. 

Meanwhile Money by its very nature is interchangeable, a ten dollar note has the identical worth to ten one dollar coins.  Further an interchangeable type should be able to be used in the Flyweight Pattern.  Instead of creating a new instance of the Money class each time it is used a cache whose key is based on Amount and CurrencyCode can be used instead.

In C# if a class in Interchangeable it must override the Equals and GetHashCode methods and the ‘==’ an ‘!=’ operators.  Thankfully Resharper will generate this boiler plate code automatically.

public class Money
{
    private readonly decimal _amount;
    private readonly string _currecyCode;

    public Money(decimal amount, string currecyCode)
    {
        _amount = amount;
        _currecyCode = currecyCode;
    }

    public decimal Amount
    {
        get { return _amount; }
    }
    public string CurrencyCode
    {
        get { return _currecyCode; }
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != typeof (Money)) return false;
        return Equals((Money) obj);
    }

    public bool Equals(Money other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return other._amount == _amount && Equals(other._currecyCode, _currecyCode);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return (_amount.GetHashCode()*397) ^ (_currecyCode != null ? _currecyCode.GetHashCode() : 0);
        }
    }

    public static bool operator ==(Money left, Money right)
    {
        return Equals(left, right);
    }

    public static bool operator !=(Money left, Money right)
    {
        return !Equals(left, right);
    }
}

 

 

Immutability – I don’t change, am interchangeable and emulate mutable operations

A Money type needs to be able to support simple arithmetic operations such as add and subtract.  As the type is immutable instead of modifying the private data of the class a new new instance is created each time the type is modified.  C# enforces the pattern of creating a new instance of the type during the arthimetic operation by making the operators statically defined.

 

public static Money operator + (Money left, Money right)
{
    if(left._currecyCode==right._currecyCode)
        throw new ArgumentException("Only Money of the same currency can be added");
    return new Money(left._amount + right._amount, left.CurrencyCode);
}

public static Money operator -(Money left, Money right)
{
    if (left._currecyCode == right._currecyCode)
        throw new ArgumentException("Only Money of the same currency can be added");
    return new Money(left._amount - right._amount, left.CurrencyCode);
}

public Money ConvertToCurrency(string newCurrencyCode)
{
  return Money(LookupConversionRate(_amount, _currencyCode, newCurrencyCode), newCurrencyCode);

}

In summary

When creating an immutable type you should consider how that type will be used.  Equality functions and operators should be added if it is interchangeable with other instances and mutable operations should be emulated by creating new instances of the type.

Tags: