밤송이 던지기 게임

Unity 3D에서 마우스 클릭으로 투사체를 발사하고 움직이는 타겟을 맞추는 게임을 구현합니다

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 슈팅 게임을 구현할 수 있습니다.


← 목차로 돌아가기