GameManager.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  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. if (duckConfig.type == 1) duckConfig.flySpeed *= 1f;
  195. else if (duckConfig.type == 2) duckConfig.flySpeed *= 1.2f;
  196. else if (duckConfig.type == 3) duckConfig.flySpeed *= 1.5f;
  197. return duckConfig;
  198. }
  199. float _lastCreateDuckTime = -1000;
  200. void CreateDuck()
  201. {
  202. if (_ductTypeList != null && _ductTypeList.Count == 0) return;
  203. theDuckCountWaitingForDogHandle++;
  204. _lastCreateDuckTime = Time.time;
  205. DuckConfig duckConfig = GetDuckConfig();
  206. Duck duck = Instantiate(duckPrefab, duckBox).GetComponent<Duck>();
  207. duck.config = duckConfig;
  208. duck.onExit += HandleOnDuckExit;
  209. duck.onFallDonwEnd += HandleOnDuckFallDown;
  210. duck.onHitDead += HandleOnHitDead;
  211. duck.onStartFlyAway += () => TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.FLY_AWAY);
  212. //恢复箭
  213. ResumeArrows(duck);
  214. }
  215. int exitDuckCount = 0;
  216. void HandleOnDuckExit(Duck duck)
  217. {
  218. if (duck.dead) Dog.Instance?.OnEvent(Dog.SensitiveEventType.DuckHit, duck);
  219. else
  220. {
  221. RemoveArrows(duck);
  222. GameUI.Instance.RenderHitDuckCount(0);
  223. Dog.Instance?.OnEvent(Dog.SensitiveEventType.DuckGetAway);
  224. }
  225. exitDuckCount++;
  226. }
  227. float _lastFallDownTime = 0;
  228. void HandleOnDuckFallDown(Duck duck)
  229. {
  230. _lastFallDownTime = Time.time;
  231. }
  232. [System.NonSerialized] public int hitCount = 0;
  233. void HandleOnHitDead(Duck duck)
  234. {
  235. hitCount++;
  236. int scoreToPlus = duck.config.type * 500;
  237. hitScore += scoreToPlus;
  238. GameUI.Instance.RenderHitDuckCount(duck.config.type);
  239. // GameUI.Instance.RenderHitScore(hitScore, GetBestScore());
  240. _CumulativeScore += scoreToPlus;
  241. GameUI.Instance.RenderHitScore(_CumulativeScore, GetBestScore());
  242. GameUI.Instance.ShowTextHitScore(scoreToPlus, duck.transform.position);
  243. RemoveArrows(duck);
  244. }
  245. public void OnModuleRotationUpdate(Quaternion rotation)
  246. {
  247. CrossHair.Instance?.UpdatePositionByModuleRotation(rotation);
  248. }
  249. public void OnModuleShooting(float speed)
  250. {
  251. if (CrossHair.Instance)
  252. {
  253. if (isGamePlaying)
  254. {
  255. if (UseOneArrow())
  256. {
  257. CrossHair.Instance.Shoot();
  258. CheckShootPointHitDuck();
  259. CheckNotifyFlyAway();
  260. }
  261. }
  262. else if (!isGameStarted)
  263. {
  264. //CrossHair.Instance.Shoot();
  265. if (GameUI.Instance.CheckHitDuckForGameStart(CrossHair.Instance.transform.position))
  266. {
  267. OnClick_GameStart();
  268. }
  269. }
  270. }
  271. }
  272. void CheckShootPointHitDuck()
  273. {
  274. bool hitDuck = false;
  275. Vector2 aimPos = CrossHair.Instance.transform.position;
  276. for (int i = Duck.DuckList.Count - 1; i >= 0; i--)
  277. {
  278. Duck duck = Duck.DuckList[i];
  279. RectTransform duckRTF = duck.transform as RectTransform;
  280. bool intersect = RectTransformUtility.RectangleContainsScreenPoint(duckRTF, aimPos);
  281. bool hitFrontBG = false;
  282. Collider2D[] hitColliders = Physics2D.OverlapPointAll(aimPos);
  283. foreach (var item in hitColliders)
  284. {
  285. if (item.name.StartsWith("BGFront"))
  286. {
  287. hitFrontBG = true;
  288. break;
  289. }
  290. }
  291. if (intersect && !hitFrontBG && duck.Hit())
  292. {
  293. hitDuck = true;
  294. break;
  295. }
  296. }
  297. if (!hitDuck)
  298. {
  299. GameUI.Instance.AddArrowOnScreen(aimPos);
  300. }
  301. }
  302. void OnClick_GameStart()
  303. {
  304. AudioManager.Instance.PlayGameStart();
  305. StartGame(false);
  306. }
  307. void StartGame(bool startImmediate)
  308. {
  309. if (isGameStarted) return;
  310. isGameStarted = true;
  311. onGameStart?.Invoke();
  312. GameUI.Instance.HandleGameStart(() =>
  313. {
  314. dogSideObject.SetActive(true);
  315. dogSideObject.GetComponent<DogSide>().onExit = () => canCreateDuck = true;
  316. TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.ROUND_X, new object[] { level });
  317. }, startImmediate);
  318. NoArrows();
  319. GameUI.Instance.RenderLevel(level);
  320. // GameUI.Instance.RenderHitScore(hitScore, GetBestScore());
  321. GameUI.Instance.RenderHitScore(_CumulativeScore, GetBestScore());
  322. }
  323. void SettleGame()
  324. {
  325. if (isGameOver) return;
  326. if (_ductTypeList == null) return;
  327. if (Dog.Instance != null && Dog.Instance.isShowing) return;
  328. if (needCreateDuckCount != exitDuckCount) return;
  329. isGameOver = true;
  330. Debug.Log("Game Over");
  331. GameUI.Instance.RenderHitDuckCount(-1);
  332. if (hitCount < passNeedHitCount)
  333. {
  334. //通关失败
  335. TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.GAME_OVER, null, () =>
  336. {
  337. UnityEngine.SceneManagement.SceneManager.LoadScene("DuckHunter");
  338. });
  339. AudioManager.Instance.PlayGameOver();
  340. Debug.Log("通关失败");
  341. }
  342. else
  343. {
  344. //完美通关
  345. if (needCreateDuckCount == hitCount)
  346. {
  347. //奖励额外积分
  348. int plusScore = 10000;
  349. hitScore += plusScore;
  350. // GameUI.Instance.RenderHitScore(hitScore, GetBestScore());
  351. _CumulativeScore += plusScore;
  352. GameUI.Instance.RenderHitScore(_CumulativeScore, GetBestScore());
  353. TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.SUPER_ARCHER, new object[] { plusScore }, ShowGamePass);
  354. AudioManager.Instance.PlayFullScore();
  355. }
  356. else
  357. {
  358. ShowGamePass();
  359. }
  360. }
  361. SaveBestScore();
  362. }
  363. void ShowGamePass()
  364. {
  365. //通关成功
  366. TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.GAME_COMPLETED, null, () =>
  367. {
  368. //自动进入下一关
  369. if (level < 100)
  370. {
  371. DefaultLevel = level + 1;
  372. AutoNextLevel = true;
  373. }
  374. UnityEngine.SceneManagement.SceneManager.LoadScene("DuckHunter");
  375. });
  376. AudioManager.Instance.PlayGamePass();
  377. Debug.Log("通关成功");
  378. }
  379. int _arrowCount;
  380. int arrowCount
  381. {
  382. get
  383. {
  384. // int count = 0;
  385. // _duckCanShootCountList.ForEach(e => count += e.shootCount);
  386. // return count;
  387. return _arrowCount;
  388. }
  389. }
  390. List<DuckCanShootCount> _duckCanShootCountList = new List<DuckCanShootCount>();
  391. class DuckCanShootCount
  392. {
  393. public Duck duck;
  394. public int shootCount;
  395. public DuckCanShootCount(Duck duck, int shootCount)
  396. {
  397. this.duck = duck;
  398. this.shootCount = shootCount;
  399. }
  400. }
  401. void ResumeArrows(Duck duck)
  402. {
  403. // _duckCanShootCountList.Add(new DuckCanShootCount(duck, 3));
  404. _arrowCount = 3;
  405. GameUI.Instance.RenderArrowCount(arrowCount);
  406. }
  407. void RemoveArrows(Duck duck)
  408. {
  409. // _duckCanShootCountList.RemoveAll(e => e.duck == duck);
  410. // GameUI.Instance.RenderArrowCount(arrowCount);
  411. }
  412. bool UseOneArrow()
  413. {
  414. if (arrowCount > 0)
  415. {
  416. // foreach (var e in _duckCanShootCountList)
  417. // {
  418. // if (e.shootCount > 0)
  419. // {
  420. // e.shootCount--;
  421. // break;
  422. // }
  423. // }
  424. _arrowCount--;
  425. GameUI.Instance.RenderArrowCount(arrowCount);
  426. return true;
  427. }
  428. return false;
  429. }
  430. void NoArrows()
  431. {
  432. // _duckCanShootCountList = new List<DuckCanShootCount>();
  433. _arrowCount = 0;
  434. GameUI.Instance.RenderArrowCount(arrowCount);
  435. }
  436. void CheckNotifyFlyAway()
  437. {
  438. // foreach (var e in _duckCanShootCountList)
  439. // if (e.shootCount == 0)
  440. // e.duck.NotifyFlyAway();
  441. if (arrowCount <= 0)
  442. foreach (var duck in Duck.DuckList)
  443. duck.NotifyFlyAway();
  444. }
  445. //累计得分
  446. private static int _CumulativeScore = 0;
  447. private static int _BestScoreVersion = 1;
  448. string GetBestScoreKey()
  449. {
  450. // return "BestScore_Level" + level + "_V" + _BestScoreVersion;
  451. return "DuckHunter_" + LoginMgr.myUserInfo.id + "_" + _BestScoreVersion;
  452. }
  453. void SaveBestScore()
  454. {
  455. string k = GetBestScoreKey();
  456. int s = PlayerPrefs.GetInt(k, 0);
  457. // if (hitScore > s) PlayerPrefs.SetInt(k, hitScore);
  458. if (_CumulativeScore > s) PlayerPrefs.SetInt(k, _CumulativeScore);
  459. }
  460. int GetBestScore()
  461. {
  462. string k = GetBestScoreKey();
  463. int s = PlayerPrefs.GetInt(k, 0);
  464. return s;
  465. }
  466. }
  467. }