게임 개요
화살 피하기 게임은 위에서 떨어지는 화살을 피하면서 생존하는 게임입니다. 플레이어는 좌우로 이동하여 화살을 피하고, 화살에 맞으면 HP가 감소합니다. HP가 0이 되면 게임 오버가 됩니다.
게임 기능
- 플레이어 이동: 좌우 화살표 키로 플레이어 이동
- 화살 생성: 일정 시간마다 화면 상단에서 화살 생성
- 화살 낙하: 생성된 화살이 아래로 떨어짐
- 충돌 감지: 플레이어와 화살의 충돌 감지
- HP 시스템: 화살에 맞으면 HP 감소
- 게임 오버: HP가 0이 되면 게임 종료
프로젝트 구조
02.Scripts/
├── PlayerController.cs # 플레이어 이동 제어
├── GameManager.cs # 게임 상태 및 HP 관리
├── ArrowGenerator.cs # 화살 생성
└── ArrowController.cs # 화살 이동 및 충돌 감지
1. 플레이어 컨트롤러 (PlayerController.cs)
기능
- 좌우 화살표 키 입력 받기
- 플레이어를 좌우로 이동시키기
구현 코드
using UnityEngine;
public class PlayerController : MonoBehaviour
{
// 플레이어의 이동 속도
public float moveSpeed = 0.2f;
void Update()
{
// 왼쪽 화살표 키 입력
if (Input.GetKey(KeyCode.LeftArrow))
{
// 왼쪽으로 이동
transform.Translate(-moveSpeed, 0, 0);
}
// 오른쪽 화살표 키 입력
if (Input.GetKey(KeyCode.RightArrow))
{
// 오른쪽으로 이동
transform.Translate(moveSpeed, 0, 0);
}
}
}
주요 개념
- Input.GetKey(): 키가 눌려있는 동안 계속 true 반환(return)
- transform.Translate(): 현재 위치를 기준으로 상대적으로 이동
- moveSpeed: 이동 속도 조절 (Inspector에서 조정 가능)
Unity 설정
- 플레이어 GameObject 생성
- PlayerController 스크립트 추가
- Sprite Renderer로 플레이어 이미지 설정
- moveSpeed 값 조정 (기본값: 0.2)
2. 게임 매니저 (GameManager.cs)
기능
- HP 게이지 관리
- HP 감소 메서드(method) 제공
구현 코드
using UnityEngine;
using UnityEngine.UI;
public class GameManager : MonoBehaviour
{
// HP 게이지를 표시하는 UI Image 컴포넌트
public Image hpGauge;
// HP를 감소시키는 메서드
public void DecreaseHp()
{
// HP 게이지의 채워진 양을 0.2만큼 감소
hpGauge.fillAmount -= 0.2f;
}
}
주요 개념
- Image.fillAmount: 0.0(비어있음) ~ 1.0(가득참) 사이의 값
- public 메서드(method): 다른 스크립트에서 호출 가능
Unity 설정
- GameManager GameObject 생성
- GameManager 스크립트 추가
- UI Canvas 생성
- Image 컴포넌트 추가 (HP 게이지용)
- Image의 Image Type을 "Filled"로 설정
- GameManager의 hpGauge에 Image 할당
3. 화살 생성기 (ArrowGenerator.cs)
기능
- 일정 시간마다 화살 생성
- 랜덤한 X 위치에 화살 생성
구현 코드
using UnityEngine;
public class ArrowGenerator : MonoBehaviour
{
// 화살 프리팹 오브젝트
public GameObject arrowPrefab;
// 화살 생성 간격 (초 단위)
float spawnTime = 0.3f;
// 경과 시간을 누적하는 변수
float delta = 0f;
void Update()
{
// 이전 프레임과 현재 프레임 사이의 시간 간격을 누적
delta += Time.deltaTime;
// 누적된 시간이 생성 간격을 초과했는지 확인
if (delta > spawnTime)
{
// 타이머를 초기화
delta = 0f;
// 화살 프리팹을 복제하여 새로운 화살 오브젝트를 생성
GameObject ar = Instantiate(arrowPrefab);
// 화살이 생성될 X 좌표를 랜덤하게 결정
float px = Random.Range(-8.4f, 8.4f);
// 생성된 화살의 위치를 설정
ar.transform.position = new Vector3(px, 6f, 0);
}
}
}
주요 개념
- Time.deltaTime: 프레임레이트와 무관하게 일정한 시간 간격 제공
- Instantiate(): 프리팹을 복제하여 새 오브젝트 생성
- Random.Range(): 랜덤한 값 생성
Unity 설정
- ArrowGenerator GameObject 생성
- ArrowGenerator 스크립트 추가
- 화살 프리팹 생성 (Arrow GameObject)
- ArrowGenerator의 arrowPrefab에 화살 프리팹 할당
- spawnTime 값 조정 (기본값: 0.3초)
4. 화살 컨트롤러 (ArrowController.cs)
기능
- 화살을 아래로 이동시키기
- 화면 밖으로 나가면 삭제
- 플레이어와의 충돌 감지
- 충돌 시 HP 감소 및 화살 삭제
구현 코드
using UnityEngine;
public class ArrowController : MonoBehaviour
{
// 화살의 이동 속도
public float arrowSpeed = 0.1f;
// 플레이어 오브젝트의 참조
GameObject player;
void Start()
{
// 씬에서 "player"라는 이름의 게임 오브젝트를 찾아 참조를 저장
player = GameObject.Find("player");
}
void Update()
{
// 화살을 아래 방향으로 이동
transform.Translate(0, -arrowSpeed, 0);
// 화살이 화면 아래로 너무 멀리 나갔는지 확인
if (transform.position.y < -6f)
{
// 화살 오브젝트를 메모리에서 제거
Destroy(gameObject);
}
// 충돌 감지를 위한 원거리 계산 (원-원 충돌 감지 알고리즘)
// 화살의 현재 위치를 2D 벡터로 저장
Vector2 p1 = transform.position; // Arrow
// 플레이어의 현재 위치를 2D 벡터로 저장
Vector2 p2 = player.transform.position; // Player
// 화살에서 플레이어로의 방향 벡터를 계산
Vector2 direction = p1 - p2;
// 두 오브젝트 사이의 거리를 계산 (벡터의 크기)
float d = direction.magnitude;
// 화살의 충돌 반경
float r1 = 0.5f; // Arrow radius
// 플레이어의 충돌 반경
float r2 = 1.0f; // Player radius
// 원-원 충돌 감지: 두 원의 중심 사이의 거리가 두 반지름의 합보다 작으면 충돌
if (d < r1 + r2)
{
// 씬에서 "GameManager"라는 이름의 게임 오브젝트를 찾아 참조를 가져옴
GameObject gm = GameObject.Find("GameManager");
// GameManager 컴포넌트를 가져와서 DecreaseHp() 메서드를 호출
gm.GetComponent<GameManager>().DecreaseHp();
// 충돌이 감지되었으므로 화살 오브젝트를 삭제
Destroy(gameObject);
}
}
}
주요 개념
- GameObject.Find(): 이름으로 GameObject 찾기
- GetComponent(): 컴포넌트 가져오기
- Vector2.magnitude: 벡터의 크기 (거리)
- 원-원 충돌 감지: 두 원의 중심 거리 < 반지름 합
Unity 설정
- 화살 프리팹에 ArrowController 스크립트 추가
- arrowSpeed 값 조정 (기본값: 0.1)
- 플레이어 GameObject 이름을 "player"로 설정
- GameManager GameObject 이름을 "GameManager"로 설정
게임 구현 단계별 가이드
1단계: 씬 설정
- 새 씬 생성: File > New Scene
- 카메라 설정: Orthographic 카메라 사용 (2D 게임)
- 배경 설정: 배경 이미지 또는 색상 설정
2단계: 플레이어 설정
-
플레이어 GameObject 생성
- GameObject > 2D Object > Sprite
- 이름을 "player"로 변경
- Sprite Renderer로 플레이어 이미지 설정
-
PlayerController 스크립트 추가
- PlayerController.cs 스크립트 생성
- 플레이어 GameObject에 추가
- moveSpeed 값 조정
3단계: 게임 매니저 설정
-
GameManager GameObject 생성
- 빈 GameObject 생성
- 이름을 "GameManager"로 변경
- GameManager.cs 스크립트 추가
-
HP 게이지 UI 설정
- Canvas 생성 (GameObject > UI > Canvas)
- Image 생성 (GameObject > UI > Image)
- Image Type을 "Filled"로 설정
- Fill Method: Horizontal
- Fill Origin: Left
- GameManager의 hpGauge에 Image 할당
4단계: 화살 설정
-
화살 프리팹 생성
- GameObject > 2D Object > Sprite
- 이름을 "Arrow"로 변경
- Sprite Renderer로 화살 이미지 설정
- ArrowController.cs 스크립트 추가
- Prefabs 폴더에 드래그하여 프리팹 생성
-
ArrowGenerator 설정
- 빈 GameObject 생성
- 이름을 "ArrowGenerator"로 변경
- ArrowGenerator.cs 스크립트 추가
- arrowPrefab에 화살 프리팹 할당
5단계: 테스트 및 조정
- 게임 실행: Play 버튼 클릭
- 속도 조정:
- 플레이어 이동 속도 (moveSpeed)
- 화살 낙하 속도 (arrowSpeed)
- 화살 생성 간격 (spawnTime)
- 충돌 범위 조정:
- 화살 반경 (r1)
- 플레이어 반경 (r2)
게임 메커니즘 상세 설명
1. 시간 기반 화살 생성
delta += Time.deltaTime; // 시간 누적
if (delta > spawnTime) // 일정 시간 경과 시
{
delta = 0f; // 타이머 리셋
// 화살 생성
}
- Time.deltaTime: 프레임레이트와 무관한 일정한 시간
- delta 누적: 경과 시간 추적
- spawnTime: 생성 간격 조절
2. 원-원 충돌 감지 알고리즘
Vector2 direction = p1 - p2; // 방향 벡터
float d = direction.magnitude; // 거리
if (d < r1 + r2) // 충돌 판정
{
// 충돌 처리
}
- 두 점 사이의 거리: 벡터의 크기(magnitude)로 계산
- 충돌 판정: 거리 < 반지름 합
- 반지름 조정: 오브젝트 크기에 맞게 설정
3. HP 시스템
hpGauge.fillAmount -= 0.2f; // HP 20% 감소
- fillAmount: 0.0 ~ 1.0 사이의 값
- 0.2 감소: 한 번에 20%씩 감소
- 5번 맞으면 게임 오버: fillAmount가 0이 되면 HP 소진
게임 개선 아이디어
1. 게임 오버 처리
public void DecreaseHp()
{
hpGauge.fillAmount -= 0.2f;
// HP가 0 이하가 되면 게임 오버
if (hpGauge.fillAmount <= 0f)
{
GameOver();
}
}
void GameOver()
{
Debug.Log("Game Over!");
Time.timeScale = 0f; // 게임 일시정지
}
2. 점수 시스템
public int score = 0;
public Text scoreText;
void Update()
{
// 시간이 지날수록 점수 증가
score += (int)(Time.deltaTime * 10);
scoreText.text = "Score: " + score;
}
3. 난이도 증가
float spawnTime = 0.3f;
float minSpawnTime = 0.1f;
void Update()
{
// 시간이 지날수록 생성 간격 감소
spawnTime = Mathf.Max(minSpawnTime, 0.3f - Time.time * 0.01f);
}
4. 사운드 효과
public AudioSource hitSound;
public AudioSource missSound;
void OnHit()
{
hitSound.Play();
}
void OnMiss()
{
missSound.Play();
}
트러블슈팅
문제 1: 화살이 생성되지 않음
원인: arrowPrefab이 할당되지 않음 해결: ArrowGenerator의 arrowPrefab에 화살 프리팹 할당
문제 2: 충돌이 감지되지 않음
원인:
- 플레이어나 GameManager 이름이 잘못됨
- 충돌 반경이 너무 작음
해결:
- GameObject 이름 확인 ("player", "GameManager")
- r1, r2 값 증가
문제 3: HP 게이지가 업데이트되지 않음
원인: hpGauge가 할당되지 않음 해결: GameManager의 hpGauge에 Image 컴포넌트 할당
문제 4: 화살이 너무 빠르거나 느림
원인: arrowSpeed 값이 적절하지 않음 해결: ArrowController의 arrowSpeed 값 조정
정리
핵심 스크립트 역할
| 스크립트 | 역할 | 주요 기능 |
|---|---|---|
| PlayerController | 플레이어 제어 | 좌우 이동 |
| GameManager | 게임 상태 관리 | HP 관리 |
| ArrowGenerator | 화살 생성 | 시간차 생성 |
| ArrowController | 화살 제어 | 이동, 충돌 감지 |
주요 Unity 기능
- Input.GetKey(): 키 입력 감지
- transform.Translate(): 오브젝트 이동
- Instantiate(): 오브젝트 생성
- Destroy(): 오브젝트 삭제
- Time.deltaTime: 프레임 독립 시간
- Vector2.magnitude: 거리 계산
- GameObject.Find(): 오브젝트 찾기
- GetComponent(): 컴포넌트 가져오기
다음 단계
이 게임을 기반으로 다음과 같은 기능을 추가할 수 있습니다:
- 게임 오버 화면
- 재시작 기능
- 점수 시스템
- 난이도 증가
- 파워업 아이템
- 사운드 효과
- 파티클 효과
연습 문제
-
게임 오버 기능을 추가하여 HP가 0이 되면 게임이 종료되도록 하세요.
-
점수 시스템을 추가하여 생존 시간에 따라 점수가 증가하도록 하세요.
-
난이도 증가 시스템을 추가하여 시간이 지날수록 화살 생성 속도가 빨라지도록 하세요.
-
화살에 맞았을 때 화면이 깜빡이는 효과를 추가하세요.
-
플레이어가 화살을 피했을 때 점수를 추가하는 보너스 시스템을 만드세요.