2D게임에서 배경 무한루프는 자주 볼 수 있다.
특히 러닝게임에서 자주 살펴볼 수 있다.
나는 일반적인 러닝게임이 아닌 NxM배열의 러닝게임이므로 2차원 배열을 사용해서 무한 루프를 구현했다.
무한 루프는 플레이어의 중심기준(아래기준 "11")으로 구현한다.
00 | 01 | 02 |
10 | 11(player) | 12 |
20 | 21 | 22 |
각각 타일마다 Collider를 생성하고 Trigger를 체크해준다.
위의 타일을 나갈 때 마다 OnTriggerExit2D가 이벤트로 발생하고 거기에 따른 타일 이동을 해주면 된다.
예를들면 플레이어가 타일"11"에서 "21"로 이동한다면
"21"가 중심이 되어야 하고 나머지("00", "01", "02")는 아래로 내려와야 한다.
예로 들면 아래와 같다.
10 | 11 | 12 |
20 | 21(player) | 22 |
00 | 01 | 02 |
근데 왜 TriggerEnter2D가 아니라 TriggerExit2D까?
-> Player의 Collider가 어느 임의의 타일을 잠시 들렸다가 다시 돌아오면 배경은 루한루프가 되지 못한다.
즉, Player의 Collider가 현재의 타일을 완전히 나갈때(Exit할 때) 검사를 해야 한다.
그리고 어느 타일에서 어느타일로 이동했는지는 player의 현재위치와 나간 타일 중심의 각도를 구하면 알 수 있다.
-45 ~ 45 : 위쪽 이동 -> 아래의 타일을 모두 위로 옮김
45 ~ 135 : 왼쪽 이동 -> 오른쪽 타일을 모두 왼쪽으로 옮김
-45 ~ -135 : 오른쪽 이동 -> 왼쪽 타일을 모두 오른쪽으로 옮김
-135 ~ 135 : 아래쪽 이동 -> 위쪽 타일을 모두 아래쪽으로 옮김
그래서 현재의 배열 인덱스를 알아내고 방향에 따른 인덱스를 옮겨주면 된다.
00 | 01 | 02 |
10 | 11 | 12 |
20 | 21 | 22 |
위쪽이동 방향 일 때 (11 -> 01로 이동했을 때, 각도가 -45 ~ 45 일 때)
-> 다른 행의 성분을 가진 타일을 모두 위로 올림 (20, 21, 22)
왼쪽이동 방향 일 때 (11 -> 10로 이동했을 때, 각도가 45 ~ 135 일 때)
-> 다른 열의 성분을 가진 타일을 모두 왼쪽으로 옮김 (02, 12, 22)
아래쪽 이동 방향 일 때 (11 -> 21로 이동했을 때, 각도가 -135 ~ 135일 때)
-> 다른 행의 성분을 가진 타일을 모두 아래로 옮김 (00, 01, 02)
오른쪽이동 방향 일 때 (11 -> 12로 이동했을 때, 각도가 -135 ~ -45 일 때)
-> 다른 열의 성분을 가진 타일을 모두 오른쪽으로 옮김 (00, 10, 20)
cf) 만약 정확히 대각선으로 이동했다면(ex. 45도, 11 -> 00) 따로 예외처리 해줘야 할 것 같지만
결국 Collider가 존재하여 다른 타일(01, 10 타일)도 Exit를 호출할 것임에 문제가 없다.
굳이 예외처리를 한다하면은 옮겨야할 타일이 그자리에 없는 경우 옮기지 않으면 된다.
내가 작성한 코드는 아래와 같다. (깔끔하지 못함 주의)
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class LoopBackground : MonoBehaviour
{
public Background background;
private GameObject[] tmp_tile; //임시 타일 public으로 받기
public GameObject[,] tile; //임시 타일을 3x3으로 바꿀 변수
private int currentIndex_i; //현재 나의 타일 인덱스 i
private int currentIndex_j; //현재 나의 타일 인덱스 j
private string tmpStringIndex; //오브젝트 이름(ex. 00 ~ 22)로 받을 변수
private void Start()
{
tmp_tile = background.tile;
tile = new GameObject[3, 3]; // 3x3
int cnt = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
tile[i, j] = tmp_tile[cnt]; //타일을 2차원으로 변경
cnt += 1;
}
}
tmpStringIndex = this.name; //오브젝트 이름을 스트링으로 받아서 인덱스에 넣음
currentIndex_i = int.Parse(tmpStringIndex[0].ToString());
currentIndex_j = int.Parse(tmpStringIndex[1].ToString());
}
private void OnTriggerExit2D(Collider2D other) //충돌 Exit처리 -> 나가면 배경이 바뀌어야 함
{
if (other.tag != "MoveCollider") return; //다른 충돌이면 그냥 리턴
if (Player.instance.isAlive == false) return; //플레이어가 죽으면 바꾸지 않음
Vector3 dir = other.transform.position - transform.position; //플레이어의 위치 - 타일의 중심 =>>> 타일 중심에서의 벡터가 나옴
float angle = Vector3.Angle(transform.up, dir); //각도
int sign = Vector3.Cross(transform.up, dir).z < 0 ? -1 : 1;
angle *= sign;
if (-45 <= angle && angle <= 45) // 위쪽
{
for (int i = 0; i < 3; i++) // 타일 3개를 옮겨야 함
{
if (currentIndex_i + 1 <= 2) // 배열에 대한 예외처리, 아래의 else문은 currentIndex_i가 2일때임
{ // 예외 : 이미 옮긴 것을 또 옮길 수 있기 때문, position.y의 차이가 24면 옮김
if (tile[currentIndex_i + 1, i].transform.localPosition.y - transform.localPosition.y == -24)
{
tile[currentIndex_i + 1, i].transform.localPosition += new Vector3(0, 24 * 3, 0); //위쪽으로 가므로 아래행을 옮김
}
}
else
{
if (tile[0, i].transform.localPosition.y - transform.localPosition.y == -24) //currentIndex_i가 2일때는 아래가 0인덱스
{
tile[0, i].transform.localPosition += new Vector3(0, 24 * 3, 0);
}
}
}
}
else if (45 <= angle && angle <= 135) // 왼쪽
{
for (int i = 0; i < 3; i++)
{
if (currentIndex_j + 1 <= 2)
{
if (tile[i, currentIndex_j + 1].transform.localPosition.x - transform.localPosition.x == 24)
{
tile[i, currentIndex_j + 1].transform.localPosition += new Vector3(-24 * 3, 0, 0);
}
}
else
{
if (tile[i, 0].transform.localPosition.x - transform.localPosition.x == 24)
{
tile[i, 0].transform.localPosition += new Vector3(-24 * 3, 0, 0);
}
}
}
}
else if (135 <= angle || -135 >= angle) // 아래쪽 -135 ~ -180 or 135 ~ 180
{
for (int i = 0; i < 3; i++)
{
if (currentIndex_i - 1 >= 0)
{
if (tile[currentIndex_i - 1, i].transform.localPosition.y - transform.localPosition.y == 24)
{
tile[currentIndex_i - 1, i].transform.localPosition += new Vector3(0, -24 * 3, 0);
}
}
else
{
if (tile[2, i].transform.localPosition.y - transform.localPosition.y == 24)
{
tile[2, i].transform.localPosition += new Vector3(0, -24 * 3, 0);
}
}
}
}
else if (-135 <= angle && angle <= -45) // 오른쪽
{
for (int i = 0; i < 3; i++)
{
if (currentIndex_j - 1 >= 0)
{
if (tile[i, currentIndex_j - 1].transform.localPosition.x - transform.localPosition.x == -24)
{
tile[i, currentIndex_j - 1].transform.localPosition += new Vector3(24 * 3, 0, 0);
}
}
else
{
if (tile[i, 2].transform.localPosition.x - transform.localPosition.x == -24)
{
tile[i, 2].transform.localPosition += new Vector3(24 * 3, 0, 0);
}
}
}
}
}
}
|
cs |
'Unity' 카테고리의 다른 글
Unity - 인디케이터(Indicator)구현 (0) | 2020.02.19 |
---|---|
Unity - 총알 구현하기(Bullet) (0) | 2020.02.17 |
Unity - 스폰(Spawn) 구현하기 (0) | 2020.02.17 |
Unity - 조이스틱(Joystick) (0) | 2020.02.15 |
Unity Asset Store 세일 (0) | 2019.11.11 |