Browse Source

Miscellaneous refactors to hide complexity

- Added GameController facade class to hide complexity and provide a
single place to access all Fungus functionality
- Removed existing facade methods on Game (redundant)
- Removed Room.OnLeave (not necessary, and possibly dangerous)
- Renamed AnimationListener.OnAnimationEvent() to CallRoomMethod (more
descriptive).
- Button component will now use existing Collider2D if one exists.
- Game component now manages CameraController configuration
- Game now adds CameraController and CommandQueue at runtime instead of
in editor (less user configuration)
- CommandQueue now owns the methods for executing command methods
- Added StringTable class to manage key/string lookups
- Moved SubstituteStrings() and FormatLinkText() to new StringTable
class
- Room.Enter() method is now private to hide implementation details
- Updated example project to match changes
master
chrisgregan 11 years ago
parent
commit
3c422f234c
  1. 13
      Assets/Fungus/Scripts/AnimationListener.cs
  2. 20
      Assets/Fungus/Scripts/Button.cs
  3. 22
      Assets/Fungus/Scripts/CameraController.cs
  4. 40
      Assets/Fungus/Scripts/CommandQueue.cs
  5. 27
      Assets/Fungus/Scripts/Commands.cs
  6. 117
      Assets/Fungus/Scripts/Game.cs
  7. 267
      Assets/Fungus/Scripts/GameController.cs
  8. 8
      Assets/Fungus/Scripts/GameController.cs.meta
  9. 50
      Assets/Fungus/Scripts/Page.cs
  10. 288
      Assets/Fungus/Scripts/Room.cs
  11. 71
      Assets/Fungus/Scripts/StringTable.cs
  12. 8
      Assets/Fungus/Scripts/StringTable.cs.meta
  13. 4
      Assets/Fungus/Scripts/StringsParser.cs
  14. BIN
      Assets/FungusExample/Animations/GreenAlienWalk.anim
  15. BIN
      Assets/FungusExample/Scenes/Example.unity

13
Assets/Fungus/Scripts/AnimationListener.cs

@ -3,10 +3,16 @@ using System.Collections;
using Fungus; using Fungus;
// Listens for animation events // Listens for animation events
// The string parameter specifies a method name on the active room class // Usage:
// 1. Attach this script to the animated sprite that you want to listen to for events.
// 2. Add an event on the animation timeline
// 3. Edit the event and choose the 'CallRoomMethod' function
// 4. In the string parameters box, enter the name of the method to call in the active Room's script.
public class AnimationListener : MonoBehaviour public class AnimationListener : MonoBehaviour
{ {
void OnAnimationEvent(string methodName) // Handler method for animation events
// The string event parameter is used to call a named method on the active room class
void CallRoomMethod(string methodName)
{ {
Room room = Game.GetInstance().activeRoom; Room room = Game.GetInstance().activeRoom;
if (room == null) if (room == null)
@ -14,6 +20,7 @@ public class AnimationListener : MonoBehaviour
return; return;
} }
room.AnimationEvent(methodName); CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.CallCommandMethod(room.gameObject, methodName);
} }
} }

20
Assets/Fungus/Scripts/Button.cs

@ -8,13 +8,13 @@ namespace Fungus
// Simple button handler class. // Simple button handler class.
// When the user taps on the button, the named method is called on ancestor game objects (if it exists). // When the user taps on the button, the named method is called on ancestor game objects (if it exists).
[RequireComponent (typeof (SpriteRenderer))] [RequireComponent (typeof (SpriteRenderer))]
[RequireComponent (typeof (BoxCollider2D))] [RequireComponent (typeof (Collider2D))]
public class Button : MonoBehaviour public class Button : MonoBehaviour
{ {
public Action buttonAction; public Action buttonAction;
public SpriteRenderer spriteRenderer; public SpriteRenderer spriteRenderer;
// Makes a sprite into a clickable button // Makes a sprite clickable by attaching a Button component (and BoxCollider2D if required)
public static void MakeButton(SpriteRenderer _spriteRenderer, Action _buttonAction) public static void MakeButton(SpriteRenderer _spriteRenderer, Action _buttonAction)
{ {
if (_spriteRenderer == null) if (_spriteRenderer == null)
@ -30,7 +30,12 @@ namespace Fungus
Destroy(oldButton); Destroy(oldButton);
} }
// This will automatically add a BoxCollider2d if none currently exists // Add a BoxCollider2d if none currently exists
if (_spriteRenderer.gameObject.GetComponent<Collider2D>() == null)
{
_spriteRenderer.gameObject.AddComponent<BoxCollider2D>();
}
Button button = _spriteRenderer.gameObject.AddComponent<Button>(); Button button = _spriteRenderer.gameObject.AddComponent<Button>();
button.buttonAction = _buttonAction; button.buttonAction = _buttonAction;
button.spriteRenderer = _spriteRenderer; button.spriteRenderer = _spriteRenderer;
@ -44,13 +49,8 @@ namespace Fungus
return; return;
} }
Room room = Game.GetInstance().activeRoom; CommandQueue commandQueue = Game.GetInstance().commandQueue;
if (room == null) commandQueue.CallCommandMethod(buttonAction);
{
return;
}
room.ExecuteCommandMethod(buttonAction);
} }
} }
} }

22
Assets/Fungus/Scripts/CameraController.cs

@ -10,13 +10,15 @@ namespace Fungus
// Supports several types of camera transition including snap, pan & fade. // Supports several types of camera transition including snap, pan & fade.
public class CameraController : MonoBehaviour public class CameraController : MonoBehaviour
{ {
// Fixed Z coordinate of camera Game game;
public float cameraZ = - 10f;
Camera mainCamera; Camera mainCamera;
float fadeAlpha = 0f;
void Start() void Start()
{ {
game = Game.GetInstance();
GameObject cameraObject = GameObject.FindGameObjectWithTag("MainCamera"); GameObject cameraObject = GameObject.FindGameObjectWithTag("MainCamera");
if (cameraObject == null) if (cameraObject == null)
{ {
@ -31,10 +33,6 @@ namespace Fungus
} }
} }
public Texture2D fadeTexture;
public float fadeAlpha = 1f;
void OnGUI() void OnGUI()
{ {
int drawDepth = -1000; int drawDepth = -1000;
@ -45,7 +43,7 @@ namespace Fungus
// 0 = scene fully obscured // 0 = scene fully obscured
GUI.color = new Color(1,1,1, 1f - fadeAlpha); GUI.color = new Color(1,1,1, 1f - fadeAlpha);
GUI.depth = drawDepth; GUI.depth = drawDepth;
GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), fadeTexture); GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), game.fadeTexture);
} }
} }
@ -114,6 +112,7 @@ namespace Fungus
PanToView(view, 0, null); PanToView(view, 0, null);
} }
// Moves camera from current position to a target View over a period of time
public void PanToView(View view, float duration, Action arriveAction) public void PanToView(View view, float duration, Action arriveAction)
{ {
if (duration == 0f) if (duration == 0f)
@ -151,6 +150,7 @@ namespace Fungus
timer = duration; timer = duration;
} }
// Apply smoothed lerp to camera position and orthographic size
float t = timer / duration; float t = timer / duration;
mainCamera.orthographicSize = Mathf.Lerp(startSize, endSize, Mathf.SmoothStep(0f, 1f, t)); mainCamera.orthographicSize = Mathf.Lerp(startSize, endSize, Mathf.SmoothStep(0f, 1f, t));
mainCamera.transform.position = Vector3.Lerp(startPos, endPos, Mathf.SmoothStep(0f, 1f, t)); mainCamera.transform.position = Vector3.Lerp(startPos, endPos, Mathf.SmoothStep(0f, 1f, t));
@ -166,13 +166,13 @@ namespace Fungus
} }
} }
// Moves camera smoothly through a sequence of Views over a period of time
public void PanToPath(View[] viewList, float duration, Action arriveAction) public void PanToPath(View[] viewList, float duration, Action arriveAction)
{ {
List<Vector3> pathList = new List<Vector3>(); List<Vector3> pathList = new List<Vector3>();
// Note: We use the z coord to tween the camera orthographic size
// Add current camera position as first point in path // Add current camera position as first point in path
// Note: We use the z coord to tween the camera orthographic size
Vector3 startPos = new Vector3(mainCamera.transform.position.x, Vector3 startPos = new Vector3(mainCamera.transform.position.x,
mainCamera.transform.position.y, mainCamera.transform.position.y,
mainCamera.orthographicSize); mainCamera.orthographicSize);
@ -218,7 +218,7 @@ namespace Fungus
void SetCameraZ() void SetCameraZ()
{ {
mainCamera.transform.position = new Vector3(mainCamera.transform.position.x, mainCamera.transform.position.y, cameraZ); mainCamera.transform.position = new Vector3(mainCamera.transform.position.x, mainCamera.transform.position.y, game.cameraZ);
} }
} }
} }

40
Assets/Fungus/Scripts/CommandQueue.cs

@ -9,14 +9,6 @@ namespace Fungus
// When a command completes, the next command is popped from the queue and exectuted. // When a command completes, the next command is popped from the queue and exectuted.
public class CommandQueue : MonoBehaviour public class CommandQueue : MonoBehaviour
{ {
[HideInInspector]
public CameraController cameraController;
public void Start()
{
cameraController = Game.GetInstance().GetComponent<CameraController>();
}
// Base class for commands used with the CommandQueue // Base class for commands used with the CommandQueue
public abstract class Command public abstract class Command
{ {
@ -25,18 +17,21 @@ namespace Fungus
List<Command> commandList = new List<Command>(); List<Command> commandList = new List<Command>();
public void AddCommand(Command command) // Adds a command to the queue for later execution
public virtual void AddCommand(Command command)
{ {
commandList.Add(command); commandList.Add(command);
} }
public void Reset() // Clears all queued commands from the list
public virtual void Reset()
{ {
StopAllCoroutines();
commandList.Clear(); commandList.Clear();
} }
public void Execute() // Executes the first command in the queue.
// When this command completes, the next command in the queue is executed.
public virtual void Execute()
{ {
if (commandList.Count == 0) if (commandList.Count == 0)
{ {
@ -50,5 +45,26 @@ namespace Fungus
Execute(); Execute();
}); });
} }
// Calls a named method on a game object to populate the command queue.
// The command queue is then executed.
public void CallCommandMethod(GameObject target, string methodName)
{
Reset();
target.SendMessage(methodName, SendMessageOptions.DontRequireReceiver);
Execute();
}
// Calls an Action delegate method to populate the command queue.
// The command queue is then executed.
public void CallCommandMethod(Action method)
{
Reset();
if (method != null)
{
method();
}
Execute();
}
} }
} }

27
Assets/Fungus/Scripts/Commands.cs

@ -77,8 +77,10 @@ namespace Fungus
public override void Execute(CommandQueue commandQueue, Action onComplete) public override void Execute(CommandQueue commandQueue, Action onComplete)
{ {
commandQueue.cameraController.SnapToView(view); Game game = Game.GetInstance();
Game.GetInstance().activeView = view;
game.cameraController.SnapToView(view);
game.activeView = view;
// Set the first page component found (if any) as the active page // Set the first page component found (if any) as the active page
Page page = view.gameObject.GetComponentInChildren<Page>(); Page page = view.gameObject.GetComponentInChildren<Page>();
@ -261,7 +263,7 @@ namespace Fungus
public override void Execute(CommandQueue commandQueue, Action onComplete) public override void Execute(CommandQueue commandQueue, Action onComplete)
{ {
Game.GetInstance().SetFlag(key, value); Game.GetInstance().state.SetFlag(key, value);
if (onComplete != null) if (onComplete != null)
{ {
onComplete(); onComplete();
@ -283,7 +285,7 @@ namespace Fungus
public override void Execute(CommandQueue commandQueue, Action onComplete) public override void Execute(CommandQueue commandQueue, Action onComplete)
{ {
Game.GetInstance().SetCounter(key, value); Game.GetInstance().state.SetCounter(key, value);
if (onComplete != null) if (onComplete != null)
{ {
onComplete(); onComplete();
@ -305,7 +307,7 @@ namespace Fungus
public override void Execute(CommandQueue commandQueue, Action onComplete) public override void Execute(CommandQueue commandQueue, Action onComplete)
{ {
Game.GetInstance().SetInventory(key, value); Game.GetInstance().state.SetInventory(key, value);
if (onComplete != null) if (onComplete != null)
{ {
onComplete(); onComplete();
@ -460,9 +462,10 @@ namespace Fungus
public override void Execute(CommandQueue commandQueue, Action onComplete) public override void Execute(CommandQueue commandQueue, Action onComplete)
{ {
commandQueue.cameraController.PanToView(view, duration, delegate {
Game game = Game.GetInstance(); Game game = Game.GetInstance();
game.cameraController.PanToView(view, duration, delegate {
game.activeView = view; game.activeView = view;
// Try to find a page that is a child of the active view. // Try to find a page that is a child of the active view.
@ -503,11 +506,12 @@ namespace Fungus
public override void Execute(CommandQueue commandQueue, Action onComplete) public override void Execute(CommandQueue commandQueue, Action onComplete)
{ {
commandQueue.cameraController.PanToPath(views, duration, delegate { Game game = Game.GetInstance();
game.cameraController.PanToPath(views, duration, delegate {
if (views.Length > 0) if (views.Length > 0)
{ {
Game game = Game.GetInstance();
game.activeView = views[views.Length - 1]; game.activeView = views[views.Length - 1];
// Try to find a page that is a child of the active view. // Try to find a page that is a child of the active view.
@ -549,9 +553,10 @@ namespace Fungus
public override void Execute(CommandQueue commandQueue, Action onComplete) public override void Execute(CommandQueue commandQueue, Action onComplete)
{ {
commandQueue.cameraController.FadeToView(view, duration, delegate {
Game game = Game.GetInstance(); Game game = Game.GetInstance();
game.cameraController.FadeToView(view, duration, delegate {
game.activeView = view; game.activeView = view;
// Try to find a page that is a child of the active view. // Try to find a page that is a child of the active view.

117
Assets/Fungus/Scripts/Game.cs

@ -4,34 +4,43 @@ using System.Collections.Generic;
namespace Fungus namespace Fungus
{ {
// Manages movement between rooms and global game state // Manages global game state and movement between rooms
[RequireComponent (typeof (CommandQueue))]
[RequireComponent (typeof (CameraController))]
public class Game : MonoBehaviour public class Game : MonoBehaviour
{ {
public bool showLinks = true; public bool showLinks = true;
public Room activeRoom; public Room activeRoom;
public string continueText = "Continue";
public int charactersPerSecond = 60;
// Fixed Z coordinate of camera
public float cameraZ = - 10f;
public float fadeDuration = 1f;
public Texture2D fadeTexture;
[HideInInspector] [HideInInspector]
public View activeView; public View activeView;
[HideInInspector] [HideInInspector]
public Page activePage; public Page activePage;
[HideInInspector]
public GameState state = new GameState(); public GameState state = new GameState();
protected Dictionary<string, string> stringTable = new Dictionary<string, string>(); [HideInInspector]
public StringTable stringTable = new StringTable();
private static Game instance;
CameraController cameraController;
public float fadeDuration = 1f; [HideInInspector]
public CommandQueue commandQueue;
public string continueText = "Continue"; [HideInInspector]
public CameraController cameraController;
public int charactersPerSecond = 60; static Game instance;
public static Game GetInstance() public static Game GetInstance()
{ {
@ -49,7 +58,8 @@ namespace Fungus
public virtual void Start() public virtual void Start()
{ {
cameraController = GetComponent<CameraController>(); commandQueue = gameObject.AddComponent<CommandQueue>();
cameraController = gameObject.AddComponent<CameraController>();
if (activeRoom == null) if (activeRoom == null)
{ {
@ -63,11 +73,6 @@ namespace Fungus
} }
} }
public Room GetCurrentRoom()
{
return GetInstance().activeRoom;
}
public void MoveToRoom(Room room) public void MoveToRoom(Room room)
{ {
if (room == null) if (room == null)
@ -79,87 +84,15 @@ namespace Fungus
// Fade out screen // Fade out screen
cameraController.Fade(0f, fadeDuration / 2f, delegate { cameraController.Fade(0f, fadeDuration / 2f, delegate {
if (activeRoom != null)
{
activeRoom.Leave();
}
activeRoom = room; activeRoom = room;
activeRoom.Enter(); // Notify room script that the Room is being entered
// Calling private method on Room to hide implementation
activeRoom.gameObject.SendMessage("Enter");
// Fade in screen // Fade in screen
cameraController.Fade(1f, fadeDuration / 2f, null); cameraController.Fade(1f, fadeDuration / 2f, null);
}); });
} }
public void Restart()
{
// TODO: Reload scene
}
public void ClearFlags()
{
state.ClearFlags();
}
public bool GetFlag(string key)
{
return state.GetFlag(key);
}
public void SetFlag(string key, bool value)
{
state.SetFlag(key, value);
}
public void ClearCounters()
{
state.ClearCounters();
}
public int GetCounter(string key)
{
return state.GetCounter(key);
}
public void SetCounter(string key, int value)
{
state.SetCounter(key, value);
}
public void ClearInventory()
{
state.ClearInventory();
}
public int GetInventory(string key)
{
return state.GetInventory(key);
}
public void SetInventory(string key, int value)
{
state.SetInventory(key, value);
}
public void ClearStringTable()
{
stringTable.Clear();
}
public string GetString(string key)
{
if (stringTable.ContainsKey(key))
{
return stringTable[key];
}
return "";
}
public void SetString(string key, string value)
{
stringTable[key] = value;
}
} }
} }

267
Assets/Fungus/Scripts/GameController.cs

@ -0,0 +1,267 @@
using UnityEngine;
using System;
using System.Collections;
using Fungus;
// This facade class gives easy access to all game control
// functionality available in Fungus
public class GameController : MonoBehaviour
{
//
// Synchronous methods
// The following methods all execute immediately
//
// Return true if the boolean flag for the key has been set to true
public bool GetFlag(string key)
{
GameState state = Game.GetInstance().state;
return state.GetFlag(key);
}
// Returns the count value for the key
// Returns zero if no value has been set.
public int GetCounter(string key)
{
GameState state = Game.GetInstance().state;
return state.GetCounter(key);
}
// Returns the inventory count value for the key
// Returns zero if no inventory count has been set.
public int GetInventory(string key)
{
GameState state = Game.GetInstance().state;
return state.GetInventory(key);
}
// Returns true if the inventory count for the key is greater than zero
public bool HasInventory(string key)
{
GameState state = Game.GetInstance().state;
return (state.GetInventory(key) > 0);
}
//
// Asynchronous methods
// The following methods all queue commands for later execution in strict serial order
//
// Wait for a period of time before executing the next command
public void Wait(float duration)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new WaitCommand(duration));
}
// Call a delegate method provided by the client
// Used to queue the execution of arbitrary code.
public void Call(Action callAction)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new CallCommand(callAction));
}
// Sets the currently active view immediately.
// The main camera snaps to the active view.
public void SetView(View view)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new SetViewCommand(view));
}
// Sets the currently active page for text rendering
public void SetPage(Page page)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new SetPageCommand(page));
}
// Sets the title text displayed at the top of the active page
public void Title(string titleText)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new TitleCommand(titleText));
}
// Writes story text to the currently active page.
// A 'continue' button is displayed when the text has fully appeared.
public void Say(string storyText)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new SayCommand(storyText));
}
// Adds an option button to the current list of options.
// Use the Choose command to display added options.
public void AddOption(string optionText, Action optionAction)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new AddOptionCommand(optionText, optionAction));
}
// Display all previously added options as buttons, with no text prompt
public void Choose()
{
Choose("");
}
// Displays a text prompt, followed by all previously added options as buttons.
public void Choose(string chooseText)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new ChooseCommand(chooseText));
}
// Changes the active room to a different room
public void MoveToRoom(Room room)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new MoveToRoomCommand(room));
}
// Sets a global boolean flag value
public void SetFlag(string key, bool value)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new SetFlagCommand(key, value));
}
// Sets a global integer counter value
public void SetCounter(string key, int value)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new SetCounterCommand(key, value));
}
// Sets a global inventory count value
// Assumes that the count value is 1 (common case)
public void SetInventory(string key)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new SetInventoryCommand(key, 1));
}
// Sets a global inventory count value
public void SetInventory(string key, int value)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new SetInventoryCommand(key, value));
}
// Sets sprite alpha to 0 immediately
public void HideSprite(SpriteRenderer spriteRenderer)
{
FadeSprite(spriteRenderer, 0, 0, Vector2.zero);
}
// Sets sprite alpha to 1 immediately
public void ShowSprite(SpriteRenderer spriteRenderer)
{
FadeSprite(spriteRenderer, 1, 0, Vector2.zero);
}
// Fades a sprite to a given alpha value over a period of time
public void FadeSprite(SpriteRenderer spriteRenderer, float targetAlpha, float duration)
{
FadeSprite(spriteRenderer, targetAlpha, duration, Vector2.zero);
}
// Fades a sprite to a given alpha value over a period of time, and applies a sliding motion to the sprite transform
public void FadeSprite(SpriteRenderer spriteRenderer, float targetAlpha, float duration, Vector2 slideOffset)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
Color color = spriteRenderer.color;
color.a = targetAlpha;
commandQueue.AddCommand(new FadeSpriteCommand(spriteRenderer, color, duration, slideOffset));
}
// Makes a sprite behave as a clickable button
public void AddButton(SpriteRenderer buttonSprite, Action buttonAction)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new AddButtonCommand(buttonSprite, buttonAction));
}
// Makes a sprite stop behaving as a clickable button
public void RemoveButton(SpriteRenderer buttonSprite)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new RemoveButtonCommand(buttonSprite));
}
// Sets an animator trigger to change the animation state for an animated sprite
public void SetAnimatorTrigger(Animator animator, string triggerName)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new SetAnimatorTriggerCommand(animator, triggerName));
}
// Pans the camera to the target view over a period of time
public void PanToView(View targetView, float duration)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new PanToViewCommand(targetView, duration));
}
// Pans the camera through a sequence of target views over a period of time
public void PanToPath(float duration, params View[] targetViews)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new PanToPathCommand(targetViews, duration));
}
// Snaps the camera to the target view immediately
public void SnapToView(View targetView)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new PanToViewCommand(targetView, 0f));
}
// Fades out the current camera view, and fades in again using the target view.
public void FadeToView(View targetView, float duration)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new FadeToViewCommand(targetView, duration));
}
// Plays game music using an audio clip
public void PlayGameMusic(AudioClip audioClip)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new PlayMusicCommand(audioClip));
}
// Stops playing game music
public void StopGameMusic()
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new StopMusicCommand());
}
// Sets music volume immediately
public void SetMusicVolume(float musicVolume)
{
SetMusicVolume(musicVolume, 0f);
}
// Fades music volume to required level over a period of time
public void SetMusicVolume(float musicVolume, float duration)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new SetMusicVolumeCommand(musicVolume, duration));
}
// Plays a sound effect once
public void PlaySound(AudioClip audioClip)
{
PlaySound(audioClip, 1f);
}
// Plays a sound effect once, at the specified volume
public void PlaySound(AudioClip audioClip, float volume)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new PlaySoundCommand(audioClip, volume));
}
}

8
Assets/Fungus/Scripts/GameController.cs.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4341f88125d5c4fe1b941bd614ae342d
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

50
Assets/Fungus/Scripts/Page.cs

@ -2,7 +2,6 @@ using UnityEngine;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace Fungus namespace Fungus
{ {
@ -64,20 +63,23 @@ namespace Fungus
public void Say(string sayText, Action sayAction) public void Say(string sayText, Action sayAction)
{ {
mode = Mode.Say; mode = Mode.Say;
string subbedText = SubstituteStrings(sayText); StringTable stringTable = Game.GetInstance().stringTable;
string subbedText = stringTable.SubstituteStrings(sayText);
WriteStory(subbedText, sayAction); WriteStory(subbedText, sayAction);
} }
public void AddOption(string optionText, Action optionAction) public void AddOption(string optionText, Action optionAction)
{ {
string subbedText = FormatLinkText(SubstituteStrings(optionText)); StringTable stringTable = Game.GetInstance().stringTable;
string subbedText = stringTable.FormatLinkText(stringTable.SubstituteStrings(optionText));
options.Add(new Option(subbedText, optionAction)); options.Add(new Option(subbedText, optionAction));
} }
public void Choose(string _chooseText) public void Choose(string _chooseText)
{ {
mode = Mode.Choose; mode = Mode.Choose;
string subbedText = SubstituteStrings(_chooseText); StringTable stringTable = Game.GetInstance().stringTable;
string subbedText = stringTable.SubstituteStrings(_chooseText);
WriteStory(subbedText, null); WriteStory(subbedText, null);
} }
@ -206,9 +208,8 @@ namespace Fungus
// Reset to idle, but calling action may set this again // Reset to idle, but calling action may set this again
mode = Mode.Idle; mode = Mode.Idle;
Room room = Game.GetInstance().activeRoom; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.CallCommandMethod(tempAction);
room.ExecuteCommandMethod(tempAction);
} }
else if (mode == Mode.Say) else if (mode == Mode.Say)
{ {
@ -274,41 +275,6 @@ namespace Fungus
outerRect.height - (boxStyle.padding.top + boxStyle.padding.bottom)); outerRect.height - (boxStyle.padding.top + boxStyle.padding.bottom));
} }
private string SubstituteStrings(string text)
{
string subbedText = text;
// Instantiate the regular expression object.
Regex r = new Regex("{.*?}");
// Match the regular expression pattern against a text string.
var results = r.Matches(text);
foreach (Match match in results)
{
string stringKey = match.Value.Substring(1, match.Value.Length - 2);
string stringValue = Game.GetInstance().GetString(stringKey);
subbedText = subbedText.Replace(match.Value, stringValue);
}
return subbedText;
}
private string FormatLinkText(string text)
{
string trimmed;
if (text.Contains("\n"))
{
trimmed = text.Substring(0, text.IndexOf("\n"));
}
else
{
trimmed = text;
}
return trimmed;
}
Rect GetScreenRect() Rect GetScreenRect()
{ {
// Y decreases up the screen in GUI space, so top left is rect origin // Y decreases up the screen in GUI space, so top left is rect origin

288
Assets/Fungus/Scripts/Room.cs

@ -10,23 +10,18 @@ namespace Fungus
// This is the main scripting interface for Fungus games. // This is the main scripting interface for Fungus games.
// Each room in your game should have a script which inherits from Room. // Each room in your game should have a script which inherits from Room.
// The OnEnter() method is called when the player enters the room. // The OnEnter() method is called when the player enters the room.
// The OnLeave() method is called when the player moves to a different room. // The GameController base class provides easy access to all story control commands
// Convenience methods are provided for accessing all features of the library. public abstract class Room : GameController
public abstract class Room : MonoBehaviour
{ {
public int visitCount; public int visitCount;
Game game; // Returns true if this is the first time the player has visited this room
CommandQueue commandQueue; public bool IsFirstVisit()
CameraController cameraController;
void Awake()
{ {
game = Game.GetInstance(); return (visitCount == 0);
cameraController = game.gameObject.GetComponent<CameraController>();
commandQueue = game.gameObject.GetComponent<CommandQueue>();
} }
// Automatically draws arrows to other Rooms referenced in public properties
void OnDrawGizmos() void OnDrawGizmos()
{ {
const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance; const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
@ -100,9 +95,13 @@ namespace Fungus
Gizmos.DrawLine(arrowPosA, arrowPosC); Gizmos.DrawLine(arrowPosA, arrowPosC);
} }
// Internal use only! Called by Game when changing room // Called by Game when player enters the room
public void Enter() void Enter()
{ {
Game game = Game.GetInstance();
CameraController cameraController = game.gameObject.GetComponent<CameraController>();
// Pick first view found in the room and snap to camera to this view. // Pick first view found in the room and snap to camera to this view.
// It is allowed for a room to not have any views. // It is allowed for a room to not have any views.
// In this case game.activeView will be null, and the camera will attempt // In this case game.activeView will be null, and the camera will attempt
@ -135,270 +134,9 @@ namespace Fungus
// Rooms may have multiple child views and page. It is the responsibility of the client // Rooms may have multiple child views and page. It is the responsibility of the client
// room script to set the appropriate view & page in its OnEnter method. // room script to set the appropriate view & page in its OnEnter method.
commandQueue.Reset(); game.commandQueue.CallCommandMethod(game.activeRoom.gameObject, "OnEnter");
SendMessage("OnEnter", SendMessageOptions.DontRequireReceiver);
commandQueue.Execute();
visitCount++; visitCount++;
} }
// Internal use only! Called by Game when changing room
public void Leave()
{
SendMessage("OnLeave", SendMessageOptions.DontRequireReceiver);
}
// Internal use only! Called by AnimationEventListener
public void AnimationEvent(string methodName)
{
ExecuteCommandMethod(methodName);
}
// Internal use only!
public void ExecuteCommandMethod(string methodName)
{
commandQueue.Reset();
SendMessage(methodName, SendMessageOptions.DontRequireReceiver);
commandQueue.Execute();
}
// Internal use only!
public void ExecuteCommandMethod(Action method)
{
commandQueue.Reset();
method();
commandQueue.Execute();
}
// Public convenience methods
// These methods all execute immediately
// Returns true if this is the first time the player has visited this room
public bool IsFirstVisit()
{
return (visitCount == 0);
}
// Return true if the boolean flag for the key has been set to true
public bool GetFlag(string key)
{
return game.GetFlag(key);
}
// Returns the count value for the key
// Returns zero if no value has been set.
public int GetCounter(string key)
{
return game.GetCounter(key);
}
// Returns the inventory count value for the key
// Returns zero if no inventory count has been set.
public int GetInventory(string key)
{
return game.GetInventory(key);
}
// Returns true if the inventory count for the key is greater than zero
public bool HasInventory(string key)
{
return (game.GetInventory(key) > 0);
}
// Public command methods
// These methods all queue commands for later execution in serial order
// Wait for a period of time before executing the next command
public void Wait(float duration)
{
commandQueue.AddCommand(new WaitCommand(duration));
}
// Call a delegate method provided by the client
// Used to queue the execution of arbitrary code.
public void Call(Action callAction)
{
commandQueue.AddCommand(new CallCommand(callAction));
}
// Sets the currently active view immediately.
// The main camera snaps to the active view.
public void SetView(View view)
{
commandQueue.AddCommand(new SetViewCommand(view));
}
// Sets the currently active page for text rendering
public void SetPage(Page page)
{
commandQueue.AddCommand(new SetPageCommand(page));
}
// Sets the title text displayed at the top of the active page
public void Title(string titleText)
{
commandQueue.AddCommand(new TitleCommand(titleText));
}
// Writes story text to the currently active page.
// A 'continue' button is displayed when the text has fully appeared.
public void Say(string storyText)
{
commandQueue.AddCommand(new SayCommand(storyText));
}
// Adds an option button to the current list of options.
// Use the Choose command to display added options.
public void AddOption(string optionText, Action optionAction)
{
commandQueue.AddCommand(new AddOptionCommand(optionText, optionAction));
}
// Displays a text prompt, followed by all previously added options as buttons.
public void Choose(string chooseText)
{
commandQueue.AddCommand(new ChooseCommand(chooseText));
}
// Changes the active room to a different room
public void MoveToRoom(Room room)
{
commandQueue.AddCommand(new MoveToRoomCommand(room));
}
// Sets a global boolean flag value
public void SetFlag(string key, bool value)
{
commandQueue.AddCommand(new SetFlagCommand(key, value));
}
// Sets a global integer counter value
public void SetCounter(string key, int value)
{
commandQueue.AddCommand(new SetCounterCommand(key, value));
}
// Sets a global inventory count value
// Assumes that the count value is 1 (common case)
public void SetInventory(string key)
{
commandQueue.AddCommand(new SetInventoryCommand(key, 1));
}
// Sets a global inventory count value
public void SetInventory(string key, int value)
{
commandQueue.AddCommand(new SetInventoryCommand(key, value));
}
// Sets sprite alpha to 0 immediately
public void HideSprite(SpriteRenderer spriteRenderer)
{
Color color = spriteRenderer.color;
color.a = 0f;
commandQueue.AddCommand(new FadeSpriteCommand(spriteRenderer, color, 0f, Vector2.zero));
}
// Sets sprite alpha to 1 immediately
public void ShowSprite(SpriteRenderer spriteRenderer)
{
Color color = spriteRenderer.color;
color.a = 1f;
commandQueue.AddCommand(new FadeSpriteCommand(spriteRenderer, color, 0f, Vector2.zero));
}
// Fades a sprite to a given alpha value over a period of time
public void FadeSprite(SpriteRenderer spriteRenderer, float targetAlpha, float duration)
{
Color color = spriteRenderer.color;
color.a = targetAlpha;
commandQueue.AddCommand(new FadeSpriteCommand(spriteRenderer, color, duration, Vector2.zero));
}
// Fades a sprite to a given alpha value over a period of time, and applies a sliding motion to the sprite transform
public void FadeSprite(SpriteRenderer spriteRenderer, float targetAlpha, float duration, Vector2 slideOffset)
{
Color color = spriteRenderer.color;
color.a = targetAlpha;
commandQueue.AddCommand(new FadeSpriteCommand(spriteRenderer, color, duration, slideOffset));
}
// Makes a sprite behave as a clickable button
public void AddButton(SpriteRenderer buttonSprite, Action buttonAction)
{
commandQueue.AddCommand(new AddButtonCommand(buttonSprite, buttonAction));
}
// Makes a sprite stop behaving as a clickable button
public void RemoveButton(SpriteRenderer buttonSprite)
{
commandQueue.AddCommand(new RemoveButtonCommand(buttonSprite));
}
// Sets an animator trigger to change the animation state for an animated sprite
public void SetAnimatorTrigger(Animator animator, string triggerName)
{
commandQueue.AddCommand(new SetAnimatorTriggerCommand(animator, triggerName));
}
// Pans the camera to the target view over a period of time
public void PanToView(View targetView, float duration)
{
commandQueue.AddCommand(new PanToViewCommand(targetView, duration));
}
// Pans the camera through a sequence of target views over a period of time
public void PanToPath(float duration, params View[] targetViews)
{
commandQueue.AddCommand(new PanToPathCommand(targetViews, duration));
}
// Snaps the camera to the target view immediately
public void SnapToView(View targetView)
{
commandQueue.AddCommand(new PanToViewCommand(targetView, 0f));
}
// Fades out the current camera view, and fades in again using the target view.
public void FadeToView(View targetView, float duration)
{
commandQueue.AddCommand(new FadeToViewCommand(targetView, duration));
}
// Plays game music using an audio clip
public void PlayGameMusic(AudioClip audioClip)
{
commandQueue.AddCommand(new PlayMusicCommand(audioClip));
}
// Stops playing game music
public void StopGameMusic()
{
commandQueue.AddCommand(new StopMusicCommand());
}
// Sets music volume immediately
public void SetMusicVolume(float musicVolume)
{
commandQueue.AddCommand(new SetMusicVolumeCommand(musicVolume, 0f));
}
// Fades music volume to required level over a period of time
public void SetMusicVolume(float musicVolume, float duration)
{
commandQueue.AddCommand(new SetMusicVolumeCommand(musicVolume, duration));
}
// Plays a sound effect once
public void PlaySound(AudioClip audioClip)
{
commandQueue.AddCommand(new PlaySoundCommand(audioClip, 1f));
}
// Plays a sound effect once, at the specified volume
public void PlaySound(AudioClip audioClip, float volume)
{
commandQueue.AddCommand(new PlaySoundCommand(audioClip, volume));
}
} }
} }

71
Assets/Fungus/Scripts/StringTable.cs

@ -0,0 +1,71 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
// Stores long or frequently repeated strings in a dictionary.
// Strings can then be retrieved using a short key string.
public class StringTable
{
Dictionary<string, string> stringTable = new Dictionary<string, string>();
public void ClearStringTable()
{
stringTable.Clear();
}
// Retrieves a string from the table
public string GetString(string key)
{
if (stringTable.ContainsKey(key))
{
return stringTable[key];
}
return "";
}
// Adds or updates a string in the table
public void SetString(string key, string value)
{
stringTable[key] = value;
}
// Replace keys in the input string with the string table entry
// Example format: "This {string_key} string"
public string SubstituteStrings(string text)
{
string subbedText = text;
// Instantiate the regular expression object.
Regex r = new Regex("{.*?}");
// Match the regular expression pattern against a text string.
var results = r.Matches(text);
foreach (Match match in results)
{
string stringKey = match.Value.Substring(1, match.Value.Length - 2);
string stringValue = GetString(stringKey);
subbedText = subbedText.Replace(match.Value, stringValue);
}
return subbedText;
}
// Chops a string at the first new line character
// Useful for link / button strings that must fit on a single line
public string FormatLinkText(string text)
{
string trimmed;
if (text.Contains("\n"))
{
trimmed = text.Substring(0, text.IndexOf("\n"));
}
else
{
trimmed = text;
}
return trimmed;
}
}

8
Assets/Fungus/Scripts/StringTable.cs.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 43c44334e66c44af1a071056e4fde1f9
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

4
Assets/Fungus/Scripts/StringsParser.cs

@ -29,6 +29,8 @@ namespace Fungus
static public void ProcessText(string text) static public void ProcessText(string text)
{ {
StringTable stringTable = Game.GetInstance().stringTable;
// Split text into lines. Add a newline at end to ensure last command is always parsed // Split text into lines. Add a newline at end to ensure last command is always parsed
string[] lines = Regex.Split(text + "\n", "(?<=\n)"); string[] lines = Regex.Split(text + "\n", "(?<=\n)");
@ -86,7 +88,7 @@ namespace Fungus
// Trim off last newline // Trim off last newline
blockBuffer = blockBuffer.TrimEnd( '\r', '\n', ' ', '\t'); blockBuffer = blockBuffer.TrimEnd( '\r', '\n', ' ', '\t');
Game.GetInstance().SetString(blockTag, blockBuffer); stringTable.SetString(blockTag, blockBuffer);
} }
// Prepare to parse next block // Prepare to parse next block

BIN
Assets/FungusExample/Animations/GreenAlienWalk.anim

Binary file not shown.

BIN
Assets/FungusExample/Scenes/Example.unity

Binary file not shown.
Loading…
Cancel
Save