AudioMixer에 대한 정보는 뭐... 다른 블로그들에 잘 나와있을테니 참고.

 

* Audio Mixer 추가하기

1. 적당한 폴더에서 우클릭 > Create > Audio Mixer

 

2. 편리한 사용을 위해 Window > Audio > Audio Mixer로 새 탭을 연다.

 

3. 적당한 그룹을 추가한다. 

Audio Mixer를 생성하고, 그룹을 추가한 상태

 

* 각 그룹을 Expose시키기

Audio Mixer를 스크립트에서 사용하기 위해서는 각각의 그룹들을 노출시켜야 하는데, 이 작업이 꼭 필요하다. Expose 과정을 거치지 않으면 경고 메시지를 받게 된다. (물론 접근도 못한다)

Expose 시키지 않은 그룹에 접근하려고 할 때의 경고 메시지

1. expose 시킬 그룹을 선택한다.

expose 시킬 믹서 그룹을 클릭만 하면 된다.

2. inspector창에서 Attenuation 아래 volume을 찾아 우클릭 > expose xxx to sctipt를 선택해서 스크립트에서 접근 가능하게 한다.

expose 시키지 않으면 스크립트 접근이 불가능하다는 것을 명심하자.

※ expose 되었다면 volume 옆에 화살표가 생긴다.

이렇게.

 

3. 이제 이 expose된 그룹에 이름을 지어주자. 기본값은 MyExposedParam이다. 우클릭 > Rename으로 원하는 이름으로 바꿔주자.

AudioMixer창의 오른쪽 위에 보면, Exposed Parameters가 나온다. 해당하는 이름에 우클릭 후 원하는 이름으로 바꾸자.

4. 이제 스크립트에서 제어할 수 있게 되었다.

 

 

* Tip

- 보통은 Slider와 연계해서 사용할텐데, Slider의 min value는 0으로, max value는 10으로 하면 적당하다.

- 딱딱 떨어지는 볼륨 (10단계 0 ~ 10) 조절을 원한다면 Slider의 mix/max value 정하는 곳 아래에 있는 Whole Numbers를 체크해주자.

- Sound mixer 볼륨은 -80 ~ 20의 값을 가진다. 보통 0이 기본값으로 보는데, 이건 원본 소리 그대로 = 100% 볼륨을 뜻한다.  특별히 볼륨을 강제로 키울 일이 없는 이상 -80 ~ 0까지만 써도 충분하다.

- Slider 값이 0 - 10인데 Mixer값은 -80 ~ 0이다. 서로 변환을 위해서는 약간의 산수 계산이 필요하다.

- Slider -> Mixer일 경우 Slider.value * 8 - 80 이면 맞아떨어진다. (-80 ~ 0)

- Mixer -> Slider일 경우 Mixer.value / 8 + 10 이면 맞아떨어진다. (0 ~ 10)

■목표

- 카메라 움직임을 특정 범위 내에서만 움직이도록 고정하고 싶다.

 

■ 조건

- 카메라 조작 입력 중, 특정 좌표를 넘어가지 못하도록 한다.

- 키보드 WASD로 상하좌우 이동이 가능하도록 한다.

- 카메라의 Position은 0,0,0이고, Rotation은 30,0,0이다.

 

■ 어떻게

- 키보드 WASD 입력으로 카메라를 전진(W)/후진(S)/좌(A)/우(D)로 이동(Panning)시킨다.

- 0,0,0을 기준으로 좌우로는 각각 5만큼씩, 앞뒤로는 각각 5만큼씩 움직일 수 있도록 제한한다.

 

■ 참고한 것

- How to make a Tower Defense Game (E07 CAMERA) - Unity Tutorial
https://www.youtube.com/watch?v=qokYflgxU6M

참고영상: (영어) Brackeys의 How to make a Tower Defense Game 강좌 영상 #7회차

 

■ 진행 및 확인

- 보통은 Input.GetAxis("Horizontal")과 같이 통합  Input System을 사용하면 편하지만, 조작에 대해 제한을 두기 위해서  Input.GetKey("□") 형식을 사용하기로 하자.

- 특정 키 값이 true이면 해당 방향으로 이동시키자.

if(Input.GetKey("w"))
	transform.Translate(Vector3.forward * speed * Time.deltaTime);

확인을 해보면...어... 잠시만. 왜 카메라가 화면 기준으로 '위' 가 아니라 바라보고 있는 앞으로 가버리는 걸까...?

원인> Space를 지정하지 않아서, 기본적으로 Local 좌표 기준으로 이동해버려서 그렇다.

Transform.Translate()의 인자값 예시
Transform.Translate의 용법 중 하나

저 코드의 뒤쪽, Space relativeTo라는 부분이 바로 그 부분에 대한 대답이 되어준다.

기본적으로 저 값이 입력되지 않으면 Space.Local로 되는 모양.

 

잠시 Local 좌표와 World 좌표의 차이를 간단히 이야기 하자면...

더보기

- Local좌표현재 조작하려는 물체의 위치, 회전 상태를 기준으로 위치나 회전이 이루어진다.

   → 물체의 위치나 회전 상태에 따라 이동, 회전이 다를 수 있다.

- World좌표는 전체 월드를 기준으로 위치, 회전 상태를 기준으로 위치나 회전이 이루어진다.

   → 물체의 위치나 회전 상태와 관계 없이, 일정한 방향과 기준으로 이동이나 회전이 이루어진다.

 

말 보다는 그림이 빠를테니 아래를 보자.

월드 좌표축과 로컬 좌표축 비교
x축(빨간 화살표)를 기준으로 30도 회전한 상태의 Cube의 월드 좌표축(왼쪽)과 로컬 좌표축(오른쪽) 자세히 보면 오른쪽의 로컬 좌표축의 y축(녹색)이 기울어져있는 것을 알 수 있다.

 

 

 

따라서 화면에 보이는 대로 움직이려면 월드 좌표축을 기준으로 움직여야하므로 Space.World로 입력한다.

기준 좌표축까지 입력하면 코드는 이런 모양이 된다.

if(Input.GetKey("w"))
	transform.Translate(Vector3.forward * speed * Time.deltaTime, Space.World);

다시 한번 테스트를 해 보면.... 잘 된다. 카메라는 화면 기준으로 앞(z축) 방향으로 이동한다.

 

이제, 카메라가 이동 할 위치를 제한해 보자. 보통의 방법은

private Vector3 pos;			// 위치 제한 계산/판단을 위한 임시 변수
private float maxXPosition;		// x축 최대값
private float minXPosition;		// x축 최소값

pos = transform.position;		// 현재 position값을 입력

if(pos.x >= maxXPosition)
	pos.x = maxXPosition;		// x축 최대값 이상이면 x축 최대값으로 조정

if(pos.x <= minXPosition)
	pos.x = minXPosition;		// x축 최소값 이하이면 x축 최소값으로 조정
    
transform.position = pos;		// 조정된 값을 현재 position에 대입

대략 이런식이 되는데, 여기서 편리한 방법이 하나 있다.

바로 Mathf.Clamp()를 이용하는 방법.

Mathf.Clamp()를 사용하면, 코드도 짧아진다!

private Vector3 pos;			// 위치 제한 계산/판단을 위한 임시 변수
private float maxXPosition;		// x축 최대값
private float minXPosition;		// x축 최소값

pos = transform.position;		// 현재 position값을 입력

// pos.x값을 최소값 ~ 최대값 사이로 잘라낸다.    
pos.x = Mathf.Clamp(pos.x, minXPosition, maxXPosition);		

transform.position = pos;		// 조정된 값을 현재 position에 대입

또는

private float maxXPosition;		// x축 최대값
private float minXPosition;		// x축 최소값

// x좌표값을 직접 다듬어버린다.
transform.position.x = Mathf.Clamp(transform.position.x, minXPosition, maxXPosition);

오오... 쓸데없는 if문이 줄어버렸다. 왠지 멋져 보이기도 한다!

게다가 직접 값을 때려박을 경우에는 코드 자체도 확 줄어버린다!

이것이 수학 함수의 위력인가!

 

흥분을 가라앉히고 Mathf.Clamp()를 살펴보면

Mathf.Clamp() 설명. 주어진 value를 min과 max 사이에서 다듬은 후 return한다.

 

이렇게 설명되어있다.

 

어느쪽을 선택해도 내 수준(=취미로 우리 아이들을 위한 게임 만들기)에서는 어느쪽을 선택해도 유의미한 퍼포먼스 변화는 없으므로 내키는 대로 쓰면 되겠다.

 

■ 결론 및 후기

- 보통은 z축에 맞춰서 캐릭터를 배치하고 현재 방향을 기준으로 회전하면 되는 상황만 주어졌었기 때문에 Space.Local이라도 상관 없었다.

- 고정된 View일 경우, 물체의 회전 상태에 따라 의도치 않은 방향으로 이동하거나 회전이 꼬여버릴 수 있다는걸 눈으로 보고 알게 되었다.

- transform.Translate()를 사용할 때는, 버릇이 될 때까지 의도적으로 Space.Local 또는 Space.World를 넣도록 하자.

- Mathf.Clamp()라는 존재는 모두의 손가락과 손목, 눈 건강에 도움이 될 것이다. (물론, 조금 멋져보이기도 한다)

- 역시, 아는 만큼 보인다는 말은 진리인 것인가...?!

'Unity3D' 카테고리의 다른 글

[Unity] AudioMixer 간단 사용법  (0) 2023.08.19
카메라를 쳐다보는 2D 스프라이트(Billboard)  (0) 2022.05.11

■ 목표

- 항상 카메라를 바라보는 Sprite

 

■ 조건

- Dungeon Crawler 스타일의 게임에서, 2D 캐릭터 또는 오브젝트를 사용하고 싶다.

- 카메라는 고정된 높이에서 수평회전과 수평 이동만 한다. (Y축 position 고정)

 

■ 어떻게

- 카메라의 위치를 항상 바라보게 회전시킨다.

- 스프라이트는 회전만 하면 된다. => 높이값을 카메라 높이로 맞춰줘야 한다.

 

■ 참고할 만한 것

https://youtu.be/cdqLIWpEvQc

던전 크롤러는 대략 이런 느낌의 게임. ( Coldfire Keep - Old School 3d Dungeon Crawling! )

■ 코드

    public GameObject cam;
    private void Awake()
    {
        // 바라보게 될 카메라를 설정한다. (기본값을 따로 찾지 못하면 하나 지정해서 넣어준다
        if (cam == null)
            cam = GameObject.Find("camMain");

        // y좌표를 카메라와 맞춘다.
        transform.position = new Vector3(transform.position.x, cam.transform.position.y, transform.position.z);

    }

    void Update()
    {
        // 항상 카메라의 위치를 바라보게 한다.
        transform.LookAt(cam.transform.position);
    }

■ 결과

움직이기 전
움직인 후

 

■ 후기

- transform.LookAt을 바로 떠올릴 수 없었다!

- Parent가 되는 Empty Object는 없어도 되더라!

- Y축 회전 이외의 방향으로 하는건 안해봐서 모르겠다!

- Y축 이외의 회전은 Parent에 스크립트를 연결해 주고, 자식을 적당한 각도로 회전시켜주면 될 것 같다.

+ Recent posts