Unity 3D에서 마우스 클릭으로 투사체(밤송이)를 발사하여 움직이는 타겟을 맞추는 게임을 만들어봅니다. Ray를 활용한 마우스 좌표 변환, 프리팹 생성, 물리 기반 발사 등을 학습합니다.
게임 구조
이 게임은 세 가지 핵심 스크립트로 구성됩니다:
| 스크립트 | 역할 |
|---|---|
BamsongiController |
밤송이(투사체) 발사, 충돌 처리, 파티클 효과 |
BamsongiGenerator |
마우스 클릭 시 밤송이 생성 및 발사 |
TargetController |
타겟(과녁) 좌우 왕복 이동 |
BamsongiController - 투사체 컨트롤러
밤송이(투사체)의 발사와 충돌 처리를 담당하는 스크립트입니다.
전체 코드
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
public class BamsongiController : MonoBehaviour
{
void Start()
{
// Shoot(new Vector3(0, 250, 2000));
}
public void Shoot(Vector3 dir)
{
GetComponent<Rigidbody>().AddForce(dir);
}
private void OnCollisionEnter(Collision collision)
{
GetComponent<Rigidbody>().isKinematic = true;
GetComponent<ParticleSystem>().Play();
transform.parent = collision.transform;
GetComponent<SphereCollider>().enabled = false;
// 밤송이 오브젝트 삭제
Destroy(gameObject, 5.0f);
}
}
핵심 개념 설명
1. public 메서드(method)로 발사 기능 제공
public void Shoot(Vector3 dir)
{
GetComponent<Rigidbody>().AddForce(dir);
}
public메서드(method)로 외부에서 호출 가능AddForce(): Rigidbody에 물리적 힘을 가해 발사dir: 발사 방향과 힘의 크기를 포함한 벡터
2. 충돌 감지 및 처리
private void OnCollisionEnter(Collision collision)
{
GetComponent<Rigidbody>().isKinematic = true;
GetComponent<ParticleSystem>().Play();
transform.parent = collision.transform;
GetComponent<SphereCollider>().enabled = false;
Destroy(gameObject, 5.0f);
}
| 코드 | 설명 |
|---|---|
isKinematic = true |
물리 시뮬레이션 비활성화 (더 이상 중력/힘 영향 안 받음) |
ParticleSystem.Play() |
충돌 시 파티클 효과 재생 |
transform.parent = collision.transform |
충돌한 오브젝트의 자식으로 설정 (타겟에 박힘) |
SphereCollider.enabled = false |
콜라이더 비활성화 (추가 충돌 방지) |
Destroy(gameObject, 5.0f) |
5초 후 오브젝트 삭제 |
isKinematic이란?
true로 설정하면 Rigidbody가 물리 엔진의 영향을 받지 않고, 스크립트나 애니메이션으로만 제어됩니다. 밤송이가 타겟에 박힌 후 떨어지지 않게 합니다.
BamsongiGenerator - 투사체 생성기
마우스 클릭 시 밤송이를 생성하고 클릭 방향으로 발사하는 스크립트입니다.
전체 코드
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BamsongiGenerator : MonoBehaviour
{
public GameObject bamsongiPrefab;
void Update()
{
// 마우스 왼쪽 클릭시 화면의 클릭 좌표에 밤송이 오브젝트 생성 및 날리기
if (Input.GetMouseButtonDown(0))
{
GameObject bamsongi = Instantiate(bamsongiPrefab);
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Vector3 worldDir = ray.direction;
bamsongi.GetComponent<BamsongiController>().Shoot(worldDir.normalized * 2000);
}
}
}
핵심 개념 설명
1. 프리팹 참조
public GameObject bamsongiPrefab;
- Inspector에서 밤송이 프리팹을 드래그하여 연결
- 프리팹: 미리 만들어둔 게임 오브젝트 템플릿
2. 마우스 클릭 감지
if (Input.GetMouseButtonDown(0))
Input.GetMouseButtonDown(0): 마우스 왼쪽 버튼 클릭0: 왼쪽,1: 오른쪽,2: 가운데 버튼
3. 프리팹 인스턴스(instance)화
GameObject bamsongi = Instantiate(bamsongiPrefab);
Instantiate(): 프리팹을 복제하여 새 게임 오브젝트 생성- 반환(return)값(return value)으로 생성된 오브젝트 참조 획득
4. Ray를 활용한 방향 계산 (핵심!)
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Vector3 worldDir = ray.direction;
bamsongi.GetComponent<BamsongiController>().Shoot(worldDir.normalized * 2000);
| 코드 | 설명 |
|---|---|
Camera.main |
메인 카메라 참조 |
ScreenPointToRay() |
화면 좌표를 3D 공간의 Ray로 변환 |
Input.mousePosition |
마우스의 화면 좌표 (픽셀 단위) |
ray.direction |
Ray의 방향 벡터 |
worldDir.normalized * 2000 |
정규화 후 힘의 크기 적용 |
Ray란?
시작점과 방향을 가진 무한한 직선입니다. 카메라에서 마우스 클릭 위치를 향해 뻗어나가는 광선으로, 3D 공간에서 마우스 클릭 위치를 파악하는 데 사용됩니다.
화면 좌표 → 월드 좌표 변환 과정
마우스 클릭 (화면 좌표)
↓
Input.mousePosition (픽셀: 예 - 640, 480)
↓
Camera.main.ScreenPointToRay()
↓
Ray (카메라 위치에서 클릭 방향으로 향하는 광선)
↓
ray.direction (월드 좌표계의 방향 벡터)
↓
발사 방향으로 사용
TargetController - 타겟 컨트롤러
과녁이 좌우로 왕복 이동하는 스크립트입니다.
전체 코드
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TargetController : MonoBehaviour
{
// 속도는 변수로 관리
float speed = 3.0f;
// 현재 x 위치와 방향을 추적
float currentX = 0f;
float direction = 1f; // 1: 오른쪽, -1: 왼쪽
void Update()
{
// 증감 연산자를 활용해서 x 위치 업데이트
currentX += speed * direction * Time.deltaTime;
// 경계에 도달하면 방향 반전
if (currentX >= 20f)
{
currentX = 20f;
direction = -1f; // 왼쪽으로 방향 전환
}
else if (currentX <= -20f)
{
currentX = -20f;
direction = 1f; // 오른쪽으로 방향 전환
}
// target 오브젝트의 x 축이 +20 -20 으로 반복되게 움직이기
transform.position = new Vector3(currentX, transform.position.y, transform.position.z);
}
}
핵심 개념 설명
1. 이동 변수(variable) 선언
float speed = 3.0f;
float currentX = 0f;
float direction = 1f; // 1: 오른쪽, -1: 왼쪽
speed: 이동 속도currentX: 현재 X 위치 추적direction: 이동 방향 (1 또는 -1)
2. Time.deltaTime을 활용한 프레임 독립적 이동
currentX += speed * direction * Time.deltaTime;
Time.deltaTime: 이전 프레임부터 현재 프레임까지의 시간 (초)- 프레임 속도와 관계없이 일정한 속도로 이동
Time.deltaTime 없이 사용하면?
고성능 PC에서는 빠르게, 저성능 PC에서는 느리게 움직입니다.Time.deltaTime을 곱하면 모든 환경에서 동일한 속도로 이동합니다.
3. 경계 체크 및 방향 반전
if (currentX >= 20f)
{
currentX = 20f;
direction = -1f;
}
else if (currentX <= -20f)
{
currentX = -20f;
direction = 1f;
}
- X 좌표가 ±20을 넘으면 방향 반전
- 경계값으로 고정하여 범위 초과 방지
4. 위치 적용
transform.position = new Vector3(currentX, transform.position.y, transform.position.z);
- X축만 변경하고 Y, Z축은 기존 값 유지
new Vector3()로 새 위치 벡터 생성
Unity 설정 체크리스트(list)
밤송이 프리팹 (Bamsongi Prefab)
- 3D 모델 또는 Sphere 오브젝트 생성
-
Rigidbody컴포넌트 추가 -
SphereCollider컴포넌트 추가 -
ParticleSystem컴포넌트 추가 (충돌 이펙트) -
BamsongiController스크립트 추가 - 프리팹으로 저장 (Project 창으로 드래그)
생성기 오브젝트 (Generator)
- 빈 GameObject 생성
-
BamsongiGenerator스크립트 추가 -
bamsongiPrefab변수(variable)에 프리팹 연결
타겟 오브젝트 (Target)
- 과녁 3D 모델 또는 Cube 오브젝트 생성
-
Collider컴포넌트 추가 (충돌 감지용) -
TargetController스크립트 추가
카메라 설정
- Main Camera에 "MainCamera" 태그 설정 (기본값)
- 카메라가 타겟과 발사 위치를 볼 수 있도록 배치
주요 개념 정리
3D vs 2D 차이점
| 항목 | 2D | 3D |
|---|---|---|
| 물리 컴포넌트 | Rigidbody2D | Rigidbody |
| 충돌 컴포넌트 | Collider2D | Collider |
| 충돌 콜백 | OnCollisionEnter2D | OnCollisionEnter |
| 좌표 | Vector2 | Vector3 |
Ray 활용 패턴
// 마우스 클릭 위치로 Ray 생성
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
// Ray 방향 사용 (발사 방향)
Vector3 direction = ray.direction;
// Raycast로 충돌 감지
if (Physics.Raycast(ray, out RaycastHit hit))
{
// hit.point: 충돌 지점
// hit.collider: 충돌한 콜라이더
}
Rigidbody.isKinematic 활용
| isKinematic | 동작 |
|---|---|
false (기본) |
물리 엔진이 제어 (중력, 충돌 반응) |
true |
스크립트/애니메이션이 제어 (물리 무시) |
요약
| 항목 | 내용 |
|---|---|
| 투사체 발사 | Rigidbody.AddForce(direction) |
| 프리팹 생성 | Instantiate(prefab) |
| 마우스 → Ray | Camera.main.ScreenPointToRay(Input.mousePosition) |
| 충돌 후 고정 | Rigidbody.isKinematic = true |
| 오브젝트 부착 | transform.parent = collision.transform |
| 지연 삭제 | Destroy(gameObject, 5.0f) |
| 왕복 이동 | direction 변수(variable)로 방향 반전 |
| 프레임 독립 이동 | speed * Time.deltaTime |
이 세 가지 스크립트를 조합하면 마우스 클릭으로 투사체를 발사하여 움직이는 타겟을 맞추는 3D 슈팅 게임을 구현할 수 있습니다.