[Unity][2D-Game] Undead Survivor (11)

suhan0304·2023년 11월 8일
0

유니티 - Undead Survivor

목록 보기
13/21
post-thumbnail

Review

  • 기초적인 UI의 개념에 대해 이해하고 구현했다.
  • 슬라이더를 이용해 경험치 바와 체력 바를 구현했다.
  • 텍스트를 이용해 킬수, 타이머, 레벨을 구현했다.
  • UI를 관리할 HUD 스크립트를 만들어 해당 오브젝트들을 관리하도록 로직을 구현했다.
  • 월드 상 좌표와 스크린 상의 좌표에 대해 이해하고 전환하는 법에 대해 알아봤다.

강의영상 (11) - 능력 업그레이드 구현


개발

아이템 데이터 만들기

기존에는 무기별로 Weapon0, Weapon1처럼 무기별로 오브젝트를 만들어줬지만 좀 더 정리된 형태로 개선하기 위해 아이템 데이터를 생성을 담당할 스크립트를 따로 만들어 관리해줄 수 있다.

MonoBehaviour 대신 SciptableObject를 상속받아서 사용한다.

[CreateAssetMenu(fileName = "Item",menuName = "Scriptable 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;
    public string intemDesc;
    public Sprite itemIcon;

    [Header("# Level Data")]
    public float baseDamage;//초기 데미지
    public int baseCount;   //초기 카운트
    public float[] damages; //레벨 업 데미지
    public int[] counts;    //레벨 업 카운트

    [Header("# Weapon")]
    public GameObject projectile;
}

CreateAssetMenu : 커스텀 메뉴를 생성하는 속성

Undead Survivor 폴더에 Data 폴더를 만든 후 Create > Scriptble Object에서 ItemData를 눌러 스크립트블 오브젝트를 생성했다.

스크립트블 오브젝트 : 다양한 데이터를 저장하는 에셋

만든 에셋에 하나의 아이템이 가진 속성들을 설정해주었다.

총 5개의 아이템을 제작해주었다.


레벨업 버튼 제작

캔버스에 레벨업 버튼을 자식 오브젝트로 넣어줄 빈 오브젝트를 LevelUp이라는 이름으로 하나 생성해주었다.

  • Width = 22, Height = 150으로 설정

  • 오른쪽 아래로 앵커 (위치 + 기준점)

  • 자식 오브젝트로 Button을 만들어준다.
    - Width = 22, Height = 30으로 설정
    - Source Image를 Panel로 설정
    - Text이름을 Text Level로 변경 후 정가운데로 앵커 설정
    - Pos Y = -9로 설정
    - Horizontal, Vertical Overflow를 Overflow로 설정
    - 글꼴 neodgm으로 글자 사이즈 5로 설정

  • 아이템 아이콘을 보여줄 이미지 오브젝트를 자식 오브젝트로 추가
    - 이름은 icon으로 설정
    - Pos Y = 3으로 설정

아이템을 관리해줄 item 스크립트를 다음과 같이 작성해주었다.

item.cs

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;   //무기 정보

    Image icon;
    Text textLevel;

    void Awake()
    {
        //자식 오브젝트 icon
        icon = GetComponentsInChildren<Image>()[1]; //첫번째[0]는 자기자신
        icon.sprite = data.itemIcon;                //itemData의 아이콘으로 초기화

        Text[] texts = GetComponentsInChildren<Text>(); //자식의 Text 컴포넌트 가져오기
        textLevel = texts[0];   //item 오브젝트에는 Text가 없어서 자식에 있는 Text만 오기 때문에 첫번째[0]로 초기화
    }

    void LateUpdate()
    {
        textLevel.text = "Lv." + (level + 1);
    }
}

item 0에 item 컴포넌트를 추가해준 후 LevelUp 오브젝트에 Vertical Layout Group을 넣어준 후 item 0을 Ctrl+D로 5개 만들어주었다.

추가적으로 버튼 클릭 이벤트를 작성해 준 후 item의 button 컴포넌트의 On click에 바로 밑에 있는 Item(Scipt)를 드래그드랍해서 등록해준 뒤 Item.OnClick 이벤트에 연결시켜주었다.

오작동을 방지하기 위해 모든 버튼의 Navigation을 None으로 변경


무기 업그레이드

기존의 플레이어가 가진 Weapon 오브젝트 삭제한 후 스크립트를 수정했다.

case ItemData.ItemType.Melee: // 근접, 원거리 무기는 같은 로직을 사용 
case ItemData.ItemType.Range: // case를 붙여준다.
    if (level == 0) //레벨이 0일 때 버튼을 누르면 웨폰 오브젝트를 생성
    {
        GameObject newWeapon = new GameObject();

        //새로운 오브젝트에 Weapon 컴포넌트 추가
        //AddComponent 함수 반환 값을 미리 선언한 변수에 저장.
        weapon = newWeapon.AddComponent<Weapon>();
        weapon.Init(data);

    }
    break;

AddComponent : 오브젝트에 컴포넌트를 추가
- 해당 컴포넌트를 함수 반환 값으로 같이 반환

Weapon을 생성한 후 Init을 이용해 초기화를 해주는데 이 때 ItemData의 값으로 초기화하기 위해 data를 매개변수로 넘겨받도록 수정했다.

public void Init(ItemData data)
{
    //Basic Set
    name = "Weapon " + data.itemId; //이름 설정
    transform.parent = player.transform; //부모 오브젝트 설정
    //플레이어 안에서 위치를 0, 0, 0으로 맞추기 때문에 LocalPostion 사용
    transform.localPosition = Vector3.zero;

    //Property Set
    id = data.itemId;
    damage = data.baseDamage;
    count = data.baseCount;

	//~~(생략)~~

}

Q. 왜 프리팹 아이디를 그냥 ItemData에 넣으면 편한데 프리팹을 넣고 init에서 프리팹 id를 따로 찾나요?
A. 스크립트블 오브젝트의 독립성을 위해 인덱스가 아닌 프리팹으로 설정

아이템 생성까지 됐으므로 레벨 업 코드를 추가 작성해주었다.

case ItemData.ItemType.Melee: // 근접, 원거리 무기는 같은 로직을 사용 
case ItemData.ItemType.Range: // case를 붙여준다.
    if (level == 0) //레벨이 0일 때 버튼을 누르면 웨폰 오브젝트를 생성
    {
        GameObject newWeapon = new GameObject();

        //새로운 오브젝트에 Weapon 컴포넌트 추가
        //AddComponent 함수 반환 값을 미리 선언한 변수에 저장.
        weapon = newWeapon.AddComponent<Weapon>();
        weapon.Init(data);

    }
    else
    {
        float nextDamage = data.baseDamage;
        int nextCount = 0;

        nextDamage += data.baseDamage * data.damages[level]; //damages를 백분율이기 때문에 곱해서 더해줌
        nextCount += data.counts[level]; //count는 단순히 counts의 레벨을 인덱스로해서 가져온 값을 더해줌

        weapon.LevelUp(nextDamage, nextCount); //Weapon의 LevelUp 함수를 이용해 레벨업
    }
    break;


장비 업그레이드

무기가 Weapon 스크립트가 있듯이 장비도 Gear 스크립트를 추가로 작성해주었다.

case ItemData.ItemType.Glove: // 무기가 아닌 장비들은 같은 로직을 사용
case ItemData.ItemType.Shoe:
    if (level == 0) //레벨이 0일 때 버튼을 누르면 웨폰 오브젝트를 생성
    {
        GameObject newGear = new GameObject();

        //새로운 오브젝트에 Weapon 컴포넌트 추가
        //AddComponent 함수 반환 값을 미리 선언한 변수에 저장.
        gear = newGear.AddComponent<Gear>();
        gear.Init(data);
    }
    else
    {
        float nextRate = data.damages[level];

        gear.LevelUp(nextRate);
    }
    break;

나중에 추가된 무기는 ApplyGear을 받지 못해 공격속도와 Speed가 높은 Level에 따른 값으로 변하지 않는다.

나중에 추가된 무기도 레벨의 영향을 받아야 하므로 Weapon에서도 ApplyGear 함수를 실행시킬 수 있도록 init과 levelup에 다음과 같은 코드를 추가해주었다.

        //Weapon이 레벨업하면 ApplyGear로 레벨업한 무기에 Gear 레벨을 적용
        player.BroadcastMessage("ApplyGear"); //플레이어에게 broadcast해주도록 부탁
        //플레이어가 가지고 있는 모든 Gear에 한해서 ApplyGear가 실행

BroadCastMessage(함수명, 인자값) : 특정 함수 호출을 모든 자식에게 방송하는 함수
- 두 번째 인자값으로 SendMessageOptions.DontRequireReceiver를 추가하면 Reveiver가 없어도 오류가 생하지 앟는다.

마지막으로 체력을 회복시켜주는 아이템 음료수는 다음과 같이 구현했다.

case ItemData.ItemType.Heal: // 일회성 아이템의 안에서는 LevelUp 함수 실행을 X
    GameManager.Instance.health = GameManager.Instance.maxHealth;
    break;

레벨 값을 올리는 로직을 무기, 장비 case에서만 실행되도록 수정해야 한다.
레벨업이 damages의 수에 도달하면 더 이상 실행하지 않기 때문에 일회성 아이템에서는 레벨업을 진행하면 안 된다.

실제 레벨업 시스템은 추후에 경험치와 레벨에 연동해서 수정할 예정이다.


결과물

profile
Be Honest, Be Harder, Be Stronger

0개의 댓글