[Unity] Electricity (13)

suhan0304·2024년 6월 16일

유니티-Electricity

목록 보기
13/18
post-thumbnail

preview Link : https://velog.io/@suhan0304/Unity-Electricity-12
gitHub Link : https://github.com/suhan0304/Electricity


먼저 게임 매니저가 아니라 다른 오브젝트에서 Set, Save, Load를 하도록 설정해줬다.


이제 저장된 Json을 로드해보자. 일단 로드 여부를 잘 확인하기 위해 Map Data Reset 기능을 추가해주었다.

Map.cs

/// Reset Map Data
public void ResetMapData() {
    level = 0;
    startNode = Vector3.zero; 
    endNode = Vector3.zero;
    nodesPosition.Clear();
    blockInventory.Clear();
}

기존과 동일하게 Reset 버튼을 GameManagerEditor에 추가해줘서 인스펙터에서 사용할 수 있도록 해준다.

Json Load

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 파일을 만들어주었다.


Level Load

원래는 그냥 Level1 파일을 불러오도록 해놨었는데 이 부분을 수정해준다. (Save, Load 동일하게 수정)

Application.dataPath + "/MapData/mapData_Level1.json")
Application.dataPath + "/MapData/mapData_Level" + map.level + ".json")

이제 MapManager에 Level을 넣어주면 해당 레벨에 맞는 데이터가 로드된다.

Level1 Load

Level2 Load

Level3 Load

레벨별 로드가 정상적으로 수행되는 것을 알 수 있다.

데이터 파일이 없는 경우에는 아래와 같이 오류가 출력되도록 하였다.


Map Generate

그렇다면 이제 맵 데이터로 Start Node, End Node, 기본 Node들의 위치를 다 받아오기 떄문에 맵을 자동으로 생성할 수 있다.

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

Map.cs

public void GenerateMapFromMapData() {
    mapGenerator.MapGenerate(this);
}

중요한 점은 MapGenerator는 Prefab을 가지고 있어야 쓸 수 있다. 게임 매니저가 모든 프리팹을 가지고 있기보다는 Prefab Repository를 하나 작성해준다. Repository를 통해 스크립트의 프리팹을 초기화하도록 해준다.

PrefabRepository.cs

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;
    }
}

아래 코드가 버튼에 연결되어있다.

GameManager.cs

public void ResetPrefabFromRepository() {
    mapGenerator.GetPrefabFromRepository();
    //TODO - BuildManager Prefabs Initialize
}

Map Generator.cs

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 및 기타 이것 저것 다 수정을 해준 후에 게임을 시작하니? 자동으로 생성되는 것을 볼 수 있다.


추가 업데이트

  • GameManager : Map Generate 실행
  • TransParentBlockControl 오류 수정

추후 예정

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


재업로드 : 순서가 좀 뒤죽박죽이라 게시글 자체를 재업로드 했다.

profile
Be Honest, Be Harder, Be Stronger

0개의 댓글