✅ 오늘의 학습 목표
1. 데이터 파싱 (2)
2. API 활용
1. Parser
1. Json
자바스크립트 객체 표기법
서버에서 데이터를 받아올 때나, 저장 데이터를 관리할 때 자주 사용한다.
Json을 사용하는 이유
- 데이터를 key : value 형식으로 깔끔하게 저장
- XML처럼 태그를 열고 닫는 거 없이 중괄호 {}와 대괄호[]로 구조 표현 가능
- 유니티에서는 JsonUtility라는 내장 파서를 사용하면 바로 C# 객체로 변환 가능
{
"characters":
[
{
"CharID": "C01",
"Name": "Player",
"HP": 100,
"Attack": 15
},
{
"CharID": "C02",
"Name": "Goblin",
"HP": 30,
"Attack": 5
},
{
"CharID": "C03",
"Name": "Dragon",
"HP": 500,
"Attack": 50
},
{
"CharID": "C04",
"Name": "Wizard",
"HP": 70,
"Attack": 20
}
]
}
[System.Serializable]
public class CharacterData
{
public string CharID;
public string Name;
public string HP;
public int Attack;
}
[System.Serializable]
public class CharacterListWrapper
{
public List<CharacterData> characters;
}
- JSON 구조에 맞춰 클래스 설계
- JSON 최상위에 있는 "characters" 배열을 List로 받기 위해 CharacterListWrapper로 감싸줌
- 주의: JSON 키 이름과 변수 이름(대소문자 포함)이 같아야 함
void Start()
{
var dataFile = Resources.Load<TextAsset>("JsonData");
var data = dataFile.text;
// var data2 = File.ReadAllText(Application.dataPath + "/Resources/JsonData.json");
ParsingCharacterJsonData(data);
}
- Resources.Load<TextAsset>: Assets/Resources 폴더 안의 JSON 파일을 불러옴.
- 확장자는 빼고 파일명만 입력
- 다른 방법: File.ReadAllText(Application.dataPath + "/Resources/JsonData.json")
→ 파일 시스템 직접 접근 (플랫폼 호환성 주의)
| 구분 | File.ReadAllText | Resources.Load |
| 방식 | 파일 시스템 접근 | Unity 리소스 시스템 사용 |
| 경로 | 어디든 가능 | 반드시 Resources 폴더 |
| 확장자 | 포함해야 함 | 생략 |
| 빌드 후 수정 | 가능 | 불가(Read-only) |
public List<CharacterData> characterDatas = new List<CharacterData>();
private void ParsingCharacterJsonData(string data)
{
Debug.Log(data);
CharacterListWrapper wrapper = JsonUtility.FromJson<CharacterListWrapper>(data);
foreach (CharacterData cData in wrapper.characters)
{
characterDatas.Add(cData);
Debug.Log($"{cData.CharID} / {cData.Name} / {cData.HP} / {cData.Attack}");
}
}
- JsonUtility.FromJson<T>(string json) : JSON 문자열을 T 타입 객체로 변환
- wrapper.characters 안에 캐릭터 정보들이 리스트 형태로 들어옴
2. XML
XML은 태그 기반이라 구조를 어노테이션으로 정확히 맵핑해주어야 데이터가 깔끔하게 들어간다.
대신 한 번 맞춰두면 XmlSerializer가 알아서 객체로 쭉 뽑아준다.
<?xml version="1.0" encoding="UTF-8"?>
<Characters>
<Character>
<CharID>C01</CharID>
<Name>Player</Name>
<HP>100</HP>
<Attack>15</Attack>
</Character>
<Character>
<CharID>C02</CharID>
<Name>Goblin</Name>
<HP>30</HP>
<Attack>5</Attack>
</Character>
<Character>
<CharID>C03</CharID>
<Name>Dragon</Name>
<HP>500</HP>
<Attack>50</Attack>
</Character>
<Character>
<CharID>C04</CharID>
<Name>Wizard</Name>
<HP>70</HP>
<Attack>20</Attack>
</Character>
</Characters>
[System.Serializable]
public class CharacterData
{
public string CharID;
public string Name;
public int HP;
public int Attack;
}
[System.Serializable]
[XmlRoot("Characters")]
public class CharacterList
{
[XmlElement("Character")]
public List<CharacterData> characters;
}
- [XmlRoot("Characters")] : XML 최상위 태그 지정
- [XmlElement("Character")] : <Characters> 안에 반복되는 <Character> 태그를 매핑
- List<CharacterData>로 모든 캐릭터 정보 저장
void Start()
{
var dataFile = Resources.Load<TextAsset>("XmlData");
string data = dataFile.text;
ParsingCharacterXmlData(data);
}
- Resources 폴더 안에 XmlData.xml이 있어야 함
- 확장자는 생략하고 이름만 입력
private void ParsingCharacterXmlData(string data)
{
Debug.Log(data);
XmlSerializer serializer = new XmlSerializer(typeof(CharacterList));
using (StringReader reader = new StringReader(data))
{
CharacterList loadedData = (CharacterList)serializer.Deserialize(reader);
characterDatas = loadedData.characters;
}
foreach (CharacterData cData in characterDatas)
{
Debug.Log($"{cData.CharID} / {cData.Name} / {cData.HP} / {cData.Attack}");
}
}
- XmlSerializer : XML 데이터를 C# 객체로 변환
- StringReader : 문자열(XML 텍스트)을 스트림처럼 읽도록 변환
- Deserialize : XML → C# 객체로 역직렬화
- 리스트에 담긴 캐릭터 정보들을 출력
JSON과 XML의 차이점
| 구분 | JSON | XML |
| 구조 | key-value | 태그 기반 |
| 매핑 | 필드명 동일 | [XmlRoot], [XmlElement] 필요 |
| 최상위 배열 | 바로 불가(래핑 필요) | 루트 태그 필수 |
| 유니티 파서 | JsonUtility | XmlSerializer |
3. 데이터 저장&불러오기
게임 진행 중 만들어지는 데이터를 JSON 파일로 저장하고 시작할 때 불러오는 로직을 붙여보자
using System;
using UnityEngine;
using System.IO;
[System.Serializable]
public class SaveData
{
public string CharID = "C01";
public string Name = "Player";
public int HP = 100;
public int Attack = 10;
public int score;
}
public class SaveDataFile : MonoBehaviour
{
private int score;
private string savePath;
void Start()
{
// Application.dataPath : Assets 폴더
// Application.persistentDataPath : 플랫폼별로 안전하게 추천하는 로컬 저장소 경로
savePath = Path.Combine(Application.persistentDataPath, "saveDataFile.json");
Load();
Debug.Log("Load Score : " + score);
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
score++;
Debug.Log("Score : " + score);
Save();
}
}
private void Save()
{
SaveData data = new SaveData();
data.score = this.score;
// string json = JsonUtility.ToJson(data);
string json = JsonUtility.ToJson(data, true);
File.WriteAllText(savePath, json);
Debug.Log("Data saved to : " + savePath);
}
private void Load()
{
if (File.Exists(savePath))
{
string json = File.ReadAllText(savePath);
SaveData data = JsonUtility.FromJson<SaveData>(json);
this.score = data.score;
}
else
{
score = 0;
}
}
void OnApplicationQuit()
{
Save();
}
}
데이터 구조
- SaveData 클래스에 캐릭터 기본값과 score를 포함.
- 점수는 런타임 중 계속 변하니까 SaveData 인스턴스를 만들어 현재 점수를 담아 저장
저장 경로 선택
- Application.persistentDataPath에 saveDataFile.json으로 저장
- 이 경로는 플랫폼별 안전한 로컬 저장소라서 PC/모바일/WebGL 등 빌드 환경에서 일관성 있게 동작
- Path.Combine으로 경로 조립(운영체제별 경로 구분자 이슈 자동 처리)
참고: Application.dataPath(Assets 폴더)는 에디터에서만 편하고 빌드 후엔 쓰기 제한이 걸릴 수 있다.
저장용이라면 persistentDataPath 고정이 마음 편함
실행 흐름
- Start() → Load()
- 시작할 때 저장 파일이 있으면 File.ReadAllText(savePath)로 JSON 문자열을 읽고
JsonUtility.FromJson<SaveData>(json)으로 역직렬화해서 score에 복원 - 파일이 없으면 score = 0으로 초기화
- 시작할 때 저장 파일이 있으면 File.ReadAllText(savePath)로 JSON 문자열을 읽고
- Update()에서 Space 입력 → Save()
- Space를 누를 때마다 score++ 후 즉시 저장(Save() 호출)
- Save()에서는 new SaveData()로 컨테이너 만들고 현재 점수를 세팅한 다음,
JsonUtility.ToJson(data, true)로 보기 좋은 포맷(pretty print) JSON 생성 → File.WriteAllText.
- OnApplicationQuit()에서 최종 저장
- 앱 종료 시 한 번 더 Save() 호출해 마지막 상태를 디스크에 보관
JsonUtility 포인트
- ToJson(obj, true)의 true는 prettyPrint 옵션
디버깅/사후 확인할 때 가독성이 좋아진다. (용량은 미세하게 늘 수 있음) - FromJson<T>는 필드명 기준 매핑이므로, JSON 키와 C# 필드명이 달라지면 값이 안 들어올 수 있다
필드명 바꿀 땐 JSON도 같이 업데이트하거나, 별도 매핑용 클래스를 둔다
PlayerPrefs와의 비교
| 구분 | PlayerPrefs | JSON |
| 구조 | key-value (string/float/int) | 자유로운 계층 구조(객체/리스트) |
| 사용 난이도 | 매우 쉬움 | 중간(클래스/직렬화 필요) |
| 데이터 크기 | 소/중 | 대용량도 OK |
| 가시성 | 내부 저장 (레지스트리/플랫폼별) | 파일로 저장 → 확인/전송 쉬움 |
| 보안 | 낮음 | 낮음(별도 암호화 필요) |
| 권장 용도 | 옵션/간단한 숫자 | 세이브 슬롯, 인벤토리, 진행 상황 등 |
이번 케이스처럼 점수 + 메타 정보 같이 구조화된 데이터는 JSON 쪽이 훨씬 관리가 편하다.
2. API 활용
API(Application Programming Interface)이란 다른 시스템/서버의 기능이나 데이터를 URL로 요청해서 쓰는 방법을 뜻한다.
게임 클라이언트(유니티) ↔ 서버(백엔드) 구조에서 읽기(READ: GET), 쓰기(WRITE: POST)를 주로 쓴다.
- 클라이언트 (Client) : 요청을 보내는 곳
- 서버 (Server) : 응답을 보내는 곳
- REST API : 클라이언트가 서버에 요청을 데이터로 전송 (서버가 이 클라이언트 입력을 사용하여 내부 함수를 시작하고 출력 데이터를 다시 클라이언트에 반환)
🥕 예행 작업
1. 데이터 활용 신청공공데이터 포털
국가에서 보유하고 있는 다양한 데이터를『공공데이터의 제공 및 이용 활성화에 관한 법률(제11956호)』에 따라 개방하여 국민들이 보다 쉽고 용이하게 공유•활용할 수 있도록 공공데이터(Datase
www.data.go.kr
UnityWebRequest 기본 흐름
- URL 조립 (쿼리 파라미터 붙이기)
- UnityWebRequest.Get(url) 또는 UnityWebRequest.Post(url, form)
- yield return request.SendWebRequest()로 비동기 대기
- request.result로 성공/실패 확인
- request.downloadHandler.text로 응답 문자열 꺼내기 (보통 JSON/XML)
- HTTPS 권장. 꼭 HTTP를 써야 할 상황이면Player > Other Settings > Configuration > Allow downloads over HTTP = Always allowed.
UnityWebRequest www = UnityWebRequest.Get(url);
yield return www.SendWebRequest();
if (www.result != UnityWebRequest.Result.Success) {
Debug.Log("Failed Data : " + www.error);
} else {
string data = www.downloadHandler.text;
Debug.Log(data);
}
1. 날씨 API

문서부터 읽기
- 필수 파라미터(예: serviceKey, pageNo, numOfRows, dataType, base_date, base_time, nx, ny) 확인
- 응답 스펙(각 필드 의미, 코드표: PTY/SKY 등) 확인
URL 만들기
URL += $"serviceKey={key}&numOfRows={numOfRows}&pageNo={pageNo}&dataType={dataType}" +
$"&base_date={base_date}&base_time={base_time}&nx={nx}&ny={ny}";
- 기본이 XML이면 &dataType=JSON을 붙이면 JSON으로 받을 수 있다
- 날짜가 옛날이면 “최근 3일만 제공” 같은 오류가 나므로 날짜/시간 최신화 필수
응답 받기 & 로그
- 데이터가 길면 콘솔에서 truncate로 잘려 보일 수 있음(데이터 자체는 제대로 들어옴)
JSON 파싱용 클래스 설계
[System.Serializable] public class Root { public Response response; }
[System.Serializable] public class Response { public Header header; public Body body; }
[System.Serializable] public class Header { public string resultCode; public string resultMsg; }
[System.Serializable] public class Body { public string dataType; public Items items; public string pageNo, numOfRows, totalCount; }
[System.Serializable] public class Items { public List<Item> item; }
[System.Serializable] public class Item { public string category, fcstDate, fcstTime, fcstValue, nx, ny; }
- 문서의 계층대로 C# 클래스를 만든다(루트→response→body→items→item)
JsonUtility로 역직렬화
var root = JsonUtility.FromJson<Root>(data);
foreach (var it in root.response.body.items.item) {
// PTY, SKY 등 골라 쓰기
}
실제 활용 (날씨 상태 매핑 예시)
private void SetWeatherType()
{
if (currentSKY == 1 && currentPTY == 0)
{
weatherType = WeatherType.Sun;
}
else if (currentSKY == 3 || currentSKY == 4)
{
weatherType = WeatherType.Cloud;
}
else if (currentPTY == 1 || currentPTY == 2 || currentPTY == 4)
{
weatherType = WeatherType.Rain;
}
else if (currentPTY == 3)
{
weatherType = WeatherType.Snow;
}
Debug.Log($"현재 날씨는 {weatherType}입니다.");
}
- 카테고리별 값 분기해서 enum으로 게임 상태에 반영
- PTY(강수형태), SKY(하늘상태) 코드표는 문서 참고해서 숫자→의미 매핑
- 리스트에서 필요한 카테고리만 필터링해 현재 상태를 계산
2. 구글 스프레드 시트
읽기(GET) - CSV 바로 가져오기
- 공유 권한을 링크가 있는 모든 사용자(보기)로 설정
- URL 뒤에 export?format=csv로 붙이면 바로 CSV로 내려받는다
- 특정 범위만: export?format=csv&range=A2:D5
- 시트 지정: &gid=시트ID
- CSV/TSV는 줄/쉼표/탭으로 나뉘므로, Split로 파싱해서 구조화
JSON으로 뽑기
- (간단 방법) Apps Script로 웹 앱을 만들어 JSON으로 변환해서 내보내기
- (정석) Google API 사용(인증 필요, 문턱은 더 높지만 안정적)
Apps Script로 GET/POST 받기
- 시트 열고 확장 프로그램 → Apps Script에서 스크립트 작성 후 배포(웹 앱)
- 접근 권한을 “모든 사용자”로 두면 유니티에서 호출 가능
function doGet(e) { return ContentService.createTextOutput("Get"); }
function doPost(e) {
var val = e.parameter.value; // Unity에서 보낸 값
// sheet.getRange(row, col).setValue(val);
return ContentService.createTextOutput("Post");
}
// GET
var www = UnityWebRequest.Get(url);
yield return www.SendWebRequest();
var read = www.downloadHandler.text;
// POST (신규 권장 방식)
WWWForm form = new WWWForm();
form.AddField("value", "123");
var www2 = UnityWebRequest.Post(url, form);
yield return www2.SendWebRequest();
var wrote = www2.downloadHandler.text;
- UnityWebRequest.PostWwwForm은 구방식. 요즘은 Post(url, WWWForm) 사용
- 민감정보/검증/인증은 백엔드에서 처리(클라에서 키/시크릿 하드코딩 금지)
- Apps Script는 배포(버전) 개념이라 수정 후 새 버전 배포를 눌러야 반영된다(웹 앱 URL은 유지 가능)
🚨 복습 필요
'Unity > 멋쟁이사자처럼 부트캠프' 카테고리의 다른 글
| [멋쟁이사자처럼부트캠프] 유니티 게임 개발 5기(60일차) - 농장 게임 (2) (6) | 2025.08.12 |
|---|---|
| [멋쟁이사자처럼부트캠프] 유니티 게임 개발 5기(59일차) - New Input System 활용 및 농장 게임 만들기 (1) (5) | 2025.08.11 |
| [멋쟁이사자처럼부트캠프] 유니티 게임 개발 5기(57일차) - 게임 디자인 패턴 (2), ScriptableObject, 데이터 파싱 (6) | 2025.08.07 |
| [멋쟁이사자처럼부트캠프] 유니티 게임 개발 5기(56일차) - 게임 디자인 패턴 (1) (9) | 2025.08.06 |
| [멋쟁이사자처럼부트캠프] 유니티 게임 개발 5기(55일차) - C# 중급 (3), LINQ (3) | 2025.08.05 |