StoryM.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  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..."));
  169. Spawn(Spawner.EnemyType.Mover, 2);
  170. yield return StartCoroutine(WaitForStoryText("弹药不够的时候记得换弹!", "Don't forget to reload the weapon before you run out of ammo!"));
  171. Spawn(Spawner.EnemyType.Shooter, 1);
  172. SetStoryText("加油,教程结束了!", "There you go, that's end of the tutrial!");
  173. yield return StartCoroutine(WaitUntilClear(1, 10f, "仔细一看,这个角色的手上连枪都没有……", "Hmm... He does not even have a gun in his hand after a closer look."));
  174. if (Player.hp < 3) {
  175. Player.hp = 3;
  176. Spawn(Spawner.EnemyType.Mover, 1);
  177. yield return StartCoroutine(WaitForStoryText("对了,教程结束得先给你回个血……", "Whoops, I almost forgot to heal you after the tutrial."));
  178. }
  179. stageCompleted = true;
  180. }
  181. IEnumerator Stage3() {
  182. arrowMax = 3; noDifficulty = false;
  183. Spawn(Spawner.EnemyType.Mover, 1);
  184. yield return StartCoroutine(WaitForStoryText("说实话啊,我觉得这个游戏有点无聊", "To be honest, I think this game is kind of boring..."));
  185. Spawn(Spawner.EnemyType.Mover, 1);
  186. yield return StartCoroutine(WaitForStoryText("我看了看,这游戏往后的新内容就只剩一种换皮怪了!", "Let's see... We only have one more skin to replace our monsters!"));
  187. Spawn(Spawner.EnemyType.Mover, 1);
  188. yield return StartCoroutine(WaitForStoryText("然后就是“在无限的怪物中生存下来吧!”的无尽模式……", "And then, all we have is endless mode of \"Survive with infinite monsters!\"....."));
  189. Spawn(Spawner.EnemyType.Mover, 1);
  190. yield return StartCoroutine(WaitForStoryText("没有升级,没有装备,没有峰回路转的牛逼剧情", "No upgrade, no equipments, no twist to the plot or any boss to fight."));
  191. Spawn(Spawner.EnemyType.Shooter, 1);
  192. yield return StartCoroutine(WaitForStoryText("并且最重要的是,“丢骰子”的主题呢?", "And most importantly, where's our \"Roll of the Dice\" theme?"));
  193. yield return StartCoroutine(WaitForStoryText("骰子、骰子……哪儿有骰子……?", "Dice... Dice... Where is the dice...?"));
  194. SetStoryText("这里一个骰子都没有!", "Not a single dice here!");
  195. arrowMax = 0;
  196. Spawn(Spawner.EnemyType.Mover, 1);
  197. yield return StartCoroutine(WaitUntilClear(0, 6f, "切题呢?作者到底咋想的?", "What's the point? What's wrong with this author?"));
  198. noDifficulty = true;
  199. yield return StartCoroutine(WaitForStoryText("要不然这样,我们随便拿个东西,把它弄成骰子算了", "How about we just grab something and make it a dice?"));
  200. yield return new WaitForSeconds(2f);
  201. InputM.DropDice(InputM.KeyType.Fire);
  202. SetStoryText("嘿,成了!", "Let's go!");
  203. stageCompleted = true;
  204. }
  205. IEnumerator Stage4() {
  206. arrowMax = 0; noDifficulty = true;
  207. yield return StartCoroutine(WaitUntilPickDice(8f, "看到右边掉下来的东西了么?把它捡起来摇一摇!", "You see the falling stuff on the right? Pick it up and try shaking it!"));
  208. stageCompleted = true;
  209. }
  210. IEnumerator Stage5() {
  211. arrowMax = 0; noDifficulty = true;
  212. yield return new WaitForSeconds(1f);
  213. yield return StartCoroutine(WaitForStoryText("噔噔噔……!", "Pow!"));
  214. yield return new WaitForSeconds(7f);
  215. yield return StartCoroutine(WaitForStoryText("你看,这就是天才制作的骰子", "See, what a master piece!"));
  216. yield return new WaitForSeconds(1.5f);
  217. Spawn(Spawner.EnemyType.Mover, 1);
  218. if (Player.hp < 3) {
  219. Player.hp = 3;
  220. yield return StartCoroutine(WaitForStoryText("让我帮你回个血,我们继续!", "Let me heal you first and then keep going!"));
  221. } else {
  222. yield return StartCoroutine(WaitForStoryText("来,我们继续!", "Let's keep going!"));
  223. }
  224. stageCompleted = true;
  225. }
  226. IEnumerator Stage6() {
  227. arrowMax = 1; noDifficulty = false;
  228. Spawn(Spawner.EnemyType.Mover, 3);
  229. yield return StartCoroutine(WaitUntilClear(1, 8f, "骰子有六面,按键有六个,完美!", "Six sides to six buttons, perfect!"));
  230. Spawn(Spawner.EnemyType.Shooter, 1);
  231. yield return StartCoroutine(WaitForStoryText("感觉如何?", "How do you feel?"));
  232. arrowMax = 3;
  233. yield return StartCoroutine(WaitForStoryText("是不是还想马上再来一颗?", "Want to have another dice now?"));
  234. Spawn(Spawner.EnemyType.Mover, 2);
  235. yield return StartCoroutine(WaitForStoryText("但如果给你太多骰子,那岂不是显得它很……普通", "But if I give you too many dices, it will look... ordinary."));
  236. arrowMax = 1;
  237. Spawn(Spawner.EnemyType.Mover, 1);
  238. yield return StartCoroutine(WaitForStoryText("不如让我们先等等,我先给你看看之前说的新敌人", "Why don't we wait while I show you the new enemy we were talking about..."));
  239. SetStoryText("额……就是换皮的那个", "Ugh... That monster with new skin!");
  240. Spawn(Spawner.EnemyType.Mover, 1);
  241. yield return StartCoroutine(WaitUntilClear(1, 6f, "别抱太大期望就是了……", "Just don't hope too much on that..."));
  242. stageCompleted = true;
  243. }
  244. IEnumerator Stage7() {
  245. arrowMax = 0; noDifficulty = false;
  246. yield return StartCoroutine(WaitForStoryText("让我找找它在哪……", "Hold on... I can't find where it is."));
  247. yield return new WaitForSeconds(1.5f);
  248. SetStoryText("卧槽!", "Shoot!");
  249. for (int i = 0; i < Mathf.Max(6, 15 - deathInStage); i++) {
  250. Spawn(Spawner.EnemyType.Mover, 1);
  251. yield return new WaitForSeconds(0.4f);
  252. }
  253. yield return StartCoroutine(WaitForStoryText("我把圆锯片的仓库弄漏了……", "I mix up the wrong repository for circular saw blades..."));
  254. yield return StartCoroutine(WaitForStoryText("明明打算之后用来做点装饰的,唉", "Awww... I was gonna use it for decoration later."));
  255. }
  256. //IEnumerator test() {
  257. // while (true) {
  258. // Spawn(Spawner.EnemyType.Mover, 3);
  259. // SetStoryText("先刷几个瞎晃悠的", "");
  260. // yield return new WaitForSeconds(3f);
  261. // Spawn(Spawner.EnemyType.Shooter);
  262. // SetStoryText("炮塔!", "");
  263. // yield return new WaitForSeconds(2f);
  264. // Spawn(Spawner.EnemyType.Heavy, 2);
  265. // SetStoryText("最后是两个贼硬的……", "");
  266. // yield return StartCoroutine(WaitUntilClear(2));
  267. // InputM.DropDice(Modules.RandomOne(InputM.keyTypes.ToList()));
  268. // SetStoryText("来一个骰子吧……?", "");
  269. // yield return StartCoroutine(WaitUntilPickDice());
  270. // yield return StartCoroutine(WaitForStoryText("准备好,下一轮要来了!", ""));
  271. // }
  272. //}
  273. int arrowMax = 0; float arrowTime = 4f;
  274. IEnumerator ArrowSpawner() {
  275. while (true) {
  276. yield return new WaitForSeconds(arrowTime);
  277. if (arrowMax > 0) Spawn(Spawner.EnemyType.Arrow, Modules.randomDefault.Next(0, arrowMax));
  278. }
  279. }
  280. }