세이브&로드 기능을 만들었습니다.
구글과 AI를 통해 세이브&로드 기능 구현법을 배웠습니다.
//Appdata.cs
using System;
[System.Serializable]
public class AppData
{
public string appName;
public int grade;
public long maintenanceCost;
public Date releaseDate;
public double[] stateRate;
// JsonUtility를 위한 기본 생성자
public AppData() { }
// App 객체를 AppData로 변환하기 위한 생성자
public AppData(App app)
{
this.appName = app.GetAppName();
this.grade = app.GetAppGrade();
this.maintenanceCost = app.GetMaintenanceCost();
this.releaseDate = app.GetReleaseDate();
double[] originalStateRate = app.GetStateRate();
this.stateRate = new double[originalStateRate.Length];
Array.Copy(originalStateRate, this.stateRate, originalStateRate.Length);
}
}
//EmployeeData.cs
[System.Serializable]
public class EmployeeData
{
public string name;
public int curHp;
public int maxHp;
public long wages;
public int level;
public int exp;
public int rank;
public int job;
public int stat;
public Date hireDate;
public bool isWorking;
// JsonUtility를 위한 기본 생성자 (필수)
public EmployeeData() { }
// Employee 객체를 EmployeeData로 변환하기 위한 생성자 (매우 유용)
public EmployeeData(Employee employee)
{
// 부모 Person의 데이터 가져오기
this.name = employee.GetName();
this.curHp = 100;
this.maxHp = employee.GetMaxHp();
// Employee의 데이터 가져오기
this.wages = employee.GetWage();
this.level = employee.GetLevel();
this.exp = employee.GetExp();
this.rank = employee.GetRank();
this.job = employee.GetJob();
this.stat = employee.GetStat();
this.hireDate = employee.GetHireDate();
this.isWorking = employee.GetIsWorking();
}
}
//SaveData.cs
using UnityEngine;
using System.Collections.Generic;
using System;
[System.Serializable]
public class SaveData
{
public long won;
public long dollar;
public long gold;
public long wonPerMonth;
public long dollarPerMonth;
public float time;
public List<string> stateKeys;
public List<int> stateValues;
public List<EmployeeData> employees;
public List<Stock> stocks;
public ValueManager employeeValue;
public ValueManager teamValue;
public ValueManager appValue;
public Date date;
public Gacha gacha;
public List<TeamData> teams;
public long wonPerClick;
public int hpLevel;
public int clickLevel;
public int reducedHpPerClick;
public int recoverHpPerSecond;
public String nickName;
public int maxHp;
public int curHp;
public SaveData(long won, long dollar, long gold, long wonPerMonth, long dollarPerMonth,
float time, List<string> stateKeys, List<int> stateValues, List<EmployeeData> employees,
List<Stock> stocks, ValueManager employeeValue, ValueManager teamValue,
ValueManager appValue, Date date, Gacha gacha, List<TeamData> teams,
long wonPerClick, int hpLevel, int clickLevel,
int reducedHpPerClick, int recoverHpPerSecond, String nickName, int maxHp, int curHp)
{
this.won = won;
this.dollar = dollar;
this.gold = gold;
this.wonPerMonth = wonPerMonth;
this.dollarPerMonth = dollarPerMonth;
this.time = time;
this.stateKeys = stateKeys;
this.stateValues = stateValues;
this.employees = employees;
this.stocks = stocks;
this.employeeValue = employeeValue;
this.teamValue = teamValue;
this.appValue = appValue;
this.date = date;
this.gacha = gacha;
this.teams = teams;
this.wonPerClick = wonPerClick;
this.hpLevel = hpLevel;
this.clickLevel = clickLevel;
this.reducedHpPerClick = reducedHpPerClick;
this.recoverHpPerSecond = recoverHpPerSecond;
this.nickName = nickName;
this.maxHp = maxHp;
this.curHp = curHp;
}
}
//SaveSystem.cs
using UnityEngine;
using System.IO;
public static class SaveSystem
{
private static string SavePath => Application.persistentDataPath + "/saves/";
public static void Save(SaveData saveData, string saveFileName)
{
if (!Directory.Exists(SavePath))
{
Directory.CreateDirectory(SavePath);
}
string saveJson = JsonUtility.ToJson(saveData);
string saveFilePath = SavePath + saveFileName + ".json";
File.WriteAllText(saveFilePath, saveJson);
Debug.Log("Save Success: " + saveFilePath);
}
public static SaveData Load(string saveFileName)
{
string saveFilePath = SavePath + saveFileName + ".json";
if (!File.Exists(saveFilePath))
{
Debug.Log("No such saveFile exists");
return null;
}
string saveFile = File.ReadAllText(saveFilePath);
SaveData saveData = JsonUtility.FromJson<SaveData>(saveFile);
return saveData;
}
}
// TeamData.cs
using System.Collections.Generic;
[System.Serializable] // JSON 저장을 위한 필수 태그
public class TeamData
{
public string teamName;
public List<AppData> managedApps; // App도 AppData로 변환해서 저장
public List<EmployeeData> teamMembers; // Employee도 EmployeeData로 변환해서 저장
public bool isProjectWorking; // 진행 중이던 프로젝트 상태
// JsonUtility를 위한 기본 생성자
public TeamData() { }
// Team 객체를 TeamData로 변환하기 위한 생성자
public TeamData(Team team)
{
this.teamName = team.GetTeamName();
this.isProjectWorking = team.GetIsProjectWorking();
// List<App> -> List<AppData> 변환
this.managedApps = new List<AppData>();
foreach (App app in team.GetManagedApps())
{
this.managedApps.Add(new AppData(app));
}
// List<Employee> -> List<EmployeeData> 변환
this.teamMembers = new List<EmployeeData>();
foreach (Employee member in team.GetTeamMembers())
{
this.teamMembers.Add(new EmployeeData(member));
}
}
}
app, employee, team의 기존 클래스는 MonoBehaviour를 상속받아서 바로 json파일로 저장할 수 없기 때문에, 이 클래스들의 정보를 보관하는 별도의 클래스를 만들어서 보관해야합니다. Stock, News등의 클래스는 MonoBehaviour를 상속받지 않기 때문에 [System.Serializable] // JSON 저장을 위한 필수 태그 만 추가해주면 됩니다.
//GameManager.cs
.
.
.
void Awake()
{
won = 10000000;
dollar = 0;
gold = 0;
wonPerMonth = 0;
dollarPerMonth = 0;
employeeValue = new ValueManager();
teamValue = new ValueManager();
appValue = new ValueManager();
// player = new Player();
date = new Date();
state = new Dictionary<string, int>();
MakeDictionary();
employees = new List<Employee>();
stocks = new List<Stock>();
AddStock();
teams = new List<Team>();
// gacha = new Gacha();
SaveData loadData = SaveSystem.Load("save_001");
if (loadData != null)
{
won = loadData.won;
dollar = loadData.dollar;
gold = loadData.gold;
wonPerMonth = loadData.wonPerMonth;
dollarPerMonth = loadData.dollarPerMonth;
time = 0;
//state 리스트버전 -> state 딕셔너리 버전
state = new Dictionary<string, int>();
for (int i = 0; i < loadData.stateKeys.Count; i++)
{
state.Add(loadData.stateKeys[i], loadData.stateValues[i]);
}
//EmployeeData -> Employee
foreach (EmployeeData empData in loadData.employees)
{
employees.Add(new Employee(empData));
}
stocks = loadData.stocks;
employeeValue = loadData.employeeValue;
teamValue = loadData.teamValue;
appValue = loadData.appValue;
date = loadData.date;
// gacha = loadData.gacha;
// TeamData -> Team
foreach (TeamData teamData in loadData.teams)
{
// 1. Team 프리팹을 씬에 생성
// 1. "Temp Team"이라는 이름으로 빈 게임 오브젝트를 씬에 생성합니다.
GameObject teamGameObject = new GameObject("Temp Team");
// 2. 생성된 빈 게임 오브젝트에 Team 스크립트(컴포넌트)를 부착합니다.
Team newTeam = teamGameObject.AddComponent<Team>();
// 이제 'newTeam' 변수를 프리팹으로 만든 것처럼 사용할 수 있습니다.
// 2. 이 팀에 속했던 직원들을 전체 직원 리스트(liveEmployeeList)에서 찾아 다시 묶어줌
List<Employee> membersForThisTeam = new List<Employee>();
foreach (EmployeeData memberData in teamData.teamMembers)
{
// 이름이나 고유 ID로 전체 직원 리스트에서 해당 직원을 찾아 추가
Employee foundMember = employees.Find(e => e.GetName() == memberData.name);
if (foundMember != null)
{
membersForThisTeam.Add(foundMember);
}
}
// 3. (동일한 방식으로) 이 팀이 관리하던 앱들을 다시 묶어줌
List<App> appsForThisTeam = new List<App>();
// ... App 찾는 로직 ...
// 4. 생성된 Team 객체에 데이터를 주입하고 초기화
newTeam.InitializeFromData(teamData, membersForThisTeam, appsForThisTeam,this);
//app관련은 임시
// 5. 관리 리스트에 추가
teams.Add(newTeam);
}
Debug.Log("gameManager Loaded.");
}
}
void Update()
{
.
.
.
if (Input.GetKeyDown("s"))
{
//Employee -> EmployeeData
List<EmployeeData> employeeDataList = new List<EmployeeData>();
foreach (Employee emp in employees)
{
employeeDataList.Add(new EmployeeData(emp));
}
// Team -> TeamData
List<TeamData> teamDataList = new List<TeamData>();
foreach (Team team in teams)
{
teamDataList.Add(new TeamData(team));
}
SaveData saveFile = new SaveData(won,dollar,gold,wonPerMonth,dollarPerMonth,time,new List<string>(state.Keys), new List<int>(state.Values) ,employeeDataList,stocks, employeeValue,teamValue,appValue,date,gacha,teamDataList,player.GetWonPerClick(), player.GetHpLevel(),player.GetClickLevel(),player.GetreducedHpPerClick(),player.GetRecoverHpPersecond(),player.GetName(),player.GetMaxHp(),player.GetCurHp());
SaveSystem.Save(saveFile, "save_001");
}
}
게임이 실행되면 게임매니저의 awake()에서 세이브파일이 있는지 없는지 확인해서, 없다면 여러가지 클래스, 데이터들을 단순 초기화, 있다면 세이브 json파일에서 불러오는 과정입니다. 이때 AppData같은 클래스들을App으로 변경하는 과정을 거칩니다.
저장은 단순히 게임 실행중에 키보드 S키가 눌리면 App같은 클래스를 AppData로 수정하고, 다른 여러가지 데이터들과 함께 json파일로 저장하는 방식입니다.
이번 주차 활동으로 개발 과정에서 구글 검색 능력이 중요한 이유를 깨달았습니다.