GameManager.cs 21 KB

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