GameManager.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  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();
  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. if (intersect && duck.Hit())
  282. {
  283. hitDuck = true;
  284. break;
  285. }
  286. }
  287. if (!hitDuck)
  288. {
  289. GameUI.Instance.AddArrowOnScreen(aimPos);
  290. }
  291. }
  292. void OnClick_GameStart()
  293. {
  294. AudioManager.Instance.PlayGameStart();
  295. StartGame(false);
  296. }
  297. void StartGame(bool startImmediate)
  298. {
  299. if (isGameStarted) return;
  300. isGameStarted = true;
  301. onGameStart?.Invoke();
  302. GameUI.Instance.HandleGameStart(() =>
  303. {
  304. dogSideObject.SetActive(true);
  305. dogSideObject.GetComponent<DogSide>().onExit = () => canCreateDuck = true;
  306. TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.ROUND_X, new object[] { level });
  307. }, startImmediate);
  308. NoArrows();
  309. GameUI.Instance.RenderLevel(level);
  310. // GameUI.Instance.RenderHitScore(hitScore, GetBestScore());
  311. GameUI.Instance.RenderHitScore(_CumulativeScore, GetBestScore());
  312. }
  313. void SettleGame()
  314. {
  315. if (isGameOver) return;
  316. if (_ductTypeList == null) return;
  317. if (Dog.Instance != null && Dog.Instance.isShowing) return;
  318. if (needCreateDuckCount != exitDuckCount) return;
  319. isGameOver = true;
  320. Debug.Log("Game Over");
  321. GameUI.Instance.RenderHitDuckCount(-1);
  322. if (hitCount < passNeedHitCount)
  323. {
  324. //通关失败
  325. TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.GAME_OVER, null, () =>
  326. {
  327. UnityEngine.SceneManagement.SceneManager.LoadScene("DuckHunter");
  328. });
  329. AudioManager.Instance.PlayGameOver();
  330. Debug.Log("通关失败");
  331. }
  332. else
  333. {
  334. //完美通关
  335. if (needCreateDuckCount == hitCount)
  336. {
  337. //奖励额外积分
  338. int plusScore = 10000;
  339. hitScore += plusScore;
  340. // GameUI.Instance.RenderHitScore(hitScore, GetBestScore());
  341. _CumulativeScore += plusScore;
  342. GameUI.Instance.RenderHitScore(_CumulativeScore, GetBestScore());
  343. TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.SUPER_ARCHER, new object[] { plusScore }, ShowGamePass);
  344. AudioManager.Instance.PlayFullScore();
  345. }
  346. else
  347. {
  348. ShowGamePass();
  349. }
  350. }
  351. SaveBestScore();
  352. }
  353. void ShowGamePass()
  354. {
  355. //通关成功
  356. TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.GAME_COMPLETED, null, () =>
  357. {
  358. //自动进入下一关
  359. if (level < 100)
  360. {
  361. DefaultLevel = level + 1;
  362. AutoNextLevel = true;
  363. }
  364. UnityEngine.SceneManagement.SceneManager.LoadScene("DuckHunter");
  365. });
  366. AudioManager.Instance.PlayGamePass();
  367. Debug.Log("通关成功");
  368. }
  369. int _arrowCount;
  370. int arrowCount
  371. {
  372. get
  373. {
  374. // int count = 0;
  375. // _duckCanShootCountList.ForEach(e => count += e.shootCount);
  376. // return count;
  377. return _arrowCount;
  378. }
  379. }
  380. List<DuckCanShootCount> _duckCanShootCountList = new List<DuckCanShootCount>();
  381. class DuckCanShootCount
  382. {
  383. public Duck duck;
  384. public int shootCount;
  385. public DuckCanShootCount(Duck duck, int shootCount)
  386. {
  387. this.duck = duck;
  388. this.shootCount = shootCount;
  389. }
  390. }
  391. void ResumeArrows(Duck duck)
  392. {
  393. // _duckCanShootCountList.Add(new DuckCanShootCount(duck, 3));
  394. _arrowCount = 3;
  395. GameUI.Instance.RenderArrowCount(arrowCount);
  396. }
  397. void RemoveArrows(Duck duck)
  398. {
  399. // _duckCanShootCountList.RemoveAll(e => e.duck == duck);
  400. // GameUI.Instance.RenderArrowCount(arrowCount);
  401. }
  402. bool UseOneArrow()
  403. {
  404. if (arrowCount > 0)
  405. {
  406. // foreach (var e in _duckCanShootCountList)
  407. // {
  408. // if (e.shootCount > 0)
  409. // {
  410. // e.shootCount--;
  411. // break;
  412. // }
  413. // }
  414. _arrowCount--;
  415. GameUI.Instance.RenderArrowCount(arrowCount);
  416. return true;
  417. }
  418. return false;
  419. }
  420. void NoArrows()
  421. {
  422. // _duckCanShootCountList = new List<DuckCanShootCount>();
  423. _arrowCount = 0;
  424. GameUI.Instance.RenderArrowCount(arrowCount);
  425. }
  426. void CheckNotifyFlyAway()
  427. {
  428. // foreach (var e in _duckCanShootCountList)
  429. // if (e.shootCount == 0)
  430. // e.duck.NotifyFlyAway();
  431. if (arrowCount <= 0)
  432. foreach (var duck in Duck.DuckList)
  433. duck.NotifyFlyAway();
  434. }
  435. //累计得分
  436. private static int _CumulativeScore = 0;
  437. private static int _BestScoreVersion = 1;
  438. string GetBestScoreKey()
  439. {
  440. // return "BestScore_Level" + level + "_V" + _BestScoreVersion;
  441. return "DuckHunter_" + LoginMgr.myUserInfo.id + "_" + _BestScoreVersion;
  442. }
  443. void SaveBestScore()
  444. {
  445. string k = GetBestScoreKey();
  446. int s = PlayerPrefs.GetInt(k, 0);
  447. // if (hitScore > s) PlayerPrefs.SetInt(k, hitScore);
  448. if (_CumulativeScore > s) PlayerPrefs.SetInt(k, _CumulativeScore);
  449. }
  450. int GetBestScore()
  451. {
  452. string k = GetBestScoreKey();
  453. int s = PlayerPrefs.GetInt(k, 0);
  454. return s;
  455. }
  456. }
  457. }