씬에서 골렘의 돌진 공격이 플레이어에게서 빗나가 벽에 부딪힐 때 그 충격으로 던전이 흔들리는 것을 카메라가 흔들리는것으로 간단하게 보여줄 수 있다.
CameraMgr(카메라 매니저)이라는 스크립트를 Empty Game Object에 넣어 해당 오브젝트를 찾아 스크립트에서 함수를 호출하여 어떤 상황에서든 간단하고 쉽게 카메라가 흔들리는 기능을 이용할 수 있도록 구현하였다.
카메라 매니저는 씬에서 하나만 존재한다.
//CameraMgr.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraMgr : MonoBehaviour
{
//메인 카메라
private Camera mCamera;
//씬이 로드될 때 카메라 암에 붙어있는 카메라의 위치를 저장하는 변수
private Vector3 mCameraOriginPos;
//카메라 흔들기의 흔들림 세기를 지정하는 변수. 기본값으로 지정하여 사용할 수 있도록 한다
[SerializeField] [Range(0.01f , 0.1f)] private float mOriginShakeRange = .05f;
//카메라 흔들기 시간을 지정하는 변수. 기본값으로 지정하여 사용할 수 있도록 한다
[SerializeField] [Range(0.1f , 1.0f)] private float mOriginShakeDuration = .5f;
//카메라를 흔드는 도중 해당 변수의 간격마다 초기 위치로 돌아가게 하는 변수. 사용하지 않으면 초기 위치로부터 크게 벗어날 수 있기에 사용해야 자연스러워짐.
[SerializeField] private int mOriginShakeInitSpacing = 5;
//카메라 흔들기에 사용되는 코루틴을 담는 변수
Coroutine mStartCameraShakeCoroutine, mEndCameraShakeCoroutine;
//씬이 로드되면 카메라를 등록하고 카메라의 초기 위치를 저장한다.
private void Start()
{
mCamera = Camera.main;
mCameraOriginPos = mCamera.transform.localPosition;
}
//카메라를 흔들기를 시작하는함수. 기본 매개변수로 호출하면 인스펙터에서 초기화 된 값으로 호출된다.
public void ShakeCamera(float shakeRange = 0, float duration = 0)
{
Debug.Log("카메라 흔들기 호출");
StopPrevCameraShakeCoroutines();
shakeRange = shakeRange == 0 ? mOriginShakeRange : shakeRange;
duration = duration == 0 ? mOriginShakeDuration : duration;
mStartCameraShakeCoroutine = StartCoroutine("StartShake", shakeRange);
mEndCameraShakeCoroutine = StartCoroutine("StopShake", duration);
}
//일정 시간동안 흔들기를 진행하는 코루틴
private IEnumerator StartShake(float shakeRange)
{
float cameraPosX, cameraPosY;
Vector3 cameraPos;
int shakeInitSpacing = mOriginShakeInitSpacing;
while(true)
{
--shakeInitSpacing;
//최대 0 ~ shakeRange * 2까지 나오는 값에서 shakeRange를 빼면 -shakeRange ~ +shakeRange 까지의 범위를 가진다.
cameraPosX = Random.value * shakeRange * 2 - shakeRange;
cameraPosY = Random.value * shakeRange * 2 - shakeRange;
cameraPos = mCamera.transform.position;
cameraPos.x += cameraPosX;
cameraPos.y += cameraPosY;
mCamera.transform.position = cameraPos;
if(shakeInitSpacing < 0)
{
shakeInitSpacing = mOriginShakeInitSpacing;
mCamera.transform.localPosition = mCameraOriginPos;
}
yield return null;
}
}
//단순히 일정 시간 후에
private IEnumerator StopShake(float duration)
{
yield return new WaitForSeconds(duration);
mCamera.transform.localPosition = mCameraOriginPos;
StopPrevCameraShakeCoroutines();
}
//비 정상적으로 짧은 시간에 여러 번 호출될경우 의도하지 않은 방향으로 진행되는것을 방지하기 위해 코루틴을 검사하여 제거한다.
private void StopPrevCameraShakeCoroutines()
{
if(mStartCameraShakeCoroutine != null)
{
StopCoroutine(mStartCameraShakeCoroutine);
}
if(mEndCameraShakeCoroutine != null)
{
StopCoroutine(mEndCameraShakeCoroutine);
}
}
}
|
cs |
private Camera mCamera;
- 메인 카메라를 담는 변수이다.
private Vector3 mCameraOriginPos;
- 씬이 로드될 때 카메라 암에 붙어있는 카메라의 상대 위치를 저장하는 변수이다.
- 카메라를 흔들고 나서 초기 위치로 돌아오도록 해야하는데, 그때 이 위치가 사용된다.
- 사용하지 않으면 카메라가 흔들리고나서 위치가 이상해진다.
[SerializeField] [Range(0.01f , 0.1f)] private float mOriginShakeRange = .05f;
- 카메라가 흔들릴 때 흔들림에 대한 강도를 조절하는 변수이다.
- 인스펙터에서 값을 지정할 수 있도록 하였는데, 카메라를 흔드는 함수를 호출할 때 기본 매개변수로 호출하면 직렬화된 값으로 편리하게 호출할 수 있도록 구현했다.
[SerializeField] [Range(0.1f , 1.0f)] private float mOriginShakeDuration = .5f;
- 카메라가 흔들릴 때 흔들리는 시간을 조절하는 변수이다.
- mOriginShakeRange와 마찬가지로 기본 매개변수로 함수 호출시 직렬화된값으로 호출되도록 구현하였다.
[SerializeField] private int mOriginShakeInitSpacing = 5;
- 카메라가 흔들리는 동안에 무작위 위치만큼 이동하게 되는데, 우연히 한 방향으로만 계속 이동한다고 가정했을 때 초기 위치를 너무 벗어나 자연스럽지 못한 연출을 할 수 있게된다. 이를 방지하기위해서 프레임 간격마다 초기 위치로 돌려놓기 위해 해당 변수를 사용한다.
Coroutine mStartCameraShakeCoroutine, mEndCameraShakeCoroutine;
- 카메라가 흔들리는 시간이 있기때문에, 코루틴을 사용한다.
- 코루틴이 작동중일때 같은 코루틴이 중복으로 호출되는경우 의도하지 않은 상황이 발생할 수 있기에 해당 변수들에 직전에 실행했던 코루틴을 담고, 필요시 멈출 수 있도록 한다.
private void Start()
- 씬이 로드되면 카메라를 가져오고, 카메라의 상대위치를 저장한다.
public void ShakeCamera(float shakeRange = 0, float duration = 0)
- 외부에서 호출되며 카메라를 흔드는 함수이다.
- 기본 매개변수로 이루어져있으며 인스펙터에서 설정된 mOriginShakeRange와 mOriginShakeDuration의 값으로 호출하거나 기본 매개변수를 사용하지 않고 임의의 값으로 호출할 수 있다.
- StopPrevCameraShakeCoroutines()은 이미 코루틴이 실행중이면 기존 코루틴을 멈추고 새롭게 흔드는 작업을 시작한다.
- 삼항 조건 연산자를 통해 기본 매개변수가 아닌 임의의 값이 들어오면 해당 값으로 카메라를 흔드는 코루틴을 호출하도록 한다.
private IEnumerator StartShake(float shakeRange)
- 카메라 흔들기를 진행하는 코루틴이다.
- 매개변수인 shakeRange는 값의 크기만큼 카메라를 크게 진동시킨다.
- shakeInitSpacing은 멤버변수인 mOriginShakeInitSpacing로 초기화되면 프레임마다 1씩 감소하는데, if(shakeInitSpacing < 0) 조건이 되면 되면 무작위로 진동중인 카메라를 다시 초기 위치로 되돌린다. 그렇게 하지 않으면 이상한 한 방향으로 계속 이동하여 자연스럽지 못한 카메라 흔들림이 연출될 수 있다.
- Random.value * shakeRange * 2 - shakeRange는 shakeRange를 -shakeRange 부터 +shakeRange까지 무작위로 받아오도록 한다.
private IEnumerator StopShake(float duration)
- 단순히 StartShake 코루틴이 실행되고 있는 것을 duration 시간 후에 StopPrevCameraShakeCoroutines() 함수를 통해 카메라의 흔들림을 멈추는 기능을 한다.
- mCamera.transform.localPosition = mCameraOriginPos;를 통해 카메라 흔들림이 멈추면 카메라 흔들림 함수를 호출하기 이전인 초기 위치로 돌려놓는다.
private void StopPrevCameraShakeCoroutines()
카메라를 흔드는 함수가 호출되어 코루틴이 실행되고 있을 때, 다른 호출이 발생되면 코루틴이 이중, 삼중... 으로 호출될 수 있다. 의도하지 않은 버그가 발생할 수 있어 각 호출마다 이전의 코루틴이 있으면 멈추도록 해야한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
//GolemController.cs
...
public class GolemController : MonoBehaviour
{
...
//카메라 매니저를 담는 변수
private CameraMgr mCamera;
...
private void OnCollisionEnter(Collision collision)
{
if (misAtt_Dash)
{
if (collision.transform.CompareTag("Wall"))
{
...
mCamera.ShakeCamera();
}
...
}
}
...
}
|
cs |
씬 내에서 골렘이 돌진공격을 할 때 플레이어를 맞추지 못하고 벽에 부딛혔을 때 간단하게 mCamera.ShakeCamera() 함수를 호출하여 카메라를 흔들리게 할 수 있다.
여기서 보여지는 함수 호출을 기본 매개변수를 이용하여 호출한것으로 mCamera.ShakeCamera(0.1f, 2.0f); 와 같이 임의 인자로 호출하여 카메라를 흔들 수 있다.
'unity game modules' 카테고리의 다른 글
[유니티] 번개 효과 (0) | 2022.07.17 |
---|---|
[유니티] 충돌 연출 및 RigidBody.AddForce()의 이해 (0) | 2022.07.17 |
[유니티] 안개 효과 (던전 입장 효과) (0) | 2022.07.16 |
[유니티] 3인칭 움직이기 (0) | 2022.07.16 |
[유니티] 공격(스킬) 범위 표시 (0) | 2022.07.16 |