About

I'm developing my first game, Age of Goblins. I develop this part time, and work at a "real" (read: paying) job full time. Age of Goblins is a three dimensional goblin empire building game. Inspired by Dwarf Fortress and Minecraft. Age of Goblins gives a player control over a small band of goblins in a cube-based sandbox world. The player can instruct the goblins to add or remove different types of cubes, build various structures, make elaborate traps, and craft a multitude of items.

Thursday, February 14, 2013

From data files to entities

Data files are just the start for creating entities in Age of Goblins. Once the definitions are read into AoG, they're stored in a catalog of "blue prints" for generating entities and materials. Each blueprint holds information for each component that will be added to the entity.

When the game requests that an instance of entity X be added to the game world, it refers to the blueprint stored for that entity. As an example, lets look at some parts of the goblin data file. The following will describe some attributes that each goblin entity will be generated with when it's added to the game world.

[Model]{
meshname="Goblin"
texturename="GoblinTextures.png"
distantdrawtype="norender"
selectionType="DynamicBone"
}
[Motion]{
maxvelocity=1.5:1.9
locomotion=Walk,Swim
}
[Skills]{
ALL=0.01:0.05,Mine=8.3:8.8,Construction=8.3:8.8
}


Each goblin will have a `model` component, a `motion` component and a `skills` component (among others). The values defined in ranges show values that will differ from goblin to goblin. In this case, I've turned Mine and Construction kills up rather high for testing purposes. I'll likely expand the skills description in the future to just select 3-4 skills to be much higher than others, which will determine starting professions. Once all this data is loaded in, we're ready to start generating goblins.

When an entity is created, some information is passed in with the creation.

  • Species information: this is used for values that are common among all instances of a species, like mobility options (walk, fly, ooze, etc.), or life requirements (air breather, water breather, nutrition requirements, etc.)
  • The location its being created: obviously, so we know where to put it.
  • Lineage information: Entities/Entity that was responsible for this entity's creation. This is a neat idea that has potential, for example: body definitions contain family traits which can be passed from parents to children. Have big ears? Your kids probably will too. I hope to introduce traits that provide resistances/strengths/weaknesses with slight modifications on creation. This way, generations of entities can actually experience some minor evolution. The spike spitters at one colony could have some interesting properties compared to the spike spitters at another colony.
All that information is passed into the entity factory that will in turn, pass it to each component the entity will have. Each component will pick and choose the information it's interested in, and tailor its creation based on that information. The entity factory is looks something like this pseudo code:

Entity createEntity(String entityName, SpawnInfo info) {
    Entity e = newEntity();
    for(ComponentInfo ci : entities.getAttributes(entityName)) {
         e.addComponent(ci.generateComponent(info))
    }
    return e;
}

The `ComponentInfo` class is a neat one. It contains the parser for reading from the data file and the code for generating a new component based of the data read in. The `ComponentInfo` object is the blueprint for a component. So, for example, the creation code for the skills component would look something like this pseudo code:

SkillsComponent generateComponent(SpawnInfo info) {
    List<Skill> skills = new List<Skill>();
    for(SkillLevelFactory slf : skills) {
        skills.add(slf.generateSkill(info));
    }
    return new SkillsComponent(skills);
}
....
SkillLevelFactory {
     SkillType skillType;
     FloatRange skillRange;
    
     Skill generateSkill(SpawnInfo info) {
          Skill s = new Skill(skillType, skillRange.getRandomValue()));
          s.applyLineageModifiers(info);
          return s;
     }
}

 Where `skills` was a list of `SkillLevelFactory` generated when the data file was read in. Essentially being a list of available base skills and their value ranges. The `ComponentInfo` objects are created for each entity, for each component they define.

The entity/component system, paired with this scripting system creates a very powerful tool for generating entities. The entities created are similar enough to be in the same species\family, but unique enough to be called individuals. Thanks for reading.

Is there something you want to know about the inner workings of Age of Goblins? Ask me about it, I may write a post about it :)

2 comments:

  1. So do you use this scripting system for every kind of entity in your game, or only creature/plant entities? Are things like items, particle effects, and minor disposable entities like arrows/bullets/etc also created from this scripting system?

    The more I read about this game, the better it sounds. Keep up the great work!

    ReplyDelete
    Replies
    1. The scripts have some effect over all in game items. Materials (so far) are the only exception. They have many of their values defined in scripts, but the components that make up a material in "entity form" are defined in code. Materials are sort of special because they're a "required" part of the game. However, other small items like seeds and ammo are defined in the scripts. I don't have the particle system in place yet, but I imagine that will be done with scripts as well.

      At this point, the scripting system is powerful enough that when adding new features, it's easier to use the scripting system than not.

      Thanks for your interest! I appreciate the feedback.

      Delete