Unity 2D FOV 연출
Unity/2020 / 2020. 6. 24. 15:58
본 글은 Code Monkey의 영상을 참고하였습니다.
https://unitycodemonkey.com/video.php?v=CSeUMTaNFYk
2D 게임에서 종종 보이는 방법입니다.
잘만 활용하면 단조로운 맵도 입체감 있게 만들 수 있고 공포 분위기 연출에 훌륭한 방법 중 하나입니다.
여러가지 방법이 있겠지만 여기선 매프레임 수십번의 레이를 쏘아 레이 도착점을 이어 메쉬를 그리는 방법입니다.
코드가 쉬운 편이고 퀄리티와 퍼포먼스에 주는 영향도 직관적입니다.
위 코드몽키 영상에서 나온 코드에서 살짝 손을 보아 시야각을 그리는 방식은 동일하지만 다루기 더 편하게 만들어본 코드입니다.
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
using UnityEngine;
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class FieldOfView : MonoBehaviour
{
[Range(0, 360)] public float fov = 90f; //시야각
public int rayCount = 90; //레이의 수 (높을수록 퀄리티↑퍼포먼스↑)
public float viewDistance = 10f; //거리
public LayerMask layerMask; //벽으로 인식할 레이어
private Camera mainCamera; //카메라
private Mesh mesh; //시야각을 그려줄 메쉬
private void Start()
{
mainCamera = Camera.main;
mesh = new Mesh();
mesh.name = "FOV_Effect";
GetComponent<MeshFilter>().mesh = mesh;
}
private void LateUpdate()
{
Vector3 mousePosition = mainCamera.ScreenToWorldPoint(Input.mousePosition);
transform.eulerAngles = new Vector3(0, 0, GetAngleFromVector(new Vector3(mousePosition.x - transform.position.x, mousePosition.y - transform.position.y, 0)));
DrawFOV();
}
private void DrawFOV()
{
float angle = fov * 0.5f;
float angleIncrease = fov / rayCount;
Vector3[] vertices = new Vector3[rayCount + 1 + 1];
Vector2[] uv = new Vector2[vertices.Length];
int[] triangles = new int[rayCount * 3];
vertices[0] = Vector3.zero;
int vertexIndex = 1;
int triangleIndex = 0;
for (int i = 0; i <= rayCount; i++)
{
Vector3 vertex;
RaycastHit2D raycastHit2D = Physics2D.Raycast(transform.position, GetVectorFromAngle(transform.eulerAngles.z + angle), viewDistance, layerMask);
if (raycastHit2D.collider == null)
{
vertex = GetVectorFromAngle(angle) * viewDistance;
}
else
{
vertex = GetVectorFromAngle(angle) * (raycastHit2D.distance / viewDistance) * viewDistance;
}
vertices[vertexIndex] = vertex;
if (0 < i)
{
triangles[triangleIndex + 0] = 0;
triangles[triangleIndex + 1] = vertexIndex - 1;
triangles[triangleIndex + 2] = vertexIndex;
triangleIndex += 3;
}
++vertexIndex;
angle -= angleIncrease;
}
mesh.vertices = vertices;
mesh.uv = uv;
mesh.triangles = triangles;
}
private Vector3 GetVectorFromAngle(float angle)
{
float angleRad = angle * (Mathf.PI / 180f);
return new Vector3(Mathf.Cos(angleRad), Mathf.Sin(angleRad));
}
private int GetAngleFromVector(Vector3 dir)
{
dir = dir.normalized;
float n = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
if (n < 0) n += 360;
int angle = Mathf.RoundToInt(n);
return angle;
}
}
|
cs |
아래 GetVectorFromAngle, GetAngleFromVector 함수는 원래 코드몽키 유틸리티용 코드에 포함된 함수입니다만 한 눈에 보기 쉬우라고 옮겨놨습니다.
rayCount값의 경우 fov와 동일해야 제일 깔끔하게 나오는 것 같습니다.
rayCount가 더 높아도 좋겠지만 그만큼 퍼포먼스가 상승합니다.
참고로 GIF에서 벽 테두리가 보이는 것은 쉐이더 효과라 위 코드만으론 불가능합니다.
'Unity > 2020' 카테고리의 다른 글
오큘러스 퀘스트 2 (0) | 2020.11.17 |
---|---|
뒤끝 서버 (0) | 2020.11.16 |
Addressable Asset system 간단하게 서버 다운로드로 실사용까지 (6) | 2020.06.23 |