
preview Link : https://velog.io/@suhan0304/Unity-Electricity-12
gitHub Link : https://github.com/suhan0304/Electricity
먼저 게임 매니저가 아니라 다른 오브젝트에서 Set, Save, Load를 하도록 설정해줬다.

이제 저장된 Json을 로드해보자. 일단 로드 여부를 잘 확인하기 위해 Map Data Reset 기능을 추가해주었다.
/// Reset Map Data
public void ResetMapData() {
level = 0;
startNode = Vector3.zero;
endNode = Vector3.zero;
nodesPosition.Clear();
blockInventory.Clear();
}
기존과 동일하게 Reset 버튼을 GameManagerEditor에 추가해줘서 인스펙터에서 사용할 수 있도록 해준다.
public static void LoadMapDataToMap(Map map) {
string fileName = Path.Combine(Application.dataPath + "/MapData/mapData_Level1.json");
// file already exist
if (!File.Exists(fileName)) {
Debug.LogError("No File (MapData)");
return;
}
string jsonFromFile = File.ReadAllText(fileName);
Vector3ListWrapper jsonData = JsonUtility.FromJson<Vector3ListWrapper>(jsonFromFile);;
map.startNode = jsonData.startNode;
map.endNode = jsonData.endNode;
map.nodesPosition = jsonData.vector3List;
}
이제 Map Reset을 눌러서 초기화 해주고

Load를 누르니?

여기서 중요한 점은 Load를 할 때는 Level의 값에 맞는 파일을 받아야 한다는 점이다. 그래서 일단 레벨 1, 2, 3 파일을 만들어주었다.
원래는 그냥 Level1 파일을 불러오도록 해놨었는데 이 부분을 수정해준다. (Save, Load 동일하게 수정)
Application.dataPath + "/MapData/mapData_Level1.json")Application.dataPath + "/MapData/mapData_Level" + map.level + ".json")
이제 MapManager에 Level을 넣어주면 해당 레벨에 맞는 데이터가 로드된다.




레벨별 로드가 정상적으로 수행되는 것을 알 수 있다.
데이터 파일이 없는 경우에는 아래와 같이 오류가 출력되도록 하였다.
그렇다면 이제 맵 데이터로 Start Node, End Node, 기본 Node들의 위치를 다 받아오기 떄문에 맵을 자동으로 생성할 수 있다.

일단 Field의 자식 오브젝트로 있는 Node를 모두 날려주었다. 이제 노드를 생성해보자. 먼저 인스펙터를 아래와 같이 바꿔준다.

public void GenerateMapFromMapData() {
mapGenerator.MapGenerate(this);
}
중요한 점은 MapGenerator는 Prefab을 가지고 있어야 쓸 수 있다. 게임 매니저가 모든 프리팹을 가지고 있기보다는 Prefab Repository를 하나 작성해준다. Repository를 통해 스크립트의 프리팹을 초기화하도록 해준다.
using UnityEngine;
using System.Collections.Generic;
[CreateAssetMenu(fileName = "PrefabRepository", menuName = "ScriptableObjects/PrefabRepository", order = 0)]
public class PrefabRepository : ScriptableObject {
public List<GameObject> prefabs;
public Dictionary<string, GameObject> prefabDictionary;
public void OnEnable() {
InitializeDictionary();
}
public void InitializeDictionary() {
prefabDictionary = new Dictionary<string, GameObject>();
foreach (var prefab in prefabs) {
if(prefab != null) {
prefabDictionary[prefab.name] = prefab;
}
}
}
public GameObject GetPrefab(string prefabName) {
if (prefabDictionary.TryGetValue(prefabName, out var prefab)) {
return prefab;
}
Debug.LogWarning($"Prefab with name {prefabName} not found!");
return null;
}
}
아래 코드가 버튼에 연결되어있다.
public void ResetPrefabFromRepository() {
mapGenerator.GetPrefabFromRepository();
//TODO - BuildManager Prefabs Initialize
}
using UnityEngine;
public class MapGenerator : MonoBehaviour
{
public PrefabRepository prefabRepository;
[Space(10)]
[Header("Node Prefabs")]
public GameObject NodePrefab;
public GameObject StartNodePrefab;
public GameObject EndNodePrefab;
public void GetPrefabFromRepository() {
prefabRepository.InitializeDictionary();
NodePrefab = prefabRepository.GetPrefab(Names.Node);
StartNodePrefab = prefabRepository.GetPrefab(Names.startNode);
EndNodePrefab = prefabRepository.GetPrefab(Names.endNode);
}
public void MapGenerate(Map map, Transform fieldObject) {
Debug.Log("Map Generation Start...");
GetPrefabFromRepository();
Debug.Log("Map Generation Finish!");
}
}
일단 여기까지만 작성하고 Prefab 초기화를 한 번 해본다.

아무런 프리팹이 없던 Map Generator에 GameManager의 Reset Prefabs 버튼을 누르면?

아래와 같이 Prefab이 자동으로 들어간다.
BuildManager도 동일하게 PrefabRepository에서 Prefab을 가져가서 사용할 수 있도록 수정할 예정이다. 정 어려우면 리팩토링 목록에 추가해놓을 에정이다.

이제 노드 프리팹들을 모두 가져왔기 때문에 맵을 Generate할 수 있다. MapGenerate에 Instantiate를 아래와 같이 추가해준다.
public void MapGenerate(Map map, Transform fieldObject) {
Debug.Log("Map Generation Start...");
GetPrefabFromRepository();
if (NodePrefab == null || StartNodePrefab == null || EndNodePrefab == null) {
Debug.LogWarning("Node Prefab Error");
return;
}
Instantiate(StartNodePrefab, map.startNode, Quaternion.identity, fieldObject);
Instantiate(EndNodePrefab, map.endNode, Quaternion.identity, fieldObject);
foreach (Vector3 vec in map.nodesPosition) {
Instantiate(NodePrefab, vec, Quaternion.identity, fieldObject);
}
Debug.Log("Map Generation Finish!");
}

아무것도 없던 필드에 아래처럼 생성이 된다. Map Generate가 잘 구현되었다.

자연스럽게 블럭이 하나씩 생성되는 느낌을 위해 코루틴으로 구현해보자.
/// Coroutines for creating nodes at intervals
IEnumerator SpawnNodesWithDelay(Map map, Transform fieldObject, float delayTime)
{
foreach (Vector3 vec in map.nodesPosition)
{
Instantiate(NodePrefab, vec, Quaternion.identity, fieldObject);
yield return new WaitForSeconds(delayTime); // 0.2초 대기
}
}
그런 다음 GameManager 및 기타 이것 저것 다 수정을 해준 후에 게임을 시작하니? 자동으로 생성되는 것을 볼 수 있다.

TransParentBlock을 현재 무조건 standardBlock이 투명하게 뜨는데 선택한 블럭으로 수정되도록 하고 BlockInventory도 구현해서 맵 별로 건설 가능한 블럭의 종류와 개수를 지정해준다. (Json 직렬화에 아마 오류가 생길 것 같아서 이것도 추후에 업데이트 할 예정이다.)
재업로드 : 순서가 좀 뒤죽박죽이라 게시글 자체를 재업로드 했다.