How should I design a data-oriented, modular gameplay action system for Unreal Mass Entity?

0
7
Asked By MellowPine47 On

I'm working in Unreal Engine and have already built a modular, data-driven gameplay action system using object-oriented patterns. A DataAsset contains several UObject-based effects, each effect implements an Execute function, and interfaces let actors respond appropriately to different effect types.

I now need a similar system for Mass Entity, but Mass follows an ECS/data-oriented design and doesn't use UObjects, interfaces, or traditional polymorphism in the same way. I'm unsure how to represent effects and decide which behavior should process them.

One idea is to store effect data in structs, perhaps with an enum identifying the effect type, then have a central system use a switch statement to add or remove the relevant fragments and tags. Separate Mass Processors would then perform the actual behavior. However, that seems difficult to scale because every new effect would require modifying the central dispatcher.

What is the usual way to build a modular, data-driven action/effect system for Mass Entity? Should behavior be split across processors that query specific fragments or tags, or is some form of centralized dispatch and type switching acceptable? Also, would adapting an object-oriented design to ECS be a serious problem, or can it work in some situations?

4 Answers

Answered By AmberLattice63 On

It’s worth looking at Unreal’s Gameplay Ability System for ideas about separating effect definitions, execution logic, targeting, and application. It is not simply a drop-in replacement for Mass Entity, and you would need to check how it fits your Mass architecture, but its concepts can still be useful even if you implement the final version with Mass fragments and processors.

MellowPine47 -

I know about the Gameplay Ability System but haven’t studied its implementation yet. I’ll look at how it separates data from execution, even if I don’t use it directly with Mass.

Answered By RiverstoneQ2 On

A switch statement is not automatically an ECS anti-pattern. A small translation or dispatch step can read an action definition and turn it into the appropriate fragment or command. The important distinction is that the switch should not contain all of the gameplay behavior; it should only convert external action data into ECS data.

For example, an action asset could describe an effect, target rules, and parameters. A dispatcher could create a damage request, movement request, status-effect fragment, or another command. Dedicated processors consume those requests. Adding a new effect may require registering one new conversion rule and writing one new processor, but the processors remain independent instead of one giant system growing indefinitely.

Answered By QuietCedar19 On

Think in terms of a data-driven registry or command pipeline if you want to avoid a large central switch. Each effect definition can identify the command or fragment type it produces, while a registration layer maps that definition to the code that handles it. The actual execution still belongs to processors, not to the data struct.

There is usually some finite point where new behavior must be connected to executable code. ECS does not eliminate that registration step; it changes where it lives. The goal is to keep the connection explicit, localized, and easy to extend rather than pretending arbitrary data can execute itself.

Answered By CloudyHarbor8 On

ECS generally works better when effects are represented as data and behavior lives in systems. Instead of putting an Execute function inside each effect struct, store the parameters needed by an effect in fragments, shared fragments, or command data. Mass Processors then query the fragments they understand and process matching entities in batches.

A separate processor can own each broad category of behavior. The entity’s archetype, tags, and fragments effectively determine which processors are interested in it. This keeps the data simple and avoids trying to recreate UObject polymorphism inside structs.

MellowPine47 -

That makes sense for separating the behavior, but I’m still unsure how a newly added effect gets routed to the right processor without changing a central system every time. Is an enum and dispatcher still reasonable for that part?

Related Questions

LEAVE A REPLY

Please enter your comment!
Please enter your name here

This site uses Akismet to reduce spam. Learn how your comment data is processed.