룰렛 MVP 패턴으로 수정
This commit is contained in:
		@@ -2,7 +2,7 @@ using UnityEngine;
 | 
			
		||||
using UnityEngine.Events;
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using UniRx;
 | 
			
		||||
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace TON
 | 
			
		||||
{
 | 
			
		||||
@@ -27,6 +27,9 @@ namespace TON
 | 
			
		||||
        private bool isSpinning = false;    // 현재 회전중인지
 | 
			
		||||
        private int selectedIndex = 0;  // 룰렛에서 선택된 아이템
 | 
			
		||||
        
 | 
			
		||||
        private RoulettePresenter presenter;
 | 
			
		||||
        private List<RoulettePiece> pieceUIs = new();
 | 
			
		||||
 | 
			
		||||
        private void Awake()
 | 
			
		||||
        {
 | 
			
		||||
            pieceAngle = 360 / roulettePieceData.Length;
 | 
			
		||||
@@ -39,16 +42,15 @@ namespace TON
 | 
			
		||||
 | 
			
		||||
        private void SpawnPiecesAndLines()
 | 
			
		||||
        {
 | 
			
		||||
            for (int i = 0; i < roulettePieceData.Length; ++i)
 | 
			
		||||
            for (int i = 0; i < presenter.RoulettePieces.Count; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                Transform piece = Instantiate(piecePrefab, pieceParent.position, Quaternion.identity, pieceParent);
 | 
			
		||||
                // 생성한 룰렛 조각의 정보 설정(아이콘, 설명)
 | 
			
		||||
                piece.GetComponent<RoulettePiece>().Setup(roulettePieceData[i]);
 | 
			
		||||
                // 생성한 룰렛 조각 회전
 | 
			
		||||
                var pieceUI = piece.GetComponent<RoulettePiece>();
 | 
			
		||||
                pieceUI.Setup(presenter.RoulettePieces[i].Model);
 | 
			
		||||
                piece.RotateAround(pieceParent.position, Vector3.back, (pieceAngle * i));
 | 
			
		||||
                
 | 
			
		||||
                pieceUIs.Add(pieceUI);
 | 
			
		||||
 | 
			
		||||
                Transform line = Instantiate(linePrefab, lineParent.position, Quaternion.identity, lineParent);
 | 
			
		||||
                // 생성한 선 회전 (룰렛 조각 사이를 구분하는 용도
 | 
			
		||||
                line.RotateAround(lineParent.position, Vector3.back, (pieceAngle * i) + halfPieceAngle);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -87,50 +89,48 @@ namespace TON
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Spin(UnityAction<RoulettePieceData> action = null)
 | 
			
		||||
        public void Bind(RoulettePresenter presenter)
 | 
			
		||||
        {
 | 
			
		||||
            if(isSpinning == true)  return;
 | 
			
		||||
            
 | 
			
		||||
            // 룰렛의 결과 값 선택
 | 
			
		||||
            selectedIndex = GetRandomIndex();
 | 
			
		||||
            // 선택된 결과의 중심 각도
 | 
			
		||||
            float angle = pieceAngle * selectedIndex;
 | 
			
		||||
            // 정확히 중심이 아닌 결과 값 범위 안의 임의의 각도 선택
 | 
			
		||||
            float leftOffset = (angle - halfPieceAngleWithPaddings) % 360;
 | 
			
		||||
            float rightOffset = (angle + halfPieceAngleWithPaddings) % 360;
 | 
			
		||||
            float randomAngle = Random.Range(leftOffset, rightOffset);
 | 
			
		||||
            
 | 
			
		||||
            // 목표 각도(targetAngle) = 결과 각도 + 360 * 회전 시간 * 회전 속도
 | 
			
		||||
            int rotateSpeed = 2;
 | 
			
		||||
            float targetangle = (randomAngle + 360 * spinDuration * rotateSpeed);
 | 
			
		||||
            
 | 
			
		||||
            Debug.Log($"SelectedIndex:{selectedIndex}, angle:{angle}");
 | 
			
		||||
            Debug.Log($"left/right/random:{leftOffset}/{rightOffset}/{randomAngle}");
 | 
			
		||||
            Debug.Log($"targetAngle:{targetangle}");
 | 
			
		||||
            
 | 
			
		||||
            isSpinning = true;
 | 
			
		||||
            StartCoroutine(OnSpin(targetangle, action));
 | 
			
		||||
            this.presenter = presenter;
 | 
			
		||||
            pieceAngle = 360f / roulettePieceData.Length;
 | 
			
		||||
            halfPieceAngle = pieceAngle * 0.5f;
 | 
			
		||||
            halfPieceAngleWithPaddings = halfPieceAngle - (halfPieceAngle * 0.25f);
 | 
			
		||||
            SpawnPiecesAndLines();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private IEnumerator OnSpin(float end, UnityAction<RoulettePieceData> action)
 | 
			
		||||
        public void Spin(System.Action<RoulettePiecePresenter> onEnd)
 | 
			
		||||
        {
 | 
			
		||||
            if (presenter.IsSpinning.Value) return;
 | 
			
		||||
            presenter.Spin(selectedPresenter =>
 | 
			
		||||
            {
 | 
			
		||||
                int selectedIndex = selectedPresenter.Index.Value;
 | 
			
		||||
                float angle = pieceAngle * selectedIndex;
 | 
			
		||||
                float leftOffset = (angle - halfPieceAngleWithPaddings) % 360;
 | 
			
		||||
                float rightOffset = (angle + halfPieceAngleWithPaddings) % 360;
 | 
			
		||||
                float randomAngle = Random.Range(leftOffset, rightOffset);
 | 
			
		||||
                int rotateSpeed = 2;
 | 
			
		||||
                float targetangle = (randomAngle + 360 * spinDuration * rotateSpeed);
 | 
			
		||||
                StartCoroutine(OnSpin(targetangle, () =>
 | 
			
		||||
                {
 | 
			
		||||
                    presenter.IsSpinning.Value = false;
 | 
			
		||||
                    onEnd?.Invoke(selectedPresenter);
 | 
			
		||||
                }));
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private System.Collections.IEnumerator OnSpin(float end, System.Action onEnd)
 | 
			
		||||
        {
 | 
			
		||||
            float current = 0;
 | 
			
		||||
            float percent = 0;
 | 
			
		||||
 | 
			
		||||
            while (percent < 1)
 | 
			
		||||
            {
 | 
			
		||||
                current = Time.deltaTime;
 | 
			
		||||
                percent += current / spinDuration;
 | 
			
		||||
                
 | 
			
		||||
                float z = Mathf.Lerp(0, end, spinningCurve.Evaluate(percent));
 | 
			
		||||
                spinningRoulette.rotation = Quaternion.Euler(0, 0, z);
 | 
			
		||||
 | 
			
		||||
                yield return null;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            isSpinning = false;
 | 
			
		||||
            
 | 
			
		||||
            if(action != null) action.Invoke(roulettePieceData[selectedIndex]);
 | 
			
		||||
            onEnd?.Invoke();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,26 @@
 | 
			
		||||
using UniRx;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
 | 
			
		||||
namespace TON
 | 
			
		||||
{
 | 
			
		||||
    public class RoulettePiecePresenter
 | 
			
		||||
    {
 | 
			
		||||
        public ReactiveProperty<Sprite> Icon { get; }
 | 
			
		||||
        public ReactiveProperty<string> Description { get; }
 | 
			
		||||
        public ReactiveProperty<int> Chance { get; }
 | 
			
		||||
        public ReactiveProperty<int> Index { get; }
 | 
			
		||||
        public ReactiveProperty<int> Weight { get; }
 | 
			
		||||
 | 
			
		||||
        public RoulettePieceData Model { get; }
 | 
			
		||||
 | 
			
		||||
        public RoulettePiecePresenter(RoulettePieceData model)
 | 
			
		||||
        {
 | 
			
		||||
            Model = model;
 | 
			
		||||
            Icon = new ReactiveProperty<Sprite>(model.icon);
 | 
			
		||||
            Description = new ReactiveProperty<string>(model.description);
 | 
			
		||||
            Chance = new ReactiveProperty<int>(model.chance);
 | 
			
		||||
            Index = new ReactiveProperty<int>(model.index);
 | 
			
		||||
            Weight = new ReactiveProperty<int>(model.weight);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
} 
 | 
			
		||||
@@ -0,0 +1,11 @@
 | 
			
		||||
fileFormatVersion: 2
 | 
			
		||||
guid: 322f049f974a11c4d8b04937b20b2180
 | 
			
		||||
MonoImporter:
 | 
			
		||||
  externalObjects: {}
 | 
			
		||||
  serializedVersion: 2
 | 
			
		||||
  defaultReferences: []
 | 
			
		||||
  executionOrder: 0
 | 
			
		||||
  icon: {instanceID: 0}
 | 
			
		||||
  userData: 
 | 
			
		||||
  assetBundleName: 
 | 
			
		||||
  assetBundleVariant: 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using UniRx;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
@@ -9,42 +9,64 @@ namespace TON
 | 
			
		||||
    {
 | 
			
		||||
        private PlayerDataManager playerDataManager;
 | 
			
		||||
        private List<RoulettePieceData> roulettePieceModels = new();
 | 
			
		||||
        public ReactiveCollection<RoulettePresenter> RoulettePieces { get; } = new();
 | 
			
		||||
        
 | 
			
		||||
        public RoulettePresenter()
 | 
			
		||||
        {
 | 
			
		||||
            // 싱글톤으로 PlayerDataManager 접근
 | 
			
		||||
            playerDataManager = PlayerDataManager.Singleton;
 | 
			
		||||
        public ReactiveCollection<RoulettePiecePresenter> RoulettePieces { get; } = new();
 | 
			
		||||
        public ReactiveProperty<bool> IsSpinning { get; } = new(false);
 | 
			
		||||
        public ReactiveProperty<RoulettePiecePresenter> SelectedPiece { get; } = new();
 | 
			
		||||
        private int accumulatedWeight;
 | 
			
		||||
 | 
			
		||||
        public RoulettePresenter(RoulettePieceData[] pieceDataArray)
 | 
			
		||||
        {
 | 
			
		||||
            playerDataManager = PlayerDataManager.Singleton;
 | 
			
		||||
            if (playerDataManager == null)
 | 
			
		||||
            {
 | 
			
		||||
                Debug.LogError("PlayerDataManager가 초기화되지 않았습니다.");
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Todo : UI 바인딩
 | 
			
		||||
            
 | 
			
		||||
            roulettePieceModels.Add(new RoulettePieceData("10",  1));
 | 
			
		||||
            roulettePieceModels.Add(new RoulettePieceData("2",  14));
 | 
			
		||||
            roulettePieceModels.Add(new RoulettePieceData("25",  1));
 | 
			
		||||
            roulettePieceModels.Add(new RoulettePieceData("400",  72));
 | 
			
		||||
            roulettePieceModels.Add(new RoulettePieceData("50",  1));
 | 
			
		||||
            roulettePieceModels.Add(new RoulettePieceData("1000",  11));
 | 
			
		||||
 | 
			
		||||
            foreach (var item in roulettePieceModels)
 | 
			
		||||
            accumulatedWeight = 0;
 | 
			
		||||
            for (int i = 0; i < pieceDataArray.Length; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                RoulettePieces.Add(new RoulettePresenter(this, item));
 | 
			
		||||
                var data = pieceDataArray[i];
 | 
			
		||||
                data.index = i;
 | 
			
		||||
                if (data.chance <= 0) data.chance = 1;
 | 
			
		||||
                accumulatedWeight += data.chance;
 | 
			
		||||
                data.weight = accumulatedWeight;
 | 
			
		||||
                roulettePieceModels.Add(data);
 | 
			
		||||
                RoulettePieces.Add(new RoulettePiecePresenter(data));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 재화 획득 메서드
 | 
			
		||||
        public void InsertRouletteResult(RoulettePieceData selectedData)
 | 
			
		||||
        public int GetRandomIndex()
 | 
			
		||||
        {
 | 
			
		||||
            // 재화 획득 코드 추가
 | 
			
		||||
            playerDataManager.AddGold(int.Parse(selectedData.description));
 | 
			
		||||
            
 | 
			
		||||
            // UI 갱신 코드 추가
 | 
			
		||||
            UIManager.Singleton.UpdateCashData();
 | 
			
		||||
            Debug.Log($"{selectedData.index}:{selectedData.description}");
 | 
			
		||||
            int weight = UnityEngine.Random.Range(0, accumulatedWeight);
 | 
			
		||||
            for (int i = 0; i < roulettePieceModels.Count; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                if (roulettePieceModels[i].weight > weight)
 | 
			
		||||
                {
 | 
			
		||||
                    return i;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Spin(Action<RoulettePiecePresenter> onResult = null)
 | 
			
		||||
        {
 | 
			
		||||
            if (IsSpinning.Value) return;
 | 
			
		||||
            IsSpinning.Value = true;
 | 
			
		||||
            int selectedIndex = GetRandomIndex();
 | 
			
		||||
            var selected = RoulettePieces[selectedIndex];
 | 
			
		||||
            SelectedPiece.Value = selected;
 | 
			
		||||
            onResult?.Invoke(selected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 결과 처리(예: 골드 지급 등)
 | 
			
		||||
        public void InsertRouletteResult(RoulettePiecePresenter selectedPresenter)
 | 
			
		||||
        {
 | 
			
		||||
            if (playerDataManager != null && int.TryParse(selectedPresenter.Description.Value, out int gold))
 | 
			
		||||
            {
 | 
			
		||||
                playerDataManager.AddGold(gold);
 | 
			
		||||
                UIManager.Singleton.UpdateCashData();
 | 
			
		||||
                Debug.Log($"{selectedPresenter.Index.Value}:{selectedPresenter.Description.Value}");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,65 +1,33 @@
 | 
			
		||||
 using System;
 | 
			
		||||
 using System.Collections;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using UniRx;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
using UnityEngine.UI;
 | 
			
		||||
 
 | 
			
		||||
using UniRx;
 | 
			
		||||
 | 
			
		||||
namespace TON
 | 
			
		||||
{
 | 
			
		||||
    // View <> Presenter <> Model
 | 
			
		||||
    // View
 | 
			
		||||
    public class RouletteSpin : MonoBehaviour
 | 
			
		||||
    {
 | 
			
		||||
        [SerializeField] private Roulette roulette;
 | 
			
		||||
        [SerializeField] private Button buttonSpin;
 | 
			
		||||
        
 | 
			
		||||
        // TODO : Roulette 변수 선언
 | 
			
		||||
 | 
			
		||||
        private RoulettePresenter roulettePresenter;
 | 
			
		||||
 | 
			
		||||
        private void Start()
 | 
			
		||||
        {
 | 
			
		||||
            // Presenter 초기화
 | 
			
		||||
            roulettePresenter = new RoulettePresenter();
 | 
			
		||||
            // TODO : UI와 Presenter 바인딩
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void Awake()
 | 
			
		||||
        {
 | 
			
		||||
            buttonSpin.onClick.AddListener(()=>
 | 
			
		||||
            roulettePresenter = new RoulettePresenter(roulette.roulettePieceData);
 | 
			
		||||
            roulette.Bind(roulettePresenter);
 | 
			
		||||
            buttonSpin.onClick.AddListener(() =>
 | 
			
		||||
            {
 | 
			
		||||
                   buttonSpin.interactable = false;
 | 
			
		||||
                   roulette.Spin(EndOfSpin);
 | 
			
		||||
                buttonSpin.interactable = false;
 | 
			
		||||
                roulette.Spin(selectedPresenter =>
 | 
			
		||||
                {
 | 
			
		||||
                    buttonSpin.interactable = true;
 | 
			
		||||
                    roulettePresenter.InsertRouletteResult(selectedPresenter);
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void EndOfSpin(RoulettePieceData selectedData)
 | 
			
		||||
        {
 | 
			
		||||
            buttonSpin.interactable = true;
 | 
			
		||||
 | 
			
		||||
            roulettePresenter.InsertRouletteResult(selectedData);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Presenter
 | 
			
		||||
    public class RouletteItemPresenter
 | 
			
		||||
    {
 | 
			
		||||
        public ReactiveProperty<string> Description { get; set; }
 | 
			
		||||
        public ReactiveProperty<int> Chance { get; set; }
 | 
			
		||||
        
 | 
			
		||||
        public ReactiveCommand BuyCommand { get; set; }
 | 
			
		||||
        
 | 
			
		||||
        private RoulettePieceData _model;
 | 
			
		||||
 | 
			
		||||
        public RouletteItemPresenter(RoulettePresenter roulettePresenter, RoulettePieceData model)
 | 
			
		||||
        {
 | 
			
		||||
            _model = model;
 | 
			
		||||
            
 | 
			
		||||
            Description = new ReactiveProperty<string>(model.description);
 | 
			
		||||
            Chance = new ReactiveProperty<int>(model.chance);
 | 
			
		||||
 | 
			
		||||
            BuyCommand = new ReactiveCommand();
 | 
			
		||||
            BuyCommand.Subscribe(_ => roulettePresenter.InsertRouletteResult(this));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user