프로젝트/건즈앤 레이첼스

[유니티 프로젝트] 인벤토리 스탯창 구현 .2 - 유저 스탯창 마무리

Bueong_E 2023. 4. 10. 23:48
반응형
SMALL

유저의 스탯을 관리하는 UI 제작을 완료하였다.

 

구현한 기능은 아래와 같다.

  • 현재 유저가 장착중인 무기 종류에 따라 바뀌는 무기 이미지 및 스킬 아이콘 변경 (info매니저 & atlas 매니저 참조)
  • 유저의 능력치 상승시 영구적인 상승과 일시적인 상능 기능 분리(info 매니저 메서드 생성)
  • 스킬 셋 이미지 터치시 팝업창 팝업, 상세 스킬별 상세 정보 확인 (손을 뗄시 팝업창 닫기)
  • 무기의 스탯 및 숙련도 info 매니저 참조를 통한 실시간 변경

 

코드

UIWeaponCharacteristic

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

public class UIWeaponCharacteristic : MonoBehaviour
{
    [SerializeField]
    private Text txtWeaponProficiency;
    [SerializeField]
    private Slider WeaponProficiencySlider;
    [SerializeField]
    private Text txtWeaponProficiencySlider;


    [SerializeField]
    private Image imgWeapon_Icon;
    [SerializeField]
    private Image WeaponSkill1_Icon;
    [SerializeField]
    private Image WeaponSkill2_Icon;
    [SerializeField]
    private Image WeaponSkill3_Icon;

    [SerializeField]
    private Text txtBulletAmount;
    [SerializeField]
    private Text txtPenetrate;
    [SerializeField]
    private Text txtkNockBackCharacteristic;
    [SerializeField]
    private Text txtkMovespeedCharacteristic;
    [SerializeField]
    private Text txtDashRecover;

    [SerializeField]
    private UIWeaponSkillPopUp uiWeaponSkillPopUp;

    public Action<Vector3,string> onSkillPopup;
    public Action onSkillPopupClose;

    private SpriteAtlas weaponIconAtlas;
    private SpriteAtlas skillIconAtlas;


    public void Init()
    {
        this.onSkillPopup = (pos,skillName) =>
        {
            this.uiWeaponSkillPopUp.gameObject.SetActive(true);
            this.uiWeaponSkillPopUp.RefreshPopup(skillName);
            this.uiWeaponSkillPopUp.transform.localPosition = new Vector3(pos.x, pos.y+5, pos.z);
        };
        this.onSkillPopupClose = () =>
        {
            this.uiWeaponSkillPopUp.gameObject.SetActive(false);
        };

        this.weaponIconAtlas = AtlasManager.instance.GetAtlasByName("UIWeaponIcon");
        this.skillIconAtlas = AtlasManager.instance.GetAtlasByName("UISkillIcon");
        this.RefreshWeaponStat();

        this.uiWeaponSkillPopUp.Init();
    }

    private void OnEnable()
    {
        this.RefreshWeaponStat();
    }

    public void RefreshWeaponStat()
    {
        this.SetWeaponIcon();
        this.SetWeaponProficiency();
        this.SetWeaponCharactoristic();
    }

    /// <summary>
    /// 무기 아이콘 업데이트
    /// </summary>
    public void SetWeaponIcon()
    {
        this.imgWeapon_Icon.sprite = this.weaponIconAtlas.GetSprite(InfoManager.instance.charactoristicInfo.currentWeaponName);
        this.SetSkillIcon();
    }

    /// <summary>
    /// 무기 숙련도 업데이트
    /// </summary>
    public void SetWeaponProficiency()
    {
        this.txtWeaponProficiency.text = string.Format("숙련도 : {0}", InfoManager.instance.charactoristicInfo.weaponProficiencyLevel);
        this.WeaponProficiencySlider.value = InfoManager.instance.charactoristicInfo.weaponProficiencyEXP * 0.01f;
        this.txtWeaponProficiencySlider.text = string.Format("{0}/{1}", InfoManager.instance.charactoristicInfo.weaponProficiencyEXP * 100 , 100);
    }

    /// <summary>
    /// 무기 특성 업데이트
    /// </summary>
    public void SetWeaponCharactoristic()
    {
        this.txtBulletAmount.text = string.Format("총알 갯수 : {0}", 1);
        this.txtPenetrate.text = string.Format("관통력 : {0}", 1);
        this.txtkNockBackCharacteristic.text = string.Format("넉백 : {0}", 1);
        this.txtkMovespeedCharacteristic.text = string.Format("이동속도 : {0}", 1);
        this.txtDashRecover.text = string.Format("대시 회복 : {0}", 1);
    }
  
    /// <summary>
    /// 스킬 아이콘 업데이트
    /// </summary>
    public void SetSkillIcon()
    {
        switch (InfoManager.instance.charactoristicInfo.currentWeaponName)
        {
            case "AK47":
                this.WeaponSkill1_Icon.sprite = this.skillIconAtlas.GetSprite("IconAssultRifleSkill_01");
                this.WeaponSkill2_Icon.sprite = this.skillIconAtlas.GetSprite("IconAssultRifleSkill_02");
                this.WeaponSkill3_Icon.sprite = this.skillIconAtlas.GetSprite("IconAssultRifleSkill_03");
                break;
            case "SPAS-12":
                this.WeaponSkill1_Icon.sprite = this.skillIconAtlas.GetSprite("IconShotGunSkill_01");
                this.WeaponSkill2_Icon.sprite = this.skillIconAtlas.GetSprite("IconShotGunSkill_02");
                this.WeaponSkill3_Icon.sprite = this.skillIconAtlas.GetSprite("IconShotGunSkill_03");
                break;
            case "AWP":
                this.WeaponSkill1_Icon.sprite = this.skillIconAtlas.GetSprite("IconSniperRifleSkill_01");
                this.WeaponSkill2_Icon.sprite = this.skillIconAtlas.GetSprite("IconSniperRifleSkill_02");
                this.WeaponSkill3_Icon.sprite = this.skillIconAtlas.GetSprite("IconSniperRifleSkill_03");
                break;
            case "UZI":
                this.WeaponSkill1_Icon.sprite = this.skillIconAtlas.GetSprite("IconSubmachineGunSkill_01");
                this.WeaponSkill2_Icon.sprite = this.skillIconAtlas.GetSprite("IconSubmachineGunSkill_02");
                this.WeaponSkill3_Icon.sprite = this.skillIconAtlas.GetSprite("IconSubmachineGunSkill_03");
                break;
        }
    }

    // 테스트용
    void Update()
    {
        if(Input.GetMouseButtonDown(1))
        {
            if(InfoManager.instance.charactoristicInfo.currentWeaponName == "AK47")
            {
                InfoManager.instance.charactoristicInfo.currentWeaponName = "AWP";
                this.SetWeaponIcon();
            }
            else if (InfoManager.instance.charactoristicInfo.currentWeaponName == "AWP")
            {
                InfoManager.instance.charactoristicInfo.currentWeaponName = "UZI";
                this.SetWeaponIcon();
            }
            else if(InfoManager.instance.charactoristicInfo.currentWeaponName == "UZI")
            {
                InfoManager.instance.charactoristicInfo.currentWeaponName = "SPAS-12";
                this.SetWeaponIcon();
            }
            else if(InfoManager.instance.charactoristicInfo.currentWeaponName == "SPAS-12")
            {
                InfoManager.instance.charactoristicInfo.currentWeaponName = "AK47";
                this.SetWeaponIcon();
            }         
        }
    }

}

UIWeaponSkillPopUp

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

public class UIWeaponSkillPopUp : MonoBehaviour
{
    [SerializeField]
    private Image imgStatPopUpSkill;
    [SerializeField]
    private Text txtStatPopUpSkillName;
    [SerializeField]
    private Text txtStatPopUpSkillDetail;

    private SpriteAtlas uiSkillAtlas; 

    public void Init()
    {
        this.uiSkillAtlas = AtlasManager.instance.GetAtlasByName("UISkillIcon");
        this.gameObject.SetActive(false);   
    }

    public void RefreshPopup(string skillName)
    {
        //실제 게임에서는 데이터 매니저 참고해서 할당 예정
        switch(skillName)
        {
            case "IconAssultRifleSkill_01":
                this.imgStatPopUpSkill.sprite = this.uiSkillAtlas.GetSprite(skillName);
                this.txtStatPopUpSkillName.text = "AssultRifleSkill_01"; 
                this.txtStatPopUpSkillDetail.text = "AssultRifleSkill_01 스킬 상세 설명";
                break;
            case "IconAssultRifleSkill_02":
                this.imgStatPopUpSkill.sprite = this.uiSkillAtlas.GetSprite(skillName);
                this.txtStatPopUpSkillName.text = "AssultRifleSkill_02";
                this.txtStatPopUpSkillDetail.text = "AssultRifleSkill_02 스킬 상세 설명";
                break;
            case "IconAssultRifleSkill_03":
                this.imgStatPopUpSkill.sprite = this.uiSkillAtlas.GetSprite(skillName);
                this.txtStatPopUpSkillName.text = "AssultRifleSkill_03";
                this.txtStatPopUpSkillDetail.text = "AssultRifleSkill_03 스킬 상세 설명";
                break;

            case "IconShotGunSkill_01":
                this.imgStatPopUpSkill.sprite = this.uiSkillAtlas.GetSprite(skillName);
                this.txtStatPopUpSkillName.text = "ShotGunSkill_01";
                this.txtStatPopUpSkillDetail.text = "ShotGunSkill_01 스킬 상세 설명";
                break;
            case "IconShotGunSkill_02":
                this.imgStatPopUpSkill.sprite = this.uiSkillAtlas.GetSprite(skillName);
                this.txtStatPopUpSkillName.text = "IconShotGunSkill_02";
                this.txtStatPopUpSkillDetail.text = "ShotGunSkill_02 스킬 상세 설명";
                break;
            case "IconShotGunSkill_03":
                this.imgStatPopUpSkill.sprite = this.uiSkillAtlas.GetSprite(skillName);
                this.txtStatPopUpSkillName.text = "IconShotGunSkill_03";
                this.txtStatPopUpSkillDetail.text = "ShotGunSkill_03 스킬 상세 설명";
                break;

            case "IconSniperRifleSkill_01":
                this.imgStatPopUpSkill.sprite = this.uiSkillAtlas.GetSprite(skillName);
                this.txtStatPopUpSkillName.text = "SniperRifleSkill_01";
                this.txtStatPopUpSkillDetail.text = "SniperRifleSkill_01 스킬 상세 설명";
                break;
            case "IconSniperRifleSkill_02":
                this.imgStatPopUpSkill.sprite = this.uiSkillAtlas.GetSprite(skillName);
                this.txtStatPopUpSkillName.text = "AssultRifleSkill_02";
                this.txtStatPopUpSkillDetail.text = "AssultRifleSkill_02 스킬 상세 설명";
                break;
            case "IconSniperRifleSkill_03":
                this.imgStatPopUpSkill.sprite = this.uiSkillAtlas.GetSprite(skillName);
                this.txtStatPopUpSkillName.text = "SniperRifleSkill_03";
                this.txtStatPopUpSkillDetail.text = "SniperRifleSkill_03 스킬 상세 설명";
                break;

            case "IconSubmachineGunSkill_01":
                this.imgStatPopUpSkill.sprite = this.uiSkillAtlas.GetSprite(skillName);
                this.txtStatPopUpSkillName.text = "SubmachineGunSkill_01";
                this.txtStatPopUpSkillDetail.text = "SubmachineGunSkill_01 스킬 상세 설명";
                break;
            case "IconSubmachineGunSkill_02":
                this.imgStatPopUpSkill.sprite = this.uiSkillAtlas.GetSprite(skillName);
                this.txtStatPopUpSkillName.text = "SubmachineGunSkill_02";
                this.txtStatPopUpSkillDetail.text = "SubmachineGunSkill_02 스킬 상세 설명";
                break;
            case "IconSubmachineGunSkill_03":
                this.imgStatPopUpSkill.sprite = this.uiSkillAtlas.GetSprite(skillName);
                this.txtStatPopUpSkillName.text = "SubmachineGunSkill_03";
                this.txtStatPopUpSkillDetail.text = "SubmachineGunSkill_03 스킬 상세 설명";
                break;

        }
    }
}

WeaponSkillCell

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

public class WeaponSkillCell : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
    [SerializeField]
    private UIWeaponCharacteristic uIWeaponCharacteristic;
 
    public void OnPointerDown(PointerEventData eventData)
    {
        var weaponSkillIcon = this.transform.GetChild(0);
        var skillName = weaponSkillIcon.GetComponent<Image>().sprite.name.Replace("(Clone)","");  
        Debug.Log(skillName);    
        this.uIWeaponCharacteristic.onSkillPopup(this.transform.localPosition, skillName);
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        this.uIWeaponCharacteristic.onSkillPopupClose();
    }
}

InfoManager

using Newtonsoft.Json;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using System.IO;

public class InfoManager
{ 
    public static readonly InfoManager instance = new InfoManager();
    public InfoManager() { }

    public StatInfo statInfo = new StatInfo();
    public InventoryInfo inventoryInfo = new InventoryInfo();
    public WeaponCharactoristicInfo charactoristicInfo = new WeaponCharactoristicInfo();   

    /// <summary>
    /// 능력치 초기화 메서드 + 자동저장
    /// </summary>
    /// <param name="powerStat">최종 수정 공격력</param>
    /// <param name="fireRateStat">최종 수정 공격속도</param>
    /// <param name="criticalHitAmount">최종 수정 치명타 피해</param>
    /// <param name="criticalHitChance">최종 수정 치명타 확률</param>
    public void InitStats(int powerStat,int fireRateStat,int criticalHitAmount,int criticalHitChance)
    {
        this.statInfo.powerStat = powerStat;
        this.statInfo.fireRateStat = fireRateStat;
        this.statInfo.criticalHitAmount = criticalHitAmount;
        this.statInfo.criticalHitChance = criticalHitChance;
        this.SaveStatInfo();       
    }

    /// <summary>
    /// 총기특성 초기화 + 총기 숙련도 초기화 ( 던전씬 엔드시 반드시 호출 )
    /// </summary>
    public void InitCharactorlisticsAndWeaponProficiency()
    {
        this.charactoristicInfo.movespeedCharacteristic = 1;
        this.charactoristicInfo.knockBackCharacteristic = 1;
        this.charactoristicInfo.bulletAmountCharacteristic = 1;
        this.charactoristicInfo.dashRecoverCharacteristic = 1;
        this.charactoristicInfo.penetrateCharacteristic = 1;
        this.charactoristicInfo.weaponProficiencyLevel = 0;
        this.charactoristicInfo.weaponProficiencyEXP = 0;
    }

    /// <summary>
    /// 플레이어 능력치 : 공격력 영구증가 + 자동 저장
    /// </summary>
    /// <param name="amount">영구증가시킬 공격력(기본값 1)</param>
    public void PermanentPowerStatIncrease(int amount = 1)
    {
        this.statInfo.powerStat += amount;
        this.SaveStatInfo();
    }

    /// <summary>
    /// 플레이어 능력치 : 공격속도 영구증가 + 자동 저장
    /// </summary>
    /// <param name="amount">영구증가시킬 공격속도(기본값 1)</param>
    public void PermanentFireRateStatIncrease(int amount = 1)
    {
        this.statInfo.fireRateStat += amount;
        this.SaveStatInfo();
    }

    /// <summary>
    /// 플레이어 능력치 : 치명타 확률 영구증가 + 자동 저장
    /// </summary>
    /// <param name="amount">영구증가시킬 치명타 피해(기본값 1)</param>
    public void PermanentCriticalHitAmountIncrease(int amount = 1)
    {
        this.statInfo.criticalHitAmount += amount;
        this.SaveStatInfo();
    }

    /// <summary>
    /// 플레이어 능력치 : 치명타 확률 영구증가 + 자동 저장
    /// </summary>
    /// <param name="amount">영구증가시킬 치명타 확률(기본값 1)</param>
    public void PermanentCriticalHitChanceIncrease(int amount = 1)
    {
        this.statInfo.criticalHitChance += amount;
        this.SaveStatInfo();
    }

    /// <summary>
    /// 플레이어 StatInfo 불러오기
    /// </summary>
    public void LoadStatInfo()
    {
        string path = string.Format("{0}/stat_info.json", Application.persistentDataPath);
        string json = File.ReadAllText(path);
        this.statInfo = JsonConvert.DeserializeObject<StatInfo>(json);
        Debug.Log("플레이어 능력치 데이터 로드 완료");
    }

    /// <summary>
    /// 플레이어 StatInfo 저장
    /// </summary>
    public void SaveStatInfo()
    {
        string path = string.Format("{0}/stat_info.json", Application.persistentDataPath);
        string json = JsonConvert.SerializeObject(this.statInfo);
        File.WriteAllText(path, json);
        Debug.Log("플레이어 능력치데이터 저장 완료");
    }

    /// <summary>
    /// 인벤토리 갯수 영구 증가(1개) +  자동 저장
    /// </summary>
    public void PermanentInventoryCountIncrease()
    {
        this.inventoryInfo.InventoryCount += 1;
        this.SaveInventoryInfo();
    }

    /// <summary>
    /// 플레이어 InventoryInfo 불러오기
    /// </summary>
    public void LoadInventoryInfo()
    {
        string path = string.Format("{0}/Inventory_Info.json", Application.persistentDataPath);
        string json = File.ReadAllText(path);
        this.inventoryInfo = JsonConvert.DeserializeObject<InventoryInfo>(json);
        Debug.Log("인벤토리 데이터 로드 완료");
    }

    /// <summary>
    /// 플레이어 Inventory 저장
    /// </summary>
    public void SaveInventoryInfo()
    {
        string path = string.Format("{0}/Inventory_Info.json", Application.persistentDataPath);
        string json = JsonConvert.SerializeObject(this.inventoryInfo);
        File.WriteAllText(path, json);
        Debug.Log("인벤토리 데이터 저장 완료");
    }

    /// <summary>
    /// 총기특성 : 이동 속도 증가 + 1 
    /// </summary>
    public void IncreaseMovespeedCharacteristic()
    {
        this.charactoristicInfo.movespeedCharacteristic += 1;
    }

    /// <summary>
    /// 총기특성 : 넉백 증가 + 1 
    /// </summary>
    public void IncreaseKnockBackCharacteristic()
    {
        this.charactoristicInfo.knockBackCharacteristic += 1;
    }

    /// <summary>
    /// 총기특성 : 총알 숫자 증가 + 1 
    /// </summary>
    public void IncreaseBulletAmountCharacteristic()
    {
        this.charactoristicInfo.bulletAmountCharacteristic += 1;
    }

    /// <summary>
    /// 총기특성 : 대시 회복 속도 증가 + 1 
    /// </summary>
    public void IncreaseDashRecoverCharacteristic()
    {
        this.charactoristicInfo.dashRecoverCharacteristic += 1;
    }

    /// <summary>
    /// 총기특성 : 관통력 증가 + 1 
    /// </summary>
    public void IncreasePenetrateCharacteristic()
    {
        this.charactoristicInfo.penetrateCharacteristic += 1;
    }

    /// <summary>
    /// 총기 숙련도 증가 +1
    /// </summary>
    public void IncreaseWeaponPreficiencyLevel()
    {
        this.charactoristicInfo.weaponProficiencyLevel += 1;    
    }

    /// <summary>
    /// 총기 경험치 증가 +4
    /// </summary>
    public void IncreaseWeaponProficiencyEXP()
    {
        this.charactoristicInfo.weaponProficiencyEXP += 4;
    }

    /// <summary>
    /// 현재 들고 있는 총기 이름 변경 (AK47, AWP, UZI, SPAS-12) (기본값 : AK47)
    /// </summary>
    /// <param name="weaponName">현재 들고 있는 무기 이름</param>
    public void ChangeCurrentWeaponName(string weaponName = "AK47")
    {
        this.charactoristicInfo.currentWeaponName = weaponName;
    }
}

명시적으로 메서드를 하나하나 구현해 주다보니 인포매니저의 역할이 커지고 스크립트가 길어졌다. 

해결할수 있는 방법이 있을지 고민해 보아야겠다. 

반응형
LIST