StoryController.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. using KairoEngine.Core;
  6. using Ink.Runtime;
  7. using UniRx;
  8. namespace KairoEngine.StorySystem
  9. {
  10. // Todo: Request events for getting and setting story variables
  11. public class StoryController
  12. {
  13. private TextAsset inkJSONAsset = null;
  14. private Story story;
  15. private string name;
  16. private bool logText = false;
  17. private bool started = false;
  18. private int lineInverval = 250;
  19. public bool wait = false;
  20. private CompositeDisposable disposables = new CompositeDisposable();
  21. private List<StoryObject> storyObjects;
  22. public StoryController(TextAsset inkJSONAsset, string storyName, bool logText = false)
  23. {
  24. this.inkJSONAsset = inkJSONAsset;
  25. this.name = storyName;
  26. this.story = new Story (inkJSONAsset.text);
  27. this.logText = logText;
  28. }
  29. public StoryController(TextAsset inkJSONAsset, string storyName, List<StoryObject> storyObjects, Transform parent = null, bool logText = false, int lineInverval = 250)
  30. {
  31. this.inkJSONAsset = inkJSONAsset;
  32. this.name = storyName;
  33. this.story = new Story (inkJSONAsset.text);
  34. this.logText = logText;
  35. this.lineInverval = lineInverval;
  36. this.storyObjects = storyObjects;
  37. foreach (var item in storyObjects)
  38. {
  39. item.instance = GameObject.Instantiate(item.prefab, parent);
  40. item.instance.SetActive(false);
  41. item.instance.name = item.instance.name.Replace("(Clone)", "");
  42. }
  43. }
  44. public void Start()
  45. {
  46. if(started) return;
  47. started = true;
  48. GenericEvents.StartListening(name, JumpToPath);
  49. EventManager.broadcast.StartListening(name, SelectStoryBranch);
  50. EventManager.broadcast.StartListening(name, PublishStorylineToObservers);
  51. if(logText) Debug.Log($"Starting {name}");
  52. story.BindExternalFunction ("WaitForTime", (int time) => Wait(time), false);
  53. story.BindExternalFunction ("Enable", (string name) => EnableGameObject(name), false);
  54. story.BindExternalFunction ("Disable", (string name) => DisableGameObject(name), false);
  55. story.BindExternalFunction ("TriggerEvent", (string name) => GenericEvents.Trigger(name), false);
  56. var storyStream = Observable.Interval(TimeSpan.FromMilliseconds(250))
  57. //.Where(_ => wait == false)
  58. .Subscribe(_ => StoryLoop())
  59. .AddTo(disposables);
  60. }
  61. public void Stop()
  62. {
  63. GenericEvents.StopListening(name, JumpToPath);
  64. EventManager.broadcast.StopListening(name, SelectStoryBranch);
  65. EventManager.broadcast.StopListening(name, PublishStorylineToObservers);
  66. disposables.Clear();
  67. started = false;
  68. if(logText) Debug.Log($"{name} has stoped.");
  69. }
  70. private void StoryLoop()
  71. {
  72. //Debug.Log(wait);
  73. if(wait) return;
  74. // Read all the content until we can't continue any more
  75. if (story.canContinue) {
  76. // Continue gets the next line of the story
  77. string text = story.Continue ();
  78. // This removes any white space from the text.
  79. text = text.Trim();
  80. // Create StoryStepData
  81. StoryStepData storyStep = new StoryStepData(StoryStepType.Line, text, story.currentTags, null);
  82. EventManager.broadcast.Trigger(name, storyStep);
  83. // Display the text if log is enabled
  84. if(logText) Debug.Log(storyStep.text);
  85. }
  86. else if( story.currentChoices.Count > 0 )
  87. {
  88. List<string> choices = new List<string>();
  89. for (int i = 0; i < story.currentChoices.Count; ++i)
  90. {
  91. Choice choice = story.currentChoices [i];
  92. choices.Add(choice.text);
  93. if(logText) Debug.Log($"Choice {i + 1}. {choice.text}");
  94. }
  95. StoryStepData storyStep = new StoryStepData(StoryStepType.Branch, "", story.currentTags, choices);
  96. EventManager.broadcast.Trigger(name, storyStep);
  97. wait = true;
  98. }
  99. else Stop();
  100. }
  101. private void SelectStoryBranch(StoryStepData storyStep)
  102. {
  103. if(storyStep.category == StoryStepType.Path)
  104. {
  105. story.ChooseChoiceIndex (storyStep.path);
  106. wait = false;
  107. StoryLoop();
  108. }
  109. }
  110. static Subject<StoryStepData> subject;
  111. public static IObservable<StoryStepData> Lines()
  112. {
  113. if(subject == null) subject = new Subject<StoryStepData>();
  114. return subject.AsObservable();
  115. }
  116. private void PublishStorylineToObservers(StoryStepData storyStep)
  117. {
  118. if(subject != null) subject.OnNext(storyStep);
  119. }
  120. public void JumpToPath(string path)
  121. {
  122. if(story != null)
  123. {
  124. if(logText) Debug.Log($"Jumping to story knot \"{path}\"");
  125. story.ChoosePathString(path);
  126. wait = false;
  127. }
  128. }
  129. #region ExternalStoryFunctions
  130. private void Wait(int time)
  131. {
  132. wait = true;
  133. Timer.Execute(time, () => wait = false);
  134. }
  135. private void EnableGameObject(string name)
  136. {
  137. for (int i = 0; i < storyObjects.Count; i++)
  138. {
  139. if(storyObjects[i].name == name) storyObjects[i].instance.SetActive(true);
  140. }
  141. }
  142. private void DisableGameObject(string name)
  143. {
  144. for (int i = 0; i < storyObjects.Count; i++)
  145. {
  146. if(storyObjects[i].name == name) storyObjects[i].instance.SetActive(false);
  147. }
  148. }
  149. #endregion
  150. }
  151. }