StoryM.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using DG.Tweening;
  4. using UnityEngine;
  5. using UnityEngine.Localization.Settings;
  6. using UnityEngine.UI;
  7. using System.Linq;
  8. public class StoryM : MonoBehaviour {
  9. // 文本
  10. public TMPro.TextMeshProUGUI textStory;
  11. public RectTransform shapeBack;
  12. /// <summary>
  13. /// 设置旁白,并返回预期时间。旁白字幕将在预期时间后消失。
  14. /// </summary>
  15. public float SetStoryText(string textCn, string textEn = "English") {
  16. bool isCn = LocalizationSettings.SelectedLocale.LocaleName == "Chinese (Simplified) (zh-CN)";
  17. textStory.text = isCn ? textCn : textEn;
  18. LayoutRebuilder.ForceRebuildLayoutImmediate(textStory.rectTransform);
  19. // 动画
  20. textStory.color = Color.black;
  21. DOTween.Kill("StoryFont"); textStory.DOColor(Color.white, 0.25f).SetId("StoryFont");
  22. DOTween.Kill("StoryBackground"); shapeBack.DOScaleX((textStory.rectTransform.rect.width + 40f) / 100f, 0.15f).SetId("StoryBackground");
  23. // 消失
  24. float time = 1f + (isCn ? textCn.Length / 4f : textEn.Split(" ").Length / 4f);
  25. StopCoroutine("WaitForHideStoryText"); StartCoroutine("WaitForHideStoryText", time);
  26. Debug.Log(time + " -> " + textCn);
  27. return time;
  28. }
  29. IEnumerator WaitForStoryText(string textCh, string textEn = "English") {
  30. yield return new WaitForSeconds(SetStoryText(textCh, textEn));
  31. }
  32. IEnumerator WaitForHideStoryText(float delay) {
  33. yield return new WaitForSeconds(delay);
  34. Debug.Log("隐藏:" + delay);
  35. HideStoryText();
  36. }
  37. void HideStoryText() {
  38. StopCoroutine("WaitForHideStoryText");
  39. textStory.text = "";
  40. DOTween.Kill("StoryBackground"); shapeBack.DOScaleX(0, 0.2f).SetId("StoryBackground");
  41. }
  42. // 刷怪
  43. private Dictionary<Spawner.EnemyType, List<Spawner>> spawners = null;
  44. public void Spawn(Spawner.EnemyType type, int count = 1) {
  45. // 初始化
  46. if (spawners == null) {
  47. spawners = new();
  48. foreach (Spawner spawner in FindObjectsOfType<Spawner>()) {
  49. if (spawners.ContainsKey(spawner.type)) {
  50. spawners[spawner.type].Add(spawner);
  51. } else {
  52. spawners[spawner.type] = new() { spawner };
  53. }
  54. }
  55. }
  56. // 实际刷怪
  57. spawners[type].Shuffle();
  58. for (int i = 0; i < count; i++) {
  59. if (i >= spawners[type].Count) i = 0;
  60. spawners[type][i].Spawn();
  61. }
  62. }
  63. // 流程控制
  64. IEnumerator WaitUntilClear(int remain, float waitTime = -1, string textCn = "", string textEn = "") {
  65. while (GetEnemyCount() > remain && !respawning) {
  66. if (waitTime >= 0f && waitTime < 0.3f) SetStoryText(textCn, textEn);
  67. waitTime -= 0.3f;
  68. yield return new WaitForSeconds(0.3f);
  69. }
  70. }
  71. int GetEnemyCount() => FindObjectsOfType<EnemyBase>().Length - FindObjectsOfType<EnemyArrow>().Length;
  72. IEnumerator WaitUntilPickDice(float waitTime = -1, string textCn = "", string textEn = "") {
  73. while (GetDiceCount() > 0 && !respawning) {
  74. if (waitTime >= 0f && waitTime < 0.3f) SetStoryText(textCn, textEn);
  75. waitTime -= 0.3f;
  76. yield return new WaitForSeconds(0.3f);
  77. }
  78. }
  79. int GetDiceCount() => FindObjectsOfType<DiceEntity>().Count(dice => !dice.pickedUp);
  80. // 故事
  81. public int stage = 0; private bool stageCompleted = true;
  82. public Image panDeath;
  83. void Start() {
  84. StartCoroutine("ArrowSpawner");
  85. StartCoroutine("Main");
  86. }
  87. IEnumerator Main() {
  88. while (true) {
  89. if (Input.GetKey(KeyCode.LeftControl) && Input.GetKeyUp(KeyCode.Q)) {
  90. SetStoryText("已跳过阶段:" + stage, "Skip Stage: " + stage);
  91. stageCompleted = true;
  92. }
  93. if (Player.hp <= 0) {
  94. stageCompleted = false;
  95. yield return StartCoroutine("Respawn");
  96. }
  97. if (stageCompleted) {
  98. deathInStage = 0;
  99. stageCompleted = false;
  100. StopCoroutine("Stage" + stage);
  101. stage++;
  102. Debug.Log("已到达阶段:" + stage);
  103. StartCoroutine("Stage" + stage);
  104. }
  105. yield return new WaitForFixedUpdate();
  106. }
  107. }
  108. private int deathInStage = 0; private bool respawning = false, noDifficulty = false;
  109. IEnumerator Respawn() {
  110. deathInStage++; respawning = true;
  111. // 停止场景
  112. arrowMax = 0;
  113. Player.instance.transform.localScale = Vector3.zero;
  114. Player.instance.GetComponent<Rigidbody2D>().velocity = Vector2.zero;
  115. Player.instance.enabled = false;
  116. StopCoroutine("Stage" + stage);
  117. StopCoroutine("HideStoryText");
  118. yield return new WaitForSeconds(1.5f);
  119. if (!noDifficulty) {
  120. _ = Modules.randomDefault.Next(0, 4) switch {
  121. 0 => SetStoryText("完了,寄咯!", "Woops, you died!"),
  122. 1 => SetStoryText("哦吼,下辈子加油吧", "Ouch, work harder next life!"),
  123. 2 => SetStoryText("诶,怎么回事?", "Yo, what's happening?"),
  124. 3 => SetStoryText("还好没开极限模式……", "Luckily I didn't have hardcore mode on..."),
  125. _ => throw new System.NotImplementedException(),
  126. };
  127. } else {
  128. _ = Modules.randomDefault.Next(0, 3) switch {
  129. 0 => SetStoryText("不是吧?这也能死?", "What? How you die from that?"),
  130. 1 => SetStoryText("你是特么故意的吧!", "Excuse me? Are you doing this on purpose?"),
  131. 2 => SetStoryText("嗯?", "Hey!"),
  132. _ => throw new System.NotImplementedException(),
  133. };
  134. }
  135. yield return new WaitForSeconds(0.5f);
  136. // 转为黑屏
  137. panDeath.DOFade(1, 0.3f); panDeath.GetComponentInChildren<TMPro.TextMeshProUGUI>().DOFade(1, 1f);
  138. yield return new WaitForSeconds(0.3f);
  139. // 复原
  140. FindObjectsOfType<EnemyBase>().ToList().ForEach(e => GameObject.Destroy(e.gameObject, 1f));
  141. Player.hp = 3;
  142. Player.instance.currentBullet = Player.instance.maxBullet;
  143. yield return new WaitForSeconds(3f);
  144. // 淡出黑屏,玩家重生
  145. respawning = false;
  146. panDeath.DOFade(0, 0.8f); panDeath.GetComponentInChildren<TMPro.TextMeshProUGUI>().DOFade(0, 0.3f);
  147. Player.instance.enabled = true;
  148. Player.instance.transform.localScale = Vector3.one;
  149. Player.instance.transform.position = new Vector3(-6, 10, 0);
  150. // 继续游戏
  151. yield return new WaitForSeconds(2f);
  152. StartCoroutine("Stage" + stage);
  153. }
  154. IEnumerator Stage1() {
  155. arrowMax = 0; noDifficulty = false;
  156. yield return new WaitForSeconds(3f);
  157. yield return StartCoroutine(WaitForStoryText("哦,哦!你好,欢迎欢迎", "Oh, oh! Hello there!"));
  158. yield return StartCoroutine(WaitForStoryText("先来过个教程啥的吧", "Let's go through a quick tutrial before we start."));
  159. yield return StartCoroutine(WaitForStoryText("游戏的按键操作写在了右上角,应该是个人都看得懂", "All control buttons are shown on the top-right corner. I bet nobody can't understand that."));
  160. SetStoryText("你不如先拿它们俩试试按键吧!", "Now, let's try some buttons with these two cute guys!");
  161. Spawn(Spawner.EnemyType.Mover, 2);
  162. yield return StartCoroutine(WaitUntilClear(0, 10f, "快点把它干掉,然后才好继续……", "Come on! You have to defeat them to continue..."));
  163. stageCompleted = true;
  164. }
  165. IEnumerator Stage2() {
  166. arrowMax = 1; noDifficulty = false;
  167. Spawn(Spawner.EnemyType.Mover, 2);
  168. yield return StartCoroutine(WaitForStoryText("哦,教程最后一条……", "Oh, a final reminder before I leave...")); //TODO t 不会leave...
  169. Spawn(Spawner.EnemyType.Mover, 2);
  170. yield return StartCoroutine(WaitForStoryText("弹药不够的时候记得右键换弹!", "Don't forget to reload the weapon before you run out of ammo!")); //TODO t
  171. Spawn(Spawner.EnemyType.Shooter, 1);
  172. Spawn(Spawner.EnemyType.Mover, 1);
  173. SetStoryText("加油,教程结束了!", "There you go, that's end of the tutrial!");
  174. yield return StartCoroutine(WaitUntilClear(1, 8f, "仔细一看,这个角色的手上连枪都没有……", "Hmm... He does not even have a gun in his hand after a closer look."));
  175. if (Player.hp < 3) {
  176. Player.hp = 3;
  177. Spawn(Spawner.EnemyType.Mover, 1);
  178. yield return StartCoroutine(WaitForStoryText("对了,教程结束得先给你回个血……", "Whoops, I almost forgot to heal you after the tutrial."));
  179. }
  180. stageCompleted = true;
  181. }
  182. IEnumerator Stage3() {
  183. arrowMax = 3; noDifficulty = false;
  184. Spawn(Spawner.EnemyType.Mover, 1);
  185. yield return StartCoroutine(WaitForStoryText("说实话啊,我觉得这个游戏有点无聊", "To be honest, I think this game is kind of boring..."));
  186. Spawn(Spawner.EnemyType.Mover, 1);
  187. yield return StartCoroutine(WaitForStoryText("我看了看,这游戏往后的新内容就只剩一种换皮怪了!", "Let's see... We only have one more skin to replace our monsters!"));
  188. Spawn(Spawner.EnemyType.Mover, 1);
  189. yield return StartCoroutine(WaitForStoryText("然后就是“在无限的怪物中生存下来吧!”的无尽模式……", "And then, all we have is endless mode of \"Survive with infinite monsters!\"..."));
  190. Spawn(Spawner.EnemyType.Mover, 1);
  191. yield return StartCoroutine(WaitForStoryText("没有升级,没有装备,没有峰回路转的牛逼剧情", "No upgrade, no equipments, no twist to the plot or any boss to fight."));
  192. Spawn(Spawner.EnemyType.Shooter, 1);
  193. yield return StartCoroutine(WaitForStoryText("并且最重要的是,“丢骰子”的主题呢?", "And most importantly, where's our \"Roll of the Dice\" theme?"));
  194. yield return StartCoroutine(WaitForStoryText("骰子、骰子……哪儿有骰子……?", "Dice... Dice... Where is the dice...?"));
  195. SetStoryText("这里一个骰子都没有!", "Not a single dice here!");
  196. arrowMax = 0;
  197. Spawn(Spawner.EnemyType.Mover, 1);
  198. yield return StartCoroutine(WaitUntilClear(0, 5f, "切题呢?作者到底咋想的?", "What's the point? What's wrong with this author?"));
  199. noDifficulty = true;
  200. yield return StartCoroutine(WaitForStoryText("要不然这样,我们随便拿个东西,把它弄成骰子算了", "How about we just grab something and make it a dice?"));
  201. yield return new WaitForSeconds(2f);
  202. InputM.DropDice(InputM.KeyType.Fire);
  203. SetStoryText("嘿,成了!", "Let's go!");
  204. stageCompleted = true;
  205. }
  206. IEnumerator Stage4() {
  207. arrowMax = 0; noDifficulty = true;
  208. yield return StartCoroutine(WaitUntilPickDice(8f, "看到右边掉下来的东西了么?把它捡起来摇一摇!", "You see the falling stuff on the right? Pick it up and try shaking it!"));
  209. stageCompleted = true;
  210. }
  211. IEnumerator Stage5() {
  212. arrowMax = 0; noDifficulty = true;
  213. yield return new WaitForSeconds(1f);
  214. yield return StartCoroutine(WaitForStoryText("噔噔噔……!", "Pow!")); //TODO: t 这是在说骰子的音效
  215. yield return new WaitForSeconds(7f);
  216. yield return StartCoroutine(WaitForStoryText("你看,这就是天才制作的骰子", "See, what a master piece!")); //TODO: t 是骰子!
  217. yield return new WaitForSeconds(1.5f);
  218. Spawn(Spawner.EnemyType.Mover, 1);
  219. if (Player.hp < 3) {
  220. Player.hp = 3;
  221. yield return StartCoroutine(WaitForStoryText("让我帮你回个血,我们继续!", "Let me heal you first and then keep going!"));
  222. } else {
  223. yield return StartCoroutine(WaitForStoryText("来,我们继续!", "Let's keep going!"));
  224. }
  225. stageCompleted = true;
  226. }
  227. IEnumerator Stage6() {
  228. arrowMax = 1; noDifficulty = false;
  229. Spawn(Spawner.EnemyType.Mover, 3);
  230. yield return StartCoroutine(WaitUntilClear(1, 6f, "骰子有六面,按键有六个,完美!", "Six sides to six buttons, perfect!"));
  231. Spawn(Spawner.EnemyType.Shooter, 1);
  232. yield return StartCoroutine(WaitForStoryText("感觉如何?", "How do you feel?"));
  233. arrowMax = 3;
  234. yield return StartCoroutine(WaitForStoryText("是不是还想马上再来一颗?", "Want to have another dice now?"));
  235. Spawn(Spawner.EnemyType.Mover, 2);
  236. yield return StartCoroutine(WaitForStoryText("但如果给你太多骰子,那岂不是显得它很……普通", "But if I give you too many dices, it will look... ordinary."));
  237. arrowMax = 1;
  238. Spawn(Spawner.EnemyType.Mover, 1);
  239. yield return StartCoroutine(WaitForStoryText("不如让我们先等等,我先给你看看之前说的新敌人", "Why don't we wait while I show you the new enemy we were talking about...?"));
  240. SetStoryText("额……就是换皮的那个", "Ugh... That monster with new skin!");
  241. Spawn(Spawner.EnemyType.Mover, 1);
  242. yield return StartCoroutine(WaitUntilClear(1, 6f, "别抱太大期望就是了……", "Just don't hope too much on that..."));
  243. stageCompleted = true;
  244. }
  245. IEnumerator Stage7() {
  246. arrowMax = 0; noDifficulty = false;
  247. yield return StartCoroutine(WaitForStoryText("让我找找它在哪……", "Hold on... I can't find where it is."));
  248. yield return new WaitForSeconds(1.5f);
  249. SetStoryText("卧槽!小心!", ""); // TODO: t 这里说的是要掉下来一堆圆锯片了
  250. for (int i = 0; i < Mathf.Max(6, 15 - deathInStage * 2); i++) {
  251. Spawn(Spawner.EnemyType.Mover, 1);
  252. yield return new WaitForSeconds(0.4f);
  253. }
  254. yield return StartCoroutine(WaitForStoryText("我把圆锯片的仓库弄漏了……", "I mix up the wrong repository for circular saw blades..."));
  255. yield return StartCoroutine(WaitForStoryText("明明打算之后用来做点装饰的,唉", "Awww... I was gonna use it for decoration later."));
  256. yield return StartCoroutine(WaitUntilClear(6, 6f, "出了这么大问题,玩家给游戏打差评怎么办?", ""));
  257. if (Player.hp < 3) {
  258. Player.hp = 3;
  259. yield return StartCoroutine(WaitForStoryText("我帮你回个血吧……唉,惹麻烦了……", ""));
  260. } else {
  261. yield return StartCoroutine(WaitForStoryText("唉,惹麻烦了……", ""));
  262. }
  263. yield return StartCoroutine(WaitUntilClear(2, 6f, "我的锯片……", ""));
  264. yield return StartCoroutine(WaitForStoryText("要不然……我再给你一颗特制按键骰子™作为补偿?", ""));
  265. yield return new WaitForSeconds(1f);
  266. InputM.DropDice(new List<InputM.KeyType>() { InputM.KeyType.Left, InputM.KeyType.Right, InputM.KeyType.Crouch }.RandomOne());
  267. SetStoryText("你的补偿来了!", "");
  268. stageCompleted = true;
  269. }
  270. IEnumerator Stage8() {
  271. arrowMax = 0; noDifficulty = true;
  272. yield return StartCoroutine(WaitUntilPickDice(5f, "难道说你不喜欢特制按键骰子™吗?别吧", ""));
  273. stageCompleted = true;
  274. }
  275. IEnumerator Stage9() {
  276. arrowMax = 1; noDifficulty = false;
  277. yield return new WaitForSeconds(7f);
  278. yield return StartCoroutine(WaitForStoryText("唔,看起来特制按键骰子™的威力还挺大", ""));
  279. }
  280. int arrowMax = 0; float arrowTime = 4f;
  281. IEnumerator ArrowSpawner() {
  282. while (true) {
  283. yield return new WaitForSeconds(arrowTime);
  284. if (arrowMax > 0) Spawn(Spawner.EnemyType.Arrow, Modules.randomDefault.Next(0, arrowMax));
  285. }
  286. }
  287. }