게임내에서 타겟을 가리키는 화살표를 구현하는 내용이다. 화살표가 타겟에 고정되며 이 화살표는 플레이어의 주변을 멤돌게 된다.
1. 오브젝트
오브젝트는 타겟을 가리킬 화살표와 움직일 캐릭터, 그리고 타겟이 될 오브젝트 3개가 있으면 준비가 끝이다.
2. 스크립트
스크립트에 필요한 내용은 다음과 같다.
1. 타겟 오브젝트
2. 타겟의 Transform
3. 화살표의 Transform
4. 플레이어와 화살표의 거리
5. 플레이어
6. 플레이어와 타겟 사이의 거리값
- 화살표의 높이는 게임의 기획따라 달라지는데 이 글에서는 바닥에 놓도록 구현하였다.
[SerializeField]
private GameObject Target;
[SerializeField]
private Transform TargetPos;
[SerializeField]
private Transform arrow;
[SerializeField]
private float distanceFromPlayer = 2.0f;
[SerializeField]
private Transform player;
[SerializeField]
private float arrowHeight = 0.5f; // 화살표의 높이
[SerializeField]
private float thresholdDistance = 2.0f;
특징은 화살표가 계속 타겟의 위치를 추적해야 하기 때문에 Update문에서 관리해야 한다는 점, 그리고 특정 거리내에 들어온다면 화살표를 없앤다는 점이다.
그렇다면 생각해야 할 것은
1. 타겟과 플레이어의 방향 벡터
2. 타겟과 플레이어의 거리
3. 화살표의 포지션
4. 화살표의 로테이션
이 세가지가 중요하다. 이는 타겟 방향으로 화살표를 바라봐야 하기 때문에 화살표 rotation을 타겟과 플레이어의 방향벡터를 구한 후, arrow의 최종 로테이션에 넣어줘야 하기 때문이다.
그리고 화살표의 포지션과 로테이션의 경우 기본 로테이션으로 화살표가 정확하게 타겟을 가리키게 해야하는 것이지 자칫하면 화살표가 방향만 가리키고 정작 위를 보고 있거나 반대로 보고 있는 현상이 일어날 수 있다.
3. Quaternion.LookRotation
타겟과 플레이어의 방향 벡터를 구하고, 이 값을 Quaternion.LookRotation() 함수에 넣게 되는데 그럼 Quaternion.LookRotation() 함수란 무엇일까
이는 주어진 방향 벡터를 기준으로 회전을 나타내는 것으로 객체를 특정 방향으로 회전시키기 위해 주로 사용된다.
Quaternion.LookRotation() 함수는 두 가지 오버로드를 제공한다.
- Quaternion.LookRotation(Vector3 forward)
- Quaternion.LookRotation(Vector3 forward, Vector3 upwards)
첫번째는 객체가 바라볼 방향만을 지정해주는 역할이다. 여기서 upwards 까지 넣어주게 된다면 위쪽 정렬까지 가능해져서 기울어진 경사면에서의 화살표 가리키기 혹은 비행물체 등등에서 쓰이게 된다.
여기서는 평지에서의 화살표 방향을 가리키기 위해 foward만 구현하도록 하자.
4. 코드
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerContainer : MonoBehaviour
{
[SerializeField]
private GameObject Target;
[SerializeField]
private Transform TargetPos;
[SerializeField]
private Transform arrow;
[SerializeField]
private float distanceFromPlayer = 2.0f;
[SerializeField]
private Transform player;
[SerializeField]
private float arrowHeight = 0.5f;
[SerializeField]
private Quaternion arrowBaseRotation = Quaternion.Euler(90, -90, 90);
void Start()
{
}
void Update()
{
UpdateArrowPositionAndRotation();
}
void UpdateArrowPositionAndRotation()
{
// 플레이어와 타겟 사이의 방향 벡터 계산
Vector3 direction = (TargetPos.position - player.position).normalized;
float thresholdDistance = 2.0f; // 거리 값
// 플레이어와 타겟 사이의 거리 계산
float distance = Vector3.Distance(player.position, TargetPos.position);
if (distance <= thresholdDistance)
{
arrow.gameObject.SetActive(false);
}
else
{
arrow.gameObject.SetActive(true);
// 화살표의 위치를 플레이어를 중심으로 원형 궤도로 설정
// 화살표의 y축 고정
Vector3 arrowPosition = player.position + direction * distanceFromPlayer;
// 지면에서 일정 높이에 위치시키기 위해 오프셋 적용
arrowPosition.y = arrowHeight;
arrow.position = arrowPosition;
// 타겟 방향으로 회전 설정
Quaternion lookRotation = Quaternion.LookRotation(direction);
// 화살표의 기본 회전 (X: 90도, Y: -90도) 설정
arrowBaseRotation = Quaternion.Euler(90, -90, 90);
// 최종 화살표의 회전 = 타겟을 바라보는 회전 * 기본 회전
arrow.rotation = lookRotation * arrowBaseRotation;
}
}
}
1. 기본 값
일단 거리값이나 화살표의 기본 회전인 arrowBaseRotation, 그리고 arrowPostion의 y축은 게임 환경에 맞게 화살표의 모양에 따라, 게임의 기획에 따라 다 다르게 된다.
2. 방향 벡터
타겟과 플레이어의 방향 벡터를 구하는 방법은 (타겟pos - 플레이어pos).nomalized 해주면 이를 구현할 수 있다. 이 값은 추후에 Quaternion.LookRotation() 함수에 넣어 화살표가 타겟방향으로 회전하게끔 해주도록 하자.
3. 플레이어와 타겟간의 거리
Vector3.Distance() 함수를 통해 플레이어와 타겟 사이의 거리를 계산하여, 자신이 지정한 거리값(thresholdDistance) 보다 작거나 같은 경우 즉, 해당 위치만큼의 범위 내에 타겟이 들어오면 화살표를 없애주도록 하자.
4. 화살표의 position
화살표의 position은 방향벡터와 플레이어 주변을 멤돌 범위를 곱한 후, 플레이어의 위치를 더해주게 된다면 플레이어 몸 주변을 멤돌게 된다. y축은 0.5로 고정하여 지면에 닿게 해주자.
5. 화살표의 rotation
Quaternion.LookRotation(direction) 으로 이전에 구한 방향 벡터를 추가해주고, 기본적으로 화살표가 어떤 모양이냐에 따라 다르지만, 기본 rotation까지 정해주도록 하자. 그리고 이 둘을 최종적으로 곱해주게 되면 arrow의 rotation까지 완성되게 된다.
회고
처음에는 플레이어 하위에 arrow를 넣고 lookrotation으로 가리키기만 하면 된다는 생각으로 구현했다가 플레이어가 rotation으로 돌고 있기 때문에 arrow도 영향을 받아서 문제가 많이 생겼다.
머리를 좀 식히고 생각해보니 굳이 함께있을 이유도 없었고, 그래서 그냥 방향벡터와 거리를 구해서 화살표의 position과 rotation만 잘 적용시켜준다면 될 것 같아서 해봤더니 잘 해결되었다.
'Unity' 카테고리의 다른 글
[Unity] 몬스터 데미지 구현 (UI Pooling) (0) | 2024.09.23 |
---|---|
A* 알고리즘 및 최적화 (0) | 2024.08.15 |
Extension Method (0) | 2024.06.25 |
오브젝트 풀링 정리 (0) | 2024.06.21 |
스택과 힙, 복사와 참조 (0) | 2024.04.18 |