작업을 시작하기에 앞서 시점을 탑뷰로 할지 쿼터뷰로 할지 고민을 좀 했다.
탑뷰 → https://namu.wiki/w/%ED%83%91%EB%B7%B0
쿼터뷰 → https://namu.wiki/w/%EC%BF%BC%ED%84%B0%EB%B7%B0
이쁘기는 쿼터뷰가 이쁜데 몬스터가 건물을 지나가거나 할때 가려진 부분만 가리고 아닌 부분은 보여주고
이런게 구현하기가 힘들 것 같아서 탑뷰로 만들기로 결정했다.
우선 기본맵을 만들어주기로 했다.
Kenny의 RPG팩의 타일들이 깔끔하고 무난해보여서 이걸로 만들기로 결정했다.
우선은 기본 맵을 만들어 주었다.
이후에 기본 길을 만들어 주었다.
위의 타일을보면 길옆에 데코? 이어주는 타일들을 하나씩 다 따로붙여주어야 하므로 상당한 노가다가 될 것이다.
그래서 지금은 길이 하나지만 이후에 길을 바꾸거나 스테이지를 여러개 만들걸 생각하여
길에 맞게 자동으로 옆쪽타일을 붙여주게 스크립트를 작성했다.
이후 시작, 끝점과 회전구간만 먼저 예외처리하여 데코를 해주었다.
마지막으로 비어있는 구간에 데코를 붙여서 길을 완성하였다.
길을 이런 모양으로 만든 이유는 여러가지 케이스를 테스트하기 위해
겹치거나 회전할 경우에도 잘 나오는지 확인하기 위해서 이렇게 만들었다.
잘 동작하는거 확인했으니 이제 원했던 대로 한갈래의 길을 만들 것이다.
기본 맵을 깔아주는 스크립트는 아래와 같다.
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 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class TileMaker : MonoBehaviour { public static float startX = 0.32f; public static float startY = 0.32f; // Use this for initialization void Start () { var gameTile = Resources.Load("TileObject", typeof(GameObject)) as GameObject; // 기본잔디 맵전체에 깔아줌 for (int i = 1; i < 20; i++) { for (int j = 1; j < 12; j++) { makeTile(gameTile, "rpgTile039", new Vector3(startX + (float)i * 0.64f, startY + (float)j * 0.64f, 0), -1); } } // 모서리 4개 makeTile(gameTile, "rpgTile036", new Vector3(startX, startY, 0), -1); makeTile(gameTile, "rpgTile038", new Vector3(startX + 19.0f * 0.64f, startY, 0), -1); makeTile(gameTile, "rpgTile000", new Vector3(startX, startY + 11.0f * 0.64f, 0), -1); makeTile(gameTile, "rpgTile002", new Vector3(startX + 19.0f * 0.64f, startY + 11.0f * 0.64f, 0), 5); // 모서리라인 4줄 for (int i = 1; i < 19; i++) { makeTile(gameTile, "rpgTile037", new Vector3(startX + (float)i * 0.64f, startY, 0), -1); makeTile(gameTile, "rpgTile001", new Vector3(startX + (float)i * 0.64f, startY + 11.0f * 0.64f, 0), 5); } for (int i = 1; i < 11; i++) { makeTile(gameTile, "rpgTile018", new Vector3(startX, startY + (float)i * 0.64f, 0), -1); makeTile(gameTile, "rpgTile020", new Vector3(startX + 19.0f * 0.64f, startY + (float)i * 0.64f, 0), 5); } } public void makeTile(GameObject gameTile, string fileName, Vector3 position, int order) { GameObject instance = Instantiate(gameTile); SpriteRenderer pRenderer = instance.AddComponent<SpriteRenderer>(); Sprite tile = Resources.Load(fileName, typeof(Sprite)) as Sprite; pRenderer.sprite = tile; pRenderer.sortingOrder = order; instance.transform.position = position; } // Update is called once per frame void Update () { } } | cs |
길을 만드는 스크립트
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 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class MakePath : MonoBehaviour { public class MovePath { public int x = 0; public int y = 0; public MovePath(int x, int y) { this.x = x; this.y = y; } } public static List<MovePath> movePath = new List<MovePath>(); // 데이터를 저장할 배열 // 1은 길, 2는 시작.끝점, 3은 꺾이는점, 4는 사이드, 5는 회전닫아주는것. public int[] map = new int[240]; // Use this for initialization void Start () { // 배열 초기화 for(int i=0; i<240; i++) { map[i] = 0; } // 길 movePath.Add(new MovePath(0, 6)); movePath.Add(new MovePath(1, 6)); movePath.Add(new MovePath(2, 6)); movePath.Add(new MovePath(3, 6)); movePath.Add(new MovePath(4, 6)); movePath.Add(new MovePath(5, 6)); movePath.Add(new MovePath(6, 6)); movePath.Add(new MovePath(7, 6)); movePath.Add(new MovePath(8, 6)); movePath.Add(new MovePath(8, 7)); movePath.Add(new MovePath(8, 8)); movePath.Add(new MovePath(9, 8)); movePath.Add(new MovePath(10, 8)); movePath.Add(new MovePath(11, 8)); movePath.Add(new MovePath(12, 8)); movePath.Add(new MovePath(12, 7)); movePath.Add(new MovePath(12, 6)); movePath.Add(new MovePath(12, 5)); movePath.Add(new MovePath(12, 4)); movePath.Add(new MovePath(11, 4)); movePath.Add(new MovePath(10, 4)); movePath.Add(new MovePath(9, 4)); movePath.Add(new MovePath(8, 4)); movePath.Add(new MovePath(8, 5)); movePath.Add(new MovePath(13, 6)); movePath.Add(new MovePath(14, 6)); movePath.Add(new MovePath(15, 6)); movePath.Add(new MovePath(16, 6)); movePath.Add(new MovePath(17, 6)); movePath.Add(new MovePath(18, 6)); movePath.Add(new MovePath(19, 6)); movePath.Add(new MovePath(10, 9)); movePath.Add(new MovePath(11, 9)); movePath.Add(new MovePath(10, 10)); movePath.Add(new MovePath(10, 11)); movePath.Add(new MovePath(10, 3)); movePath.Add(new MovePath(10, 2)); movePath.Add(new MovePath(10, 1)); movePath.Add(new MovePath(10, 0)); movePath.Add(new MovePath(10, 0)); // 일단 길만들기 foreach (MovePath path in movePath) { // 마지막은 자연스러운 삭제를 위해 추가한 경로이므로 맵생성 x if (path != movePath[movePath.Count - 1]) { makeTile(path, "rpgTile024", 5); map[path.y * 20 + path.x] = 1; } } // 시작길, 꺾이는길 먼저 만들기 foreach (MovePath path in movePath) { if (path != movePath[movePath.Count - 1]) { makeSpecialTile(path, 1); } } // 이제 남은 자리에 사이드 타일 붙이기 foreach (MovePath path in movePath) { if (path != movePath[movePath.Count - 1]) { makeSideTile(path, 1); } } } public void makeSpecialTile(MovePath path, int order) { // 시작점과 끝점이면 양옆 다른 타일 생성 // 왼쪽시작점 위아래 타일생성 if (path.x <= 0 && path.y > 0 && path.y < 12) { MovePath upPath = new MovePath(path.x, path.y + 1); MovePath downPath = new MovePath(path.x, path.y - 1); makeTile(upPath, "rpgTile036", order + 2); makeTile(downPath, "rpgTile000", order + 2); map[(path.y + 1) * 20 + path.x] = 2; map[(path.y - 1) * 20 + path.x] = 2; } // 오른쪽 시작점 위아래 타일생성 else if (path.x >= 19 && path.y > 0 && path.y < 12) { MovePath upPath = new MovePath(path.x, path.y + 1); MovePath downPath = new MovePath(path.x, path.y - 1); makeTile(upPath, "rpgTile038", order + 2); makeTile(downPath, "rpgTile002", order + 2); map[(path.y + 1) * 20 + path.x] = 2; map[(path.y - 1) * 20 + path.x] = 2; } // 위시작점 좌우 타일생성 else if (path.y >= 11 && path.x > 0 && path.x < 20) { MovePath rightPath = new MovePath(path.x + 1, path.y); MovePath leftPath = new MovePath(path.x - 1, path.y); makeTile(leftPath, "rpgTile002", order + 2); makeTile(rightPath, "rpgTile000", order + 2); map[path.y * 20 + path.x - 1] = 2; map[path.y * 20 + path.x + 1] = 2; } // 아래시작점 좌우 타일생성 else if (path.y <= 0 && path.x > 0 && path.x < 20) { MovePath rightPath = new MovePath(path.x + 1, path.y); MovePath leftPath = new MovePath(path.x - 1, path.y); makeTile(leftPath, "rpgTile038", order + 2); makeTile(rightPath, "rpgTile036", order + 2); map[path.y * 20 + path.x - 1] = 2; map[path.y * 20 + path.x + 1] = 2; } // 시작, 끝점이 아닐때만 나머지검사 if (path.x > 0 && path.x < 19 && path.y > 0 && path.y < 12) { // 꺾이는 부분이면 꺾이는 블럭생성. 근데 꺾이는부분 오더 우선 // 위와 왼쪽이 있으면(┘ 모양) if (map[(path.y + 1) * 20 + path.x] == 1 && map[path.y * 20 + path.x - 1] == 1) { MovePath leftupPath = new MovePath(path.x - 1, path.y + 1); MovePath rightdownPath = new MovePath(path.x + 1, path.y - 1); // 땅이 없는 자리에만 생성 if (map[(path.y + 1) * 20 + path.x - 1] != 1) { makeTile(leftupPath, "rpgTile038", order + 2); map[(path.y + 1) * 20 + path.x - 1] = 3; } if (map[(path.y - 1) * 20 + path.x + 1] != 1) { makeTile(rightdownPath, "rpgTile022", order); map[(path.y - 1) * 20 + path.x + 1] = 5; } } // 위와 오른쪽이 있으면(└ 모양) if (map[(path.y + 1) * 20 + path.x] == 1 && map[path.y * 20 + path.x + 1] == 1) { MovePath rightupPath = new MovePath(path.x + 1, path.y + 1); MovePath leftdownPath = new MovePath(path.x - 1, path.y - 1); // 땅이 없는 자리에만 생성 if (map[(path.y + 1) * 20 + path.x + 1] != 1) { makeTile(rightupPath, "rpgTile036", order + 2); map[(path.y + 1) * 20 + path.x + 1] = 3; } if (map[(path.y - 1) * 20 + path.x - 1] != 1) { makeTile(leftdownPath, "rpgTile021", order); map[(path.y - 1) * 20 + path.x - 1] = 5; } } // 아래와 왼쪽이 있으면(┐ 모양) if (map[(path.y - 1) * 20 + path.x] == 1 && map[path.y * 20 + path.x - 1] == 1) { MovePath leftdownPath = new MovePath(path.x - 1, path.y - 1); MovePath rightupPath = new MovePath(path.x + 1, path.y + 1); // 땅이 없는 자리에만 생성 if (map[(path.y - 1) * 20 + path.x - 1] != 1) { makeTile(leftdownPath, "rpgTile002", order + 2); map[(path.y - 1) * 20 + path.x - 1] = 3; } if (map[(path.y + 1) * 20 + path.x + 1] != 1) { makeTile(rightupPath, "rpgTile004", order); map[(path.y + 1) * 20 + path.x + 1] = 5; } } // 아래와 오른쪽이 있으면(┌ 모양) if (map[(path.y - 1) * 20 + path.x] == 1 && map[path.y * 20 + path.x + 1] == 1) { MovePath rightdownPath = new MovePath(path.x + 1, path.y - 1); MovePath leftupPath = new MovePath(path.x - 1, path.y + 1); // 땅이 없는 자리에만 생성 if (map[(path.y - 1) * 20 + path.x + 1] != 1) { makeTile(rightdownPath, "rpgTile000", order + 2); map[(path.y - 1) * 20 + path.x + 1] = 3; } if (map[(path.y + 1) * 20 + path.x - 1] != 1) { makeTile(leftupPath, "rpgTile003", order); map[(path.y + 1) * 20 + path.x - 1] = 5; } } } } public void makeSideTile(MovePath path, int order) { // 시작, 끝점이 아닐때만 나머지검사 if (path.x > 0 && path.x < 19 && path.y > 0 && path.y < 11) { // 상하좌우검사 // 비어있거나 회전닫는블럭이면 덮어씌우고 사이드 생성 if (map[(path.y + 1) * 20 + path.x] == 0 || map[(path.y + 1) * 20 + path.x] == 5) { MovePath upPath = new MovePath(path.x, path.y + 1); makeTile(upPath, "rpgTile037", order + 1); map[(path.y + 1) * 20 + path.x] = 4; } if (map[(path.y - 1) * 20 + path.x] == 0 || map[(path.y - 1) * 20 + path.x] == 5) { MovePath downPath = new MovePath(path.x, path.y - 1); makeTile(downPath, "rpgTile001", order + 1); map[(path.y - 1) * 20 + path.x] = 4; } if (map[path.y * 20 + path.x - 1] == 0 || map[path.y * 20 + path.x - 1] == 5) { MovePath leftPath = new MovePath(path.x - 1, path.y); makeTile(leftPath, "rpgTile020", order + 1); map[path.y * 20 + path.x - 1] = 4; } if (map[path.y * 20 + path.x + 1] == 0 || map[path.y * 20 + path.x + 1] == 5) { MovePath rightPath = new MovePath(path.x + 1, path.y); makeTile(rightPath, "rpgTile018", order + 1); map[path.y * 20 + path.x + 1] = 4; } } } public void makeTile(MovePath path, string fileName, int order) { var gameTile = Resources.Load("TileObject", typeof(GameObject)) as GameObject; GameObject instance = Instantiate(gameTile); SpriteRenderer pRenderer = instance.AddComponent<SpriteRenderer>(); Sprite tile = Resources.Load(fileName, typeof(Sprite)) as Sprite; pRenderer.sprite = tile; pRenderer.sortingOrder = order; // 시작 x, y는 0.32로 똑같으므로 instance.transform.position = new Vector3(TileMaker.startX + path.x * 0.64f, TileMaker.startY + path.y * 0.64f); } // Update is called once per frame void Update () { } } | cs |
MovePath라는 클래스를 만들어 List로 관리하였다.
그 이유는 타일의 1칸은 가로 세로 64픽셀이지만 1단위로 관리하기위해서 편의를 위해 만들었다.
그리고 map이라는 배열을 만들어 맵 위치에 무엇이 들어있는지를 저장하여 맵을 관리하였다.
'프로그래밍 공부 > Unity 프로젝트' 카테고리의 다른 글
2D 타워디펜스 - 3. 몬스터 애니메이션, 스프라이트시트 사용하기 (0) | 2018.04.12 |
---|---|
2D 타워디펜스 - 2. 길만들기 + 몬스터생성, 이동 (2) | 2018.04.12 |
테트리스 (3) | 2018.04.11 |
2D 슈팅게임 (0) | 2018.04.11 |
캔버스를 이용한 2D 슈팅게임 (미완성) (0) | 2018.04.11 |