2
\$\begingroup\$

I'm using component based design and am at the stage or re-factoring simple player input to be data driven.

Currently i have a PlayerControlComponent, which an entity has if it should be player controlled. Currently only a single entity has this.

I have an InputSystem that acts on entities with PlayerControlComponent, PhysicalComponent and MoveableComponent components.

Below is the code that actually does the entity creation:

if (_InputActionManager.IsAction(_ActionFireBullet))
{
    if (WorldManager.CanDoAction(playerControlComponent.CreateBulletActionId))
    {
        // Create a bullet and fire it
        using (var entityTemplate = WorldManager.GetEntityTemplate(@"EntityTemplates\Bullet"))
        {
            var bulletPhysicalComponent = entityTemplate.Item.GetComponentOfType<PhysicalComponent>();
            var bulletMoveableComponent = entityTemplate.Item.GetComponentOfType<MoveableComponent>();

            bulletPhysicalComponent.Position = physicalComponent.Position + physicalComponent.Direction * physicalComponent.Radius;
            bulletPhysicalComponent.Direction = physicalComponent.Direction;
            bulletMoveableComponent.Velocity = moveableComponent.Velocity + physicalComponent.Direction * 200;
        }

        WorldManager.MarkActionDone(playerControlComponent.CreateBulletActionId);
    }
}

I want to get to the stage where I can have an XML file that indicates some how that a given entity will create a new entity based on a given template and set initial values such as position, direction and velocity in the above example.

I want to avoid having to change code and maybe add systems and components for each type of thing I want to spawn.

For example, currently if I wanted to add the ability for an enemy to spawn a missile I'd need to define my missle entity template (fine), create a new component to mark the entity as being able to fire a missle, then create a system that uses that component (want to avoid), then create a system with code similar to the above (want to avoid).

As another example, say I want to change the speed of the bullet, currently I do that in code, but I want to be able to do that in a data-driven way.

How can I create and manage a way of creating an entity based on an event occuring, with properties based on the entity that created it? i.e. Player presses Fire, bullet spawned at ship location, moving away from ship.

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Disclaimer: The ideas on this post are untested.

One solution that comes to my mind, is perhaps to use a Factory Method together with Reflection. Your external template file (XML or JSON) would provide a description of each type of entity, listing all of its components and their initial parameters. Then:

  1. The Factory Method takes care of instantiating the components knowing only their names. Similar to what you already seem to have but with a string key.

  2. Reflection would then be used to access the component's properties by name and set their initial values. IIRC, relevant methods are Object.GetType(), Type.GetProperty(name), PropertyInfo.SetValue(object, value, null).

If your initial property values were simple values without dependencies this would probably be enough. But your example seems to need a lot more complexity than this, because it depends on the parent's values, and is in the form of an expression, not a simple value.

That certainly makes things more complicated. I can foresee two roads for incorporating that behavior:

  1. Either you implement some sort of simplified scripting system with your own syntax and fitting your needs, that would receive the necessary context, parsing the expression and executing it accordingly.

    This system would need to be able to handle a set of basic data types (int, float, string, boolean, Vector2, Vector3), would need to be able to access properties on the parent component (which would be translated to Reflection calls), and know how to perform the basic arithmetic operations between data types. I don't think this would be an easy task.

  2. Or another alternative I can think about is maybe using C# runtime compilation (I talk a little about it here and show an example) and put C# code directly in the template.

    Then you would go through the template file at load time and prepare/compile one method for each initialization entry, taking the parent entity as a parameter. This way you can put C# code directly in the template, which would be executed later when instantiating the entities. The biggest advantage is not having to create your own scripting language though.

Something like this on your template (take all that follows as a sort of pseudocode, I have not considered all the possibilities):

<component name="Bullet">
    <property name="Position" value="parent.physicalComponent.Position + parent.physicalComponent.Direction * parent.physicalComponent.Radius;" />
</component>

Which would be wrapped and compiled at runtime inside a method such as (notice the use of the dynamic keyword to disable static checking):

public static object GetBulletPositionInitialValue(dynamic parent)
{
    return parent.physicalComponent.Position + parent.physicalComponent.Direction * parent.physicalComponent.Radius;
}

Notice that the method also follows a naming convention Get + ComponentName + PropertyName + InitialValue so that you can access it later by name using reflection.

I'm just shooting out a few ideas though, I'm not entirely sure whether this would actually work though. :-)

\$\endgroup\$
4
  • \$\begingroup\$ Thanks for all the ideas and the very long answer. As I'm targeting the xbox i'll go for a simple version of #1 as it can't do code compilation which is a shame. \$\endgroup\$ Jan 4, 2012 at 10:20
  • \$\begingroup\$ I see. I hope using Reflection does not cause problems on the XBox (performance). Otherwise you'd have to change to using some sort of property map I guess. \$\endgroup\$ Jan 4, 2012 at 15:16
  • \$\begingroup\$ Yeah, I'll probably end up with a small list of supported properties and very simple operations. It should be enough for my needs - don't want to over-engineer it. \$\endgroup\$ Jan 4, 2012 at 15:57
  • \$\begingroup\$ Maybe even more complicated (but tempting) would be to combine some kind of ContentProcessor (like in XNA, not sure if you are using it in your project) with Dynamic Language Runtime features to parse XML and generate the needed code which can then be compiled. This probably would be a project of its own... ;-) \$\endgroup\$ Jan 5, 2012 at 18:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .