반응형
오늘의 구현 목표
- Path 타일 기반으로 Waypoint 생성
- 몬스터 이동 시스템 1차 구현
- 기존 GridManager에 Waypoint를 만들어주는 함수 구현
- 만들어 둔 PathTile을 순서대로 가져와서 이동가능한 Waypoint로 구현
|
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
|
using UnityEngine;
using System.Collections.Generic;
public class GridManager : MonoBehaviour
{
public static GridManager Instance { get; private set; }
public int width = 16;
public int height = 12;
public float cellSize = 1f;
public GameObject buildablePrefab;
public GameObject pathPrefab;
public Transform tileParent;
[Header("Path Tiles")] public List<Vector2Int> pathTiles = new List<Vector2Int>();
[Header("Waypoints")] public List<Transform> waypoints = new List<Transform>();
private GridTile[,] tiles;
private void Awake()
{
if (Instance != null && Instance != this)
{
Debug.LogWarning("여러 개의 GridManager가 씬에 있습니다.");
}
Instance = this;
GenerateGrid();
GenerateWaypoints();
}
private void GenerateGrid()
{
tiles = new GridTile[width, height];
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
Vector2Int pos = new Vector2Int(x, y);
bool isPath = pathTiles.Contains(pos);
GameObject prefab = isPath ? pathPrefab : buildablePrefab;
TileType tileType = isPath ? TileType.Path : TileType.Buildable;
CreateTile(pos, prefab, tileType);
}
}
}
private void CreateTile(Vector2Int gridPos, GameObject prefab, TileType tileType)
{
Vector3 worldPos = new Vector3(gridPos.x * cellSize, 0f, gridPos.y * cellSize);
GameObject obj = Instantiate(prefab, worldPos, Quaternion.identity, tileParent);
GridTile tile = obj.GetComponent<GridTile>();
if (tile == null)
{
tile = obj.AddComponent<GridTile>();
}
tile.Init(gridPos, tileType);
tiles[gridPos.x, gridPos.y] = tile;
}
private void GenerateWaypoints()
{
waypoints.Clear();
if (tiles == null)
{
Debug.LogError("타일이 아직 생성되지 않았습니다. GenerateGrid 이후에 호출해야 합니다.");
return;
}
foreach (Vector2Int gridPos in pathTiles)
{
if (gridPos.x < 0 || gridPos.x >= width || gridPos.y < 0 || gridPos.y >= height)
{
Debug.LogWarning($"PathTile {gridPos} 좌표가 Grid 범위를 벗어났습니다.");
continue;
}
GridTile tile = tiles[gridPos.x, gridPos.y];
if (tile == null)
{
Debug.LogWarning($"PathTile {gridPos} 위치에 타일이 없습니다.");
continue;
}
waypoints.Add(tile.transform);
}
if (waypoints.Count == 0)
{
Debug.LogWarning("Waypoint가 하나도 생성되지 않았습니다. pathTiles를 확인하세요.");
}
}
public Transform GetWaypoint(int index)
{
if (index < 0 || index >= waypoints.Count)
return null;
return waypoints[index];
}
public int WaypointCount => waypoints.Count;
#if UNITY_EDITOR
private void OnDrawGizmosSelected()
{
if (pathTiles == null || pathTiles.Count == 0)
return;
Gizmos.color = Color.yellow;
Vector3 prevPos = Vector3.zero;
bool hasPrev = false;
foreach (Vector2Int gridPos in pathTiles)
{
Vector3 worldPos = new Vector3(gridPos.x * cellSize, 0f, gridPos.y * cellSize);
Vector3 drawPos = worldPos + Vector3.up * 0.3f;
Gizmos.DrawSphere(drawPos, 0.1f);
if (hasPrev)
{
Gizmos.DrawLine(prevPos, drawPos);
}
prevPos = drawPos;
hasPrev = true;
}
}
#endif
}
|
cs |
몬스터가 Waypoint를 따라 이동하도록 구현
|
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
|
using UnityEngine;
public class MonsterAI : MonoBehaviour
{
[Header("Move Settings")]
[SerializeField] private float moveSpeed = 2f;
[SerializeField] private float stoppingDistance = 0.05f;
private int _currentIndex = 0;
private Transform _currentTarget;
private void Start()
{
if (GridManager.Instance == null)
{
Debug.LogError("GridManager 인스턴스가 없습니다.");
enabled = false;
return;
}
if (GridManager.Instance.WaypointCount == 0)
{
Debug.LogError("Waypoint가 하나도 없습니다. pathTiles를 설정했는지 확인하세요.");
enabled = false;
return;
}
Transform startPoint = GridManager.Instance.GetWaypoint(0);
transform.position = startPoint.position;
_currentIndex = 1;
SetNextTarget();
}
private void Update()
{
MoveAlongPath();
}
private void MoveAlongPath()
{
if (_currentTarget == null)
return;
Vector3 targetPos = _currentTarget.position;
Vector3 dir = targetPos - transform.position;
dir.y = 0f;
float distanceToTarget = dir.magnitude;
float moveThisFrame = moveSpeed * Time.deltaTime;
if (distanceToTarget <= moveThisFrame + stoppingDistance)
{
_currentIndex++;
SetNextTarget();
return;
}
Vector3 move = dir.normalized * moveThisFrame;
transform.position += move;
if (dir.sqrMagnitude > 0.0001f)
{
transform.rotation = Quaternion.LookRotation(dir);
}
}
private void SetNextTarget()
{
if (_currentIndex >= GridManager.Instance.WaypointCount)
{
ReachGoal();
return;
}
_currentTarget = GridManager.Instance.GetWaypoint(_currentIndex);
}
private void ReachGoal()
{
Destroy(gameObject);
}
}
|
cs |
결과물
반응형
'게임 개발 > 랜덤 타워 디펜스' 카테고리의 다른 글
| [랜덤 타워 디펜스] Day 6 타워 랜덤 생성 시스템 구현 (0) | 2025.12.27 |
|---|---|
| [랜덤 타워 디펜스] Day 5 타워 데이터 셋팅 및 합성 시스템 (0) | 2025.12.21 |
| [랜덤 타워 디펜스] Day 4 기초 UI 및 타워 건설 (0) | 2025.12.12 |
| [랜덤 타워 디펜스] Day 2 마우스 호버 기능 및 Orbit Camera 기본 구현 (0) | 2025.12.09 |
| [랜덤 타워 디펜스] Day 1 그리드 매니저 기본 설계 (0) | 2025.12.08 |