Carrot
본문 바로가기
Unity/멋쟁이사자처럼 부트캠프

[멋쟁이사자처럼부트캠프] 유니티 게임 개발 5기(9일차) - 게임 오브젝트 업그레이드 및 구현

by 독기품은토끼 2025. 5. 23.
✅ 오늘의 학습 목표
1. 게임 캐릭터 이동 성능 업그레이드
2. 총알 발사 오브젝트 구현
3. 태양계 자전, 공전 오브젝트 구현

 

1. 캐릭터 이동 성능(Movement) 업그레이드 (3)

1. Input System

저번 포스팅에서 Input System의 이야기를 다뤄봤다.

GetAxis 외에도 Raw라는 기능도 있는데, 이것도 한번 알아봐 보자

 

1.1. GetAxis와 GetAxisRaw의 차이

void Update()
{
    //float h = Input.GetAxis("Horizontal"); // 수평 Z의 값
    //float v = Input.GetAxis("Vertical"); // 수직 X의 값

    float h = Input.GetAxisRaw("Horizontal"); // 수평 Z의 값
    float v = Input.GetAxisRaw("Vertical"); // 수직 X의 값

    Vector3 dir = new Vector3(h, 0, v).normalized;
    //Vector3 dir = new Vector3(h, 0, v);
    //Vector3 normalDir = dir.normalized; // 정규화 과정 (0 ~ 1)


    Debug.Log($"현재 입력 : {dir}");

    transform.position += dir * moveSpeed * Time.deltaTime;
}
항목 Input.GetAxis Input.GetAxisRaw
리턴 값 범위 -1.0 ~ 1.0 사이의 부드러운 값 -1, 0, 1의 정수값
반응 방식 부드럽게 가속/감속함 (스무딩 적용) 즉시 반응 (스무딩 없음)
사용 용도 부드러운 움직임이 필요한 경우 정밀한 방향 입력이나 빠른 반응이 필요할 때
예시 캐릭터 움직임의 자연스러운 처리 메뉴 선택, 빠른 회전, 정밀 조작 등
GetAxis GetAxisRaw

 

개쩌는 눈을 갖고 계신 분이라면 차이가 확 느껴지려나..?

Axis는 부드러운 느낌, Raw는 약간 딱딱한 느낌이 나는 거 같기는 하다..

 

1.2. Normalized

 

콘솔창을 확인해 보면 대각선으로 이동할 경우 2개의 벡터 값이 입력되기 때문에 벡터값이 합산되어 dir 값을 반환함

 

 

이러면 방향키를 한 개만 눌렀을 때보다 속도가 1.41배 빨라짐을 알 수 있음.

이런 문제점을 개선하기 위하여 normalized를 통해 정규화 작업을 해주는 것임!

 

2. LookAt

LookAt은 현재 오브젝트의 전방 방향(Vector3.forward)을, 지정한 대상의 위치를 향하도록 회전시키는 기능이다.

transform.LookAt(transform.position + normalDir);

 

▶ LookAt 사용 예시

  • 캐릭터나 카메라의 시선 처리
  • 총구
  • 포탑

디코에서 훔쳐옴 ㅇㅅㅇ

 

 

LookAt은 라디안 기반으로 회전을 계산한다.

위치는 바뀌지 않고 오로지 회전만 변경시킨 다는 것에 유의하자!

 

 

방향을 바꿀 때마다 오브젝트의 방향이 바뀐다! 좀 더 생동감이 넘침ㅎ0ㅎ

 

3.  Awake

캐릭터를 바라보는 포탑 만들기

🥕 예행 작업
1. Script 생성 (StudyLookAt)
2. 포탑 Object 만들기
using UnityEngine;

public class StudyLookAt : MonoBehaviour
{
    public Transform targetTf;
    public Transform turretHead;

    void Start()
    {
        targetTf = GameObject.FindGameObjectWithTag("Player").transform;
    }

    void Update()
    {
        turretHead.LookAt(targetTf);
    }
}

 

코드 실행 흐름을 살펴보면, GameObject and Prefab 씬에서는 캐릭터를 생성하고, 포탑이 그 캐릭터를 바라보도록 구현되어 있다.

하지만 Start() 함수 안에서 캐릭터를 생성한 직후 포탑이 해당 캐릭터를 찾게 될 경우,  
실행 순서에 따라 포탑이 캐릭터를 아직 찾지 못하는 문제가 발생할 수 있다.
즉, 포탑 오브젝트가 먼저 Start()를 실행하고 캐릭터는 나중에 생성된다면,  
포탑 입장에서는 캐릭터가 존재하지 않는 상태이기 때문에 Null 오류가 발생할 수 있다.

이러한 실행 순서 문제를 방지하기 위해,  
Start()보다 먼저 호출되는 Awake() 함수에서 오브젝트 초기화를 수행하여 모든 오브젝트가 안전하게 참조되도록 구성하는 것이 좋다.

using UnityEngine;

public class StudyGameObject : MonoBehaviour
{
    public GameObject prefab;

    void Awake()
    {
        CreateREPO();
    }
 }

 

그래서 StudyGameObject 스크립트의 캐릭터 생성을 최우선으로 하기 위해 Awake 메소드 안에 선언해 주면 끝!

야무지게 잘 쳐다봄 ㅎㅋ

 

3.1. GameManager

 

Awake(), Start() 등등.. 나중에 이런 걸 어떻게 다 신경 써서 구현하냐! 할 때~ 사용하는 것이 GameManager 이다.

GameManager는 Unity에서 게임 전반을 관리하는 중심 역할을 하는 스크립트이다!

 

뭐 예를 들면 씬 전환이나.. 스코어 점수 합산이나.. 기타 등등등..

 

2. 총알 오브젝트 구현

🥕 예행 작업
1. Script 생성 (Bullet)
2. 총알 Object 만들기
3. 총알 프리팹 적용

 

1. 총알 스크립트 작성

using UnityEngine;

public class Bullet : MonoBehaviour
{
    public float bulletSpeed = 100f;

    void Update()
    {
        transform.position += transform.forward * bulletSpeed * Time.deltaTime;
    }
}

 

2. 총알 프리팹에 해당 스크립트를 적용

 

3. StudyLookAt(포탑에 적용된 스크립트)에 총알 생성 구현

using UnityEngine;

public class StudyLookAt : MonoBehaviour
{
    public Transform targetTf;
    public Transform turretHead;

    public GameObject bulletPrefab; // 총알 프리팹
    public Transform firePos; // 발사 위치

    void Start()
    {
        targetTf = GameObject.FindGameObjectWithTag("Player").transform;
    }

    void Update()
    {
        turretHead.LookAt(targetTf);

        Instantiate(bulletPrefab, firePos.position, firePos.rotation);
    }
}

 

4. 유니티 에디터 - 인스펙터에 오브젝트 연결

 

이렇게 설정하면

Bullet을 생성하고, 위치나 회전은 firePos 기준으로 총알이 발사된다!

 

5. 타이머 적용

총알이 쉴 틈 없이 발사되니 타이머 기능을 추가해봅시돠

    void Update()
    {
        turretHead.LookAt(targetTf);

        timer += Time.deltaTime;
        if (timer >= cooldownTime)
        {
            timer = 0f;
        }

        // 총알 생성
        Instantiate(bulletPrefab, firePos.position, firePos.rotation);
    }

 

맞아도 안 아파하는 녀석 ^-^!!

 

3. 태양계 구현

1. Assets 다운로드

 

Planets of the Solar System 3D | 3D 주변환경 | Unity Asset Store

Elevate your workflow with the Planets of the Solar System 3D asset from Evgenii Nikolskii. Find this & other 주변환경 options on the Unity Asset Store.

assetstore.unity.com

 

 

2. 프로젝트 정리

 

에셋이 많아질수록 관리가 힘들어지니 기존에 만들어둔 "99. Resources" 폴더에 다운로드한 에셋을 저장시키자!

 

3. Overview 씬 열기

 

만약 머테리얼들이 모두 깨져있다면 이 방법으로 해결하기

 

4. 행성 정리

 

행성 크기에 맞추어 행성들을 좀 정리해 준다.

 

5. 스크립트 작성

using UnityEngine;

public class PlanetRotation : MonoBehaviour
{
    public Transform targetPlanet;

    public float rotSpeed = 30f; // 자전 속도

    public float revolutionSpeed = 100f; // 공전 속도

    public bool isRevolution = false; // 논리 타입 -> true / false

    void Update()
    {
        // 자기 자신이 회전하는 기능
        transform.Rotate(Vector3.up * rotSpeed * Time.deltaTime);

        if (isRevolution == true)
        {
            // 공전하는 기능
            transform.RotateAround(targetPlanet.position, Vector3.up, revolutionSpeed * Time.deltaTime);
        }
    }
}

 

  • transform.Rotate(...): 현재 오브젝트 회전
  • transform.RotateAround(...): 특정 위치를 중심으로 오브젝트 회전

 

6. 인스펙터 연결

 

과학과는 아주 무관하게 근거 없는 랜덤 스피드로 설정 ^-^

 

링가링가링가 링가링가링 (나만 떠오름?)

 

 

 


 

 

 

 

모델링? 이라고 하기도 애매한데.. 암튼 오브젝트 만드는 날은 진짜 정신이 없다!!

잘 만들려는 욕심과 그렇지 못한 창의력 때문인지 자꾸 오브젝트 다듬느라 수업 진도를 놓침 ㅋ

얼레벌레 따라잡으면 또 오브젝트 만들고 있고!!

태양계 할 때에는 진짜 오브젝트별로 크기가 엄청 큰지 카메라도 엄청 멀리 있어서 휠 열심히 돌리느라 죽는 줄 알았음

쉬는 시간마다 안 쉬고 정리해서 그런가 오늘따라 넘 힘드네...

 

주말에 약속이 있어서 주간 회고가 가능할지는 모르겠으나 일단 목표를 한번 잡아봅시다.

 

1. 유니티 단축키 정리

2. C# 코드 기능별로 어떻게 구현했는지 복습