I’m doing some refactoring on my game, and in the process I’m running up against a question that has cropped up for me a few times before: the question of how to implement prefab objects with parameters.
My game makes heavy use of object templates that describe the overall structure of a node, but the individual script components require parameters that are specific for a particular instance of the object. Currently, I am making use of a system where a node and component hierarchy can be instanced from a template provided as a Lua table. I create the table, seed it with the various parameters, then pass it off to a Lua function that traverses a table and instances the node and component hierarchy. So I might have an object template for a fireball spell that looks like this:
local desc=
{
Components=
{
{Type="ParticleEmitter", Material="Effects/flame.xml", UpdateInvisible=false, NumParticles=500,
Sorted=false, Relative=false, MinRotationSpeed=-60, MaxRotationSpeed=60, MinDirection=Vector3(-0.25,-1,-0.25), MaxDirection=Vector3(0.25,-1,0.25),
MinVelocity=0.5, MaxVelocity=1, MinParticleSize=Vector2(0.5, 0.5), MaxParticleSize=Vector2(0.75,0.75), MinEmissionRate=90, MaxEmissionRate=105,
ConstantForce=Vector3(0,1,0), SizeMul=Rect(0.5,0.5), FaceCamera=true, MinTimeToLive=0.5, MaxTimeToLive=1,
Color=Color(0.1,0.045,0.35),
},
{Type="Light", LightType=LIGHT_POINT, Color={r=1.5,g=0.75,b=0.45}, Range=4, CastShadows=true},
{Type="ScriptObject", Classname="SpawnedAction", Parameters={ownernode=args.caster}},
{Type="ScriptObject", Classname="Projectile", Parameters={startpos={x=myx,y=myy+0.25,z=myz}, endpos={x=targetpos.x,y=targety,z=targetpos.y}, speed=8, archeight=2}},
{Type="ScriptObject", Classname="ObjectSpawnerPayload", Parameters={desc=fireballexplosion}},
{Type="ScriptObject", Classname="DamageSingleTargetPayload",
Parameters=
{
target=args.hexmap:getObjectOrAuxID(args.targetx, args.targetz),
attacker=args.caster,
attack="test fireball",
damage=dmg
}
},
{Type="ScriptObject", Classname="DoTPayload", Parameters={dot={ttl=10, counter=0, attack="Fiery Corruption",
damage=dmg, ownerid=args.caster:GetID()}}},
{Type="CombatCameraControllerTemporary"},
}
}
Then I can instance the object from that description. The table is generated local to (in this example) a Spell:Execute function, which passes parameters (skill level, spell caster attack and damage modifiers, etc…) to those script objects that require them. Some of the parameters can be other object description tables (such as the ObjectSpawnerPayload script object, which spawns its designated object upon receipt of the TriggerPayload event, to make the fireball explode in a flash of particles). Since the table is built as a local when Execute is called, it is easy to seed the parameters to it upon table construction, so that the proper data is in place and available when the components are created.
However, this method is highly reliant upon Lua and doesn’t work as well in the statically-typed languages of C++ and AngelScript.
What I’m looking for is ideas on how to implement a similar system that isn’t tied to Lua. I have thought about using Scene::InstantiateJSON to instance from a JSON template, but I still have the issue of seeding the various parameters to the components. (Many of the parameters might be a struct or class type, such as DamageSingleTargetPayload which takes a DamageRecord structure.) If I try to construct the JSON description in-place like I do with the tables, then I have the problem of seeding these non-JSON-value type parameters throughout. I could generate the components without parameters, then iterate the instanced node hierarchy and all components, and set parameters manually after the template is instantiated, but this seems clunky and inelegant to me.
Anyone have any ideas? How do you guys handle prefab instancing with parameters?