Wednesday, January 4, 2017

Unreal Engine Quest Framework Part 2: Design

It is that time now. The time to begin the Quest, to a Quest Plugin that will meet all your Questing needs and desires in Unreal Engine 4. This first post of Part 2 of an Unreal Engine Quest Framework will go over the high level design of such a system. I will go over two prototypes that have lead me to my current design. I will also discuss the requirements for such a Plugin. Finally, I will discuss the final high level design of the Quest Framework in Unreal Engine 4.
So, without further ado, let us move on-wards in our Quest (I promise, I will not stop).

Old Prototypes

First, I am making this framework with previous experience. As we all know, there is a Part 1 to the Quest Framework. This was the initial prototype. There were obvious issues with it I will discuss at a later time. I also made a second prototype. It turned into a mess. I will discuss everything that went wrong when implementing it.

Prototype the First

The original prototype consisted had two clases: AQuest and AInfo. AInfo classes where AObjective nested in an AQuest. This framework supported Binary Quests - pass or fail type scenarios. AObjective object tracked it's own completion state. AObjective tracked state by using two int32 parameters: CurrentProgress and TotalProgressNeeded. There was no replication, no RPC, just dumb state tracking and some FText for the UI.
This was a flawed design lacking robustness.
These flaws were many. It was too simple, required a lot of work to integrate, and did not have any management included. Using two AInfo classes as a base resulted in serialization, binary, and network overhead. Combined with having to spawn Actors to run quests, a lot of resources became wasted. Finally, there was no management of Quests and Objectives outside of their scope.
There was no easy way to edit Quests and Objectives in the Unreal Engine 4 Editor. It required needless Blueprint Subclasses of AObjective and AQuest to build quest paths.

Prototype the Second

The second prototype was somewhat more advanced.
It used UObject as the base class and Instanced everything. There were objects named UQuest, UObjective, and UReward. Each of these classes had a specific purpose.
The core of the system was the UQuest object. It contained a list of UObjectives. Then the UObjectives had URewards for applying a rewards system for completing objectives. UQuest had three objects of UQuestState that drove the logic of a UQuest.
An example of these states were a UQuestState_Active, UQuestState_Passed, and a UQuestState_Failed. Then there were child classes of these states such as UQuestState_Transition. These managed how transitions worked when changing state. They also ran the actual logic behind a UQuest object. Essentially, UQuest was a StateMachine.
It became a mess. Worse yet, adding in Replication, UI features, and ActorComponents, made it worse. There was too much complexity and overlapping class responsibilities. Binding to new events added a lot of complexity. It also made management of quests and objectives harder. It was a lot and it was doing too much.
With the old prototypes explained there were several lessons that I learned. A Quest Framework should be simple. A framework for end developers to create customized Questing experiences for their players. It should not force Quests into the world. It should not force metadata parameters such as a Title, Pictures, Sounds, etc. It should be event based and have the ability to adapt to many states and results. It should allow any interested party to observe state without coupling to the quest framework.

Requirements of a Robust and Flexible Quest Plugin

So, what is it that we desire in a Quest Plugin for Unreal Engine 4?
Well, it needs to be generic and support many use cases. Such use cases would be single or multi player and dedicated servers. It needs to support saving status and/or state and progress. It needs to not force implementation, such as what parameters to use in the UI. It needs to support replication on demand as well as server managed RPC methods. It needs to be lightweight.
Being generic and the support for many use cases allows for a core foundation of a Quest Framework / Plugin. This will allow use of it  in many game projects. It must not dictate quest types, quest metadata, and how quests progress.
A good Plugin should have network support built in. This is 2017 after all, if your game isn't networked in some way, well, it is a fun single player game. Plus, lots of people like to make MMOs, which (probably) requires some networking and (may) have lots of fun quests. This means a Quest Framework needs to support Unreal Engine's Replication and RPC frameworks.
Quests are a way to track player achievements within a game and to guide the player to some end goal. These games are not short and allow for the player to leave for extended periods of time. This is usually why games have a Save system. Unreal Engine 4 allows for a SaveGame framework. A good Quest Plugin / Framework will support this as well.
Finally, a good Quest Framework will not force implementation. It will only allow for adaptation and let the developer decide presentation.
With this in mind, I have concocted a design for a general Quest Framework in the Unreal Engine 4.

Quest Framework Overview

So, with this in mind I will explain the core concepts for the new Quest Framework in Unreal Engine 4.
The concepts involve the mixed use of several class types. These types are UDataAssets, custom Interfaces, an Event/Message hub, as well as a Graph Editor for quests. Finally - for good measure - we will use UActorComponents as a way to let the Gameplay code interact with the quests. And yes, this will be a lot of work - but a good system or framework is always worth the workload, especially if it is reusable.
The various objects inherited from UDataAsset will be quest, objective, and rewards descriptors. The actual data defined in the class will be by the developer. (EDIT: After writing this article, I may leverage the new feature of TMap in Blueprints). Think of this as the Blackboard object in Unreal Engine 4 Behavior Trees.
Interface UObjects will be logic drivers for the Quest Framework. Such drivers will detect the state of an objective and a quest. It will also moderate rewards received, how to give out rewards, and various other tasks. Think of these as a similar role to Tasks, Services, and Decorators in Behavior Trees in Unreal Engine 4.
We have defined the roles an structure of quests and objectives. Now I can go into how to decouple questing logic from the rest of the application. From current experience, event or message based systems are great at this. This is because we just need to create a proxy event object or a message object that transmits information we care about. This reduces overhead of knowing exactly what a quest or objective object is.
Finally, a nice feature to have would be a Graph Editor. The Graph Editor will also have functions that allow us to create new quests, objectives, logic, and quest flow. The Graph Editor will also allow us to layout the paths and tracks of a quest.
That is it for Unreal Engine Quest Framework Part 2: Design - check back later where we start defining some code!

No comments:

Post a Comment