To help encourage players to discover more of Hevn, we've recently added the concept of "objectives". This will likely feel familiar to those who have played RPGs or really any game that requires completing various types of tasks or quests. For the purposes of this post, the terms "task", "quest", and "objective" are used interchangeably to mean "something that needs to be done by the player". Several quest based systems already exist on the market, but after research it made the most sense to implement a simple custom solution. In this post I'll try to share how we're implementing a flexible objective based system that provides a foundation to create an immersive and unique experience.
To begin with, let's take a quick look at the core objective types currently in Hevn. Note that more may be added as necessary. Also many objectives are optional however whatever decision is made, it will have some sort of impact on the game.
- Fix - Finding and repairing objects in the game world.
- Inspect - Navigating to an object and monitoring it for a set period of time. Other events may trigger while the player is monitoring the object.
- Collect - Accumulating items in the game world and placing them in the character's inventory.
- Location - Navigating to a specific place or general area in the game world.
- PlayerAttribute - Increasing or decreasing one or more player attributes to a specified threshold.
These 5 types provide a decent base to build interesting objectives with, many of which can be chained. Another advantage to using a custom objectives system is they can also be used to drive the main storyline or an alternate side story in creative ways that would only make sense in Hevn. One simple example is a quest to reduce the character's sanity attribute at a specific location with a particular item in the player's inventory to essentially unlock the ability to experience something.
All of the above core objective types are derived from the base class Objective. This class serves the purpose to define what an objective is as well as to integrate with the core game saving/state functionality, which all objectives need to do. Here's a look at what an Objective consists of:
All of the variable values above are pre-defined in JSON. JSON provides the much needed flexibility, especially when designing more involved chained objectives. Here's what the variables mean:
- id - A unique String value to identify this objective.
- name - The name of the objective as presented to the player.
- description - The description provided in the objective's menu in the game's UI.
- finishMessage - The message to display to the user when the objective is done.
- targetTransformId - The optional name of a transform in the game world that the player might need to interact with.
- nextObjectiveId - The optional id of an objective that is triggered once this one is completed.
- sceneName - The name of the level or scene where the objective takes place.
- objectiveScope - It's either a main plot objective or a side objective.
- objectiveState - Can either be Not Started, Started, or Finished.
Below is an example of the JSON definition for a "Collect" objective type (purely for testing purposes). A CollectObjective is an objective that asks the player to gather items in the game world and place them in the character's inventory. This particular objective requires the player to pick up and equip two shoes. Simple really.
To get the above objective functional, two things had to happen. The first is defining a listener interface to handle events that need to fire when the player adds or removes items in their inventory:
With an interface defined and managed by the InventoryItemHandler class, an objective can now listen in when an item is added or removed. Here's a look at how the CollectObjectives class currently handles these events:
Every time an item is added or removed from the inventory, this objective can check to see if the requirements have been met. A similar implementation is done for the other objectives either through the use of listeners or binding scripts to objects in the game world at run time that can be triggered by the player.
So at this point, we can now plug this objective into the game by either triggering it at an in-game computer monitor or through various other ways as needed by the story. We can also easily add or edit existing objectives all in JSON without frustration. In the game, here's what the screen looks like when an objective is triggered (note that a trailer/video with the sound effects are coming soon):
And here's what the current Objectives Menu looks like in it's most simple form (still a work in progress):
We're very excited to finally be at a point where we can work on the objectives in the actual game. There is still lots to do as far as chaining or grouping objectives goes, but hopefully even at this stage this helps to add another layer of immersion that is both fun and interesting.
Thanks so much for reading! Until next time.