Kairoengine story system based on the Ink language.

James Peret 2fc1144913 Updated package dependencies and bumped to v0.2.0 8 months ago
Editor 917fb1c94d Initial commit 1 year ago
Prefabs 917fb1c94d Initial commit 1 year ago
Runtime 2fc1144913 Updated package dependencies and bumped to v0.2.0 8 months ago
Tests 83e97600d2 Updated meta files 1 year ago
.gitignore 917fb1c94d Initial commit 1 year ago
Editor.meta 917fb1c94d Initial commit 1 year ago
Prefabs.meta 917fb1c94d Initial commit 1 year ago
Readme.md 2fc1144913 Updated package dependencies and bumped to v0.2.0 8 months ago
Readme.md.meta 917fb1c94d Initial commit 1 year ago
Runtime.meta 917fb1c94d Initial commit 1 year ago
Tests.meta 917fb1c94d Initial commit 1 year ago
package.json 2fc1144913 Updated package dependencies and bumped to v0.2.0 8 months ago
package.json.meta 83e97600d2 Updated meta files 1 year ago

Readme.md

📦 KairoEngine.StorySystem v0.2.0

The Story System uses the Ink Language and runtime to navigate through a story written in a plain text file. This package contains the Story Module that receives an ink story and runs it. The story can show lines and branches, execute functions in unity and wait for events. Unity also has an API for navigating, getting and setting variables in the story.

🛑Required packages

  • KairoEngine.Core
  • KairoEngine.UI
  • Ink
  • UniRX
  • TextMeshPro
  • Sirenix

📄Namespaces

  • KairoEngine.StorySystem
  • KairoEngine.StorySystem.UI
  • KairoEngine.StorySystem.EditorTests

📙Modules

  • Story Module – Loads a story configuration, instantiates a story controller and starts the story playback.

🔷Components

  • StoryViewUI – A generic UI for showing text and buttons based on story events.
  • StoryButton – A button used in the Story View UI
  • StoryText – A text object used in the Story View UI

✔Getting Started

To get started using the Story module, first add it to a game config and add an installer prefab to a scene. Then install [Inky](), the Ink editor. Create a new Ink story, save the file and add it to the Unity project. Unity will generate a JSON file from the Ink file then add it the story module configuration.

A simple example Ink story:

Once upon a time...

 * There was a choice.
 * There was another choice.

- And they lived happily ever after.
    -> END

When this story is run on Unity after been loaded with the story module, it will read the first line and send it as an event to the game. Then it will read all choices and send them as a single event to the game. The story system will wait for another event containing the chosen path. The system will then send an event containing the last line of text in the story and then will stop.

The story system publishes events containing StoryStepData that other scripts can subscribe to. This object contains data about that passage of the story. It can be a line of text, a list of choices or a integer for the path that has been selected.

When the Ink story runs, lines and branches will be sent as events imidiatly in order. Wait functions can delay that process. Once a branch has been reached, the story will wait for an event to be sent back containing the selected path.

Below, in the Unity Functions section there are instructions on how to send and receive story events with code examples.

🧰Ink Functions

Use these functions in an Ink document to execute things in Unity. Each function has a usage pattern and the actual function that needs to go somewhere inside the Ink document.

Wait

Make the story wait for a certain amount of time. In the Ink story file, use ~Wait(time) anywhere in the story to make unity wait the amout of time before continuing the story.

// Example Usage
Something happens
~ Wait(3000)
After three seconds another thing happens

Add the functions below for declaring a external function to Ink and a fallback function to make it work in the Inky editor

EXTERNAL WaitForTime(time)
=== function Wait(time) ===
~WaitForTime(time)
<> <i>(Wait {time} ms)</i>
=== function WaitForTime(time) ===
~x = ""
Enable / Disable GameObject

Enable and disable GameObjects. In Ink, use ~Enable("StoryGameObjectName") or ~ Disable("StoryGameObjectName"). Add prefabs for the GameObjects used in the story to the list on the Story Module config.

// Show a menu in the game and close it after the choice is made
~ Enable("MainMenuUI")
Main Menu
    + [Start Game]
        ~ Disable("MainMenuUI")
        -> StartGame
    + [End Game]
        ~ Disable("MainMenuUI")
        -> END

Add the function below anywhere on the ink document:

EXTERNAL Enable(name)
EXTERNAL Disable(name)
=== function Enable(name) ===
> Enable <i>{name}</i>
=== function Disable(name) ===
> Disable <i>{name}</i>
Wait for Event
Trigger Events

Triggers a GenericEvent in unity. Pass in a string containing the name of the event to be triggered. Example:

~ TriggerEvent("MyCustomEvent")
EXTERNAL TriggerEvent(name)
=== function TriggerEvent(name) ===
> Trigger event "<i>{name}</i>"
Change Scene
Control Slideshow
Set Camera
PlaySFX
Play Soudtrack

🧰Unity Functions

These are functions used in Unity to change and navigate a Ink story. Also there are helper function for doing various things like observers and events.

Go to Story Knot
Get Variable
Set Variable
Receive Story Events

To receive story events, simply subscribe to events with the story name and a function.

EventManager.broadcast.StartListening(storyName, OnStoryStep);

The function for these events needs to receive story step data, for example:

void OnStoryStepData(StoryStepData storyStep)
{
    Debug.Log($"> {storyStep.text}");
}

Don't forget to stop listening for events when the script is done. For example, using a monobehaviour derived class:

void OnDisable()
{
    EventManager.broadcast.StopListening(storyName, OnStoryStep);
}
Send Story Events

When the story has reached a branch, it will wait ultil it receives an event containing the selected path.

int path = 0;
StoryStepData storyStep = new StoryStepData(StoryStepType.Path, text, null, null, path)
EventManager.broadcast.Trigger(storyName, storyStep )
Story Observer

Instead of declaring delegates using events, it's possible to subscribe to story steps using observers:

CompositeDisposable composite = new CompositeDisposable();
// Subscribe to the custom observer
// Other UniRX functions can be chained here
StoryController.Lines().Subscribe(storyStep => {
    Debug.Log(storyStep.text);
    // Stop the observer
    composite.Dispose()
}).AddTo(composite);

The Story Controller Lines observer requires the kairoEngine.StorySystem namespace.

📄Changelog

v0.2.0
  • Upgraded GameModule system

🎈Back Log

  • Support for multiple stories
  • More tests