본문 바로가기

Unity 공부/Unity_2D

[Day 11] 레벨업 시스템

[ 레벨업 시스템 ] --> 레벨업 시 무기를 선택하는 로직 구현

  • Canvas에서 우클릭 후 UI --> Image 생성(LevelUp)
        - 앵커 누른 후 Shift + Alt 누른 후 꽉 찬 이미지로 선택
        - 색상은 검은색에 A값을 150으로 설정
  • 기존의 LevelUp 오브젝트 이름을 ItemGroup으로 변경
  • LevelUp에서 우클릭 후 UI --> Image 생성(Panel)
        - Source Sprite를 Panel로 변경
        - Width = 100 | Height = 130으로 설정(마음대로)
        - 색상은 R = 40, G =145 , B = 112(마음대로)
  • Panel에서 우클릭 후 UI --> Legacy --> Text 생성(Text Title)
        - 앵커 누른 후 Shift + Alt 누른 후 상단 꽉 찬 이미지 클릭
        - 텍스트 중앙정렬로 설정(Alignment)
        - Height = 20으로 설정
        - Font = neodgm으로 설정
        - 색상은 흰색
        - Text = 축하합니다! (Enter) 레벨이 상승했습니다!
  • Text에 Add Component
        - Shadow(마음대로)
  • ItemGroup을 Panel에 자식으로 넣기(드래그&드랍)
        - 앵커 선택 후 Shift + Alt 누른 후 꽉 찬 이미지 클릭
        - Control Child Size에서 Width와 Height 모두 체크
        - Spacing = 1로 설정
        - Left, Right, Bottom = 5 | Top = 25로 설정
        - Item 3,4 비활성화
  • Item\Icon의 앵커 누른 후 Shift + Alt 누른 후 왼쪽 중단 이미지 클릭
        - Pos X = 6 | Pos Y = 3으로 설정
  • Text Level의 앵커 누른 후 Shift + Alt 누른 후 왼쪽 중단 이미지 클릭
        - Width = 18로 설정
        - Pos X = 6 | Pos Y = -10으로 설정
  • Text Level을 Ctrl + D로 복사
        - 이름을 Text Name으로 설정
         - Text = 아이템 이름
        - Font Size = 7로 설정
        - Pos X = 26 | Pos Y = 6
        - 텍스트 좌측 정렬로 설정
  • Text Name을 Ctrl + D로 복사
        - 이름을 Text Desc로 설정
        - Font Size = 5로 설정
        - Text = 아이템 설명 (Enter) 아이템 설명
        - Pos X = 27 | Pos Y = -7로 설정
  • Text Level, Text Desc 색상을 Panel 색상과 비슷하게 설정
  • Item 1,2,3,4 모두 지운 후 Item 0를 4개 복사
        - Item의 Data를 자신에 맞게 설정
        - Item 3,4 비활성화
  • 기존의 ItemData 스크립트에 코드 추가
    ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName = "Item", menuName = "Scriptble Object/ItemData")]
public class ItemData : ScriptableObject
{
    public enum ItemType { Melee, Range, Glove, Shoe, Heal }
    [Header("# Main Info")]
    public ItemType itemType;
    public int itemId;
    public string itemName;
    [TextArea] // 텍스트 여러 줄 입력 가능
    public string itemDesc;
    public Sprite itemIcon;

    [Header("# Level Data")]
    public float baseDamage;
    public int baseCount;
    public float[] damages;
    public int[] counts;

    [Header("# Weapon")]
    public GameObject projectile;
    public Sprite hand;
}
  • Item 0의 Item Desc = 데미지 {0}% 증가 (Enter) 회전체 {1}개 추가
  • Item 1의 Item Desc = 데미지 {0}% 증가 (Enter) 관통력 {1} 추가
  • Item 2의 Item Desc = 연사속도 {0}% 증가 
  • Item 3의 Item Desc = 이동속 {0}% 증가 
  • Item 4의 Item Desc = 생명력 전체 회복
  • 기존의 Item 스크립트에 코드 추가
    ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Item : MonoBehaviour
{
    public ItemData data;
    public int level;
    public Weapon weapon;
    public Gear gear;

    Image icon;
    Text textLevel;
    Text textLName; // 이름 변수
    Text textDesc; // 설명 변수

    private void Awake()
    {
        icon = GetComponentsInChildren<Image>()[1];
        icon.sprite = data.itemIcon;

        Text[] texts = GetComponentsInChildren<Text>();
        textLevel = texts[0];
        textLName = texts[1]; //이름 변수 초기화
        textDesc = texts[2]; //설명 변수 초기화
        textLName.text = data.itemName; // 설명 변수 초기화
    }

    private void OnEnable()
    {
        textLevel.text = "LV." + (level + 1);

        switch (data.itemType) // 로직 분리
        {
            case ItemData.ItemType.Melee: // Weapon
            case ItemData.ItemType.Range: // Weapon
                textDesc.text = string.Format(data.itemDesc, data.damages[level] * 100, data.counts[level]);
                break;
            case ItemData.ItemType.Glove: // Gear
            case ItemData.ItemType.Shoe: // Gear
                textDesc.text = string.Format(data.itemDesc, data.damages[level] * 100);
                break;
            default:
                textDesc.text = string.Format(data.itemDesc);
                break;
        } 
    }
    
    //LateUpdate() 삭제

    public void OnClick()
    {
        switch(data.itemType)
        {
            case ItemData.ItemType.Melee:
            case ItemData.ItemType.Range:
                if(level == 0){
                    GameObject newWeapon = new GameObject();
                    weapon = newWeapon.AddComponent<Weapon>();
                    weapon.Init(data);
                }
                else{
                    float nextDamage = data.baseDamage;
                    int nextCount = 0;

                    nextDamage += data.baseDamage * data.damages[level];
                    nextCount += data.counts[level];

                    weapon.LevelUp(nextDamage, nextCount);
                }

                level++;
                break;
            case ItemData.ItemType.Glove:
            case ItemData.ItemType.Shoe:
                if (level == 0){
                    GameObject newGear = new GameObject();
                    gear = newGear.AddComponent<Gear>();
                    gear.Init(data);
                }
                else{
                    float nextRate = data.damages[level];
                    gear.LevelUp(nextRate);
                }

                level++;
                break;
            case ItemData.ItemType.Heal:
                GameManager.instance.hp = GameManager.instance.maxHp;
                break;
        }

        if(level == data.damages.Length)
        {
            GetComponent<Button>().interactable = false;
        }
    }
}
  • C# 스크립트 생성(LevelUp)
    ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using System.Net.Http.Headers;
using UnityEngine;

public class LevelUp : MonoBehaviour
{
    RectTransform rect; // RectTransform 변수
    Item[] items; // Item[] 배열 변수

    private void Awake()
    {
        rect = GetComponent<RectTransform>(); // Rectransform 초기화
        items = GetComponentsInChildren<Item>(true); // Item[] 초기화
    }

    public void Show() // 창 활성화
    {
        Next();
        rect.localScale = Vector3.one; // 활성화
        GameManager.instance.Stop(); // Stop() 호출
    }

    public void Hide() // 창 비활성화
    {
        rect.localScale = Vector3.zero; // 비활성화
        GameManager.instance.Resume(); // Resume() 호출
    }

    public void Select(int index) 
    {
        items[index].OnClick(); // 버튼 클릭
    }

    void Next()
    {
        // 1. 모든 아이템 비활성화
        foreach (Item item in items)
        {
            item.gameObject.SetActive(false);
        }
        // 2. 그 중에서 래넘 3개 아이템 활성화
        int[] ran = new int[3];
        while(true)
        {
            ran[0] = Random.Range(0, items.Length);
            ran[1] = Random.Range(0, items.Length);
            ran[2] = Random.Range(0, items.Length);
            if (ran[0] != ran[1] && ran[1] != ran[2] && ran[0] != ran[2]) // 모두 같지 않게 선택이 됐을 때, 빠져나가기
                break;
        }

        for(int index=0; index < ran.Length; index++)
        {
            Item ranItem = items[ran[index]];
            
            // 3. 만렙 아이템의 경우는 소비 아이템으로 대체
            if (ranItem.level == ranItem.data.damages.Length)
            {
                items[4].gameObject.SetActive(true);
            }
            else
            {
                ranItem.gameObject.SetActive(true);
            }


        }

    }
}
  • 기존의 GameManager 스크립트에 코드 추가
    ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameManager : MonoBehaviour
{
    public static GameManager instance;
    [Header("# Game Conrol")]
    public bool isLive; // bool 변수
    public float gameTime;
    public float maxGameTime = 2 * 10f;
    [Header("# Player Info")]
    public int hp;
    public int maxHp = 100;
    public int level;
    public int kill;
    public int exp;
    public int[] nextExp = { 3, 5, 10, 100, 150, 210, 280, 360, 450, 600 };
    [Header("# Game Object")]
    public PoolManager pool;
    public Player player;
    public LevelUp uiLevelUp; // LevelUp 변수

    private void Awake()
    {
        instance = this; 
    }

    void Start()
    {
        hp = maxHp;

        // 임시 스크립트 (첫번째 캐릭터 무기 선택)
        uiLevelUp.Select(0);
    }

    void Update()
    {
        if(!isLive)
        {
            return;
        }
        gameTime += Time.deltaTime;

        if (gameTime > maxGameTime){
            gameTime = maxGameTime;
        }
    }


    public void GetExp()
    {
        exp++;
        if (exp == nextExp[Mathf.Min(level, nextExp.Length-1)]) // 최고 경험치를 그대로 사용
        {
            level++;
            exp = 0;
            uiLevelUp.Show(); // LevelUp 창 활성화
        }
    }

    public void Stop()
    {
        isLive = false;
        Time.timeScale = 0; // 시간의 흐름 = 0 (배속)
    }

    public void Resume()
    {
        isLive = true;
        Time.timeScale = 1; // 시간의 흐름 = 1
    }

}
  • LevelUp 오브젝트에 Add Component
        - LevelUp(Script)
  • GameManager 오브젝트의 Ui Level Up에 LevelUp 오브젝트 넣기(드래그&드랍)
  • Item 0~4 다중선택 후 Button의 On Click()에서 +버튼 누른 후, LevelUp 오브젝트 넣기(드래그&드랍)
        - No Function을 LevelUp --> Hide로 변경
  • LevelUp의 Rect Transform Scale = 0 | 0 | 0 으로 설정
  • 각 스크립트의 Update 계열 로직에 조건 추가(GameManager, Player, Enemy, Spawner, Weapon)
    ㅡ아래의 조건 추가ㅡ
if (!isLive)
	return;
  • 기존의 HUD 스크립트에 코드 추가
    ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using static Cinemachine.DocumentationSortingAttribute;

public class HUD : MonoBehaviour
{
    public enum InforType { Exp, Level, Kill, Time, Health}
    public InforType type;

    Text myText;
    Slider mySlider;

    void Awake()
    {
        myText = GetComponent<Text>();
        mySlider = GetComponent<Slider>();
    }

    private void LateUpdate()
    {
        switch (type)
        {
            case InforType.Exp:
                float curExp = GameManager.instance.exp;
                // 최고 경험치를 그대로 사용
                float maxExp = GameManager.instance.nextExp[Mathf.Min(GameManager.instance.level, GameManager.instance.nextExp.Length - 1)];
                mySlider.value = curExp/maxExp;
                break;

            case InforType.Level:
                myText.text = string.Format("Lv.{0:F0}", GameManager.instance.level);
                break;
            
            case InforType.Kill:
                myText.text = string.Format("{0:F0}", GameManager.instance.kill);
                break;
            
            case InforType.Time:
                float remainTime = GameManager.instance.maxGameTime - GameManager.instance.gameTime;
                int min = Mathf.FloorToInt(remainTime / 60);
                int sec = Mathf.FloorToInt(remainTime % 60);
                myText.text = string.Format("{0:D2}:{1:D2}", min, sec);
                break;
            
            case InforType.Health:
                float curHp = GameManager.instance.hp;
                float maxHp = GameManager.instance.maxHp;
                mySlider.value = curHp / maxHp;
                break;
        }
    }

}

 

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

 

★Slow and Steady★

'Unity 공부 > Unity_2D' 카테고리의 다른 글

[Day 13] 플레이 캐릭터 선택  (0) 2023.07.19
[Day 12] 게임 시작과 종료 구현  (0) 2023.07.18
[Day 10] 무기 장착 표현  (0) 2023.07.16
[Day 9] 능력 업그레이드 구현  (0) 2023.07.15
[Day 8] HUD 제작  (0) 2023.07.14