Actor Abilities Architecture Assistance

Started by
5 comments, last by Contusions 12 years, 6 months ago
I'm trying to figure out the best way to implement actor abilities in my current project. I feel like this is a common enough problem that someone could provide me with some good insight on the matter. The simplest solution would be to hardcode abilities onto specific actor subclasses or onto components within those subclasses. The problem with this approach is I plan to use a rather large collective pool of abilities which actors pick and choose from, so I'm looking to use a more data-driven approach where abilities would be loaded from an XML file.

Currently each ability has a Cost as well as Segments. Effects are pooled inside of Segments(for lack of a better word?) and each Segment has a target type, i.e. SingleHostile. Also Effect is an abstract class and there are specific subclasses for certain types of effects. So when an ability is activated the Cost is payed and targets are parsed based on each Segment's target type, once targets have been gathered each Effect inside of said Segment is resolved on the target actor. This all seems to work fine until I want to include conditions for being able to activate an ability, most cases would simply be evaluated based on the conditional type and an actor's current status. Going on my current design I should have a Conditional component attached to abilities which will have to be evaluated as well as a number of subclasses of Conditional.

I feel like this approach is getting out of hand for what I may want to do with abilities but I'm not sure how else to go about this if I want to build abilities from data files. A simpler approach I believe would just be to have a script for each ability, but I'd rather have the option of building abilities inside an external application rather than writing a script every time I want to add a new one.

Any feedback would be appreciated. Thanks.
Advertisement
I'm afraid I don't see the problem here; isn't it just as simple as:

if(someAgent.GetCurrentAbility().MeetsConditions()) { someAgent.GetCurrentAbility().Fire(); }

?

Use virtual dispatch to get MeetConditions to do the right thing for each of the possible subclasses of Condition, and the "complexity" of adding this feature is basically one line of code overhead. ...well, 2 or 4 depending on formatting ;-)

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]


I'm afraid I don't see the problem here; isn't it just as simple as:

if(someAgent.GetCurrentAbility().MeetsConditions()) { someAgent.GetCurrentAbility().Fire(); }

?

Use virtual dispatch to get MeetConditions to do the right thing for each of the possible subclasses of Condition, and the "complexity" of adding this feature is basically one line of code overhead. ...well, 2 or 4 depending on formatting ;-)


Thanks for the quick response. I think I was over thinking the implementation, your solution works fine if the Condition is pertinent to the actor playing the ability. But in the case of when the Condition depends on the target of an ability shouldn't I evaluate the conditional at a broader scope? Perhaps inside of the Match? Also in this case I need to attach a Condition to each segment rather than the ability itself as each segment has it's own target associated with it. Or rather change which actors can be targeted based on the conditional.

I should probably just implement the thing this way and refactor based on my needs, but I'd rather get it right the first time if I can.
Well, the simple approach would be to set up Ability::MeetsConditions() to iterate over its contained Segments, and have each Segment check itself to see if it is applicable based on its current target and conditions. That way you preserve the abstraction and simple check at the high level, while taking care of the low level details that need to be handled per Segment.

Of course, it could be that I'm just oversimplifying things in my head; for instance, I'm not sure what exactly a Match is or how it relates to the behavior of the other elements?

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

A Match is where all of the actors for a specific instance of combat are registered essentially. It contains components like TurnDispatch to keep track of the turn timer and turn order, as well as any sort of functionality which involves multiple actors in the combat instance. But I agree with what you're saying that it's not really the Match's job to verify conditionals, I don't want Match becoming a dreaded Manager class (if it isn't already).

Here's sort of the flow as I see it now, including your suggestions. (Controller in this case is what's driving Actor behavior, which is driven by AI or player input, depending on the actor)


private void ActivateAbility(Ability ability) //This will be in Actor.Controller
{
if (Ability.IsPlayable(this.OwningActor)) //This checks that the actor can pay the costs, as well as checking the Ability's conditional if it has one
{
Targets targets = this.ParseTargets(ability);
if (Ability.TargetConditionsMet(targets)) //Handles conditionals attached to individual segments.
{
this.OwningActor.PayCost(ability);
Ability.ResolveSegments(targets);
}
else
return; //Or ActivateAbility(ability) to parse targets again, depends on actual implementation.
}
else
return;
}



This isn't a verbatim implementation but if anyone sees any glaring holes, or an object which shouldn't be performing a specific task let me know. But I think this is the most logical flow and breakdown of responsibilities.
Looks like a reasonable outline to me :-)

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Thanks for your help, I think this will do the job.

This topic is closed to new replies.

Advertisement