[24회차수업내용] 250618
1. 몬스터 처치 + 아이템 드롭 실습
2. Layer 이해하기
1.1 몬스터 클릭 시 대미지 적용
using System.Collections;
using UnityEngine;
// 몬스터 기본 동작을 정의하는 추상 클래스
public abstract class Monster : MonoBehaviour
{
private SpriteRenderer sRenderer; // 몬스터의 스프라이트 렌더러
private Animator animator; // 몬스터의 애니메이터
[SerializeField] protected float hp = 3f; // 체력 (외부에서 수정 가능)
[SerializeField] protected float moveSpeed = 3f; // 이동 속도
private int dir = 1; // 이동 방향 (1: 오른쪽, -1: 왼쪽)
private bool isMove = true; // 이동 중인지 여부
private bool isHit = false; // 피격 중인지 여부
public abstract void Init(); // 자식 클래스에서 반드시 구현해야 하는 초기화 메서드
void Start()
{
// 컴포넌트 가져오기
sRenderer = GetComponent<SpriteRenderer>();
animator = GetComponent<Animator>();
Init(); // 자식 클래스가 구현한 초기화 실행
}
// 마우스 클릭 시 실행됨 (테스트용 피격)
void OnMouseDown()
{
StartCoroutine(Hit(1)); // 코루틴 실행해서 1 데미지 입히기
}
void Update()
{
Move(); // 매 프레임 이동 처리
}
// 좌우 반복 이동하는 로직
void Move()
{
if (!isMove)
return; // isMove가 false면 아래 코드 실행 안 하고 함수 종료
// 이동 처리
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;
}
}
// 피격 처리 (코루틴 사용, 일정 시간 멈춤)
IEnumerator Hit(float damage)
{
if (isHit)
yield break; // 이미 피격 중이면 중복 실행 방지
isHit = true;
isMove = false; // 이동 중지
hp -= damage; // 체력 감소
// 체력이 0 이하가 되면 몬스터 오브젝트 제거
if (hp <= 0)
{
animator.SetTrigger("Death"); // 죽음 애니메이션 실행
yield return new WaitForSeconds(3f); // 3초 후 삭제
Destroy(gameObject);
yield break;
}
animator.SetTrigger("Hit"); // 피격 애니메이션 실행
yield return new WaitForSeconds(0.65f); // 피격 애니메이션 대기 시간
isHit = false;
isMove = true; // 이동 재개
}
}
* 리마인드
- IEnumerator는 C#에서 코루틴(Coroutine)을 만들 때 사용하는 반환형
- 코루틴 = 시간이 걸리는 작업을 여러 프레임에 나눠서 실행하는 함수
- 여기서는 중복클릭/실행을 막기 위해 사용
IEnumerator 함수이름(float 값)
{
// 실행할 코드
yield return new WaitForSeconds(값);
}
StartCoroutine(함수이름(3f)); // 3초 대기하는 코루틴 호출
*애니메이터 연결

* 클릭되려면, 즉 OnMouseDown() 메서드가 정상적으로 호출되려면 해당 게임 오브젝트에 Collider가 반드시 있어야 함.
1.2 몬스터 생성 범위 조정 in Unity
* camera size
- Orthographic 카메라(2D 게임 등 평면적 게임에서 사용) 일 때만 활성화되는 값.
- 화면에 보이는 절반 높이를 의미.
- 이 실습에서는 (-8 ~ 8)을 범위로 잡았으니 그에 맞게 조정
1.3 스포너매니저 _ 몬스터 스폰 + 아이템 드롭
using System.Collections;
using UnityEngine;
public class SpawnManager : MonoBehaviour
{ // 개수가 정해져있으니까 리스트보다 더 빠른 배열을 사용
[SerializeField] private GameObject[] monsters; // 생성할 몬스터 프리팹 배열 (에디터에서 할당)
[SerializeField] private GameObject[] items; // 생성할 아이템 프리팹 배열 (에디터에서 할당)
IEnumerator Start()
{
// 무한 반복 → 게임 시작 시 몬스터가 계속 주기적으로 생성됨
while (true)
{
yield return new WaitForSeconds(3f); // 3초 대기 후 다음 실행
var randomIndex = Random.Range(0, monsters.Length); // 몬스터 종류 랜덤 선택
var randomX = Random.Range(-8, 9); // 생성 위치 X 좌표 랜덤 (-8 ~ 8)
var randomY = Random.Range(-3, 5); // 생성 위치 Y 좌표 랜덤 (-3 ~ 4)
var createPos = new Vector3(randomX, randomY, 0); // 생성 위치 설정
Instantiate(monsters[randomIndex], createPos, Quaternion.identity); // 몬스터 생성 (회전 없음)
}
}
// 특정 위치에 랜덤 아이템을 생성하는 메서드
public void DropCoin(Vector3 dropPos)
{
// 아이템 배열에서 랜덤 인덱스 선택
var randomIndex = Random.Range(0, items.Length);
// 선택된 아이템 프리팹을 지정한 위치에 회전 없이 생성
Instantiate(items[randomIndex], dropPos, Quaternion.identity);
}
}
*리마인드 / while (true) + yield return new WaitForSeconds() 구조:
- while + yield 조합은 반복적으로 일정 시간마다 무언가를 실행할 때 자주 사용
- while (true) = 무한반복
IEnumerator SomeCoroutine()
{
while (true)
{
// 반복적으로 실행할 코드
yield return new WaitForSeconds(시간);
// 일정 시간 대기 후 다시 반복
}
}
<주의> 정수형 Random.Range(int min, int max)
- min 이상, max 미만 값 반환 : 마지막 값 포함시키려면 +1 해준다
- -8 이상, 9 미만 → 결과적으로 -8 ~ 8 값 나옴.
<-> 실수형 Random.Range(float min, float max) : 그대로 쓰면 마지막 값 포함됨
- → min 이상, max 이하 값 반환
* Instantiate(monsters[randomIndex], createPos, Quaternion.identity);
Instantiate(원본, 위치, 회전);
| 원본(Prefab) | 생성할 오브젝트 (ex. 프리팹, 씬에 존재하는 오브젝트) |
| 위치(Vector3) | 생성할 위치 |
| 회전(Quaternion) | 생성할 회전 값 (보통 Quaternion.identity 사용) |
- Quaternion.identity = 회전 없음
- 회전 있다면 = Quaternion.Euler(x축 회전, y축 회전, z 축 회전)
1.4 몬스터 코드 (1.1의 코드 + spawner랑 연결)
using System.Collections;
using UnityEngine;
public abstract class Monster : MonoBehaviour
{
public SpawnManager spawner; // 스폰 매니저 참조 (몬스터가 코인 드롭 시 사용)
private SpriteRenderer sRenderer; // 스프라이트 렌더러 컴포넌트
private Animator animator; // 애니메이터 컴포넌트
[SerializeField] protected float hp = 3f; // 체력 (외부에서 조정 가능)
[SerializeField] protected float moveSpeed = 3f; // 이동 속도 (외부에서 조정 가능)
private int dir = 1; // 이동 방향 (1: 오른쪽, -1: 왼쪽)
private bool isMove = true; // 이동 가능 상태 플래그
private bool isHit = false; // 공격 중복 방지 플래그
public abstract void Init(); // 자식 클래스에서 초기화 구현
void Start()
{
spawner = FindFirstObjectByType<SpawnManager>(); // 씬에서 스폰 매니저 찾기
sRenderer = GetComponent<SpriteRenderer>(); // 스프라이트 렌더러 가져오기
animator = GetComponent<Animator>(); // 애니메이터 가져오기
Init(); // 자식 클래스 초기화 호출
}
void OnMouseDown()
{
StartCoroutine(Hit(1)); // 클릭 시 체력 1 감소 코루틴 실행
}
void Update()
{
Move(); // 매 프레임 이동 처리
}
void Move()
{
if (!isMove)
return;
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; // 스프라이트 원래 상태
}
}
IEnumerator Hit(float damage)
{
if (isHit) // 이미 공격 중이면 중복 실행 방지
yield break;
isHit = true;
isMove = false; // 공격받는 동안 이동 정지
hp -= damage; // 체력 감소
if (hp <= 0) // 체력이 0 이하일 경우 죽음 처리
{
animator.SetTrigger("Death"); // 죽음 애니메이션 실행
// 몬스터 사망 시 → 현재 위치에 아이템(코인) 생성 요청
// (SpawnManager의 DropCoin 메서드 호출, 아이템 랜덤 생성)
// transform.position : 현재 몬스터의 위치 값 (죽은 위치)
spawner.DropCoin(transform.position);
yield return new WaitForSeconds(3f); // 죽음 애니메이션 대기
Destroy(gameObject); // 몬스터 오브젝트 제거
yield break; // 코루틴 종료
}
animator.SetTrigger("Hit"); // 히트 애니메이션 실행
yield return new WaitForSeconds(0.65f); // 히트 애니메이션 대기
isHit = false; // 공격 상태 해제
isMove = true; // 이동 재개
}
}
*리마인드
* FindFirstObjectByType<SpawnManager>(); <-> GetComponent<SpriteRenderer>();
: SpawnManager는 별도의 오브젝트에 붙어 있어서, 몬스터 스크립트 내에서 직접 접근할 수 없기에,
FindFirstObjectByType으로 찾는다. (씬 내에서 해당 타입(SpawnManager)을 가진 첫 번째 게임오브젝트를 찾아 반환)
: 반면 SpriteRenderer 는 현재 게임오브젝트에 붙어있어서 GetComponent 을 사용)
1.5 아이템 위로 뿌리는 기능 (spawner에 DropCoin 수정)
public void DropCoin(Vector3 dropPos)
{
var randomIndex = Random.Range(0, items.Length); // 랜덤 인덱스 설정
GameObject item = Instantiate(items[randomIndex], dropPos, Quaternion.identity);
// 생성된 아이템의 Rigidbody2D 컴포넌트 가져오기
Rigidbody2D itemRb = item.GetComponent<Rigidbody2D>();
// 아이템에 X축 방향으로 랜덤한 힘 가하기
itemRb.AddForceX(Random.Range(-2f, 2f), ForceMode2D.Impulse);
// 아이템에 Y축 방향으로 위로 솟아오르는 힘 가하기
itemRb.AddForceY(3f, ForceMode2D.Impulse);
// 아이템에 랜덤한 회전력(토크) 가하기
float ranPower = Random.Range(-1.5f, 1.5f);
itemRb.AddTorque(ranPower, ForceMode2D.Impulse);
}
• ForceMode2D.Impulse: 이 힘이 즉각적인 충격(impulse)으로 가해짐 / 폭발이나 점프와 같은 효과에 적합
*Collider / Rigidbody 필요 (Freeze Rotation 활성화)
2.1 Unity Layer 이해하기
- 게임 오브젝트를 그룹화하는 분류 체계
- 총 32개 레이어를 만들 수 있음 (0~31번)
- 주로 카메라 렌더링 제어와 충돌 검사 필터링에 사용함
-기본레이어
| 0 | Default | 기본 레이어. 아무것도 지정하지 않은 오브젝트가 속함. 대부분의 오브젝트 기본값. |
| 1 | TransparentFX | 투명 효과가 필요한 오브젝트에 사용. 레이캐스트 무시 등 특수 처리가 가능. |
| 2 | Ignore Raycast | 레이캐스트 검사에서 무시되는 레이어. 예: 플레이어가 쏜 총알이 자신을 맞추지 않게 할 때 사용. |
| 3 | (사용자 지정 없음) | 비어있음, 필요하면 이름 지정 가능. |
| 4 | Water | 물 오브젝트용 레이어. 프로젝트에 따라 특별히 처리할 수 있음. |
| 5 | UI | UI 요소에 할당. UI 렌더링이나 입력 처리에 도움. |
2.2 충돌 필터링_ 레이어 충돌 매트릭스 (Layer Collision Matrix)
: Add layer로 Monster, Coin Layer 생성 후
- Edit → Project Settings → Physics 2D → Layer Collision Matrix에서 설정
"Monster" 레이어에 속한 게임 오브젝트(예: 몬스터 캐릭터)와 "Coin" 레이어에 속한 게임 오브젝트(예: 코인 아이템)가 물리적으로 충돌하지 않게 한다.

- 2D 물리 시스템에서만 적용됨 (3D 물리는 Physics → Layer Collision Matrix 따로 있음).
- Collider 컴포넌트가 있어야 충돌 체크가 진행됨.
- Rigidbody2D가 함께 있어야 물리 충돌과 상호작용이 잘 됨.
2.3 Order in Layer (레이어 내 순서)
숫자가 높을수록 더 나중에 그려지므로, 화면상에서 더 앞에 보임.
이미 배운 내용들을 다시 끌어와서 이것저것 구현해 보았다. 직접 프로젝트에 적용해 보니 공부한 내용이 더 흥미롭고 재미있게 다가왔다. 하지만 여전히 익숙하지 않아서 복습의 필요성을 느꼈다. 앞으로도 꾸준한 복습과 실습을 통해 이해를 깊게 하고 실력을 확실히 다져야겠다는 다짐을 하게 되었다.
'프로그래밍 > 유니티 부트캠프' 카테고리의 다른 글
| 유니티(게임수학_외적내적/ 타일 생성 포탑 설치 실습 / 조이스틱구현1) _ 멋쟁이사자처럼 유니티 부트캠프 후기 26회차 (0) | 2025.06.23 |
|---|---|
| 유니티(몬스터 공격 실습/아이템획득/게임수학/터렛회전) _ 멋쟁이사자처럼 유니티 부트캠프 후기 25회차 (2) | 2025.06.23 |
| 유니티(캡슐화,인터페이스/상속 실습 - 몬스터, 아이템) _ 멋쟁이사자처럼 유니티 부트캠프 후기 23회차 (2) | 2025.06.17 |
| 유니티(오버로딩,상속,가상화/추상화,인터페이스 실습) _ 멋쟁이사자처럼 유니티 부트캠프 후기 22회차 (0) | 2025.06.17 |
| 유니티(형변환,객체지향프로그래밍) _ 멋쟁이사자처럼 유니티 부트캠프 후기 21회차 (0) | 2025.06.13 |