diff --git a/Gameton-06/Assets/Gameton/Scripts/UI/RouletteSpin/Roulette.cs b/Gameton-06/Assets/Gameton/Scripts/UI/RouletteSpin/Roulette.cs index d9f90f8c..af769742 100644 --- a/Gameton-06/Assets/Gameton/Scripts/UI/RouletteSpin/Roulette.cs +++ b/Gameton-06/Assets/Gameton/Scripts/UI/RouletteSpin/Roulette.cs @@ -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 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().Setup(roulettePieceData[i]); - // 생성한 룰렛 조각 회전 + var pieceUI = piece.GetComponent(); + 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 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 action) + public void Spin(System.Action 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(); } } } diff --git a/Gameton-06/Assets/Gameton/Scripts/UI/RouletteSpin/RoulettePiecePresenter.cs b/Gameton-06/Assets/Gameton/Scripts/UI/RouletteSpin/RoulettePiecePresenter.cs new file mode 100644 index 00000000..68f48d64 --- /dev/null +++ b/Gameton-06/Assets/Gameton/Scripts/UI/RouletteSpin/RoulettePiecePresenter.cs @@ -0,0 +1,26 @@ +using UniRx; +using UnityEngine; + +namespace TON +{ + public class RoulettePiecePresenter + { + public ReactiveProperty Icon { get; } + public ReactiveProperty Description { get; } + public ReactiveProperty Chance { get; } + public ReactiveProperty Index { get; } + public ReactiveProperty Weight { get; } + + public RoulettePieceData Model { get; } + + public RoulettePiecePresenter(RoulettePieceData model) + { + Model = model; + Icon = new ReactiveProperty(model.icon); + Description = new ReactiveProperty(model.description); + Chance = new ReactiveProperty(model.chance); + Index = new ReactiveProperty(model.index); + Weight = new ReactiveProperty(model.weight); + } + } +} \ No newline at end of file diff --git a/Gameton-06/Assets/Gameton/Scripts/UI/RouletteSpin/RoulettePiecePresenter.cs.meta b/Gameton-06/Assets/Gameton/Scripts/UI/RouletteSpin/RoulettePiecePresenter.cs.meta new file mode 100644 index 00000000..d1910e86 --- /dev/null +++ b/Gameton-06/Assets/Gameton/Scripts/UI/RouletteSpin/RoulettePiecePresenter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 322f049f974a11c4d8b04937b20b2180 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Gameton-06/Assets/Gameton/Scripts/UI/RouletteSpin/RoulettePresenter.cs b/Gameton-06/Assets/Gameton/Scripts/UI/RouletteSpin/RoulettePresenter.cs index 325ad67d..3ee4772b 100644 --- a/Gameton-06/Assets/Gameton/Scripts/UI/RouletteSpin/RoulettePresenter.cs +++ b/Gameton-06/Assets/Gameton/Scripts/UI/RouletteSpin/RoulettePresenter.cs @@ -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 roulettePieceModels = new(); - public ReactiveCollection RoulettePieces { get; } = new(); - - public RoulettePresenter() - { - // 싱글톤으로 PlayerDataManager 접근 - playerDataManager = PlayerDataManager.Singleton; + public ReactiveCollection RoulettePieces { get; } = new(); + public ReactiveProperty IsSpinning { get; } = new(false); + public ReactiveProperty 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 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}"); + } } } } diff --git a/Gameton-06/Assets/Gameton/Scripts/UI/RouletteSpin/RouletteSpin.cs b/Gameton-06/Assets/Gameton/Scripts/UI/RouletteSpin/RouletteSpin.cs index cbf14ac0..2ae81b18 100644 --- a/Gameton-06/Assets/Gameton/Scripts/UI/RouletteSpin/RouletteSpin.cs +++ b/Gameton-06/Assets/Gameton/Scripts/UI/RouletteSpin/RouletteSpin.cs @@ -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 Description { get; set; } - public ReactiveProperty Chance { get; set; } - - public ReactiveCommand BuyCommand { get; set; } - - private RoulettePieceData _model; - - public RouletteItemPresenter(RoulettePresenter roulettePresenter, RoulettePieceData model) - { - _model = model; - - Description = new ReactiveProperty(model.description); - Chance = new ReactiveProperty(model.chance); - - BuyCommand = new ReactiveCommand(); - BuyCommand.Subscribe(_ => roulettePresenter.InsertRouletteResult(this)); - } } }