using System; using System.Collections.Generic; using DG.Tweening; using UnityEngine; using UnityEngine.UI; public class HorseRushPanel : MonoBehaviour { [SerializeField] HorseRushManager _horseRushManager; [SerializeField] List _bubbleCardList; [SerializeField] List _touchButtonObjectList; [SerializeField] GameObject _commander; [SerializeField] Button _leftButton; [SerializeField] Button _rightButton; [SerializeField] GameObject _leftEffect; [SerializeField] GameObject _rightEffect; #region TEST [Header("## SLIDER")] [SerializeField] Slider _timer; [SerializeField] Image _fillImage; [SerializeField] Text _rushTimeText; [SerializeField] Text _feverTimeText; [SerializeField] Slider _bottomSlider; [SerializeField] Image _bottomFillImage; [Header("## UI")] [SerializeField] Text _scoreText; [SerializeField] Text _comboText; [SerializeField] GameObject _combo; [SerializeField] Image _background; [SerializeField] Image _stunImage; [SerializeField] Image _loveEffectImage; #endregion #region Rush System member variable float STUN_TIME; float RUSH_LIMIT_TIME; float FEVER_TIME; float BONUS_TIME; int DEFAULT_FEVER_COUNT; int FEVER_INCREASE_MIN; int FEVER_INCREASE_MAX; int FEVER_INCREASE_LIMIT; bool _isGameStart = false; public bool IsGameStart => _isGameStart; bool _isFree; bool _isGameOver = true; float _limitTime; public float LimitTime => _limitTime; float _rushTime; public float RushTime => _rushTime; float _addRushTimeValue; float _stunTime; public float StunTime => _stunTime; bool IsStun => _stunTime > 0; float _feverTime; public float FeverTime => _feverTime; bool IsFever => _feverTime > 0; // 전체 누적 콤보 int _totalComboCount = 0; int _comboCount = 0; int _levelComboCount = 0; int _feverLevel = 0; long _score = 0; // 피버 관련 변수 추가 int _currentFeverStreak = 0; // 현재 연속 피버 횟수 int _maxFeverStreak = 0; // 최대 연속 피버 횟수 public int MaxFeverStreak => _maxFeverStreak; int _missionFeverCount = 0; // 미션 성공으로 지급된 photo 아이디 int _missionSuccessPhotoID = -1; public int MissionSuccessPhotoID => _missionSuccessPhotoID; // 더블 스코어 관련 변수 추가 private int _normalDoubleScoreCount = 0; // 일반 상태에서의 더블 스코어 성공 횟수 public int NormalDoubleScoreCount => _normalDoubleScoreCount; #endregion #region UI System member variable float NORMAL_BUBBLE_MOVE_SPEED = 0.05f; float FEVER_BUBBLE_MOVE_SPEED = 0.0f; float BUBBLE_MOVE_SPEED = 0.1f; readonly float BUBBLE_MOVE_Y_VALUE = 240f; readonly float BUUBLE_MOVE_Y_ADDED_VALUE = 2640f; readonly float DEFAULT_LIMIT_TIME = 180f; #endregion private Animator _leftAnimator; private Animator _rightAnimator; int _touchSoundCount = 0; float _nextTimeUpdate = 0.1f; private Sprite _feverBgSprite; private Sprite _normalBgSprite; List _normalTouchSound = new List { eSound.s020_Noraml_Hit, eSound.s021_Noraml_Hit, eSound.s022_Noraml_Hit, eSound.s023_Noraml_Hit, eSound.s024_Noraml_Hit, eSound.s025_Noraml_Hit }; List _impactTouchSound = new List { eSound.s026_Impact_Hit, eSound.s027_Impact_Hit, eSound.s028_Impact_Hit, eSound.s029_Impact_Hit }; // 클래스 멤버 변수에 추가 private float _lastTouchTime = 0f; // 애니메이션 진행 여부 확인용 플래그 변수 추가 private bool _isAnimationPlaying = false; void Awake() { STUN_TIME = 0.5f; RUSH_LIMIT_TIME = 2f; FEVER_TIME = 8f; BONUS_TIME = 0.4f; #if UNITY_EDITOR DEFAULT_FEVER_COUNT = 20; #else DEFAULT_FEVER_COUNT = 100; #endif FEVER_INCREASE_MIN = 5; FEVER_INCREASE_MAX = 15; FEVER_INCREASE_LIMIT = 10; _leftButton.onClick.AddListener(() => Touch(isTouchLeft: true)); _rightButton.onClick.AddListener(() => Touch(isTouchLeft: false)); // 버튼의 넓이만 스크린의 절반으로 설정 나머지는 원래 사이즈 그대로로 _leftButton.GetComponent().sizeDelta = new Vector2(Screen.width / 2, _leftButton.GetComponent().sizeDelta.y); _rightButton.GetComponent().sizeDelta = new Vector2(Screen.width / 2, _rightButton.GetComponent().sizeDelta.y); _feverBgSprite = Resources.Load("Prefabs/HorseRush/Image/RushBg_Fever"); _normalBgSprite = Resources.Load("Prefabs/HorseRush/Image/RushBg"); } void Start() { _leftAnimator = _leftEffect.GetComponent(); _rightAnimator = _rightEffect.GetComponent(); //_missionFeverCount = DataManager.Instance.GlobalValue("MISSION_FEVER_COUNT"); } void Update() { // 키보드 입력 처리 if (Input.GetKeyDown(KeyCode.LeftArrow)) { Touch(isTouchLeft: true); } if (Input.GetKeyDown(KeyCode.RightArrow)) { Touch(isTouchLeft: false); } if (!_isGameStart) return; _rushTime -= Time.deltaTime; _limitTime -= Time.deltaTime; if (_nextTimeUpdate <= 0) { TimeSpan timeSpan = TimeSpan.FromSeconds(_limitTime); _rushTimeText.text = string.Format("{0:D2}:{1:D2}", timeSpan.Minutes, timeSpan.Seconds); _nextTimeUpdate = 0.1f; } _nextTimeUpdate -= Time.deltaTime; if (_rushTime <= 0 || _limitTime <= 0) { _isGameStart = false; _isGameOver = true; _horseRushManager.GameOver(_isFree, _score, _normalDoubleScoreCount, _maxFeverStreak, _missionSuccessPhotoID); gameObject.SetActive(false); } _timer.value = _limitTime / DEFAULT_LIMIT_TIME; if (IsFever) { _bottomSlider.value = _feverTime / FEVER_TIME; } else { _bottomSlider.value = _rushTime / RUSH_LIMIT_TIME; } _stunTime = Mathf.Max(0, _stunTime - Time.deltaTime); if (IsStun) { _touchButtonObjectList.ForEach(obj => obj.GetComponent().fillAmount = 1 - _stunTime / STUN_TIME); } bool beforeFever = IsFever; _feverTime = Mathf.Max(0, _feverTime - Time.deltaTime); bool canFeverIncreaseCondition = (DEFAULT_FEVER_COUNT + (FEVER_INCREASE_MAX * _feverLevel)) < _levelComboCount; bool canDefaultComboCondition = (DEFAULT_FEVER_COUNT + (FEVER_INCREASE_MIN * _feverLevel)) < _comboCount; if (canDefaultComboCondition && canFeverIncreaseCondition) { Debug.Log("###### F E V E R ######"); SoundInfo.Ins.Play_BGM(eBGM.b003_Fever); // _bottomFillImage.color = new Color(1, 0.84f, 0.33f, 1); FadeFeverBg(_feverBgSprite); LevelUpFever(); } if (beforeFever && !IsFever) { SoundInfo.Ins.Play_BGM(eBGM.b002_MiniGame); // _bottomFillImage.color = new Color(0.86f, 0, 0, 1); FadeFeverBg(_normalBgSprite); } } void OnEnable() { _combo.SetActive(false); _stunImage.DOFade(0, 0); _stunImage.fillAmount = 1; _loveEffectImage.DOFade(0, 0); _loveEffectImage.fillAmount = 1; _timer.value = 1; _bottomSlider.value = 1; _limitTime = DEFAULT_LIMIT_TIME; TimeSpan timeSpan = TimeSpan.FromSeconds(_limitTime); _rushTimeText.text = string.Format("{0:D2}:{1:D2}", timeSpan.Minutes, timeSpan.Seconds); _scoreText.text = "0"; Init(); } void OnDisable() { _isGameStart = false; } void Init() { for (int i = 0; i < _bubbleCardList.Count; i++) { _bubbleCardList[i].transform.DOKill(); float moveValue = BUUBLE_MOVE_Y_ADDED_VALUE + (-i * BUBBLE_MOVE_Y_VALUE); _bubbleCardList[i].transform.DOLocalMoveY(moveValue, BUBBLE_MOVE_SPEED); _bubbleCardList[i].SetScale(i, BUBBLE_MOVE_SPEED); _bubbleCardList[i].SetCard(IsFever); _bubbleCardList[i].SetOpacity(i, IsFever); } _touchButtonObjectList.ForEach(obj => obj.GetComponent().fillAmount = 1); } public void GameStart(bool isFree) { gameObject.SetActive(true); //if (GameManager.Instance.IsPackageCPurchased()) //{ // // 피버 발생 조건 20% 감소, 미션 카운트 5->3회 // DEFAULT_FEVER_COUNT = 80; // FEVER_INCREASE_MIN = 4; // FEVER_INCREASE_MAX = 12; //} //else //{ // DEFAULT_FEVER_COUNT = 100; // FEVER_INCREASE_MIN = 5; // FEVER_INCREASE_MAX = 15; //} _isGameOver = false; //var albums = DataManager.Instance.GetAllPhotoDatas(); //var curPhotos = albums[GameManager.Instance.SelectedMinigameAlbum.ID]; //foreach (var photo in curPhotos.Values) //{ // if (photo.CollectionMethod == NerdNavis.AdultGacha.Enum.CollectionMethod.FullCollection) // { // _feverBgSprite = Resources.Load(photo.ImagePath); // } // else if (GameManager.Instance.CurrentMinigameType == GameManager.MinigameType.Sexy && photo.CollectionMethod == NerdNavis.AdultGacha.Enum.CollectionMethod.Mission) // { // _normalBgSprite = Resources.Load(photo.ImagePath); // } // else if (GameManager.Instance.CurrentMinigameType == GameManager.MinigameType.General && photo.CollectionMethod == NerdNavis.AdultGacha.Enum.CollectionMethod.Default) // { // _normalBgSprite = Resources.Load(photo.ImagePath); // } //} FadeFeverBg(_normalBgSprite); // 게임 상태 초기화 _isFree = isFree; _limitTime = DEFAULT_LIMIT_TIME; _rushTime = RUSH_LIMIT_TIME; _stunTime = 0; _feverTime = 0; _totalComboCount = 0; _comboCount = 0; _levelComboCount = 0; _feverLevel = 0; _score = 0; // UI 초기화 _combo.SetActive(false); _stunImage.DOFade(0, 0); _stunImage.fillAmount = 1; _loveEffectImage.DOFade(0, 0); _loveEffectImage.fillAmount = 1; _timer.value = 1; _bottomSlider.value = 1; // 시간 텍스트 초기화 TimeSpan timeSpan = TimeSpan.FromSeconds(_limitTime); _rushTimeText.text = string.Format("{0:D2}:{1:D2}", timeSpan.Minutes, timeSpan.Seconds); // 점수 텍스트 초기화 _scoreText.text = "0"; SetAddRushTime(); // 피버 스트릭 초기화 추가 _currentFeverStreak = 0; _maxFeverStreak = 0; // 미션 성공으로 지급된 photo 아이디 초기화 _missionSuccessPhotoID = -1; // 더블 스코어 카운트 초기화 _normalDoubleScoreCount = 0; Init(); } public void Touch(bool isTouchLeft) { // 애니메이션이 진행 중일 때는 입력 무시 if (_isAnimationPlaying && !IsFever) return; if (_isGameOver) return; // 현재 시간이 마지막 터치 시간 + 이동 속도보다 작으면 입력 무시 if (Time.time < _lastTouchTime + (IsFever ? FEVER_BUBBLE_MOVE_SPEED : NORMAL_BUBBLE_MOVE_SPEED)) { return; } _isGameStart = true; if (IsStun) { return; } // 유효한 입력이므로 마지막 터치 시간 업데이트 _lastTouchTime = Time.time; if (isTouchLeft) { _leftAnimator.SetTrigger("Touch"); } else { _rightAnimator.SetTrigger("Touch"); } BubbleCard lastBubbleCard = _bubbleCardList[^1].GetComponent(); bool isCorrect = isTouchLeft ? lastBubbleCard.IsLeftCarrot : !lastBubbleCard.IsLeftCarrot; if (lastBubbleCard.IsFever) { isCorrect = true; } if (isCorrect) { AddComboCount(lastBubbleCard.IsGoldCarrot); MoveBubbleCard(); lastBubbleCard.transform.SetAsFirstSibling(); _rushTime = Mathf.Min(RUSH_LIMIT_TIME, _rushTime + _addRushTimeValue); } else { _comboCount = 0; _comboText.text = ConvertToSpriteText(0); _combo.SetActive(false); // 콤보가 끊길 때 피버 스트릭도 초기화 _currentFeverStreak = 0; if (lastBubbleCard.IsSkullStone) { _isGameStart = false; _isGameOver = true; _horseRushManager.GameOver(_isFree, _score, _normalDoubleScoreCount, _maxFeverStreak, _missionSuccessPhotoID); } else { _stunImage.DOFade(1, 0.2f).OnComplete(() => _stunImage.DOFade(0, 0.2f)); _stunTime = STUN_TIME; } } } private string ConvertToSpriteText(int count) { string countString = count.ToString(); _combo.SetActive(count >= 1); _combo.transform.localScale = Vector3.one; if (count == 1) { _combo.transform.DOScale(1.2f, 0.2f).OnComplete(() => _combo.transform.DOScale(1f, 0.2f)); } return countString; } public void MoveBubbleCard() { // 애니메이션 시작 전 플래그 활성화 _isAnimationPlaying = true; // 기존의 DOTween 시퀀스 생성 및 애니메이션 처리 코드 DOTween.Kill(_bubbleCardList[^1].transform); if (_bubbleCardList == null || _bubbleCardList.Count == 0) return; Sequence sequence = DOTween.Sequence(); BubbleCard lastCard = _bubbleCardList[^1]; if (lastCard == null || lastCard.transform == null) return; lastCard.transform.DOKill(); lastCard.transform.localPosition = new Vector3(lastCard.transform.localPosition.x, BUUBLE_MOVE_Y_ADDED_VALUE, lastCard.transform.localPosition.z); _bubbleCardList.RemoveAt(_bubbleCardList.Count - 1); _bubbleCardList.Insert(0, lastCard); lastCard.SetCard(IsFever); for (int i = 0; i < _bubbleCardList.Count; i++) { var card = _bubbleCardList[i]; if (card == null || card.transform == null) continue; card.transform.DOKill(); float moveValue = BUUBLE_MOVE_Y_ADDED_VALUE + (-i * BUBBLE_MOVE_Y_VALUE); // 각 카드의 트윈을 시퀀스에 추가하기 전에 유효성 검사 var tween = card.transform.DOLocalMoveY(moveValue, BUBBLE_MOVE_SPEED) .SetTarget(card.transform) .OnKill(() => { if (card != null) card.transform.localPosition = new Vector3(card.transform.localPosition.x, moveValue, card.transform.localPosition.z); }); sequence.Join(tween); card.SetScale(i, BUBBLE_MOVE_SPEED); card.SetOpacity(i, IsFever); } // 시퀀스가 완료되거나 중단될 때의 처리 sequence.OnKill(() => { foreach (var card in _bubbleCardList) { if (card != null && card.transform != null) { DOTween.Kill(card.transform); } } _isAnimationPlaying = false; }); } void AddComboCount(bool isDoubleScore) { _totalComboCount++; _comboCount++; BubbleCard lastBubbleCard = _bubbleCardList[^1]; if (!lastBubbleCard.IsFever && isDoubleScore) { _normalDoubleScoreCount++; } if (!IsFever) { _levelComboCount++; } if (_totalComboCount % 100 == 0) { SetAddRushTime(); } int addScore = 1; _score += isDoubleScore ? addScore * 2 : addScore; _comboText.transform.localScale = Vector3.one; StartBounceEffect(); int soundLimit = isDoubleScore ? 5 : 9; var targetList = isDoubleScore ? _impactTouchSound : _normalTouchSound; if (soundLimit < _touchSoundCount++) { SoundInfo.Ins.Play_OneShot(targetList[UnityEngine.Random.Range(0, targetList.Count)]); Sequence loveSequence = DOTween.Sequence(); loveSequence.Append(_loveEffectImage.DOFade(0.3f, 0.15f)) .Append(_loveEffectImage.DOFade(0.1f, 0.1f)) .Append(_loveEffectImage.DOFade(0.4f, 0.15f)) .Append(_loveEffectImage.DOFade(0, 0.3f)); loveSequence.Play(); _touchSoundCount = 0; } else { SoundInfo.Ins.Play_OneShot(eSound.s001_ButtonClick); } _scoreText.text = _score.ToString(); _comboText.text = ConvertToSpriteText(_comboCount); } void LevelUpFever() { _feverTime = FEVER_TIME; Init(); _levelComboCount = 0; _feverLevel = Mathf.Min(_feverLevel + 1, FEVER_INCREASE_LIMIT - 1); _currentFeverStreak++; _maxFeverStreak = Mathf.Max(_maxFeverStreak, _currentFeverStreak); //if (_maxFeverStreak >= HorseRushManager.Instance.MissionFeverCount) //{ // // 현재 앨범의 사진중에 mission 타입이 있는지 확인하고, 없으면 레벨을 1 증가 // var albums = DataManager.Instance.GetPhotoDatasByAlbumID(GameManager.Instance.SelectedMinigameAlbum.ID); // foreach (var photo in albums.Values) // { // if (photo.CollectionMethod == NerdNavis.AdultGacha.Enum.CollectionMethod.Mission) // { // if (DataManager.Instance.PhotoBoost.GetLevel(photo.ID) == 0) // { // _missionSuccessPhotoID = photo.ID; // UIEvents.ShowToast(Local.GetLocalizedUIString("SEXY_MODE_UNLOCKED", new object[] { Local.GetLocalizedCSVString(DataManager.Instance.GetAlbumData(DataManager.Instance.GetPhotoData(photo.ID).AlbumID).Name) })); // break; // } // } // } //} } void SetAddRushTime() { int isNotHumanCount = 20000; if (_totalComboCount >= isNotHumanCount) { _addRushTimeValue = 0; } else { _addRushTimeValue = Mathf.Max(0.2f, ((BONUS_TIME * 100f) - Mathf.Round(_totalComboCount / (30f / _totalComboCount * 150f))) / 100f); Debug.Log($"addRushTimeValue: {_addRushTimeValue}"); } } void FadeFeverBg(Sprite newSprite) { Sequence sequence = DOTween.Sequence(); _background.color = new Color(_background.color.r, _background.color.g, _background.color.b, 1f); _background.sprite = newSprite; sequence.Append(_background.DOFade(0, 0.15f)) .Append(_background.DOFade(1, 0.15f)); } void StartBounceEffect() { if (_comboText == null) return; float bounceDuration = 0.2f; float maxScale = 1.5f; Vector3 originalScale = _comboText.transform.localScale; Vector3 targetScale = originalScale * maxScale; DOTween.Kill(_comboText.transform); Sequence sequence = DOTween.Sequence(); sequence.SetTarget(_comboText.transform); sequence.Append(_comboText.transform.DOScale(targetScale, bounceDuration / 2).SetEase(Ease.OutQuad)) .Append(_comboText.transform.DOScale(originalScale, bounceDuration / 2).SetEase(Ease.InQuad)); } }