HYNGNG | 알곡사료

1일차 : 헬기 움직이기 본문

유니티/P1 : 유니티에서 헬리콥터 구현하기

1일차 : 헬기 움직이기

hyngng 2022. 6. 23. 21:34
728x90
반응형

🙂블로그 이전했습니다!🙂

 

이 프로젝트는

이 미친 헬기를 제대로 구현하는 것에

목표가 있다.

 

 

다행히도 이 공격헬기 3D 모델은

무료로 간단히 받을 수 있음에도 불구하고

메인로터나 부사수가 조종하는 기관포 모델 등이

구분되어 나뉘어 있었어서,

 

여러가지 실제 공격헬기의 기능을 구현해볼 수 있는

재미있는 장난감이 될 수 있겠다.

 


 

먼저 로터를 돌려 보고 싶어서 코드부터 짰다.

 

using UnityEngine;
using System.Collections;

public class Heli_RotorMovement : MonoBehaviour {

	public float RotorSpeed;

	void Start () {
		RotorSpeed = 1500.0f;
	}

	void Update () {
		transform.Rotate(new Vector3(0,1,0) * Time.deltaTime * RotorSpeed);
	}
}

 

※ Time.deltaTime은 이전 프레임에서 이후 프레임까지의 시간을 말한다.

※ new Vector3(0,1,0)은 일종의 표준안이기 때문에 Vector.up을 입력해 쓸 수도 있다.

※ 기본적인 문법인데, C#에서 float을 선언할 때는 일종의 접미사 f를 붙여줘야 한다.

 

 

스크립트를 짠 뒤 로터에 적용했더니

일단 로터가 아무 입력 없이도 잘 돌아가기 시작했다.

 


헬기를 직접 타고 있는 것을 구현해보자.

 

 

FPCamera라는 이름으로

카메라를 하나 더 만들어준 다음

주사수석에 배치한 뒤,

 

기존의 3인칭 카메라에 적용시켰던

플레이어(헬기)를 따라가는 스크립트를 적용시켰다.

 

 

+ 프로펠러까지 돌아가니

정말 헬기를 타고 있다는 기분이 나는 느낌이다.


 

다음으로 W와 D키로 헬기가

수직 방향의 이동을 할 수 있도록 조정해보자.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Heli_Movement : MonoBehaviour
{
    Rigidbody rigid;

    void Awake()
    {
        rigid = GetComponent<Rigidbody>();
    }
 
    void FixedUpdate()
    {
        float v = Input.GetAxisRaw("Vertical");
        rigid.AddForce(new Vector3(0, v, 0), ForceMode.VelocityChange);
    }
}

 

이를 위해 기존의 미친 헬기 코드를

W와 S에 대해서만 입력을 받아 수직 운동을 하도록 바꾸었다.

 

 

그랬더니 잘 작동을 하긴 하는데,

밑의 터레인(땅)과의 충돌검사가 무슨 이유에선지 제대로 이루어지지 않아

떨어질 때 랜덤하게 땅 밑으로 꺼지는 문제가 있었다.

 

 

원인을 찾아보니

Collision Detection이 Discrete로 설정되어 있는 것이 문제였다.

이를 Continuous로 설정해주면 해결할 수 있었다. 더불어,

 

 

처음 보는 이 둘의 차이를 Unity 공식 메뉴얼에서 찾아 좀 더 명확히 알 수 있었다.

다른 곳의 설명도 참조해보니, 대략

Continuous는 보간 검사를 실시하여 움직이는 대상과 정지한 대상 사이의 충돌 검사에

사용한다는 것 같다.

 

단...충돌 검사 빈도가 높아지는 만큼 연산량이 늘어난다고 한다.

여러 곳에서 강조하는 것을 보니 편하다고 Continuous를 남발하면 안 될 것 같다.

 


 

잠깐 쉬어가는 느낌으로

배경을 바꾸어 보자.

 

 

분위기를 내기 위해 SkyBox를 새벽으로 바꾸고

3D 프로젝트를 시작하면 기본적으로 같이 딸려오는

Directional Light 각도를 SkyBox에 맞게 조정했다.

 

훨씬 보기 예쁘다.

 


 

1인칭 뷰를 만들었는데,

3인칭 뷰도 사용할 수 있다면 좋겠다는 생각이 들었다.

만들어보자.

 

1인칭 카메라는 사수와 부사수의 자리에,

3인칭 카메라는 헬기의 꼬리에서 좀 더 떨어진 자리에 하나,

부사수 자리의 앞에 하나 놓았다.

 

코드를 작성해보자.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraSwitching : MonoBehaviour
{
    public Camera FP1Camera;
    public Camera TP1Camera;
    public Camera FP2Camera;
    public Camera TP2Camera;
    public bool KeyRef1;
    public bool KeyRef2;

    void Start()
    {
        FP1Camera.enabled = true;
        FP2Camera.enabled = false;
        TP1Camera.enabled = false;
        TP2Camera.enabled = false;
        KeyRef1 = false;
        KeyRef2 = false;
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.F1))
        {
            FP1Camera.enabled = true;
            FP2Camera.enabled = false;
            TP1Camera.enabled = false;
            TP2Camera.enabled = false;
            KeyRef1 = false;
            KeyRef2 = false;
        }

        if (FP1Camera.enabled == true || TP1Camera.enabled == true)
        {
            if(Input.GetKeyDown("v"))
            {
                if (KeyRef1 == true){
                    FP1Camera.enabled = true;
                    TP1Camera.enabled = false;
                    KeyRef1 = false;
                }
                else
                {
                    FP1Camera.enabled = false;
                    TP1Camera.enabled = true;
                    KeyRef1 = true;
                }
            }
        }

        if (Input.GetKeyDown(KeyCode.F2))
        {
            FP1Camera.enabled = false;
            FP2Camera.enabled = true;
            TP1Camera.enabled = false;
            TP2Camera.enabled = false;
            KeyRef1 = false;
            KeyRef2 = false;
        }

        if (FP2Camera.enabled == true || TP2Camera.enabled == true)
        {
            if(Input.GetKeyDown("v"))
            {
                if (KeyRef2 == true){
                    FP2Camera.enabled = true;
                    TP2Camera.enabled = false;
                    KeyRef2 = false;
                }
                else
                {
                    FP2Camera.enabled = false;
                    TP2Camera.enabled = true;
                    KeyRef2 = true;
                }
            }
        }
    }
}

 

음....

객체지향 코드작성에 익숙하지 않아서

객체지향 코드로 만들 수 있을 것 같은데

절차지향 코드가 되어버렸다.

 

핵심 원리는,

1인칭 카메라와 3인칭 카메라의 이름을

각각 FPCamera, TPCamera로 지어주고

KeyRef라는 이름의 bool(T or F) 변수를 만든 뒤

 

Input.GetKeyDown 함수를 이용해

V키를 누르면 KeyRef값이 true와 false로 전환됨에 따라

1인칭 카메라와 3인칭 카메라가 토글되는 것이다.

 

 

그런데 스크립트는 오류가 나지 않게 잘 만들었는데

단순히 스크립트는 만들어 두는 것 만으로는

스크립트가 작동하지 않았고

 

그렇다고 이 스크립트를 헬기나 카메라에 적용하기엔 부적절해서,

코드는 작성을 마쳤는데 구현을 어떻게 하는지 모르는...문제가 생겼다.

 

이에 인터넷의 도움을 받아보니

 

 

Hierachy창에서 빈 오브젝트(Create Empty)를 만들어

적용하여 해결할 수 있었다.

 

나의 경우 CameraManager로 이름짓고

스크립트를 넣어 주었다.

 

 

잘 작동하는 모습을 확인할 수 있었다.

 


 

이제 헬기가 AD 입력으로 회전도 할 수 있었으면 하는 바람이 생겼고

코드를 작성했다.

 

WS 입력으로 하늘을 날도록 하는 코드에서

float AD = Input.GetAxisRaw("Horizontal");

transform.Rotate(new Vector3(0, AD, 0) * Time.deltaTime * 100);

을 추가하여 돌아가도록 만들었는데,

 

 

돌아가긴 돌아가지만

헬기의 움직임과 카메라의 움직임이 맞지 않아

위상차가 나는 문제가 있었다.

 

그런데 이는 설정을 좀 더 건드리는 도중

 

Hierachy 창에서 카메라들을 헬기 하위 오브젝트(?)로 넣어두고

앞서 카메라가 헬기(플레이어)를 따라가도록 하는 스크립트를 제거해 보았다가

우연히 쉽게 해결할 수 있었다.

 

 

4개의 모든 카메라에서

의도한 대로 잘 작동하는 모습이다.

 


 

오늘의 요약 : 

✓ 돌아가는 로터 구현

✓ 1, 3인칭 카메라 구현

✓ 헬기의 수직 방향 운동, 원형 운동 구현

728x90
반응형