본문 바로가기
Unity/Undead Survivor

레벨업 시스템(LevelUp System) / 손과 무기 장착 표현(Hands) / 캐릭터 선택(Character Select)

by hwan91 2025. 3. 19.

LevelUp.cs

플레이어가 레벨업할 때 실행되는 UI 관리 스크립트로, 레벨업 UI를 표시하고 랜덤한 3개의 아이템을 선택하여 활성화,

플레이어가 선택한 아이템을 적용하는 역할을 한다.

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

public class LevelUp : MonoBehaviour
{
    RectTransform rect; // 레벨업 UI의 크기 및 위치 조절
    Item[] items; // 레벨업 UI에서 표시할 아이템 목록

    void Awake()
    {
        rect = GetComponent<RectTransform>();
        // GetComponentsInChildren<T>(true) = 비활성화된 아이템도 포함하여 가져올 수 있게함
        items = GetComponentsInChildren<Item>(true); // 현재 오브젝트의 자식 중 Item 컴포넌트가 있는 모든 오브젝트를 가져옴
    }

    // 레벨업 UI 표시
    public void Show()
    {
        Next(); // 아이템 선택(랜덤 3개)

        // Vector3.one = (1, 1, 1)
        rect.localScale = Vector3.one; // 크기를 원래 크기로 설정하여 UI를 보이게 함

        GameManager.instance.Stop(); // 게임 일시 정지
        AudioManager.instance.PlaySfx(AudioManager.Sfx.LevelUp); // 레벨업 효과음 재생
        AudioManager.instance.EffectBgm(true); // BGM 효과 적용
    }

    // 레벨업 UI 숨기기
    public void Hide()
    {
        // Vector3.one = (0, 0, 0)
        rect.localScale = Vector3.zero; // 크기를 0으로 만들어 완전히 숨김

        GameManager.instance.Resume(); // 게임 재시작
        AudioManager.instance.PlaySfx(AudioManager.Sfx.Select); // 선택 효과음 재생
        AudioManager.instance.EffectBgm(false); // BGM 효과 해제
    }

    // 레벨업 UI에서 선택한 아이템을 적용하는 기능, 실행은 GamaManager.cs에서
    public void Select(int index)
    {
        items[index].OnClick();
    }

    /* 실제로 게임을 실행해보면 3개 중 만렙을 달성한 아이템이 선택되었을 때
     * 선택지가 3개가 아니라 2개만 나오는 상황이 있어 추후 수정 예정 */
    // 랜덤한 3개의 아이템 선택
    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] ) { // && == and
                break; // 중복이 없을 때만 빠져나감
            }
        }

        // 3. 선택된 3개 아이템의 버튼 활성화
        for (int index = 0; index < ran.Length; index++) {
            Item ranItem = items[ran[index]];

            // 4. 만렙 아이템이면 소비 아이템으로 대체
            if (ranItem.level == ranItem.data.damages.Length) { // damages.Length = 최대 레벨
                // 소비 아이템이 1개이기 때문에 수동으로 활성화 코드 작성
                items[4].gameObject.SetActive(true); // 소비 아이템 활성화
                // 소비 아이템이 여러개인 경우
                // items[Random.Range(4, 7)].gameObject.SetActive(true);
            }
            else {
                ranItem.gameObject.SetActive(true);
            }
        }
    }
}

Hands.cs

플레이어 캐릭터의 손과 무기를 장착하고 반전(flip) 상태를 조정하는 역할을 담당한다.

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

public class Hand : MonoBehaviour
{
    public bool isLeft; // 손 구분을 위한 변수 선언, true면 왼손(근거리), false면 오른손(원거리)
    public SpriteRenderer spriter;

    SpriteRenderer player; // 플레이어의 스프라이트 렌더러

    Quaternion leftRot = Quaternion.Euler(0, 0, -15); // 왼손 회전값, 오일러 각도를 사용하여 약간 아래쪽을 향하도록 회전 설정
    Quaternion leftRotReverse = Quaternion.Euler(0, 0, -165); // 캐릭터가 뒤집혀도 왼손이 올바르게 보이도록 설정

    Vector3 rightPos = new Vector3(0.35f, -0.14f, 0); // 오른손 위치값, 캐릭터의 우측에 위치하게 설정
    Vector3 rightPosReverse = new Vector3(-0.15f, -0.14f, 0); // 캐릭터가 뒤집히면 오른손도 반대쪽으로 이동

    void Awake()
    {
        player = GetComponentsInParent<SpriteRenderer>()[1];
    }

    // 프레임마다 손의 위치와 방향 조정
    // LateUpdate를 사용하여 플레이어의 움직임(Update)을 반영한 후 손의 위치와 방향이 조정되게 함
    void LateUpdate()
    {
        bool isReverse = player.flipX; // 플레이어의 fliX(반전) 상태

        if (isLeft) { // 왼손
            transform.localRotation = isReverse ? leftRotReverse : leftRot;
            spriter.flipY = isReverse; // flipY가 true면 손이 좌우 반전됨
            /* sortingOrder = 스프라이트의 레이어 순서 결정
             * 4 : 플레이어보다 뒤쪽
             * 6 : 플레이어보다 앞쪽 */
            spriter.sortingOrder = isReverse ? 4 : 6;
        }
        else { // 오른손
            transform.localPosition = isReverse ? rightPosReverse : rightPos;
            spriter.flipX = isReverse; // flipX가 true면 오른손이 좌우 반전됨
            spriter.sortingOrder = isReverse ? 6 : 4;
        }
    }
}

Character.cs

플레이어 캐릭터의 ID에 따라 달라지는 공용 속성(이동 속도, 공격 속도, 데미지 등)을 제공하는 정적 클래스로, 특정 오브젝트(Player, Enemy 등)에 부착되지 않고 다른 스크립트에서 공통적으로 사용된다.

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

/* 이런 속성들은 각각의 캐릭터(Player, Enemy, NPC 등) 스크립트에서 따로 설정할 수도 있으나
     * 그렇게된다면 같은 기능을 여러 곳에서 중복 구현해야하기 때문에 코드가 비효율적임
     * 따라서, 이렇게 별도 클래스로 분리해서 정의한다면 재사용성이 증가하여
     * 여러 개체에서 동일한 기준으로 속도를 조정할 수 있기에 효율적인 코드 작성이 가능함 */
public class Character : MonoBehaviour
{
     /* get {}을 사용해 속성을 선언하면 변수가 아니라 속성이 되어
     * 값을 저장하는 게 아닌 get {} 내부에서 계산된 값을 반환함
     * 즉, 변경할 수 없고 매번 계산된 값을 가져오는 읽기 전용 속성 */

    // 이동 속도
    public static float Speed
    {
        get { return GameManager.instance.playerId == 0 ? 1.1f : 1f; }
    }

    // 근거리 무기 속도
    public static float WeaponSpeed
    {
        get { return GameManager.instance.playerId == 1 ? 1.1f : 1f; }
    }

    // 원거리 무기 속도
    public static float WeaponRate
    {
        get { return GameManager.instance.playerId == 1 ? 0.9f : 1f; }
    }

    // 데미지 증가
    public static float Damage
    {
        get { return GameManager.instance.playerId == 2 ? 1.2f : 1f; }
    }

    // 관통력
    public static int Count
    {
        get { return GameManager.instance.playerId == 3 ? 1 : 0; }
    }
}