Game Client Lee Hwanguk 2023. 4. 15. 05:54

#기존에 만든 주사위에서 몇가지 수정해야 할 부분이 있었다
 1. 주사위가 한쪽으로만 돌아간다(랜덤한 힘을 주었지만 레인지의 범위가 좁아 계속 같은 힘을 받는 것처럼 보였다)
 
 2. 주사위의 6면을 물음표 이미지로 바꿨다 (물음표 이미지의 주사위가 돌아가다가 멈추면 해당 면에 당첨된 아이템이 나오게 수정했다)
 
 3. 주사위의 결과를 코루틴으로 제어하니 억지스러운 연출이 나왔다(움직임이 멈추면 주사위의 결과가 보여지도록 .velocity.magnitude ==0 이라는 조건문으로 제어했다)
 
 4. 주사위의 결과 이미지를 AtlasManager와 연동시켜 해당 아이템의 정보까지 볼수 있도록 만들어야한다
 
 5. 주사위는 항상 같은 면의 결과가 나오게 컨트롤 하였고 정해진 수치의 확률에 따라 결과가 나오도록 확률 데이터를 연동시켜야했다. (데이터 테이블이 필요할지 정해진 수치를 메서드화 하여 오브잭트가 가지고 있게해야할지 고민된다.)
 
6.주사위가 돌아가는 동안은 UI창의 닫기 기능이 활성화 되면 안된다. (Close버튼과 dim버튼 비활성화)
 
7. 주사위의 결과를 확인하려면 해당 이미지를 터치하고 있는동안 결과 아이템의 자세한 스펙을 확인 할 수 있게 로직을 만들어보자. 
 
8. 이외의 다른 로직은 동일하다.
 
#아틀라스 매니져 오브잭트를 만들고 주사위 결과에 따라 해당 스프라이트로 보여지게 연출하자
 1. 열거형으로 아이템의 등급 (다이아,골드,아이언,우드), 아이템의 타입(활,도끼,검,완드,풀 회복, 하나회복)을 지정하고
      Random.Range를 통해 해당 숫자가 나오면 등급과 타입을 정해주고 아틀라스를 가져왔다
 2. 문자열 결합을 통해 "등급_타입" 으로 만들고 아틀라스를 가져왔다
 
#스크립트
*AtlasManager

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.U2D;

public class AtlasManager : MonoBehaviour
{
    public static AtlasManager instance;

    public SpriteAtlas UIWeaponIconAtlas;
    public SpriteAtlas UISkillIconAtlas;
    public SpriteAtlas UIEquipmentIconAtlas;
    public SpriteAtlas UIRewardIconAtlas;
    public Dictionary<string, SpriteAtlas> dicIconAtals = new Dictionary<string, SpriteAtlas>();

    public void Awake()
    {
        instance = this;
        var WeaponIconatlasName = UIWeaponIconAtlas.name.Replace("Atlas","");
        var SkillIconatlasName = UISkillIconAtlas.name.Replace("Atlas","");
        var EquipmentIconatlasName = UIEquipmentIconAtlas.name.Replace("Atlas","");
        var RewardIconName = UIRewardIconAtlas.name.Replace("Atlas", "");

        this.dicIconAtals.Add(WeaponIconatlasName, UIWeaponIconAtlas);
        this.dicIconAtals.Add(SkillIconatlasName, UISkillIconAtlas);
        this.dicIconAtals.Add(EquipmentIconatlasName, UIEquipmentIconAtlas);
        this.dicIconAtals.Add(RewardIconName, UIRewardIconAtlas);
    }

    public SpriteAtlas GetAtlasByName(string name)
    {
        return this.dicIconAtals[name];
    }

}

*UIDiceDirector

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UI;

public class UIDiceDirector : MonoBehaviour
{
    public UIDice uiDice;
    public Button btnDice;
    private void Awake()
    {
        this.uiDice.Init();

        this.btnDice.onClick.AddListener(() => {
            this.uiDice.gameObject.SetActive(true);
        });


    }

}

*UIDice

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.U2D;
using UnityEngine.UI;

public class UIDice : MonoBehaviour
{
    public Button closeBtn;
    public GameObject btnGo;
    private Button rollBtn;
    public DiceScript dice;
    public Button dim;

    private void Start()
    {
        Debug.Log("UIDice");
    }
    public void Init()
    {
        this.dice.Init();
        this.rollBtn = this.btnGo.GetComponent<Button>();
        this.closeBtn.onClick.AddListener(() => { 
            this.gameObject.SetActive(false);
        });
        this.dim.onClick.AddListener(() => {
            this.gameObject.SetActive(false);
        });
        this.rollBtn.onClick.AddListener(() => { //돌고 있는 중이면 또 눌리면 안됨
            this.dice.RollDice();
            this.rollBtn.interactable=false; //button컴포넌트 비활성화
            StartCoroutine(this.DiceBtnSetting());
            this.BtnGoColorDown();
            this.dice.DiceResultImgInit();
            this.closeBtn.interactable = false;
            this.dim.interactable = false;
            
        });
    }

    private IEnumerator DiceBtnSetting()
    {
        while (true)
        {
            yield return new WaitForSeconds(0.5f);

            if (this.dice.rb.velocity.magnitude == 0)
            {
                this.dice.StopDice();
                this.rollBtn.interactable = true;
                this.BtnGoColorUp();
                this.dice.DiceResultImg();
                this.closeBtn.interactable = true;
                this.dim.interactable = true;

                //PercentageTest
                this.dice.GradePercentage();
                this.dice.TypePercentage();
                yield break;
            }           
        }
    }

    private void BtnGoColorDown() //알파값 down
    {
        var imgBoxGo=this.btnGo.transform.Find("imgBox").GetComponent<Image>();
        var txtSelectGo = this.btnGo.transform.Find("txtSelect").GetComponent<Text>();

        Color imgBoxGoColor = imgBoxGo.color;
        imgBoxGoColor.a = 0.5f;
        imgBoxGo.color= imgBoxGoColor;

        Color txtSelectGoColor= txtSelectGo.color;
        txtSelectGoColor.a = 0.5f;
        txtSelectGo.color= txtSelectGoColor;
    }
    private void BtnGoColorUp() //알파값 up
    {
        var imgBoxGo = this.btnGo.transform.Find("imgBox").GetComponent<Image>();
        var txtSelectGo = this.btnGo.transform.Find("txtSelect").GetComponent<Text>();

        Color imgBoxGoColor = imgBoxGo.color;
        imgBoxGoColor.a = 1f;
        imgBoxGo.color = imgBoxGoColor;

        Color txtSelectGoColor = txtSelectGo.color;
        txtSelectGoColor.a = 1f;
        txtSelectGo.color = txtSelectGoColor;
    }

}

*DiceScript

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
using UnityEngine.UI;

public class DiceScript : MonoBehaviour
{
    private enum ErewardGrade  
    {
        Wood=0,
        Iron=1,
        Gold=2,
        Diamond=3
    }
    private enum ErewardType
    {
        Arrow=0,
        Axe=1,
        Sword=2,
        Wand=3,
        FullFood=4,
        OneFood=5
    }
    private ErewardType eRewardType;
    private ErewardGrade eRewardGrade;


    public Rigidbody rb;
    public GameObject[] resultImg; // 0 - before이미지 , 1 - after이미지
    void Start()
    {
        this.rb = GetComponent<Rigidbody>();

    }
    public void Init()
    {
        this.transform.localPosition = new Vector3(-978.4013f, -589.6378f, -0.42f);
        this.transform.rotation= Quaternion.Euler(0f, 65.3f, -90f);
    }
    public void RollDice()
    {
        this.rb.isKinematic = false;
        float dirX = Random.Range(200, 700); //랜덤레인지의 폭이 좁을수록 비슷한 연출이 나옴
        float dirY = Random.Range(200, 700);
        float dirZ = Random.Range(200, 700);
        this.transform.position = new Vector3(0, 3f, 0); //높이 y=3 로 고정
        this.transform.rotation = Quaternion.identity; //회전 -> 0, 안하면 다른 위치의 y축에서 떨어짐 
        rb.AddForce(this.transform.up * 500); //y축으로 500만큼의 힘을 가하다
        rb.AddTorque(dirX, dirY, dirZ); //3개의 축(x,y,z)에 랜덤한 힘(0~500까지의 랜덤한 수)으로 회전하는 힘을 가한다
    }

    //회전 멈춤, 위치고정
    public void StopDice()
    {
        this.rb.isKinematic = true;
        this.transform.DOMove(new Vector3(0, 2.5f, 0), 2f).SetEase(Ease.OutCirc);
        Quaternion targetRotation = Quaternion.Euler(0f, -24.752f, 0f);
        this.transform.DORotate(targetRotation.eulerAngles, 0.01f).SetEase(Ease.OutCirc);
    }

    //percentage(확률 컨트롤)
    public void GradePercentage()
    {
        int ranGrade=Random.Range(0,3);        
        this.eRewardGrade = (ErewardGrade)ranGrade;
        //Debug.LogFormat("Grade:{0}", this.eRewardGrade); 
        //소모아이템 frame은 Iron으로 고정
        if (this.eRewardType == ErewardType.OneFood || this.eRewardType == ErewardType.FullFood)
        {
            this.eRewardGrade=ErewardGrade.Iron;
        }
    }
    public void TypePercentage()
    {
        int ranType = Random.Range(0, 5);
        this.eRewardType = (ErewardType)ranType;
        //Debug.LogFormat("Type:{0}", this.eRewardType);
    }
    public string ResultIcon()
    {
        var resultGrade = this.eRewardGrade.ToString();
        var resultType = this.eRewardType.ToString();       
        var resultIcon = resultGrade + "_" + resultType;
        if (resultType == "FullFood" || resultType == "OneFood")
        {
            resultIcon = resultType;
        }
        //Debug.LogFormat("<Color=red>resultIcon:{0}</Color>", resultIcon);
        return resultIcon;
    }
    public void ShowResultIcon()
    {
        var resultSprite = this.resultImg[0].GetComponent<SpriteRenderer>(); //Icon
        var resultSpriteAtlas = AtlasManager.instance.GetAtlasByName("UIEquipmentIcon");
        //Debug.LogFormat("ResultIcon:{0}", ResultIcon());
        resultSprite.sprite = resultSpriteAtlas.GetSprite(ResultIcon());
        this.resultImg[0].gameObject.transform.localScale = new Vector3(2.5f, 2.5f, 2.5f);
    }

    //스프라이트 이미지 교체(확률 컨트롤이 필요함)
    public void DiceResultImg()
    {
        this.resultImg[0].gameObject.SetActive(true); //Icon ->Type
        this.resultImg[1].gameObject.SetActive(true); //Frame ->Grade
        this.resultImg[2].gameObject.SetActive(false); //InitIcon
        this.ShowResultIcon();

    }
    public void DiceResultImgInit()
    {
        this.resultImg[0].gameObject.SetActive(false); //Icon
        this.resultImg[1].gameObject.SetActive(false); //Frame
        this.resultImg[2].gameObject.SetActive(true); //InitIcon
    }

    

}

 
#영상

*아이템의 info를 어떻게 유저에게 보여줄지 고민이 된다

#연출적인 면은 크게 수정할 부분이 없었지만 디테일한 부분들을 수정하는데 시간을 많이 썼다
 이제 해당 결과아이템의 info를 불러오고 유저에게 어떤식으로 보여줄지 고민하면 될 것 같다
 유저가 터치하는 동안 보여줄지 팝업을 띄워서 보여줄지 기기 테스트를 통하여 유저가 편한 방법을 택해야겠다