Incorporating ChatGPT into a Unity prototype (Part 2 of 2)
In Part 1, I discussed how we interface with ChatGPT. In Part 2, I will focus on the design of our game, and how we generate narrative subsequent to the opening scene, as well as how our game mechanics affect this generated narrative.
Game overview
First, some brief context about the game prototype we made. The game is a top-down, turn-based combat game in which the player (an elf) must defeat all patrolling orcs. Orcs are capable of spotting the player gets too close. Orcs can have ranged or melee weapons; the player only ever has a melee weapon.
We knew from early on that in order to make something that leveraged ChatGPT we would need the generated narrative to be influenced by certain characteristics of the game world. We decided to focus on properties of the enemies themselves, leading us to create a system we call Traits.
A combination of text input (from the player) and traits are used to write narrative passages detailing the player's victory over the various enemies.
Traits
Traits are essentially status effects. They have a variety of effects:
Burning
- damage per turnKnockdown
- turn skippedDrunk
- deal & take more damageSober
- deal & take less damageEasily-distracted
- chance to skip turnHungover
- chance attack will miss if using a bowShort-sighted
- shorter range for spotting the playerOne-armed
- chance attack will miss if using a melee weapon
Most of these are assigned to enemies at the start of the game and remain for its entirety; Burning
and Knockdown
are exceptions to this, as Knockdown
has a chance of occurring when the player attacks an enemy and Burning
is triggered by being close to a barrel when it explodes.
Player input
Upon defeating an enemy, the game halts, and the player is presented with a text prompt: How does the elf dispatch this foe? Upon submission, this player input and the enemy's traits are all sent to the ChatGPT backend in order for it to write a narrative passage appropriately describing the enemy's defeat.
ChatGPT Post and Response
Upon defeating an enemy, the following call is made to the ChatGPT backend:
Note that we are sending both player input (the text
property) and a list of all traits
that the enemy possesses to ChatGPT.
Initially, we were only sending the names of the traits. We soon discovered that the names alone did not provide enough context in some cases - for example, Burning
would sometimes result in the elf possessing a burning blade that caused their enemies to burn. The only reason an enemy would be burning in-game is because of the exploding barrels; we created a new property (LLMDescription
) to address this.
LLMDescription
is then obtained in the aforementioned GameManager.ProcessEnemyKill()
via some simple string building by overriding ToString()
:
Result
The following is an example of an orc with the Drunk
trait being defeated by a player who entered "decapitated" when prompted:
Overall, we were pretty happy with the results. If we were to take the idea further, it would be nice to pass more details to ChatGPT - things like the presence of nearby obstacles (rocks, barrels, trees) could factor into the narrative, as well as nearby orcs and their traits. Furthermore, narrative could be generated more frequently, e.g. when an orc spots the enemy player and begins chasing them.
This summary was deliberately a high-level one - you can always check out the repo if you want to see everything, or to try the game out yourself.
Note - if you want ChatGPT functionality, you'll need your own API key. Without an API key, you won't get any of the fancy, generated narrative.