1. 오늘의 할 일
UI만들고 아이템도 만들기 위해서
Interface를 확실히 잡아놓고 넘어갈 생각이다.
= 막연히 '다중 상속 가능' '아무튼 쓰기 편함'의 상태에서 벗어나도록 하자.
2. 인터페이스에 대해 정리해보자
Interface란?
- 소프트웨어끼리 접촉·공통되는 부분. 순화어로 '접속'
- C#에서 Class는 여러 개의 Interface를 상속받을 수 있음 (다중 상속 가능!)
- 보통 같은 기능을 가진, 다른 객체들에게 사용한다.
public interface IDamageAble
{
void TakeDamage(int amount); // 데미지를 입는 메서드
}
public class Enemy : MonoBehaviour, IDamageAble //Enemy 클래스는 MonoBehaviour와 IDamageAble 인터페이스를 상속받음
{
public void TakeDamage(int amount) //IDamageAble 인터페이스의 TakeDamage 메서드 구현
{
// 적의 체력을 amount 만큼 감소시키고, 피 흘리는 효과, 아파하는 애니메이션 처리
Debug.Log($"적에게 {amount} 대미지를 입혔습니다!");
}
}
public class Building : MonoBehaviour, IDamageAble // Building 클래스는 MonoBehaviour와 IDamageAble 인터페이스를 상속받음
{
public void TakeDamage(int amount) // IDamageAble 인터페이스의 TakeDamage 메서드 구현
{
//건물의 내구도를 amount 만큼 감소시키고, 갈라지는 효과, 부서지는 소리 처리
Debug.Log($"건물에 {amount} 대미지를 입혔습니다!");
}
}
= 둘 다 대미지를 받지만(대미지를 받는 기능 공통), 서로 다른 기능을 수행해야할 때 사용할 수 있다!
특징: 이렇게 해두면, 공격 메서드나 그와 같은 효과가 드는 메서드를 사용했을 때 '대미지'를 받을 수 있는지 확인하고 그에 해당하는 객체에만 영향을 끼칠 수 있다.
public class Bullet : MonoBehaviour
{
private void OnTriggerEnter2D(Collider2D collision) //총알이 콜라이더 내부에 들어갔을 때
{
// 충돌한 오브젝트가 IDamageAble 인터페이스를 구현하고 있는지 확인
IDamageAble damageableObject = collision.GetComponent<IDamageAble>();
//구현한 값이 null이 아니라면 = 구현하고 있는 객체라면
if (damageableObject != null)
{
// IDamageAble 인터페이스를 통해 TakeDamage 메서드 호출
damageableObject.TakeDamage(10); // 10의 데미지 입히기-메서드로 구현한 경우.
//10이 아니라 Bullet자체의 공격력 매개변수를 넣을 수도 있다. (공격력 범위 지정 8~12)
}
//공격 했으니 해당 오브젝트(총알) 파괴
Destroy(gameObject);
}
}
위의 코드를 적용했다고 쳤을 때, 본래 Interface를 사용하지 않았을 때는 레이어나 태그 등을 확인해가며 얘는 가능하고 쟤는 불가능하고… 등을 직접 적용시켜줘야했는데,
이 경우에는 스크립트 내에 해당 요소가 있는지 확인하면 되니까 편해진다.
Interface에 있는 요소 = 해당 오브젝트에는 반드시 적용되어야 하는 요소가 되기 때문에, 해당 인터페이스를 가지고 있는 것 자체가 분류의 기준이 될 수 있는 것이다.
그럼 Interface랑 ScriptableObject랑 힘을 합치면 어떻게 될까. (퓨전)
정답:
Interface에는 뭐가 필요한지 적어두고(아이템 이름, 아이템 설명, 장착가능여부, 사용 가능 여부, 필요 시: 아이콘, 가격, 회복량, 무게 등) = 아이템에는 뭐가 필요해요! 하고 알려주는 역할
ScriptableObject에는 그 데이터를 적을 수 있도록 만든다. (각 오브젝트의 이름, 설명, 장착여부 등을 담을 수 있는 탬플릿)
= 여기다가 쓰세요! 하고 펼쳐진 노트
그럼 이제 ScriptableObject로 만든 ItemData를, 인스펙터 창에서 직접 집어넣어주면 된다.
물론 〈특정기능이 반드시 필요합니다.〉가 된다면 abstract를 함께 활용할 수 있다.
(기본 아이템 데이터인 Scriptabale Object에 불필요한 메서드 내용을 포함하지 않음)
대충 이런 느낌
Scriptable Object :얘들아!!! Interface에서 Use()메서드 꼭 만들래!!! >> 자식 오브젝트에게 상속 (기능은 각자 구현, ScriptableObjetc 스크립트 내부에서는 구현하지 않음.)
하지만 처음에 사용했듯, 굳이 abstract로 다시 쓰지 않아도 Interface에 존재한다면 강제적으로 구현하긴 해야한다.
그럼 그냥 필요한 데이터 선언용 Interface와, 필요 기능 선언용 Interface를 같이 구현해도 문제없다.
(이 경우, 데이터 선언용 Interface를 Scriptable Object 스크립트가 상속받아주면 된다.)
그럼 실제 아이템에, 필요한 두 개의 인터페이스를 상속받아서 구현하면 된다.
인터페이스만 잡자면 이런구조.
// 모든 아이템이 구현해야 할 기본 인터페이스 (정보 제공)
public interface IItem
{
string ItemName { get; }
string Description { get; }
Sprite Icon { get; }
}
// 소모품 기능 인터페이스
public interface IConsumable
{
void Consume(GameObject user); // 아이템을 '소비'하는 기능
// 소모품 관련 추가 속성이나 메서드 (HP 회복량 등 - 일반 아이템 메서드에 넣어도 OK)
}
// 장비 기능 인터페이스
public interface IEquipable
{
EquipSlot EquipSlot { get; } // 장착되는 슬롯 정보
void Equip(GameObject user); // 아이템 장착 기능
void Unequip(GameObject user); // 아이템 해제 기능
// 장비 관련 추가 속성이나 메서드(장비의 공격력이나 속도버프 등 - 일반 아이템 메서드에 넣어도 OK)
}
// 장비 슬롯 종류
public enum EquipSlot { Weapon, Armor, Accessory }
그럼 장비는 public class Equipment: IItem, IEquipable, ItemData 를 상속받아서 사용하면 된다.
필요한 정보와 기능만 골라서 담을 수 있는 인터페이스 쇼핑이다.
3. 마무리
내가 잘 이해한 게 맞을까 싶을 땐 써두는게 편하다(확실히)
내일은 이해한 걸 바탕으로 아이템 인벤토리까지 구현을 해볼...예정...이다!
내일 목표: 개인 프로젝트에 HP바 넣기, 아이템 인벤토리 만들기
'Unity_본캠프' 카테고리의 다른 글
[내일배움캠프 30일차] Ray 빔~!!! (1) | 2025.05.20 |
---|---|
[내일배움캠프 28일차] 델리...케이트...람...다? (2) | 2025.05.16 |
[내일배움캠프 25일차] Oh, Event. (2) | 2025.05.13 |
[내일배움캠프 24일차] 생각보다 길은 단순함에 있다 (1) | 2025.05.12 |
[내일배움캠프 23일차] Unity팀 프로젝트: 트랩 / 클리어용 아이템 (0) | 2025.05.09 |