using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; namespace DuckHunter { public class GameManager : MonoBehaviour { public static GameManager Instance; [SerializeField] GameObject dogObject; [SerializeField] GameObject dogSideObject; [SerializeField] GameObject duckPrefab; [SerializeField] RectTransform duckBox; [System.NonSerialized] public bool isGameStarted; [System.NonSerialized] public bool isGameOver; public bool isGamePlaying { get => isGameStarted && !isGameOver; } public System.Action onGameStart; void Awake() { Instance = this; dogObject.SetActive(true); level = DefaultLevel; } void OnDestroy() { if (Instance == this) Instance = null; } void Start() { TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.GAME_START); if (AutoNextLevel) { AutoNextLevel = false; StartGame(true); } UserGameAnalyse1.CreateWhenGameStart(); } void Update() { UpdateCheckMouseHit(); UpdateForAutoCreateDucks(); SettleGame(); #if UNITY_EDITOR if (Input.GetKeyDown(KeyCode.A)) { Time.timeScale = 10; } if (Input.GetKeyUp(KeyCode.A)) { Time.timeScale = 1; } #endif } void UpdateCheckMouseHit() { if (Input.GetMouseButtonDown(0)) { if (EventSystem.current.currentSelectedGameObject == null) { CrossHair.Instance.transform.position = Input.mousePosition; OnModuleShooting(10); } } } /// /// 基础初速度 /// public static float BaseFlySpeed = 50; /// /// 下次从多少分开始 /// public static int DefaultLevel = 1; private static bool AutoNextLevel = false; [System.NonSerialized] public int hitScore; //得分 [System.NonSerialized] public int level = 1; /// /// 通关需要击落的鸭子数量 /// int passNeedHitCount; int needCreateDuckCount; bool canCreateDuck; [System.NonSerialized] public int theDuckCountWaitingForDogHandle; float _createDuckInterval; void UpdateForAutoCreateDucks() { if (isGameOver) return; if (!canCreateDuck) return; _createDuckInterval = 0; if (level <= 60) { if (theDuckCountWaitingForDogHandle > 0) return; } else if (level <= 80) { if (theDuckCountWaitingForDogHandle > 0) _createDuckInterval = 5; if (theDuckCountWaitingForDogHandle > 1) return; } else //<=100 { if (theDuckCountWaitingForDogHandle > 0) _createDuckInterval = 5; if (theDuckCountWaitingForDogHandle > 2) return; } if (!Dog.Instance || Dog.Instance.isShowing) return; if (Time.time - _lastCreateDuckTime < _createDuckInterval) return; CreateDuck(); } List _ductTypeList = null; void InitDuckTypeList(int greenCount, int blueCount, int redCount) { if (_ductTypeList != null) return; _ductTypeList = new List(); for (int i = 0; i < greenCount; i++) _ductTypeList.Add(1); for (int i = 0; i < blueCount; i++) _ductTypeList.Add(2); for (int i = 0; i < redCount; i++) _ductTypeList.Add(3); _ductTypeList.Sort((a, b) => Random.value < 0.5 ? -1 : 1); needCreateDuckCount = _ductTypeList.Count; } static float[] _FlyAngles1 = { 75, 180 - 75 }; static float[] _FlyAngles2 = { 75, 60, 180 - 75, 180 - 60 }; static float[] _FlyAngles3 = { 45, 60, 180 - 45, 180 - 60 }; static float[] _FlyAngles4 = { 30, 45, 60, 180 - 30, 180 - 45, 180 - 60 }; static float RangeFlyAngle(float[] angles) { return angles[Random.Range(0, angles.Length)]; } DuckConfig GetDuckConfig() { DuckConfig duckConfig = new DuckConfig(); if (level <= 20) duckConfig.positionX = Random.Range(duckBox.rect.width / 2 - 200, duckBox.rect.width / 2 + 50); else duckConfig.positionX = Random.Range(250, duckBox.rect.width - 350); if (level <= 10) { InitDuckTypeList(10, 0, 0); passNeedHitCount = 6; duckConfig.touchBoundCount = 4; duckConfig.flyAngle = RangeFlyAngle(_FlyAngles1); } else if (level <= 15) { InitDuckTypeList(5, 5, 0); passNeedHitCount = 7; duckConfig.touchBoundCount = 4; duckConfig.flyAngle = RangeFlyAngle(_FlyAngles1); } else if (level <= 18) { InitDuckTypeList(5, 3, 2); passNeedHitCount = 8; duckConfig.touchBoundCount = 4; duckConfig.flyAngle = RangeFlyAngle(_FlyAngles1); } else if (level <= 20) { InitDuckTypeList(4, 4, 2); passNeedHitCount = 9; duckConfig.touchBoundCount = 4; duckConfig.flyAngle = RangeFlyAngle(_FlyAngles1); } else if (level <= 40) { InitDuckTypeList(3, 4, 3); passNeedHitCount = 10; duckConfig.touchBoundCount = 5; duckConfig.flyAngle = RangeFlyAngle(_FlyAngles2); } else if (level <= 60) { InitDuckTypeList(3, 3, 4); passNeedHitCount = 10; duckConfig.touchBoundCount = 6; duckConfig.flyAngle = RangeFlyAngle(_FlyAngles3); } else if (level <= 80) { InitDuckTypeList(2, 4, 4); passNeedHitCount = 10; duckConfig.touchBoundCount = 7; duckConfig.flyAngle = RangeFlyAngle(_FlyAngles4); } else if (level <= 100) { InitDuckTypeList(2, 3, 5); passNeedHitCount = 10; duckConfig.touchBoundCount = 8; duckConfig.flyAngle = RangeFlyAngle(_FlyAngles4); } duckConfig.type = _ductTypeList[0]; _ductTypeList.RemoveAt(0); duckConfig.flySpeed = BaseFlySpeed * (1 + (level - 1) * 0.05f); if (duckConfig.type == 1) duckConfig.flySpeed *= 1f; else if (duckConfig.type == 2) duckConfig.flySpeed *= 1.2f; else if (duckConfig.type == 3) duckConfig.flySpeed *= 1.5f; return duckConfig; } float _lastCreateDuckTime = -1000; void CreateDuck() { if (_ductTypeList != null && _ductTypeList.Count == 0) return; theDuckCountWaitingForDogHandle++; _lastCreateDuckTime = Time.time; DuckConfig duckConfig = GetDuckConfig(); Duck duck = Instantiate(duckPrefab, duckBox).GetComponent(); duck.config = duckConfig; duck.onExit += HandleOnDuckExit; duck.onFallDonwEnd += HandleOnDuckFallDown; duck.onHitDead += HandleOnHitDead; duck.onStartFlyAway += () => TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.FLY_AWAY); //恢复箭 ResumeArrows(duck); } int exitDuckCount = 0; void HandleOnDuckExit(Duck duck) { if (duck.dead) Dog.Instance?.OnEvent(Dog.SensitiveEventType.DuckHit, duck); else { RemoveArrows(duck); GameUI.Instance.RenderHitDuckCount(0); Dog.Instance?.OnEvent(Dog.SensitiveEventType.DuckGetAway); } exitDuckCount++; } float _lastFallDownTime = 0; void HandleOnDuckFallDown(Duck duck) { _lastFallDownTime = Time.time; } [System.NonSerialized] public int hitCount = 0; void HandleOnHitDead(Duck duck) { hitCount++; int scoreToPlus = duck.config.type * 500; hitScore += scoreToPlus; GameUI.Instance.RenderHitDuckCount(duck.config.type); GameUI.Instance.RenderHitScore(hitScore, GetBestScore()); GameUI.Instance.ShowTextHitScore(scoreToPlus, duck.transform.position); RemoveArrows(duck); } public void OnModuleRotationUpdate(Quaternion rotation) { CrossHair.Instance?.UpdatePositionByModuleRotation(rotation); } public void OnModuleShooting(float speed) { if (CrossHair.Instance) { if (isGamePlaying) { if (UseOneArrow()) { CrossHair.Instance.Shoot(); CheckShootPointHitDuck(); CheckNotifyFlyAway(); } } else if (!isGameStarted) { //CrossHair.Instance.Shoot(); if (GameUI.Instance.CheckHitDuckForGameStart(CrossHair.Instance.transform.position)) { OnClick_GameStart(); } } } } void CheckShootPointHitDuck() { bool hitDuck = false; Vector2 aimPos = CrossHair.Instance.transform.position; for (int i = Duck.DuckList.Count - 1; i >= 0; i--) { Duck duck = Duck.DuckList[i]; RectTransform duckRTF = duck.transform as RectTransform; bool intersect = RectTransformUtility.RectangleContainsScreenPoint(duckRTF, aimPos); if (intersect && duck.Hit()) { hitDuck = true; break; } } if (!hitDuck) { GameUI.Instance.AddArrowOnScreen(aimPos); } } void OnClick_GameStart() { AudioManager.Instance.PlayGameStart(); StartGame(false); } void StartGame(bool startImmediate) { if (isGameStarted) return; isGameStarted = true; onGameStart?.Invoke(); GameUI.Instance.HandleGameStart(() => { dogSideObject.SetActive(true); dogSideObject.GetComponent().onExit = () => canCreateDuck = true; TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.ROUND_X, new object[] { level }); }, startImmediate); NoArrows(); GameUI.Instance.RenderLevel(level); GameUI.Instance.RenderHitScore(hitScore, GetBestScore()); } void SettleGame() { if (isGameOver) return; if (_ductTypeList == null) return; if (Dog.Instance != null && Dog.Instance.isShowing) return; if (needCreateDuckCount != exitDuckCount) return; isGameOver = true; Debug.Log("Game Over"); GameUI.Instance.RenderHitDuckCount(-1); if (hitCount < passNeedHitCount) { //通关失败 TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.GAME_OVER, null, () => { UnityEngine.SceneManagement.SceneManager.LoadScene("DuckHunter"); }); AudioManager.Instance.PlayGameOver(); Debug.Log("通关失败"); } else { //完美通关 if (needCreateDuckCount == hitCount) { //奖励额外积分 int plusScore = 10000; hitScore += plusScore; GameUI.Instance.RenderHitScore(hitScore, GetBestScore()); TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.SUPER_ARCHER, new object[] { plusScore }, ShowGamePass); AudioManager.Instance.PlayFullScore(); } else { ShowGamePass(); } } SaveBestScore(); } void ShowGamePass() { //通关成功 TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.GAME_COMPLETED, null, () => { //自动进入下一关 if (level < 100) { DefaultLevel = level + 1; AutoNextLevel = true; } UnityEngine.SceneManagement.SceneManager.LoadScene("DuckHunter"); }); AudioManager.Instance.PlayGamePass(); Debug.Log("通关成功"); } int arrowCount { get { int count = 0; _duckCanShootCountList.ForEach(e => count += e.shootCount); return count; } } List _duckCanShootCountList = new List(); class DuckCanShootCount { public Duck duck; public int shootCount; public DuckCanShootCount(Duck duck, int shootCount) { this.duck = duck; this.shootCount = shootCount; } } void ResumeArrows(Duck duck) { _duckCanShootCountList.Add(new DuckCanShootCount(duck, 3)); GameUI.Instance.RenderArrowCount(arrowCount); } void RemoveArrows(Duck duck) { _duckCanShootCountList.RemoveAll(e => e.duck == duck); GameUI.Instance.RenderArrowCount(arrowCount); } bool UseOneArrow() { if (arrowCount > 0) { foreach (var e in _duckCanShootCountList) { if (e.shootCount > 0) { e.shootCount--; break; } } GameUI.Instance.RenderArrowCount(arrowCount); return true; } return false; } void NoArrows() { _duckCanShootCountList = new List(); GameUI.Instance.RenderArrowCount(arrowCount); } void CheckNotifyFlyAway() { foreach (var e in _duckCanShootCountList) if (e.shootCount == 0) e.duck.NotifyFlyAway(); } private static int _BestScoreVersion = 1; string GetBestScoreKey() { return "BestScore_Level" + level + "_V" + _BestScoreVersion; } void SaveBestScore() { string k = GetBestScoreKey(); int s = PlayerPrefs.GetInt(k, 0); if (hitScore > s) PlayerPrefs.SetInt(k, hitScore); } int GetBestScore() { string k = GetBestScoreKey(); int s = PlayerPrefs.GetInt(k, 0); return s; } } }