오늘 한 것
- 지난 시간에 배운 정의 데이터 / 가변 상태 / 파생 데이터를 시간과 주식에 적용
- 게임 시작일을
2000년 1월 1일, 한 턴을 7일로 설정 다음 주버튼으로 턴을 진행하고 날짜를 갱신- 주식의 변하지 않는 정의와 플레이 중 변하는 현재 상태를 분리
- 삼성전자, SK하이닉스, 현대자동차 3종의 주식 정의 데이터 추가
- 한 턴이 지날 때마다 각 주가가 직전 가격 기준 ±10% 범위에서 변하도록 구현
- 새 게임에서는 시간과 주가를 초기화하고, 은행에 다녀오면 현재 상태를 유지
이번 내용은 새로운 데이터 구조를 배우는 시간이 아니라, 지난 시간에 배운 게임 데이터 3분류를 실제 게임 도메인에 적용하는 응용편이다.
1. 시간도 게임 데이터다
게임의 시간은 현실처럼 저절로 흐르지 않는다. 현재 게임에서는 플레이어가
다음 주 버튼을 눌렀을 때 current_turn이 1 증가한다.
| |
시간 관련 데이터는 다음처럼 분류한다.
| 값 | 분류 | 이유 |
|---|---|---|
시작일 2000-01-01 | 정의 데이터 | 게임 제작 시 정하고 플레이 중 바뀌지 않음 |
턴당 7일 | 정의 데이터 | 시간 진행 규칙 |
current_turn | 가변 상태 | 플레이 중 계속 증가함 |
| 현재 날짜 | 파생 데이터 | 시작일과 현재 턴으로 계산 가능 |
| 화면의 주차 | 파생 데이터 | current_turn + 1로 계산 가능 |
현재 날짜를 상태로 저장하지 않는 이유
턴과 날짜를 둘 다 저장하면 한쪽만 갱신되어 서로 어긋날 수 있다.
| |
따라서 실제로 저장하는 시간 상태는 current_turn 하나뿐이다.
| |
GameState.current_date()는 Godot의 Time 싱글톤을 이용해 이 계산 결과를 달력
형식의 Dictionary로 돌려준다.
턴은 현재 단계에서 새로운 구조가 아니다
현재 구현에서 턴은 여러 가변 상태 중 게임 시간의 기준으로 선택한 값이다.
| |
구조적으로 둘 다 가변 상태를 변경하는 코드다. 나중에 시간, 주가, 회사 실적, 뉴스, 생활비 등 여러 시스템의 갱신 순서를 한곳에서 관리하게 되면 턴 루프나 업데이트 파이프라인이라는 새로운 구조로 발전할 수 있다. 현재는 그 단계가 아니다.
2. 초기 주가와 현재 주가
처음에는 기준 가격이라는 표현을 사용했지만 의미가 모호했다. 전일 종가나 적정
가격도 기준 가격이라고 부를 수 있고, 이 값들은 플레이 중 변할 수 있다.
이번에 필요한 값은 새 게임의 현재 주가를 만드는 원본이므로 initial_price,
즉 초기 주가라고 이름 붙였다.
| |
| 회사명 | 초기 주가 |
|---|---|
| 삼성전자 | 10,000원 |
| SK하이닉스 | 5,000원 |
| 현대자동차 | 20,000원 |
이 가격은 데이터 구조 학습을 위한 임의의 게임 값이며 실제 주가를 나타내지 않는다.
3. StockDef — 변하지 않는 정의
StockDef는 주식 한 종의 정의 데이터 스키마다.
| |
실제 값은 .tres 파일 3개에 저장한다.
| |
MachineDef와 같은 데이터 주도 구조다. 회사 종류를 늘릴 때 주가 계산 코드를
복사하지 않고 StockDef 데이터만 추가할 수 있다.
4. StockState — 현재 플레이의 가변 상태
.tres의 initial_price를 턴마다 직접 수정하면 정의 데이터와 현재 상태가 섞인다.
그래서 현재 주가는 별도의 StockState 객체가 가진다.
| |
두 객체의 관계는 다음과 같다.
| |
StockDef: 파일로 저장하고 여러 곳이 공유하는 불변 원본이므로ResourceStockState: 현재 플레이에서만 사용하는 가벼운 객체이므로RefCounted
백엔드로 비유하면 StockDef는 종목 마스터이고 StockState는 현재 게임 세이브에
들어갈 종목별 레코드다. 회사명을 StockState에 다시 복사하지 않고 정의 객체를
참조하므로, 회사명의 원본은 한 곳에만 존재한다.
새 게임에서는 정의 데이터로 현재 상태를 생성한다.
| |
5. 턴마다 현재 주가 변경
GameState.advance_turn()은 현재 턴을 증가시킨 뒤 세 주식의 현재 가격을 갱신한다.
| |
현재 가격은 -10%부터 +10% 사이의 임의 비율로 변한다.
| |
중요한 점은 초기 주가가 아니라 직전 현재 주가를 기준으로 계산한다는 것이다.
| |
초기 주가를 기준으로 매번 계산하면 이전 턴의 변화가 다음 턴으로 이어지지 않는다. 계산 결과는 정수로 반올림하고 주가가 1원보다 작아지지 않도록 제한한다.
6. 상태의 수명
current_turn과 stock_states는 Autoload인 GameState에 있다. 따라서 Game 씬에서
은행 씬으로 이동해도 객체가 사라지지 않는다.
| |
반면 타이틀에서 새 게임을 시작하면 다음 순서로 초기화한다.
| |
같은 데이터라도 어느 노드가 소유하는지에 따라 수명이 결정된다는 지난 시간의 내용을 다시 적용한 것이다.
7. 데이터 분류 전수 조사
정의 데이터
| 값 | 위치 |
|---|---|
| 게임 시작일 | GameState.START_DATE |
| 한 턴의 일수 | GameState.DAYS_PER_TURN |
| 회사명 | StockDef.company_name과 각 .tres |
| 초기 주가 | StockDef.initial_price와 각 .tres |
| 주가 변화 범위 ±10% | _update_stock_prices()의 게임 규칙 |
가변 상태
| 값 | 위치 | 새 게임 | 은행 왕복 |
|---|---|---|---|
| 현재 턴 | GameState.current_turn | 0으로 초기화 | 유지 |
| 주식별 현재 주가 | GameState.stock_states | 초기 주가로 초기화 | 유지 |
파생 데이터
| 값 | 무엇으로부터 계산하는가 |
|---|---|
| 현재 날짜 | 시작일, 현재 턴, 턴당 일수 |
| 화면 주차 | current_turn + 1 |
| 시간 라벨 | 현재 날짜와 화면 주차 |
| 주가 라벨 | 회사명, 현재 주가, 초기 주가 |
현재 구현에는 등락액과 등락률이 없지만 필요할 때 저장하지 않고 계산할 수 있다.
| |
단, 지난주 대비 등락률은 현재 주가와 초기 주가만으로 계산할 수 없다. 과거 가격을 보관해야 하므로 가격 이력을 추가한 뒤 파생 데이터로 계산해야 한다.
8. 구현 파일
| |
9. 실습
- 버튼을 눌러 시간이 변하는 모습
- 시간이 지남에 따라 주가가 랜덤하게 변하는 모습
다음에 이어서 볼 것 (아이디어)
- 주가 이력을 저장하고 현재 주가와 지난주 주가의 차이 이해하기
- 가격 이력에서 등락액과 등락률을 파생 데이터로 계산하기
- 보유 수량과 평균 매입가를 추가해 매수·매도 상태 설계하기
- 턴에 반응하는 시스템이 많아질 때 갱신 순서를 관리하는 턴 루프 공부하기

