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

[멋쟁이사자처럼부트캠프] 유니티 게임 개발 5기(8일차) - 컴포넌트 활용 및 C# 기초 학습

by 독기품은토끼 2025. 5. 22.
✅ 오늘의 학습 목표
1. GameObject 접근
2. C# 기초 학습(5)

 

1. GameObject 접근

1. GameObject.Find("오브젝트이름")의 동작 방식

Unity 공식 문서에 따르면 GameObject.Find는

씬 안에 있는 모든 루트 오브젝트를 위에서부터 순회하면서, 첫 번째로 찾은 오브젝트를 반환한다.

따라서 이름이 중복되는 오브젝트가 있을 경우 성능 측에서 문제가 발생할 수 있다.

 

1.1. Tag를 통한 오브젝트 반환 (Find의 단점을 보완)

// 기존 코드
obj = GameObject.Find("Main Camera");

// 변경 후 코드
obj = GameObject.FindGameObjectWithTag("Player");

 

이렇게 코드를 변경하면,

오브젝트를 찾을 때 해당 Tag를 먼저 찾아서 반환한다.

❓ 근데 나중가면 Tag도 중복이 많아질텐데 이게 최선인가? 싶었음
찾아보니 Tag는 Tag내의 오브젝트 별로 문자열을 비교하는 게 아니라
태그별로 관리되는 내부 목록(해시 구조)에서 첫 번째 오브젝트를 찾는 구조였음


모든 문자열 비교(Find) VS Tag 중에 첫번째 꺼(Tag)
이 차이인 듯! 결론은 속도 차이가 어마무시함

 

1.2. Tag 적용 방법

 

1.3. Tag 추가 방법

 

 

2. 컴포넌트(Component) 접근

2.1. Inspector 접근

obj = GameObject.FindGameObjectWithTag("Player");

Debug.Log($"<color=#FF0000>이름 : {obj.name}"); // 게임오브젝트의 이름
Debug.Log($"태그 : {obj.tag}"); // 게임오브젝트의 태그
Debug.Log($"위치 : {obj.transform.position}"); // 게임오브젝트의 Transform 컴포넌트의 위치
Debug.Log($"회전 : {obj.transform.rotation}"); // 게임오브젝트의 Transform 컴포넌트의 회전
Debug.Log($"크기 : {obj.transform.localScale}"); // 게임오브젝트의 Transform 컴포넌트의 크기
// transform = GetComponent<Transform>()

// MeshFilter 컴포넌트에 접근해서 mesh를 Log 메세지로 출력하는 기능
Debug.Log($"Mesh 데이터 : {obj.GetComponent<MeshFilter>().mesh}");

// MeshRenderer 컴포넌트에 접근해서 material을 Log 메세지로 출력하는 기능
Debug.Log($"Meterial 데이터 : {obj.GetComponent<MeshRenderer>().material}");

 

맨 처음 log를 보면 html 문법을 적용해서 색상을 정할 수 있다.

그리고 Rotation의 결과 값은 쿼터니언으로 표기된다. (이 부분은 나중에 학습하신다 함)

항목 오일러 회전 (Euler) 쿼터니언 회전 (Quaternion)
설명 X, Y, Z 축으로 각각 회전 수학적 구조로 4개의 값 (x, y, z, w)로 회전 표현
직관성 사람에게 직관적 이해는 어렵지만, 컴퓨터는 효율적
단점 짐벌락(Gimbal Lock) 발생 가능 짐벌락 없음
회전 연산 느리고 복잡할 수 있음 부드럽고 정확한 회전
Unity 사용 방식 transform.eulerAngles로 확인 transform.rotation에서 쿼터니언 값 확인

 

 

2.2. 활성상태 접근

 

2.2.1. Mesh Renderer

오브젝트의 Mesh(모양, 형태) 데이터를 가지고 Render(그리는) 기능

// obj의 MedshRenderer에 접근해서 활성상태를 False로 변경하겠다.
obj.GetComponent<MeshRenderer>().enabled = false;

 

False로 설정해 두었기 때문에 오브젝트는 있지만 시각적으로는 아무것도 보이지 않음

 

▶ Mesh Renderer 사용 예시

  • 오브젝트가 공격받을 때 반짝이는 이펙트
  • 숨겨진 길이 활성화되면서 점점 나타남
  • 넘어가지지 않는 길

 

2.2.2. SetActive

화면 안에 안 보이게만 하는 것이 아니라 존재 자체를 없애는 기능 (Alt + Shift + A)

obj = GameObject.FindGameObjectWithTag("Player");
objTf = GameObject.FindGameObjectWithTag("Player").transform;

// obj의 GameObject 활성상태를 False
obj.SetActive(false);

// 형 변환 (Transform 타입 -> GameObject 타입)
objTf.gameObject.SetActive(false);

 

Object 자체를 활성화시켰기 때문에 인스펙터 창에서 체크가 풀려있음

 

[Object 복습]

 

유니티의 기본단위 : 게임 오브젝트 (GameObject)

모든 GameObject는 Transform 컴포넌트를 갖는다.

 

3. 컴포넌트(Component) 추가

using UnityEngine;

public class StudyComponent : MonoBehaviour
{
    public GameObject obj;

    public Mesh msh;
    public Material mat;

    public void CreateCube()
    {
	// obj = new GameObject();
        // obj.name = "Cube";
        obj = new GameObject("Cube");

        obj.AddComponent<MeshFilter>();
        obj.GetComponent<MeshFilter>().mesh = msh;

        obj.AddComponent<MeshRenderer>();
        obj.GetComponent<MeshRenderer>().material = mat;

        obj.AddComponent<BoxCollider>();
    }

    void Start()
    {
    	// 1. void 구현해서 Cube 생성
        //obj = new GameObject("Cube");

        //obj.AddComponent<MeshFilter>();
        //obj.GetComponent<MeshFilter>().mesh = msh;

        //obj.AddComponent<MeshRenderer>();
        //obj.GetComponent<MeshRenderer>().material = mat;

        //obj.AddComponent<BoxCollider>();

        // CreateCube();
        
        // 2. Unity 기본 메소드 활용
        obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
    }
}

 

코드를 실행시키면 Cube가 생성됨을 확인할 수 있다.

이렇게 유니티 에디터를 통해서 Cube를 생성하지 않고 스크립트를 통해서도 Object를 생성할 수 있다.

 

4. Prefab 활용

🥕 예행 작업
1. Scene 생성 (GameObject and Prefab)
2. Script 생성 (StudyGameObject)
3. 빈 오브젝트 생성 (Spawner)

 

4.1. GameObject 생성

using UnityEngine;

public class StudyGameObject : MonoBehaviour
{
    public GameObject prefab;

    public Vector3 pos;
    public Quaternion rot;

    void Start()
    {
        // GameObject를 생성하는 기능
        GameObject obj = Instantiate(prefab, pos, rot);
        obj.name = "R.E.P.O 캐릭터";
    }
}

 

4.2. GameObject 삭제 1

public GameObject destroyOb;

void Start()
{
    // 매개 변수로 들어간 게임 오브젝트를 파괴하는 기능
    Destroy(destroyOb, 3f); // 3초 뒤 파괴
}

해당 코드를 실행시키면 Plane 오브젝트가 삭제됨

 

4.3. GameObject 삭제 2

🥕 예행 작업
1. Script 생성 (DestroyEvent)
2. Cube, Sphere, Capsule 생성
using UnityEngine;
using UnityEngine.Assertions.Must;

public class DestoryEvent : MonoBehaviour
{
    public float destroyTime = 3f;
    
    void Start()
    {
        Destroy(this.gameObject, destroyTime);
    }
    
    // OnDestroy()는 Update()나 Start()처럼 Unity가 자동으로 실행해주는 함수
    // 그래서 호출하지 않아도 콘솔창에 나타남
    private void OnDestroy()
    {
        Debug.Log($"{this.gameObject.name}이 파괴되었습니다.");
    }
}

 

 

▶ Destroy 예시

  • FPS 게임에서 총알을 삭제할 때 사용 됨
  • 폭발 효과

 

5. GetChild (자식 오브젝트)

 

'Repo'라는 Prefab 이하에는 여러 개의 자식 오브젝트가 있다.

 public void CreateREPO()
    {
        GameObject obj = Instantiate(prefab);
        obj.name = "R.E.P.O 캐릭터";

        Debug.Log($"{obj.name}이 생성되었습니다.");

        Transform objTf = obj.transform;

        int count = objTf.childCount;

        //Debug.Log($"캐릭터의 자식 오브젝트의 수 : {obj.transform.childCount}");
        //Debug.Log($"캐릭터의 자식 오브젝트의 수 : {objTf.childCount}");
        Debug.Log($"캐릭터의 자식 오브젝트의 수 : {count}");

        Debug.Log($"캐릭터의 첫번째 자식 오브젝트의 이름 : {objTf.GetChild(0).name}");

        Debug.Log($"캐릭터의 마지막 자식 오브젝트의 이름 : {objTf.GetChild(obj.transform.childCount - 1).name}");
    }
}

 

GetChild 함수를 통해서 해당 오브젝트의 자식 오브젝트를 확인할 수 있다.

 

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

6.1. Input Manager

Input System(Old - Legacy)은 입력값에 대한 약속된 시스템을 뜻한다.

  • 예시
    - 이동 : WASD, 방향키
    - 점프 : SpaceBar
    - 총쏘기 : 마우스 왼 클릭

6.2. Unity 에디터 우측 하단에 버튼을 통해서 Input Manager에 접근 가능

 

Positive Button을 보면 어떤 키로 작동하는지 확인할 수 있다.

 

6.3. Input System을 활용해보쟛~

using UnityEngine;

public class Movement : MonoBehaviour
{
    public float moveSpeed = 5f;
    
    void Update()
    {
        float h = Input.GetAxis("Horizontal"); // 수평 (좌우)
        float v = Input.GetAxis("Vertical"); // 수직 (위아래)

        Vector3 dir = new Vector3(h, 0, v);
        Debug.Log($"현재 입력 : {dir}");

        transform.position += dir * moveSpeed * Time.deltaTime;
    }
}

 

이전 코드에 비해 엄청 단순해졌음을 확인할 수 있다.

이 외에도 캐릭터가 기존에는 좀 딱딱하게 움직였다면 GetAxisr는 [-1,0,1] 사이의 값을 반환하기 때문에 훨씬 부드러워졌다.

 

 

Destroy 스크립트 비활성화를 안 해서 ㅋㅋ.. 갑자기 오브젝트들이 다 삭제됨

저런 오브젝트들을 통과 못하게 한번 구현해서 움직여보는 것도 괜찮은 복습일 듯?

 

2. C# 기초 학습(5)

1. 매개변수

public void AddMethod(int num1, int num2)
{
	int result = num1 + num2;
}

void Start()
{
	AddMethod(10, 20);
}

# 오버로드(Overload) = 매개변수 타입만 다른 함수 3종
public void OnMethod(int a) {}
public void OnMethod(float a) {}
public void OnMethod(string a) {}
  • num1, num2 = 매개 변수 = Parameter(인자) = 함수를 정의할 때 사용되는 변수
  • 10, 20 = 전달 인자 = Argument(인자) = 함수가 호출될 때 사용되는 변수 값

 

이렇게 매개변수를 사용하냐 안 하냐에 따라 기능이 조금씩 달라짐!

 

 


 

 

 

 

강사님께서 수업 시작하고 한 시간 정도? 는 복습을 해주시는데 듣다가 맨날 멍 때리고 어느 순간 진도 나가고 있는 걸 발견함

얼레리? 부랴부랴 강사님 노션이나 디코보고 타자 와다다 치고 정리 와다다 매번 정신이 없음!!

 

그런데 강사님이 이 글을 봐주실지 모르겠지만.. 복습양을 조~금만 줄여주시길.. 간곡히 부탁드리고 싶다!!

매번 말하지만 넘 불안함.. 책에 있는 내용, 인강에 있는 내용들만 배우고 끝날까 봐... 응용이 필요한 것들은 알아서 해라! 이럴까 봐..

물론 여쭤보면 친절하게 알려주실 것 같기는 한데 수강생이 120명인데..!? 현실적으로 힘들 것 같다.

나는 그냥 복습은 알아서 하라 시키고.. 좀 더 실무에서 많이 쓰는 기능적인걸 많이 보여주셨음 하는 그런 바람이..

 

근데 지금은 이거보다 더 큰 문제가 발생함

오늘 이야기 들어보니까 회고팀 정해지면 팀원끼리 복습하는 거 같던데 나 같은 파워 I가 잘 적응할 수 있을지 모르겠다..

에바핑~~~~

 

암튼 얼레벌레.. 지나간 오늘 하루.. 오늘도 수고했다!