using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Title : MonoBehaviour
{
public string sceneName = "SampleScene";
public static Title instance;
private SaveAndLoad theSaveNLoad;
private void Awake()
{
if(instance == null)
{
instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(this.gameObject);
}
}
public void ClickStart()
{
Debug.Log("로딩");
this.gameObject.SetActive(false);
SceneManager.LoadScene(sceneName);
}
public void ClickLoad()
{
Debug.Log("로드");
StartCoroutine(LoadCoroutine());
}
IEnumerator LoadCoroutine()
{
AsyncOperation operation = SceneManager.LoadSceneAsync(sceneName);
while (!operation.isDone)
{
yield return null;
}
theSaveNLoad = FindAnyObjectByType<SaveAndLoad>();
theSaveNLoad.LoadData();
this.gameObject.SetActive(false);
}
public void ClickExit()
{
Debug.Log("종료");
Application.Quit();
}
}
using UnityEngine;
using System.IO;
using System.Collections.Generic;
[System.Serializable]
public class SaveData
{
public Vector3 playerPos;
public Vector3 playerRot;
public List<int> invenArrayNumber = new List<int>();
public List<string> invenItemName = new List<string>();
public List<int> invenItemNumber = new List<int>();
}
public class SaveAndLoad : MonoBehaviour
{
private SaveData saveData = new SaveData();
private string SAVE_DATA_DIRECTORY;
private string SAVE_FILENAME = "/SaveFile.txt";
private PlayerController thePlayer;
private Inventory theInven;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
SAVE_DATA_DIRECTORY = Application.dataPath + "/Saves";
if(!Directory.Exists(SAVE_DATA_DIRECTORY))
Directory.CreateDirectory(SAVE_DATA_DIRECTORY);
}
public void SaveData()
{
thePlayer = FindAnyObjectByType<PlayerController>();
theInven = FindAnyObjectByType<Inventory>();
saveData.playerPos = thePlayer.transform.position;//플레이어 위치
saveData.playerRot = thePlayer.transform.eulerAngles;//플레이어 벡터 방향
Slot[] slots = theInven.GetSlots();
for(int i = 0; i < slots.Length; i++)
{
if( slots[i].item != null)
{
saveData.invenArrayNumber.Add(i);
saveData.invenItemName.Add(slots[i].item.itemName);
saveData.invenItemNumber.Add(slots[i].itemCount);
}
}
string json = JsonUtility.ToJson(saveData);
File.WriteAllText(SAVE_DATA_DIRECTORY + SAVE_FILENAME, json);
Debug.Log("저장 완료");
Debug.Log(json);
}
public void LoadData()
{
if (File.Exists(SAVE_DATA_DIRECTORY + SAVE_FILENAME))
{
string loadJson = File.ReadAllText(SAVE_DATA_DIRECTORY + SAVE_FILENAME);
saveData = JsonUtility.FromJson<SaveData>(loadJson);
thePlayer = FindAnyObjectByType<PlayerController>();
theInven = FindAnyObjectByType<Inventory>();
thePlayer.transform.position = saveData.playerPos;
thePlayer.transform.eulerAngles = saveData.playerRot;
for(int i = 0; i < saveData.invenItemName.Count; i++)
{
theInven.LoadToInven(saveData.invenArrayNumber[i], saveData.invenItemName[i], saveData.invenItemNumber[i]);
}
Debug.Log("로드 완료");
}
else
Debug.Log("세이브 파일이 없습니다");
}
}
using UnityEngine;
public class StopMenu : MonoBehaviour
{
[SerializeField] private GameObject go_BaseUi;
[SerializeField] private SaveAndLoad theSaveNLoad;
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.P))
{
if (!GameManager.isPause)
CallMenu();
else
{
CloseMenu();
}
}
}
private void CallMenu()
{
GameManager.isPause = true;
go_BaseUi.SetActive(true);
Time.timeScale = 0f;
}
private void CloseMenu()
{
GameManager.isPause = false;
go_BaseUi.SetActive(false);
Time.timeScale = 1f;
}
public void ClickSave()
{
Debug.Log("세이브");
theSaveNLoad.SaveData();
}
public void ClickLoad()
{
Debug.Log("로드");
theSaveNLoad.LoadData();
}
public void ClickExit()
{
Debug.Log("종료");
Application.Quit();
}
}
using UnityEngine;
public class Inventory : MonoBehaviour
{
public static bool inventoryActivated = false;
//필요한 컴포넌트
[SerializeField]
private GameObject go_InventoryBase;
[SerializeField]
private GameObject go_SlotsParent;
private Slot[] slots;
public Slot[] GetSlots() { return slots; }
[SerializeField] private Item[] items;
public void LoadToInven(int _arrayNum, string _itemName, int _itenNum)
{
for (int i = 0; i < items.Length; i++)
{
if (items[i].itemName == _itemName)
slots[_arrayNum].AddItem(items[i], _itenNum);
}
}
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
slots = go_SlotsParent.GetComponentsInChildren<Slot>();
}
// Update is called once per frame
void Update()
{
TryOpenInventory();
}
private void TryOpenInventory()
{
if (Input.GetKeyDown(KeyCode.I))
{
inventoryActivated = !inventoryActivated;
if (inventoryActivated)
OpenInventory();
else
CloseInventory();
}
}
private void OpenInventory()
{
GameManager.isOpenInventory = true;
go_InventoryBase.SetActive(true);
}
private void CloseInventory()
{
GameManager.isOpenInventory = false;
go_InventoryBase.SetActive(false);
}
public void AcquireItem(Item _item, int _count = 1)
{
if (Item.ItemType.Equipment != _item.itemType)
{
for (int i = 0; i < slots.Length; i++)
{
if (slots[i].item != null)
{
if (slots[i].item.itemName == _item.itemName)
{
slots[i].SetSlotCount(_count);
return;
}
}
}
}
for (int i = 0; i < slots.Length; i++)
{
if (slots[i].item == null)
{
slots[i].AddItem(_item, _count);
return;
}
}
}
}
이번 강좌에서는 마지막 강좌 세이브 & 로드를 구현하겠다
플레이어의 위치, 플레이어의 방향, 아이템 인벤토리 내역을 저장하고 로드한다
일단 Title 스크립트부터 열어주자
10번은 Title씬을 인스턴스화 해준다
12번은 세이브엔로드 스크립트를 장착해준다
14번 줄의 void Awake함수는 타이틀 씬이 다른 씬으로 이동해도 파괴되는 것을 방지해준다
이유는 씬을 이동하면서 세이브 파일 데이터를 로드하기 전까지는 필요하기 때문이다
ClickStart()함수를 보면
30번줄에 타이틀 씬을 비활성화해주는 것을 달아놨다
이게 있어야 다른 씬으로 넘어가고 타이틀 씬을 비 활성화해 줄 수 있다
ClickLoad는 코루틴으로 된 Load를 불러와준다
LoadCoroutine()함수이다
42번 줄은 스테이지 씬을 로드해주는 것이다
44번의 while문은 위의 스테이지 로드가 끝날때까지 대기해주는 것이다 실제 구현되면 노란색으로 스크린이 됬다가 넘어간다
나머지 내용은 주석을 참고하자
이제 StopMenu 스크립트를 열어주자
6번줄에 추가한 내용이 있다
세이브엔로드를 장착해준다
한눈에 알아보기 쉽게 작성했다 참고해주자
이제 Inventory 스크립트를 열어주자
15번 줄에 Slot[] GetSlots()로 린턴해주어서 외부로 아이템 정보를 보내준다
19번줄이 실제 아이템을 저장하는데 정보를 저장해주는 함수이다 주석으로 설명해놓았다
이제 SaveData 스크립트를 작성해주자
2번 줄을 보면 System.IO 를 작성하여 세이브파일을 생성할 수 있게 using를 가져왔다
이제 커스텀 변수를 보자
커스텀 클레스 이므로 5번줄의 내용을 작성해줬다
8번과 9번은 각 캐릭터의 위치와 방향이다 Json은 이 두가지를 한꺼번에 저장하지 못하므로 따로 기록한다
11~13번은 아이템 저장 데이터다
이제 SaveAndLoad 스크립트의 기본 변수를 보자
17번은 새로운 세이브 파일을 작성하게 해준ㄷ나
나머지는 주석 그대로의 내용이다
void Stat()함수의 내용이다
주석을 참고해주자
SaveData() 함수의 내용이다
36번과 37번은 플레이어 컨트롤과 인벤토리 스크립트를 장착해준 것이다
39와 40번은 플레이어의 위치와 방향을 저장해준다
42번은 아이템의 슬롯 데이터를 받아와서...
for문을 아이템 개수만큼 돌려주면서
if문으로 아이템 슬롯이 비어있지 않다면
48~50번이 각 인벤토리 슬롯 위치, 아이템 이름, 아이템 개수이다
54번줄은 Json파일을 생성하여 준다
그리고 그 파일을 물리적으로 저장해서 윈도우의 디렉토리에 파일로 남긴다
58번과 59번은 콘솔로 저장완료를 출력한 후 Json 파일의 내용을 콘솔로 출력한다
LoadData() 함수이다
if문으로 조건을 걸고 파일 디렉토리에 세이브 파일이 있을대 실행하게 한 다음
66번줄에 string문으로 Json파일을 읽어온다
67번줄에 Json파일을 풀어주는 작업을 하고
69와 70번줄은 플레이어 컨트롤과 인벤토리 스크립트를 로드해준 것이다
72와73번줄은 플레이어의 위치와 방향을 저장해준 것이다
75번은 아이템을 불러오는데
인벤토리 슬롯 넘버, 인벤토리 아이템 이름, 인벤토리 아이템 개수를 불러와준다
그뒤 콜솔에 로드 완료를 출력해준다
82번은 세이브 파일이 없으면 없다고 출력해주는 것이다
이렇게 해서 세이브 로드를 구현했다 테스트를 해보면...
구현이 끝났다 ㅜㅜ
드디어 다 공부했다!!
'FPS서바이벌 디펜스' 카테고리의 다른 글
33.타이틀 메뉴 (2) | 2025.06.06 |
---|---|
32.일시정지 메뉴 (0) | 2025.06.06 |
31.수영과 호흡 (0) | 2025.06.06 |
30.물구현과 수영 시스템 (0) | 2025.06.03 |
29.낮과 밤 구현하기 (0) | 2025.06.03 |