GameManager.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.EventSystems;
  5. namespace DuckHunter
  6. {
  7. public class GameManager : MonoBehaviour
  8. {
  9. public static GameManager Instance;
  10. [SerializeField] GameObject dogObject;
  11. [SerializeField] GameObject dogSideObject;
  12. [SerializeField] GameObject duckPrefab;
  13. [SerializeField] RectTransform duckBox;
  14. [System.NonSerialized] public bool isGameStarted;
  15. [System.NonSerialized] public bool isGameOver;
  16. public bool isGamePlaying { get => isGameStarted && !isGameOver; }
  17. public System.Action onGameStart;
  18. void Awake()
  19. {
  20. Instance = this;
  21. dogObject.SetActive(true);
  22. if (!AutoNextLevel)
  23. {
  24. DefaultLevel = 1;
  25. _CumulativeScore = 0;
  26. }
  27. level = DefaultLevel;
  28. }
  29. void OnDestroy()
  30. {
  31. if (Instance == this) Instance = null;
  32. }
  33. void Start()
  34. {
  35. TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.GAME_START);
  36. if (AutoNextLevel)
  37. {
  38. AutoNextLevel = false;
  39. StartGame(true);
  40. }
  41. UserGameAnalyse1.CreateWhenGameStart(13);
  42. }
  43. void Update()
  44. {
  45. UpdateCheckMouseHit();
  46. UpdateForAutoCreateDucks();
  47. SettleGame();
  48. #if UNITY_EDITOR
  49. if (Input.GetKeyDown(KeyCode.A))
  50. {
  51. Time.timeScale = 10;
  52. }
  53. if (Input.GetKeyUp(KeyCode.A))
  54. {
  55. Time.timeScale = 1;
  56. }
  57. #endif
  58. }
  59. void UpdateCheckMouseHit()
  60. {
  61. if (Input.GetMouseButtonDown(0) && BowCamera.isTouchMode)
  62. {
  63. if (EventSystem.current.currentSelectedGameObject == null)
  64. {
  65. CrossHair.Instance.transform.position = Input.mousePosition;
  66. OnModuleShooting(10);
  67. }
  68. }
  69. }
  70. /// <summary>
  71. /// 基础初速度
  72. /// </summary>
  73. public static float BaseFlySpeed = 50;
  74. /// <summary>
  75. /// 下次从多少分开始
  76. /// </summary>
  77. public static int DefaultLevel = 1;
  78. private static bool AutoNextLevel = false;
  79. [System.NonSerialized] public int hitScore; //得分
  80. [System.NonSerialized] public int level = 1;
  81. /// <summary>
  82. /// 通关需要击落的鸭子数量
  83. /// </summary>
  84. int passNeedHitCount;
  85. int needCreateDuckCount;
  86. bool canCreateDuck;
  87. [System.NonSerialized] public int theDuckCountWaitingForDogHandle;
  88. float _createDuckInterval;
  89. void UpdateForAutoCreateDucks()
  90. {
  91. if (isGameOver) return;
  92. if (!canCreateDuck) return;
  93. _createDuckInterval = 0;
  94. if (level <= 60)
  95. {
  96. if (theDuckCountWaitingForDogHandle > 0) return;
  97. }
  98. else if (level <= 80)
  99. {
  100. if (theDuckCountWaitingForDogHandle > 0) _createDuckInterval = 5;
  101. if (theDuckCountWaitingForDogHandle > 1) return;
  102. }
  103. else //<=100
  104. {
  105. if (theDuckCountWaitingForDogHandle > 0) _createDuckInterval = 5;
  106. if (theDuckCountWaitingForDogHandle > 2) return;
  107. }
  108. if (!Dog.Instance || Dog.Instance.isShowing) return;
  109. if (Time.time - _lastCreateDuckTime < _createDuckInterval) return;
  110. CreateDuck();
  111. }
  112. List<int> _ductTypeList = null;
  113. void InitDuckTypeList(int greenCount, int blueCount, int redCount)
  114. {
  115. if (_ductTypeList != null) return;
  116. _ductTypeList = new List<int>();
  117. for (int i = 0; i < greenCount; i++) _ductTypeList.Add(1);
  118. for (int i = 0; i < blueCount; i++) _ductTypeList.Add(2);
  119. for (int i = 0; i < redCount; i++) _ductTypeList.Add(3);
  120. _ductTypeList.Sort((a, b) => Random.value < 0.5 ? -1 : 1);
  121. needCreateDuckCount = _ductTypeList.Count;
  122. }
  123. static float[] _FlyAngles1 = { 75, 180 - 75 };
  124. static float[] _FlyAngles2 = { 75, 60, 180 - 75, 180 - 60 };
  125. static float[] _FlyAngles3 = { 45, 60, 180 - 45, 180 - 60 };
  126. static float[] _FlyAngles4 = { 30, 45, 60, 180 - 30, 180 - 45, 180 - 60 };
  127. static float RangeFlyAngle(float[] angles)
  128. {
  129. return angles[Random.Range(0, angles.Length)];
  130. }
  131. DuckConfig GetDuckConfig()
  132. {
  133. DuckConfig duckConfig = new DuckConfig();
  134. if (level <= 20) duckConfig.positionX = Random.Range(duckBox.rect.width / 2 - 200, duckBox.rect.width / 2 + 50);
  135. else duckConfig.positionX = Random.Range(250, duckBox.rect.width - 350);
  136. if (level <= 10)
  137. {
  138. InitDuckTypeList(10, 0, 0);
  139. passNeedHitCount = 6;
  140. duckConfig.touchBoundCount = 4;
  141. duckConfig.flyAngle = RangeFlyAngle(_FlyAngles1);
  142. }
  143. else if (level <= 15)
  144. {
  145. InitDuckTypeList(5, 5, 0);
  146. passNeedHitCount = 7;
  147. duckConfig.touchBoundCount = 4;
  148. duckConfig.flyAngle = RangeFlyAngle(_FlyAngles1);
  149. }
  150. else if (level <= 18)
  151. {
  152. InitDuckTypeList(5, 3, 2);
  153. passNeedHitCount = 8;
  154. duckConfig.touchBoundCount = 4;
  155. duckConfig.flyAngle = RangeFlyAngle(_FlyAngles1);
  156. }
  157. else if (level <= 20)
  158. {
  159. InitDuckTypeList(4, 4, 2);
  160. passNeedHitCount = 9;
  161. duckConfig.touchBoundCount = 4;
  162. duckConfig.flyAngle = RangeFlyAngle(_FlyAngles1);
  163. }
  164. else if (level <= 40)
  165. {
  166. InitDuckTypeList(3, 4, 3);
  167. passNeedHitCount = 10;
  168. duckConfig.touchBoundCount = 5;
  169. duckConfig.flyAngle = RangeFlyAngle(_FlyAngles2);
  170. }
  171. else if (level <= 60)
  172. {
  173. InitDuckTypeList(3, 3, 4);
  174. passNeedHitCount = 10;
  175. duckConfig.touchBoundCount = 6;
  176. duckConfig.flyAngle = RangeFlyAngle(_FlyAngles3);
  177. }
  178. else if (level <= 80)
  179. {
  180. InitDuckTypeList(2, 4, 4);
  181. passNeedHitCount = 10;
  182. duckConfig.touchBoundCount = 7;
  183. duckConfig.flyAngle = RangeFlyAngle(_FlyAngles4);
  184. }
  185. else if (level <= 100)
  186. {
  187. InitDuckTypeList(2, 3, 5);
  188. passNeedHitCount = 10;
  189. duckConfig.touchBoundCount = 8;
  190. duckConfig.flyAngle = RangeFlyAngle(_FlyAngles4);
  191. }
  192. duckConfig.type = _ductTypeList[0]; _ductTypeList.RemoveAt(0);
  193. //duckConfig.flySpeed = BaseFlySpeed * (1 + (level - 1) * 0.05f);
  194. //2023-7-25修改:速度还是以80关的做为初始速度,后面的关卡再按原来的公式增加
  195. duckConfig.flySpeed = BaseFlySpeed * (1 + (level + 79 - 1) * 0.05f);
  196. if (duckConfig.type == 1) duckConfig.flySpeed *= 1f;
  197. else if (duckConfig.type == 2) duckConfig.flySpeed *= 1.2f;
  198. else if (duckConfig.type == 3) duckConfig.flySpeed *= 1.5f;
  199. return duckConfig;
  200. }
  201. float _lastCreateDuckTime = -1000;
  202. void CreateDuck()
  203. {
  204. if (_ductTypeList != null && _ductTypeList.Count == 0) return;
  205. theDuckCountWaitingForDogHandle++;
  206. _lastCreateDuckTime = Time.time;
  207. DuckConfig duckConfig = GetDuckConfig();
  208. Duck duck = Instantiate(duckPrefab, duckBox).GetComponent<Duck>();
  209. duck.config = duckConfig;
  210. duck.onExit += HandleOnDuckExit;
  211. duck.onFallDonwEnd += HandleOnDuckFallDown;
  212. duck.onHitDead += HandleOnHitDead;
  213. duck.onStartFlyAway += () => TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.FLY_AWAY);
  214. //恢复箭
  215. ResumeArrows(duck);
  216. }
  217. int exitDuckCount = 0;
  218. void HandleOnDuckExit(Duck duck)
  219. {
  220. if (duck.dead) Dog.Instance?.OnEvent(Dog.SensitiveEventType.DuckHit, duck);
  221. else
  222. {
  223. RemoveArrows(duck);
  224. GameUI.Instance.RenderHitDuckCount(0);
  225. Dog.Instance?.OnEvent(Dog.SensitiveEventType.DuckGetAway);
  226. }
  227. exitDuckCount++;
  228. }
  229. float _lastFallDownTime = 0;
  230. void HandleOnDuckFallDown(Duck duck)
  231. {
  232. _lastFallDownTime = Time.time;
  233. }
  234. [System.NonSerialized] public int hitCount = 0;
  235. void HandleOnHitDead(Duck duck)
  236. {
  237. hitCount++;
  238. int scoreToPlus = duck.config.type * 500;
  239. hitScore += scoreToPlus;
  240. GameUI.Instance.RenderHitDuckCount(duck.config.type);
  241. // GameUI.Instance.RenderHitScore(hitScore, GetBestScore());
  242. _CumulativeScore += scoreToPlus;
  243. GameUI.Instance.RenderHitScore(_CumulativeScore, GetBestScore());
  244. GameUI.Instance.ShowTextHitScore(scoreToPlus, duck.transform.position);
  245. RemoveArrows(duck);
  246. }
  247. public void OnModuleRotationUpdate(Quaternion rotation)
  248. {
  249. CrossHair.Instance?.UpdatePositionByModuleRotation(rotation);
  250. }
  251. public void OnModuleShooting(float speed)
  252. {
  253. if (CrossHair.Instance)
  254. {
  255. if (isGamePlaying)
  256. {
  257. if (UseOneArrow())
  258. {
  259. CrossHair.Instance.Shoot();
  260. CheckShootPointHitDuck();
  261. CheckNotifyFlyAway();
  262. }
  263. }
  264. else if (!isGameStarted)
  265. {
  266. //CrossHair.Instance.Shoot();
  267. if (GameUI.Instance.CheckHitDuckForGameStart(CrossHair.Instance.transform.position))
  268. {
  269. OnClick_GameStart();
  270. }
  271. }
  272. }
  273. }
  274. void CheckShootPointHitDuck()
  275. {
  276. bool hitDuck = false;
  277. Vector2 aimPos = CrossHair.Instance.transform.position;
  278. for (int i = Duck.DuckList.Count - 1; i >= 0; i--)
  279. {
  280. Duck duck = Duck.DuckList[i];
  281. RectTransform duckRTF = duck.transform as RectTransform;
  282. bool intersect = RectTransformUtility.RectangleContainsScreenPoint(duckRTF, aimPos);
  283. bool hitFrontBG = false;
  284. Collider2D[] hitColliders = Physics2D.OverlapPointAll(aimPos);
  285. foreach (var item in hitColliders)
  286. {
  287. if (item.name.StartsWith("BGFront"))
  288. {
  289. hitFrontBG = true;
  290. break;
  291. }
  292. }
  293. if (intersect && !hitFrontBG && duck.Hit())
  294. {
  295. hitDuck = true;
  296. break;
  297. }
  298. }
  299. if (!hitDuck)
  300. {
  301. GameUI.Instance.AddArrowOnScreen(aimPos);
  302. }
  303. }
  304. void OnClick_GameStart()
  305. {
  306. AudioManager.Instance.PlayGameStart();
  307. StartGame(false);
  308. }
  309. void StartGame(bool startImmediate)
  310. {
  311. if (isGameStarted) return;
  312. isGameStarted = true;
  313. onGameStart?.Invoke();
  314. GameUI.Instance.HandleGameStart(() =>
  315. {
  316. dogSideObject.SetActive(true);
  317. dogSideObject.GetComponent<DogSide>().onExit = () => canCreateDuck = true;
  318. TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.ROUND_X, new object[] { level });
  319. }, startImmediate);
  320. NoArrows();
  321. GameUI.Instance.RenderLevel(level);
  322. // GameUI.Instance.RenderHitScore(hitScore, GetBestScore());
  323. GameUI.Instance.RenderHitScore(_CumulativeScore, GetBestScore());
  324. }
  325. void SettleGame()
  326. {
  327. if (isGameOver) return;
  328. if (_ductTypeList == null) return;
  329. if (Dog.Instance != null && Dog.Instance.isShowing) return;
  330. if (needCreateDuckCount != exitDuckCount) return;
  331. isGameOver = true;
  332. Debug.Log("Game Over");
  333. GameUI.Instance.RenderHitDuckCount(-1);
  334. if (hitCount < passNeedHitCount)
  335. {
  336. //通关失败
  337. TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.GAME_OVER, null, () =>
  338. {
  339. UnityEngine.SceneManagement.SceneManager.LoadScene("DuckHunter");
  340. });
  341. AudioManager.Instance.PlayGameOver();
  342. Debug.Log("通关失败");
  343. }
  344. else
  345. {
  346. //完美通关
  347. if (needCreateDuckCount == hitCount)
  348. {
  349. //奖励额外积分
  350. int plusScore = 10000;
  351. hitScore += plusScore;
  352. // GameUI.Instance.RenderHitScore(hitScore, GetBestScore());
  353. _CumulativeScore += plusScore;
  354. GameUI.Instance.RenderHitScore(_CumulativeScore, GetBestScore());
  355. TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.SUPER_ARCHER, new object[] { plusScore }, ShowGamePass);
  356. AudioManager.Instance.PlayFullScore();
  357. }
  358. else
  359. {
  360. ShowGamePass();
  361. }
  362. }
  363. SaveBestScore();
  364. GameOverInterface.OnGameOver(GameMgr.gameType);
  365. }
  366. void ShowGamePass()
  367. {
  368. //通关成功
  369. TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.GAME_COMPLETED, null, () =>
  370. {
  371. //自动进入下一关
  372. if (level < 100)
  373. {
  374. DefaultLevel = level + 1;
  375. AutoNextLevel = true;
  376. }
  377. UnityEngine.SceneManagement.SceneManager.LoadScene("DuckHunter");
  378. });
  379. AudioManager.Instance.PlayGamePass();
  380. Debug.Log("通关成功");
  381. }
  382. int _arrowCount;
  383. int arrowCount
  384. {
  385. get
  386. {
  387. // int count = 0;
  388. // _duckCanShootCountList.ForEach(e => count += e.shootCount);
  389. // return count;
  390. return _arrowCount;
  391. }
  392. }
  393. List<DuckCanShootCount> _duckCanShootCountList = new List<DuckCanShootCount>();
  394. class DuckCanShootCount
  395. {
  396. public Duck duck;
  397. public int shootCount;
  398. public DuckCanShootCount(Duck duck, int shootCount)
  399. {
  400. this.duck = duck;
  401. this.shootCount = shootCount;
  402. }
  403. }
  404. void ResumeArrows(Duck duck)
  405. {
  406. // _duckCanShootCountList.Add(new DuckCanShootCount(duck, 3));
  407. _arrowCount = 3;
  408. GameUI.Instance.RenderArrowCount(arrowCount);
  409. }
  410. void RemoveArrows(Duck duck)
  411. {
  412. // _duckCanShootCountList.RemoveAll(e => e.duck == duck);
  413. // GameUI.Instance.RenderArrowCount(arrowCount);
  414. }
  415. bool UseOneArrow()
  416. {
  417. if (arrowCount > 0)
  418. {
  419. // foreach (var e in _duckCanShootCountList)
  420. // {
  421. // if (e.shootCount > 0)
  422. // {
  423. // e.shootCount--;
  424. // break;
  425. // }
  426. // }
  427. _arrowCount--;
  428. GameUI.Instance.RenderArrowCount(arrowCount);
  429. return true;
  430. }
  431. return false;
  432. }
  433. void NoArrows()
  434. {
  435. // _duckCanShootCountList = new List<DuckCanShootCount>();
  436. _arrowCount = 0;
  437. GameUI.Instance.RenderArrowCount(arrowCount);
  438. }
  439. void CheckNotifyFlyAway()
  440. {
  441. // foreach (var e in _duckCanShootCountList)
  442. // if (e.shootCount == 0)
  443. // e.duck.NotifyFlyAway();
  444. if (arrowCount <= 0)
  445. foreach (var duck in Duck.DuckList)
  446. duck.NotifyFlyAway();
  447. }
  448. //累计得分
  449. private static int _CumulativeScore = 0;
  450. private static int _BestScoreVersion = 1;
  451. string GetBestScoreKey()
  452. {
  453. // return "BestScore_Level" + level + "_V" + _BestScoreVersion;
  454. return "DuckHunter_" + LoginMgr.myUserInfo.id + "_" + _BestScoreVersion;
  455. }
  456. void SaveBestScore()
  457. {
  458. string k = GetBestScoreKey();
  459. int s = PlayerPrefs.GetInt(k, 0);
  460. // if (hitScore > s) PlayerPrefs.SetInt(k, hitScore);
  461. if (_CumulativeScore > s) PlayerPrefs.SetInt(k, _CumulativeScore);
  462. }
  463. int GetBestScore()
  464. {
  465. string k = GetBestScoreKey();
  466. int s = PlayerPrefs.GetInt(k, 0);
  467. return s;
  468. }
  469. }
  470. }