One of the changes I made in the weeks leading up to my contest deadlines was to pull some of the player-specific combat logic, like that for attack chains, combos, and flinching, out into their own objects. Doing this let me apply that same combat logic to monsters and other entities in the game world, which cut down on duplication considerably.
However, doing this made it clear that I had some architectural issues to tackle: All of these mechanics were heavily dependent on the tunable constants for the creature in question, which meant I couldn’t just pull methods and variables out of my entity classes into classes of their own.
To solve the problem of accessing an object’s constants, I came up with a solution based on reflection. I can define a helper object designed to handle an aspect of an entity’s mechanics – for example, a HealthPool object to manage the creature’s health, along with associated aspects like regeneration. The helper object can define instance variables for the constants it needs access to, like so:
public class HealthPool {
public Constant<float> HealthMax = null;
public Constant<float> HealthPassiveRegen = null;
public Constant<float> HealthRegenDelayTime = null;
public Constant<float> HealthRegenRampTime = null;
public Constant<float> FlinchThreshold = null;
public Constant<float> FlinchThresholdDecay = null;
public readonly RuntimeEntity Entity;
public readonly ITimeProvider TimeProvider;
public float Health = 0.0f;
Note that these variables are the same name and type as the actual tunable constants – the difference is that instead of being static, they’re instance variables. Doing this allows me to pull a function out of an entity’s source code without needing to change the way it references particular constants, since the constants have the exact same names as before.
Of course, since these variables default to null, we need some way to fill them in with references to the actual tunable constants we want to use. To do that, we apply reflection:
public static void BindConstants (object destination, params Type[] sourceTypes) {
var genericConstant = typeof(Constant<>);
var destinationType = destination.GetType();
var destinationFields = new Dictionary<string, FieldInfo>();
foreach (var field in
destinationType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy)
) {
var fieldName = field.Name;
var fieldType = field.FieldType;
if (!fieldType.IsGenericType || fieldType.GetGenericTypeDefinition() != genericConstant)
continue;
destinationFields[fieldName] = field;
}
foreach (var sourceType in sourceTypes) {
foreach (var field in
sourceType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy)
) {
var fieldName = field.Name;
var fieldType = field.FieldType;
if (!fieldType.IsGenericType || fieldType.GetGenericTypeDefinition() != genericConstant)
continue;
FieldInfo destinationField = null;
if (destinationFields.TryGetValue(fieldName, out destinationField)) {
destinationField.SetValue(destination, field.GetValue(null));
destinationFields.Remove(fieldName);
}
}
}
if (destinationFields.Count > 0) {
var constants = String.Join(", ", (from key in destinationFields.Keys select key).ToArray());
var types = String.Join(", ", (from type in sourceTypes select type.Name).ToArray());
throw new InvalidDataException(String.Format("Type(s) {0} do not declare the following constants:\n{1}", types, constants));
}
}
What we’re doing here is pretty simple: We accept a reference to an object that has constants requiring binding, and a list of source types to retrieve constants from. The function operates in two stages: First, we enumerate all the instance variables defined in the target object, and build a list of all the tunable constants it has that need to be bound. After that, we enumerate all the static fields of the provided source types, looking for constants that have names matching those of the instance variables on the target object, binding them where appropriate. After this, we can simply check to see if our list of constants is empty or not – if it’s empty, we successfully bound all our constants, and if it’s not, we know that one or more of the desired constants was missing.
We get a few useful things out of this: First, accepting a list of types allows us to do simple inheritance of constants. If we first check the most-derived type and then the base type of an entity, that allows us to define a ‘default value’ for a particular constant, like ‘Maximum Health’, in a base class, and then define a new constant with the same name in the derived type. This also allows us to create ‘global defaults’ for a given constant – for example, if we always put Game at the end of the type list, we can have global game-wide constants for things like physics parameters, and only override them in specific classes if necessary.
Finally, to wire things up, we just need to do a little work in the constructor for our helper object:
public HealthPool (RuntimeEntity entity, ITimeProvider timeProvider) {
Entity = entity;
TimeProvider = timeProvider;
ConstantManager.BindConstants(this, entity.GetType(), entity.Game.GetType());
Health = HealthMax;
}
In this case, we’re initializing the HealthPool using the constants defined in the entity, and falling back to any constants defined in the Game when the entity doesn’t specify them. If a necessary constant is missing, we’ll get an exception thrown when constructing our helper object. Once we’ve bound the constants, we can just use them like we would otherwise – in this case, the HealthPool automatically initializes itself based on the HealthMax constant.
This is definitely preferable to the approach I used to use for exposing an entity’s constants – previously, for important constants like an entity’s bounding box size, I’d define an abstract property in a base class, and override it in each derived type to return the value of the constant. Now, I don’t need to use any abstract members or interfaces; I can just bind to the constants once when I initialize my helper objects.
One thing of note is that since this technique uses reflection, you might run into performance issues if you’re binding constants repeatedly. This is pretty trivial to solve, however; you can just cache the results of a constant binding operation based on the destination and source types, since those aren’t going to change at runtime.

