[멋쟁이사자처럼부트캠프] 유니티 게임 개발 5기(23일차) - 캡슐화 및 인터페이스&상속 실습
by 독기품은토끼2025. 6. 17.
✅ 오늘의 학습 목표 1. 캡슐화와 프로퍼티에 대해 알아보기 2. 인터페이스를 활용해서 아이템 줍기 / 사용 / 버리기 기능 구현해보기 3. 상속과 인터페이스를 활용해서 몬스터 움직임 구현해보기 4. 번외) 깃허브 날짜 변경
1. 캡슐화
1. 개념
외부로부터 데이터 접근 및 수정을 보호하는 방법으로 프로퍼티를 통해 데이터를 읽거나 바꾸도록 해주는 개념이다.
Property (프로퍼티) : 캡슐화한 데이터
private int number1 = 10;
number1은 private라서 외부 클래스에서 직접 접근이 불가하다.
public class StudyProperty : MonoBehaviour
{
private int number1 = 10;
public int number2 = 20;
public int Number1
{
get
{
return number1;
}
set
{
number1 = value;
}
}
public int Number2 { get; set; } = 20;
public int Number3 { get; private set; } = 30;
}
// 타 클래스에서 접근 가능
using UnityEngine;
public class ExternalClass : MonoBehaviour
{
public StudyProperty studyProperty;
void Start()
{
// 프로퍼티 접근으로 읽고 쓰기 가능
int num1 = studyProperty.Number1;
studyProperty.Number1 = 100;
// public 필드라 그냥 접근 가능
int num2 = studyProperty.number2;
}
}
이렇게 프로퍼티를 만들어주면 다른 클래스에서는 프로퍼티명으로 접근이 가능하게 된다.
2. 상태 변경 로직
캡슐화는 단순히 데이터를 보호하는 것뿐만 아니라 값이 바뀔 때 처리해야 하는 로직도 같이 처리할 수 있다.
using Unity.Android.Gradle.Manifest;
using UnityEngine;
public class StudyProperty : MonoBehaviour
{
private float hp = 100f;
public float Hp
{
get { return hp; }
// private set { hp = value; } // 외부에서 수정 불가 = Hit 메서드 실행 불가
set
{
if (value < 0)
{
hp = 0f;
Death();
}
else
{
hp = value;
}
}
}
public void Hit(float damage)
{
Hp -= damage;
}
public void Death()
{
Debug.Log("몬스터 죽음");
}
}
이렇게 Hp를 통해 체력이 깎이고, 0 밑으로 내려가면 Death()를 호출하는 로직을 만들 수 있다는 뜻이다!
▶ set을 private로 선언할 경우
// private set { hp = value; }
이렇게 되면 외부에서는 Hp 값을 바꿀 수 없게 된다.
그러면 위에서 구현한 Hit() 메서드에서 Hp -= damage; 이 부분이 에러가 나게 된다는 뜻이다. (Hit()도 클래스 외부 입장이라 접근이 불가능)
3. SerializeField (시리얼라이즈)
private로 선언한 변수를 유니티 인스펙터 창에 노출시키고 싶을 때 사용하는 키워드다.
[SerializeField] private float moveSpeed = 20f;
이렇게 접근제한자 앞에 [SerializeField]를 붙여주면 코드 상에서는 private라 외부 접근은 불가능하지만
유니티 인스펙터 창에서는 값 수정이 가능하다.
// 프로퍼티는 유니티 에디터에 나타나지 않음
private float moveSpeed2 = 10f;
public float MoveSpeed2
{
get { return moveSpeed2; }
set { moveSpeed2 = value; }
}
반면에 프로퍼티는 아무리 public 이어도 기본적으로 인스펙터에 보이지 않는다.
4. 그 외 Attribute
SerializeField 외에도 많이 사용되는 애트리뷰트를 정리해 보았다.
Attribute
기능
[Header("제목")]
인스펙터에서 섹션 제목 달기
[SerializeField]
private 필드도 인스펙터에 노출
[Range(min, max)]
슬라이더로 숫자 범위 제한
[Space(n)]
인스펙터 간격 주기
2. IDropItem 실습
인터페이스를 활용해서 아이템을 줍고, 사용하고, 버리는 기능을 만들어 볼 것이다.
총(Gun)과 손전등(FlashLight) 같은 아이템을 구현
캐릭터가 아이템 근처에 가면 자동으로 아이템을 줍기
클릭이나 스페이스바로 상호작용되도록 구현
🥕 예행 작업 1. Scene 생성 (InterfaceItem) 2. Script 생성 (IDropItem, CharacterControl, Gun, Flashlight) 3. Assets 다운로드
using UnityEngine;
public abstract class Monster : MonoBehaviour
{
private SpriteRenderer sRenderer;
[SerializeField] protected float hp = 3f;
[SerializeField] protected float moveSpeed = 3f;
// 화면 끝까지 가면 방향을 바꾸기 위한 값
private int dir = 1;
public abstract void Init();
void Start()
{
sRenderer = GetComponent<SpriteRenderer>();
Init(); // 자식 클래스에서 정의한 값으로 초기화
}
void OnMouseDown()
{
Hit(1);
}
void Update()
{
Move();
}
void Move()
{
transform.position += Vector3.right * dir * moveSpeed * Time.deltaTime;
if (transform.position.x > 8f)
{
dir = -1;
sRenderer.flipX = true;
}
else if (transform.position.x < -8f)
{
dir = 1;
sRenderer.flipX = false;
}
}
void Hit(float damage)
{
hp -= damage;
if (hp <= 0)
{
Debug.Log("몬스터 쥬금!");
Destroy(gameObject);
}
}
}
abstract void Init()
자식 클래스에서 꼭 구현해야 되는 abstract 함수를 구현해 주었고
각 몬스터별로 체력이나 속도를 여기서 다르게 설정해 준다.
OnMouseDown()
유니티 자체 메서드로 마우스 클릭 시 실행됨
Move()
카메라의 크기가 -8부터 8까지라 Move() 메서드에서 (-8, 8) 범위 밖으로 오브젝트가 움직이지 않도록 설정
오브젝트의 방향 값(dir)이 바뀔 때 오브젝트가 바라보는 방향도 바꿔주기 위해 SpriteRenderer 설정
Hit() : 몬스터 죽음 구현
2. 자식 클래스
public class Goblin : Monster
{
public override void Init()
{
hp = 3f;
moveSpeed = 3f;
}
}
////////////////////////////////////////////
public class Skeleton : Monster
{
public override void Init()
{
hp = 10f;
moveSpeed = 1f;
}
}
////////////////////////////////////////////
public class FlyingEye : Monster
{
public override void Init()
{
hp = 2f;
moveSpeed = 5f;
}
}
////////////////////////////////////////////
public class Mushroom : Monster
{
public override void Init()
{
hp = 5f;
moveSpeed = 2f;
}
}
부모 클래스에서 선언한 Init() 메서드를 자식 클래스에서 오버라이드하여 각자 다르게 구현
부모 클래스에서 hp와 moveSpeed를 protected 제한자로 선언해 주었기 때문에 hp와 speed 수정 가능
오브젝트 설정하는 부분은 생략했슴다 독기토끼 알잘딱 오네가이 (__)
4. Github 날짜 변경
깃 커밋하는 걸 자꾸 까먹어서 결국 야매 커밋을 해버렸다
나는 깃 데스크탑을 써본 적이 이번이 처음이라 익숙한 터미널로 커밋해 줄 것이니 참고바람!
(근데 이것도 깃 설정한 거에 따르니 이 방법을 따라 하면 큰일 날 수 있음.. 메인브렌치 잘봐주십쇼)
1. Git Bash 열기
.git 폴더가 있는 곳에서 빈 공간 우클릭 후 'Open Git Bash here'을 클릭한다.
2. 명령어 순서대로 입력
git add .
# 커밋날짜, 커밋명 등 초록색 부분은 꼭 수정하셔야합니다.
GIT_COMMITTER_DATE="2025-06-16T18:00:00" git commit --date="2025-06-16T18:00:00" -m "메세지"
git push origin main
▶ 명령어 설명
명령어
설명
git add .
모든 변경 파일 스테이징
GIT_COMMITTER_DATE=...
커밋자 날짜(작성한 사람 기준)
--date=...
저자 날짜 (작성 시각)
-m 첫 번째
커밋 메시지 제목 (깃데스크탑 -> Summary)
-m 두 번째
커밋 메시지 본문 (깃데스크탑 -> Description)
git push origin main
main 브랜치로 푸시
브랜치 이름이 main이 아닌 경우 main을 master나 다른 브랜치명으로 바꿔주어야 한다.
푸시하려는데 뭐 인증창 나와서 막혔다 & 뭔가 불안하다 하면 푸시는 그냥 깃 데스크탑에서 진행해 주어도 무방하다.
= 커밋 시간만 바꿔서 넣어주면 되는 시스템
어제 날짜로 잘 커밋되었다!
근데 \n 줄 바꿈 명령어는 안 통하네 ㄷㄷ
이 부분은 담에 또 야매 커밋하는 일 생기면 그때 포스팅 업데이트 하겠슴다!
흠냐 오늘 뭐 놀지도 않았는데 포스팅이 왜캐 늦어졌지
오늘은 오랜만에 오브젝트 움직임 구현하려니까 어라 어떻게 했더라?? 상황 발생했구..
중간에 자꾸 null 값 참조했다는 에러가 떠서 오랫동안 씨름했는데 알고보니 그냥 에디터 오류였다..
아무리 찾아도 문제가 없길래 설마? 하고 재접했는데 정상 작동..^-^ 이런식으로 억까하면 화 잔뜩!!!나