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); if (!AutoNextLevel) { DefaultLevel = 1; _CumulativeScore = 0; } level = DefaultLevel; } void OnDestroy() { if (Instance == this) Instance = null; } void Start() { TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.GAME_START); if (AutoNextLevel) { AutoNextLevel = false; StartGame(true); } } void onDeviceShoot(float speed) { OnModuleShooting((int)speed); } 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) && BowCamera.isTouchMode) { 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); //2023-7-25修改:速度还是以80关的做为初始速度,后面的关卡再按原来的公式增加 duckConfig.flySpeed = BaseFlySpeed * (1 + (level + 79 - 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()); _CumulativeScore += scoreToPlus; GameUI.Instance.RenderHitScore(_CumulativeScore, GetBestScore()); GameUI.Instance.ShowTextHitScore(scoreToPlus, duck.transform.position); RemoveArrows(duck); } public void OnModuleRotationUpdate(Quaternion rotation) { CrossHair.Instance?.UpdatePositionByModuleRotation(rotation); } public void OnModuleShooting(float speed, bool bAddCount = false) { if (CrossHair.Instance) { if (isGamePlaying) { if (UseOneArrow(bAddCount)) { 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); bool hitFrontBG = false; Collider2D[] hitColliders = Physics2D.OverlapPointAll(aimPos); foreach (var item in hitColliders) { if (item.name.StartsWith("BGFront")) { hitFrontBG = true; break; } } if (intersect && !hitFrontBG && 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()); GameUI.Instance.RenderHitScore(_CumulativeScore, GetBestScore()); } //重新加载游戏 public void onReLoadGame() { string sceneName = UnityEngine.SceneManagement.SceneManager.GetActiveScene().name; UnityEngine.SceneManagement.SceneManager.LoadScene(sceneName); } public void onBackHome() { UnityEngine.SceneManagement.SceneManager.LoadScene("EnterTheInfraredScene",UnityEngine.SceneManagement.LoadSceneMode.Single); } 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, () => { string sceneName = UnityEngine.SceneManagement.SceneManager.GetActiveScene().name; UnityEngine.SceneManagement.SceneManager.LoadScene(sceneName); //UnityEngine.SceneManagement.SceneManager.LoadScene("DuckHunter"); }); AudioManager.Instance.PlayGameOver(); Debug.Log("通关失败"); } else { //完美通关 if (needCreateDuckCount == hitCount) { //奖励额外积分 int plusScore = 10000; hitScore += plusScore; // GameUI.Instance.RenderHitScore(hitScore, GetBestScore()); _CumulativeScore += plusScore; GameUI.Instance.RenderHitScore(_CumulativeScore, GetBestScore()); TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.SUPER_ARCHER, new object[] { plusScore }, ShowGamePass); AudioManager.Instance.PlayFullScore(); } else { ShowGamePass(); } } SaveBestScore(); GameOverInterface.OnGameOver(GameMgr.gameType); } void ShowGamePass() { //通关成功 TextGameScreenCenter.Instance.ShowText(TextGameScreenCenter.TextName.GAME_COMPLETED, null, () => { //自动进入下一关 if (level < 100) { DefaultLevel = level + 1; AutoNextLevel = true; } string sceneName = UnityEngine.SceneManagement.SceneManager.GetActiveScene().name; UnityEngine.SceneManagement.SceneManager.LoadScene(sceneName); //UnityEngine.SceneManagement.SceneManager.LoadScene("DuckHunter"); }); AudioManager.Instance.PlayGamePass(); Debug.Log("通关成功"); } int _arrowCount; int arrowCount { get { // int count = 0; // _duckCanShootCountList.ForEach(e => count += e.shootCount); // return count; return _arrowCount; } } 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)); _arrowCount = 3; GameUI.Instance.RenderArrowCount(arrowCount); } void RemoveArrows(Duck duck) { // _duckCanShootCountList.RemoveAll(e => e.duck == duck); // GameUI.Instance.RenderArrowCount(arrowCount); } bool UseOneArrow(bool bAddCount = false) { if (arrowCount > 0) { // foreach (var e in _duckCanShootCountList) // { // if (e.shootCount > 0) // { // e.shootCount--; // break; // } // } _arrowCount--; GameUI.Instance.RenderArrowCount(arrowCount); return true; } return false; } void NoArrows() { // _duckCanShootCountList = new List(); _arrowCount = 0; GameUI.Instance.RenderArrowCount(arrowCount); } void CheckNotifyFlyAway() { // foreach (var e in _duckCanShootCountList) // if (e.shootCount == 0) // e.duck.NotifyFlyAway(); if (arrowCount <= 0) foreach (var duck in Duck.DuckList) duck.NotifyFlyAway(); } //累计得分 private static int _CumulativeScore = 0; private static int _BestScoreVersion = 1; string GetBestScoreKey() { // return "BestScore_Level" + level + "_V" + _BestScoreVersion; return "DuckHunter_" + LoginMgr.myUserInfo.id + "_" + _BestScoreVersion; } void SaveBestScore() { string k = GetBestScoreKey(); int s = PlayerPrefs.GetInt(k, 0); // if (hitScore > s) PlayerPrefs.SetInt(k, hitScore); if (_CumulativeScore > s) PlayerPrefs.SetInt(k, _CumulativeScore); } int GetBestScore() { string k = GetBestScoreKey(); int s = PlayerPrefs.GetInt(k, 0); return s; } } }