플레이어의 자유로운 카메라 시점이동은 답답함을 해소하고 적극적으로 월드를 탐색하고 수 많은 편리함을 제공할 수 있께 해준다. 하지만 카메라가 벽을 통과하고 오브젝트를 통과하여 의도하지 않은 연출이 나타나는경우 득보다 실이 될 수 있는 경우가 생긴다. 이러한 점을 개선하기위해 카메라가 오브젝트를 통과하지 못하도록 구현하였다.
이전에 다룬 3인칭 시점 구현하기 글에서 보여준 스크립트에서 카메라와 관련된 기능을 CameraTPS.cs로 별도로 구분하여 추후에 다른 프로젝트에서 해당 스크립트로 이식하기 쉽도록 재구성하였다.
구현 아이디어?
카메라의 위치를 카메라 암으로부터 뒤로 뻗어나가게 한 후, 카메라 암으로부터 카메라의 위치까지의 방향 벡터를 카메라에서 레이캐스트를 쏴 레이캐스트의 출력에서 오브젝트가 있다고 판단되는경우 방향 벡터의 반대 방향으로 카메라를 조금씩 가까이 하도록 하면 된다고 판단하여 구현하였다.
//CameraTPS.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraTPS : MonoBehaviour
{
//방향을 담는 열거형 변수
public enum CameraDirection
{
FORWARD,
LEFT,
RIGHT,
BACK
}
//동서남북 방향으로 어디를 바라보고 있는지 확인하도록 하는 추가기능의 방향 변수
public static CameraDirection mDirection;
//카메라가 붙을 '카메라 스탠드' 트랜스폼
[SerializeField] private Transform mCameraStand;
//플레이어로부터 카메라까지의 거리
private float mCameraDist;
//플레이어로부터 가로거리
[SerializeField] private float mCameraWidth;
//플레이어로부터 세로거리
[SerializeField] private float mCameraHeight;
//레이케스트 후 플레이어쪽으로 올 거리 민감도 (값이 클수록 크게 당겨져옴)
[SerializeField] private float mCameraFixDist = 1.0f;
//카메라 회전 시 각도를 얼만큼 제한시킬것인지에 대한 변수
[SerializeField] private float mLowestRot;
[SerializeField] private float mHighestRot;
//플레이어로부터 카메라 위치까지의 방향을 담는 벡터
Vector3 mDirectionForArmToCam;
Vector3 mRayTarget;
RaycastHit mHitInfo;
void Start()
{
//플레이어에서 카메라까지의 길이(거리)
mCameraDist = Mathf.Sqrt(mCameraWidth * mCameraWidth + mCameraHeight * mCameraHeight);
//플레이어에서 카메라위치까지의 방향벡터
mDirectionForArmToCam = new Vector3(0, mCameraHeight, mCameraWidth).normalized;
}
//매 프레임마다 호출되어 카메라암의 회전과 카메라의 춛돌을 검사하여 처리한다.
void Update()
{
LookAround();
CameraMove();
}
//카메라의 충돌을 검사하고 위치를 조절한다.
private void CameraMove()
{
//카메라의 위치를 초기화 한다.
mCameraStand.transform.position = transform.position;
//레이캐스트할 벡터 방향
mRayTarget = mCameraStand.transform.up * mCameraHeight +
mCameraStand.transform.forward * mCameraWidth;
//레이캐스트를 통해 벡터 방향에 물체가 있는지 확인한다.
Physics.Raycast(mCameraStand.transform.position, mRayTarget, out mHitInfo, mCameraDist);
if (mHitInfo.point != Vector3.zero && mHitInfo.transform.gameObject.tag == "Untagged")//레이케스트 성공시
{
//mHitInfo로 옮긴다.
mCameraStand.transform.position = mHitInfo.point;
//카메라 보정
mCameraStand.transform.Translate(mDirectionForArmToCam * -1 * mCameraFixDist);
}
else
{
//로컬좌표를 0으로 맞춘다. (플레이어로 옮긴다.)
mCameraStand.transform.localPosition = Vector3.zero;
//카메라위치까지의 방향벡터 * 카메라 최대거리 로 옮긴다.
mCameraStand.transform.Translate(mDirectionForArmToCam * mCameraDist);
//카메라 보정
mCameraStand.transform.Translate(mDirectionForArmToCam * -1 * mCameraFixDist);
}
}
//플레이어가 자유롭게 카메라를 회전한다.
private void LookAround()
{
Vector2 mouseDelta = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));
Vector3 camAngle = mCameraStand.transform.rotation.eulerAngles;
float x = camAngle.x - mouseDelta.y;
if (x < 180f)
{
x = Mathf.Clamp(x, -1f, mHighestRot);
}
else
{
x = Mathf.Clamp(x, 360 - mLowestRot, 360);
}
mCameraStand.transform.rotation = Quaternion.Euler(x, camAngle.y + mouseDelta.x, camAngle.z);
}
//동서남북 절대방향으로 카메라가 바라보고있는 방향을 체크하기위한 추가기능 함수.
private void CheckDirection()
{
float yAngle = mCameraStand.transform.rotation.eulerAngles.y;
if ((yAngle >= 0 && yAngle < 45) || (yAngle > 315 && yAngle < 360))
{
mDirection = CameraDirection.FORWARD;
}
else if (yAngle > 45 && yAngle < 135)
{
mDirection = CameraDirection.RIGHT;
}
else if (yAngle > 135 && yAngle < 225)
{
mDirection = CameraDirection.BACK;
}
else
{
mDirection = CameraDirection.LEFT;
}
}
}
|
cs |
public enum CameraDirection { ... }
public static CameraDirection mDirection;
- 플레이어가 바라보는 방향을 절대적인 동서남북의 방향으로 나타내는 부가 기능이다.
- FORWARD는 북쪽,LEFT는 서쪽을 나타낸다.
[SerializeField] private Transform mCameraStand;
- CameraTPS.cs가 붙을 오브젝트의 인스펙터에서 지정해준다.
- mCameraStand는 카메라를 자식으로 가질 부모이다. 카메라를 자식으로 가지는 구조로 한 이유는 카메라를 단독적으로 움직이는 기능을 자유롭게 구현하기 위해서이다.
private float mCameraDist;
- 플레이어로부터 카메라까지읙 거리를 담는 변수이다.
- Start()에서 한번 호출되며 초기회된다.
[SerializeField] private float mCameraWidth;
[SerializeField] private float mCameraHeight;
- 트랜스폼 값과 별개로 인스펙터에서 지정한 두 변수의 값으로 카메라의 상대적 위치를 결정한다.
- 값의 크기 기준은 유니티 월드에서 1m로 기준으로 하였다.
[SerializeField] private float mCameraFixDist = 1.0f;
- 카메라가 벽이나 오브젝트에 충돌하여 충돌하지 않을때까지 위치를 조정하는 위치 조정 값에 대한 조정값.
Vector3 mDirectionForArmToCam;
- 플레이어 중심으로부터 카메라까지의 방향을 담는다.
- 카메라를 보정할 때 보정하는 방향을 지정하기 위해 사용한다.
Vector3 mRayTarget;
RaycastHit mHitInfo;
- 레이캐스트를 발사할 때, 관련 값들이 매 프레임마다 생성되는것을 방지하기위해 멤버변수로 할당하였다.
void Start()
- mCameraWidth와 mCameraHeight를 이용하여 플레이어로부터 카메라까지의 거리인 mCameraDist를 계산한다.
-
mDirectionForArmToCam를 설정하여 방향을 저장한다.
void Update()
- 매 프레임마다 카메라의 움직임과 보정에 대한 함수를 호출한다.
- private void CameraMove()
- 카메라의 위치를 보정하는 함수이다.
- 기본적으로 보정은 카메라의 위치가 카메라 암으로부터 시작한다.
- 카메라 암으로부터 충돌하거나 하지 않는경우에 따라 연산이 다르게 작동한다.
- 레이캐스트가 성공한경우, 카메라 스탠드의 위치를 해당 point로 옮긴 후 카메라 스탠드의 뒤에 물체가 있다고 판단할 수 있다. 이런경우 중심으로부터 카메라까지 방향의 반대에서 mCameraFixDist변수의 값인 보정 민감도만큼 이동시킨다.
private void LookAround()
- 이전에 다룬 글에서 작성한 소스코드와 동일하다. 마우스의 x, y의 이동값을 받고 카메라의 방향을 회전시킨다.
- mHighestRot 와 mLowestRot의 값으로 카메라의 상하 각도 조절을 제한한다.
private void CheckDirection()
- 동서남북의 절대적인 방향을 계산하는 추가 기능의 함수이다.
'unity game modules' 카테고리의 다른 글
[유니티] 게임 옵션 저장 (0) | 2022.08.03 |
---|---|
[유니티] .obj 파일을 인터넷으로 다운로드하여 사용 (0) | 2022.07.31 |
[유니티] 사운드를 편하게 관리하는 사운드매니저 (0) | 2022.07.19 |
[유니티] 대사 관리 및 다국어지원 (0) | 2022.07.18 |
[유니티] 대사 말풍선 기능 (0) | 2022.07.17 |