OOP_Console_Project #003

SeonggyuMin·2025년 4월 9일

1. 목표

백로그

1. 자원 시스템 구현
2. 기초 UI 구현
3. 우주선 내부 맵 구현
4. 내부 이동(WASD)
5. Add-on 시스템 기본 구현
6. 조타실 이동 및 성간지도 구현
7. 갈래형 맵 생성 (DFS 기반)
8. Encounter 시스템 설계
9. Encounter 관리 클래스 구현
10. 장비 파견 시스템 구현
11. 게임오버/승리 조건 구현
12. 게임 루프 설계 및 흐름 통합
13. 랜덤 인카운터 배치
14. Add-on 효과 적용
15. 텍스트 로그 개선
16. 유틸 클래스 구현
17. 은하계 정보 씬 구현
18. 씬 스택 구조 기반 뒤로 가기 구현
19. 성간 지도에서 현재 위치 표현
20. 뒤로가기 시 현재 위치 저장 및 불러오기

기본
1, 2, 3, 4, 5, 6, 11, 12, 15

응용
8, 9, 10, 13, 16, 17, 18, 19, 20

도전
7, 14

어제 구현한 내용: 1, 2, 3, 4, 6, 16, 17, 18
오늘 구현한 내용: 8(일부만), 10, 11, 12, 15
구현하지 못한 내용: 5, 7, 9, 13, 14, 19, 20

2. 구현 내용

8. Encounter 시스템 설계

외계 문명과의 조우 시 퀴즈를 통해 자원을 보상으로 얻는 시스템

  • nodeInfo를 매개변수로 받고 if문을 통해 현재 Id를 판별 후 각각의 질문을 나누어서 출력
    • 답을 맞출 시 LocationType 값이 FuelEncounter 또는 OxygenEncounter일 경우, 각각 연료 또는 산소 5 충전

10. 장비 파견 시스템 구현

움직일 수 있는 드론을 통해 자원을 수집하는 시스템

  • CollectMap에서 2차원 bool, char 배열을 구현하여 맵을 구성
  • CollectMapDrone에서 Player와 같은 구조의 플레이어블 드론 구현

11. 게임오버/승리 조건 구현

산소 및 연료가 0 이하일 때 게임오버 시키는 시스템

  • ResourceManager 클래스에서 Consume 메서드에서 연료와 산소를 감산할 때 if문을 통해 0이하인지 검산
  • 조건식이 만족하면 GameManagerGameOverReason메서드를 호출하여 게임루프 종료

12. 게임 루프 설계 및 흐름 통합

게임 루프 내에서 씬 전환을 위해 스택 구조 혹은 전환 구조의 메서드 구현

  • 오버로딩된 ChangeScene을 통해 매개변수에 따라 결과값이 달라져야 하는 씬과 항상 똑같은 씬을 구분
  • Dictionary<Tkey, Tvalue> 자료구조를 통해 해당 씬 클래스를 string으로 관리
  • PushScene, PopScene 메서드를 통해 씬의 스택 구조 구현

15. 텍스트 로그 개선

텍스트의 표기 방법 다양화

  • Util 정적 클래스를 통해 DelayedText, 오버로딩된 PrintText 메서드 등을 추가하여 사용

3. 문제 및 해결

1. 매번 새로운 씬에서 Ship, Player에 대한 인스턴스를 생성해야 되는 문제

게임의 많은 씬에서 Player, Ship에 대한 정보를 사용하기 때문에 각 씬마다 새로 생성 및 전달하는 방식이 비효율적이었다.
따라서 Game 클래스에서 정적 필드를 선언하여 단일 인스턴스를 유지하면서도 전체적인 접근이 가능하게 변경 이후 Start 메서드에서 한 번만 초기화 하여 사용하였다.

public static Player player { get; set; }
public static Ship ship { get; set; }

// ...

public static void Start()
{
	ship = new Ship();
	player = new Player(3, 3);

2. 은하 정보를 참조하는 과정에서 불필요한 참조 및 복사 발생

기존의 방식은 GalaxyMap 클래스에서 배열 맵 데이터 뿐만 아니라 GalaxyNodeInfo의 인스턴스를 생성해두어 관리하고 있었다. 그러나 TravelState 클래스에서는 인접 리스트 그래프를 가지고 있어 은하계에 대한 정보가 분산되어 바뀔 때마다 참조 및 복사가 이루어져야 했다. 따라서 한 클래스에 정보를 모두 넣어 불필요한 동작을 줄였다.

static TravelState()
{
	CurrentNodeId = 0;
	
	ConnectedNodes = new List<int>[12];
	
	ConnectedNodes[0] = new List<int> { 1, 2 };
	ConnectedNodes[1] = new List<int> { 3, 4 };
	// ...

public GalaxyMap()
{
	GalaxyNodes = new Dictionary<int, GalaxyNodeInfo>
{
    { 0, new GalaxyNodeInfo(0, "Start", "시작 지점", "무사히 살아남아 지구로 귀환하세요.", true) },
    { 1, new GalaxyNodeInfo(1, "Fuel", "연료 충전 지점", "이 은하는 연료가 풍부해보입니다. 근처에 들러 연료를 충전할 수 있을 것 같습니다.", false) },
    { 2, new GalaxyNodeInfo(2, "FuelEncounter", "외계 문명 조우 지점", "이 은하에는 발전된 문명이 살고 있습니다. 근처에 들러 대화를 나눠볼 수 있을 것 같습니다.", false) },
	// ...

리팩토링 전 내용

4 해결 및 구현하지 못한 내용

1. 미구현된 내용

    1. Add-on 시스템 기본 구현
    1. 갈래형 맵 생성 (DFS 기반)
    1. Encounter 관리 클래스 구현
    1. 랜덤 인카운터 배치
    1. Add-on 효과 적용
    1. 성간 지도에서 현재 위치 표현
    1. 성간 지도에서 뒤로가기 시 현재 위치 저장 및 불러오기

2. 해결하지 못한 내용

  • GalaxyNodesDictionary<Tkey, Tvalue>의 자료구조, ConnectedNodesList<T>의 자료구조이기에 1대1 대응이 같은 클래스 내에서도 쉽게 이루어지지 않아 참조 및 복사를 위해서는 새로운 자료구조 GalaxyNodePositionMap = new Dictionary<(int, int), int>를 통해 별개로 매칭시켜야 했다. 그러나 설계 초기에 자료구조 통일 혹은 좌표 정보를 포함시키는 등의 설계를 하였다면 훨씬 좋았을 것 같다.

0개의 댓글