-
Notifications
You must be signed in to change notification settings - Fork 0
Custom Effect Types
TDRS comes preloaded with an array of readily-available effect functions. This guide is for folks who might need to augment the built-in set with additional functions. A majority of users should not need to do this. This process requires creating new IEffect
and IEffectFactory
classes. This page takes users though a tutorial of this process. We use the built-in AddAgentTrait
function as an example.
Before we get started, let's review how effects are specified by a game designer and subsequently instantiated at runtime by the game engine. Effects are called as a single string value containing the name of the effect function followed by some number of parameter values, each separated by one or more spaces. When we need to instantiate and effect, we take this string, divide it into its parts and pass these parts to the effect factory responsible for constructing effects of the given type.
Effects are classes that implement the IEffect
interface which requires a class to define an Apply()
method. This method is called when we want to apply the side-effects of the effect function. TDRS does not enforce a specific constructor format or set of class fields. Those are left to the discretion of the end-user.
Below is the implementation of the AddAgentTrait
effect. It adds a trait to an agent for a specified amount of time and overrides the trait description to say why the agent has the given trait. The inclusion of the ToString()
method is optional. User's may find it helpful for debugging.
// AddAgentTrait.cs
public class AddAgentTrait : IEffect
{
private Agent m_agent;
private string m_traitID;
private int m_duration;
private string m_descriptionOverride;
public AddAgentTrait(
Agent agent,
string traitID,
int duration,
string descriptionOverride
)
{
m_agent = agent;
m_traitID = traitID;
m_duration = duration;
m_descriptionOverride = descriptionOverride;
}
public void Apply()
{
m_agent.AddTrait(m_traitID, m_duration, m_descriptionOverride);
}
public override string ToString()
{
return $"AddAgentTrait {m_agent.UID} {m_traitID} {(m_duration == -1 ? "" : m_duration)}";
}
}
Next, we need to create a new factory class that will create instances of the AddAgentTrait
effect when it is called within social events. Our factory must implement the IEffectFactory
interface that requires we provide implementations for the EventName
property and the CreateInstance()
method. The code below is defines the factory for the AddAgentTrait
effect. When defining your own factories, please remember:
-
The
EffectName
property should return the name of the effect that we want this factory to correspond to. For example, if someone uses the effectAddAgentTrait ?owner dubious 5
, then the factory with anEventName
of "AddAgentTrait" will be selected to instantiate the effect. -
The
CreateInstance()
method is responsible for creating a specific effect instance. It accepts two parameters: a binding context and the arguments to the effect call as an array of strings. The context contains binding information to help convert variables in the effect call, in this case?owner
, to instances of social agents within the game. -
Use the
System.ArgumentException
class when something goes wrong in the factory. All the parameters are passed as strings. So the factory must parse any numerical or boolean values. So, when things go wrong, you need to provide adequate error messaging to help track down the issue.ArgumentException
is caught by the TDRS' internal code and re-raised with additional information to help with debugging.
// AddAgentTraitFactory.cs
public class AddAgentTraitFactory : IEffectFactory
{
public string EffectName => "AddAgentTrait";
public IEffect CreateInstance(
EffectContext ctx,
params string[] args
)
{
if (args.Length < 2)
{
string argStr = string.Join(" ", args);
throw new System.ArgumentException(
$"Incorrect number of arguments for 'AddAgentTrait {argStr}'. "
+ $"Expected at least 2 but was {args.Length}."
);
}
string agentVar = args[0];
string traitID = args[1];
int duration = -1;
if (!ctx.Engine.HasAgent(ctx.Bindings[agentVar].ToString()))
{
throw new System.ArgumentException(
$"No Agent found with ID: {ctx.Bindings[agentVar]}"
);
}
if (args.Length >= 3)
{
if (!int.TryParse(args[2], out var value))
{
throw new System.ArgumentException(
$"Expected integer as 3rd argument but was '{args[2]}'"
);
}
duration = value;
}
return new AddAgentTrait(
ctx.Engine.GetAgent(ctx.Bindings[agentVar].ToString()),
traitID,
duration,
ctx.Description
);
}
}
The last step before you can use your event is to add an instance of your effect factory to the EffectLibrary
instance within the SocialEngine
.
Effect factories are loaded when the SocialEngineController.Initialize()
method is called. This call will fire an OnRegisterEffectFactories
event with the current SocialEngine
state as a parameter.
The steps below create a "plugin" class that you can add all your custom factories to.
- Create a new C# Script and name it "CustomEffectFactories"
- Open the file in your code editor of choice
- Add a
public void HandleRegisterFactories(SocialEngine engine)
Method to the class (sample code provided below). - Inside the
Start
method addHandleRegisterFactories
as a subscriber to theOnRegisterEffectFactories
event (see code below). - Inside the HandleRegisterFactoriesMethod, add your custom effect factory to the EffectLibrary. Here we have added the
AddAgentTraitFactory
. - Add the
CustomEffectFactories
script as a component on the GameObject that has yourSocialEngineController
.
using UnityEngine;
public class CustomEffectFactories : MonoBehaviour
{
void Start()
{
SocialEngineController.OnRegisterEffectFactories +=
HandlerRegisterFactories;
}
public void HandleRegisterFactories(SocialEngine engine)
{
engine.EffectLibrary.AddEffectFactory(
new AddAgentTraitFactory()
);
// Add additional custom effect factories below.
}
}
Add your new effect to a new or existing social event!