SoundGameController.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. using System.Collections;
  2. using UnityEngine;
  3. using UnityEngine.InputSystem;
  4. public class SoundGameController : MonoBehaviour
  5. {
  6. SoundTrackManager soundTrackManager = new();
  7. GameObject notePrefabSwipe, notePrefabTap;
  8. float gameStartTime;
  9. float GameEndTime;
  10. // 游戏得分统计
  11. int score = 0;
  12. int combo = 0;
  13. int PerfectCount = 0;
  14. int GoodCount = 0;
  15. int PoorCount = 0;
  16. int MissCount = 0;
  17. int totalCount = 0;
  18. // TapOrSwipe 触控检测
  19. Vector2 pressDownPosition = new Vector2(0, 0);
  20. Vector2 pressUpPosition = new Vector2(0, 0);
  21. float pressDownTime = 0f;
  22. float pressUpTime = 0f;
  23. // Start is called once before the first execution of Update after the MonoBehaviour is created
  24. void Start()
  25. {
  26. TextAsset soundTrackJson = Resources.Load<TextAsset>("WalkDogs/SoundTrack/track_1");
  27. if (soundTrackJson != null)
  28. {
  29. string soundTrackString = soundTrackJson.text;
  30. soundTrackManager.ImportFromJson(soundTrackString);
  31. }
  32. notePrefabSwipe = Resources.Load<GameObject>("WalkDogs/Note/NoteSwipe");
  33. notePrefabTap = Resources.Load<GameObject>("WalkDogs/Note/NoteTap");
  34. StartCoroutine(PlaySoundGame());
  35. }
  36. // Update is called once per frame
  37. void Update()
  38. {
  39. }
  40. IEnumerator PlaySoundGame()
  41. {
  42. // 加载音乐
  43. AudioClip audioClip = Resources.Load<AudioClip>(soundTrackManager.resource);
  44. AudioSource audioSource = gameObject.AddComponent<AudioSource>();
  45. audioSource.clip = audioClip;
  46. audioSource.Play();
  47. gameStartTime = Time.time;
  48. GameEndTime = gameStartTime + soundTrackManager.length;
  49. while (Time.time < GameEndTime)
  50. {
  51. // 用于提前n秒创建音符
  52. foreach (var note in soundTrackManager.soundAction)
  53. {
  54. if (!note.isActive && Time.time >= (note.time - GameData.noteStartLeadTime))
  55. {
  56. note.isActive = true;
  57. CreateNote(note.time, note.action, soundTrackManager.soundAction.IndexOf(note).ToString());
  58. continue;
  59. }
  60. }
  61. // 检测音符是否超时未被点击
  62. foreach (var note in soundTrackManager.soundAction)
  63. {
  64. float TapTimeDeadline = note.time + gameStartTime + 0.35f; // 计算点击事件超时
  65. if (note.isActive && !note.isTapped && Time.time > TapTimeDeadline)
  66. {
  67. note.isTapped = true;
  68. MissCount++;
  69. Debug.Log("Miss!" + Time.time + " Tap time deadline: " + TapTimeDeadline + " total miss:" + MissCount);
  70. Debug.Log("index of note:" + soundTrackManager.soundAction.IndexOf(note));
  71. break;
  72. }
  73. }
  74. // 检测游戏是否结束并统计分数
  75. totalCount = PerfectCount + GoodCount + PoorCount + MissCount;
  76. if (totalCount == soundTrackManager.soundAction.Count)
  77. {
  78. GameEndTime = Time.time;
  79. Debug.Log("Game Over!");
  80. Debug.Log($"Perfect: {PerfectCount}, Good: {GoodCount}, Poor: {PoorCount}, Miss: {MissCount}");
  81. Debug.Log($"Total Count: {totalCount}");
  82. Debug.Log($"Score: {score}");
  83. Debug.Log($"Combo: {combo}");
  84. // 结束游戏
  85. break; // 跳出 while 循环
  86. }
  87. yield return new WaitForSeconds(0.01f);
  88. }
  89. yield return null;
  90. }
  91. private void CreateNote(float hitTime, string action, string noteName)
  92. {
  93. GameObject note;
  94. if (action == "tap")
  95. {
  96. note = Instantiate(notePrefabTap);
  97. }
  98. else
  99. {
  100. note = Instantiate(notePrefabSwipe);
  101. }
  102. note.gameObject.name = noteName;
  103. NoteController noteController = note.GetComponent<NoteController>();
  104. noteController.speed = soundTrackManager.speed;
  105. noteController.hitTime = hitTime;
  106. noteController.action = action;
  107. }
  108. // 触控检测,检测通过按下和和抬起的触控点位置计算点击或者上下左右滑动
  109. public void TapOrSwipe(InputAction.CallbackContext context)
  110. {
  111. if (context.phase == InputActionPhase.Started)
  112. {
  113. pressDownPosition = Pointer.current.position.ReadValue();
  114. pressDownTime = Time.time;
  115. return;
  116. }
  117. if (context.phase == InputActionPhase.Canceled)
  118. {
  119. pressUpPosition = Pointer.current.position.ReadValue();
  120. pressUpTime = Time.time;
  121. float deltaX = pressUpPosition.x - pressDownPosition.x;
  122. float deltaY = pressUpPosition.y - pressDownPosition.y;
  123. float distance = Mathf.Sqrt(deltaX * deltaX + deltaY * deltaY);
  124. // Debug.Log($"deltaX: {deltaX}, deltaY: {deltaY}, distance: {distance}");
  125. float timeDelta = pressUpTime - pressDownTime;
  126. string action;
  127. if (timeDelta > 0.2f)
  128. {
  129. return;
  130. }
  131. else
  132. {
  133. if (distance < 20f)
  134. {
  135. action = "tap";
  136. }
  137. else
  138. {
  139. if (Mathf.Abs(deltaX) > Mathf.Abs(deltaY))
  140. {
  141. if (deltaX > 0)
  142. {
  143. action = "right";
  144. }
  145. else
  146. {
  147. action = "left";
  148. }
  149. }
  150. else
  151. {
  152. if (deltaY > 0)
  153. {
  154. action = "up";
  155. }
  156. else
  157. {
  158. action = "down";
  159. }
  160. }
  161. }
  162. }
  163. TouchResponse touchResponse = new TouchResponse(action, pressUpTime);
  164. // Debug.Log($"TouchResponse: {touchResponse.action}, {touchResponse.time}");
  165. // 检测点击的音符
  166. ScoreCheck(touchResponse);
  167. }
  168. return;
  169. }
  170. private void ScoreCheck(TouchResponse touchResponse)
  171. {
  172. if (touchResponse != null)
  173. {
  174. foreach (var note in soundTrackManager.soundAction)
  175. {
  176. // float TapTimeDeadline = note.time + gameStartTime + 0.35f; // 计算点击事件超时
  177. // if (note.isActive && !note.isTapped && Time.time > TapTimeDeadline)
  178. // {
  179. // note.isTapped = true;
  180. // MissCount++;
  181. // Debug.Log("Miss!" + Time.time + " Tap time deadline: " + TapTimeDeadline + " total miss:" + MissCount);
  182. // Debug.Log("index of note:" + soundTrackManager.soundAction.IndexOf(note));
  183. // break;
  184. // }
  185. float TapTimeDelta = Mathf.Abs(touchResponse.time - (note.time + gameStartTime)); // 计算点击时间和音符时间的差值
  186. if (note.isActive && !note.isTapped && TapTimeDelta < 0.3f)
  187. {
  188. note.isTapped = true;
  189. if (touchResponse.action == note.action)
  190. {
  191. if (TapTimeDelta < 0.1f)
  192. {
  193. score += 100;
  194. combo++;
  195. PerfectCount++;
  196. Debug.Log("Perfect!" + Time.time + " total perfect:" + PerfectCount);
  197. string noteName = soundTrackManager.soundAction.IndexOf(note).ToString();
  198. DestroyNote(noteName);
  199. }
  200. else if (TapTimeDelta < 0.2f)
  201. {
  202. score += 30;
  203. combo = 0;
  204. GoodCount++;
  205. Debug.Log("Good!" + Time.time + " total good:" + GoodCount);
  206. string noteName = soundTrackManager.soundAction.IndexOf(note).ToString();
  207. DestroyNote(noteName);
  208. }
  209. else
  210. {
  211. score += 10;
  212. combo = 0;
  213. PoorCount++;
  214. Debug.Log("Poor!" + Time.time + " total poor:" + PoorCount);
  215. }
  216. }
  217. else
  218. {
  219. combo = 0;
  220. MissCount++;
  221. Debug.Log("Wrong!" + Time.time + " total miss:" + MissCount);
  222. }
  223. Debug.Log("index of note:" + soundTrackManager.soundAction.IndexOf(note));
  224. break;
  225. }
  226. }
  227. }
  228. }
  229. private void DestroyNote(string noteName)
  230. {
  231. GameObject note = GameObject.Find(noteName);
  232. if (note != null)
  233. {
  234. Destroy(note);
  235. }
  236. else
  237. {
  238. Debug.Log("Note not found: " + noteName);
  239. }
  240. }
  241. }
  242. public class TouchResponse
  243. {
  244. public string action = ""; // 触控动作 up, down, left, right, tap, none(表示无效)
  245. public float time;
  246. public TouchResponse(string action, float time)
  247. {
  248. this.action = action;
  249. this.time = time;
  250. }
  251. }