게임 개발 포트폴리오 | TSEROF

내일배움캠프 1기 Unity 게임 개발 과정 트랙 수료생 최종 프로젝트 'TSEROF '을 소개합니다.
Feb 26, 2024
게임 개발 포트폴리오 | TSEROF
 
notion image
 

프로젝트 결과물 소개


  • 💭GAMEGUIDLINE
    • 시작화면에서 저장 슬롯을 만들고 플레이 해보세요!
    • 스테이지선택화면에서 탐험하고 싶은 스테이지를 골라서 스테이지들을 자유롭게 탐험해보세요. (포탈에 불이 꺼져있다면 이전 스테이지를 먼저 클리어해주세요)
    • 방향키와 점프를 활용하여 각각의 Stage들을 탐험하고 숨겨진 퍼즐 아이템을 획득해 보세요.
  • 📽️INGAME
    • notion image
      StartScene
      notion image
      Stage1
      notion image
      notion image
      StageSelect
      notion image
      Stage2
       
      Stage3
  • 📜STORY 어느 날 잠에서 깨어난 소녀 샬롯. 무언가 소중한 걸 잊고 있다는 느낌에 그 무언가를 찾아 여행을 떠나기로 결심하게 됩니다. 샬롯과 함께 여행을 하며 샬롯의 잊어버린 추억의 조각들을 찾아보세요!

기술적인 도전 과제

🗣️
담당자: 김어진

싱글톤과 interface를 사용하여 코드 개선

⚠️문제 사항
  • interface 형태인 C# IDataPersistence는 GameData의 정보를 받아줌.
    • 저장과 로드를 담당하는 SaveGame(), LoadGame()
    • 저장하고 로드할 변수들을 받아주는 SaveData(), LoadData()
    • 저장할 변수들을 설정하는 GameData()
    • → 각 함수 간의 기능의 분리가 모호함
      → 저장할 변수가 여러 개의 경우 변수와 관련된 함수들의 구분이 어려움
 
🆕개선 방식
  • C# GameData에 저장할 변수들을 설정
  • interface 형태인 C# IDataPersistence는 GameData의 정보를 받아줌.
    • SaveData(GameData data), LoadData(GameData data)
    • 저장할 변수와 관련된 Script들은 IDataPersistence 상속
  • DataPersistenceManager은 싱글톤패턴을 활용하여 구현
 
💫개선 결과
  • 자주 사용하는 함수를 통일함으로써 코드 관리가 용이해짐.

SerializableDictionary와 GenerateGuid()를 사용하여 변수 관리

⚠️문제 사항
  • interface 형태인 C# IDataPersistence는 GameData의 정보를 받아줌.
    • 저장과 로드를 담당하는 SaveGame(), LoadGame()
    • 저장하고 로드할 변수들을 받아주는 SaveData(), LoadData()
    • 저장할 변수들을 설정하는 GameData()
    • → 각 함수 간의 기능의 분리가 모호함
      → 저장할 변수가 여러 개의 경우 변수와 관련된 함수들의 구분이 어려움
 
🆕개선 방식
  • 배열이 아닌 SerializableDictionary <string, bool> 타입 사용
    • Inspector에서 보여주기 위해 SerializableDictionary 사용
  • 리스트의 Key값인 string은 GenerateGuid()를 사용해 id를 생성하여 구별
 
💫개선결과
  • Dictonary와 GenerateGuid()를 통해 id를 생성함으로써 코드의 복잡도 감소

XOR 암호화와 백업시스템을 활용한 JSon 기능 보완 및 확장

⚠️문제 사항
→ 유저들이 로컬 파일 내에서 데이터를 변형 및 삭제할 가능성 존재
 
🆕개선 방식
  • 다양한 암호화 방식 중 계산이 가장 빠른 XOR 암호화를 통해 암호화
  • File.Copy를 통해 백업 파일을 생성
    • C# FileDataHandler에 Main 파일이 만들어지면 백업 파일 자동 생성
    • 데이터 로드시 Main 파일과 백업 파일 비교하여 삭제된 데이터 복구
 
💫개선결과
  • 암호화를 통해 데이터의 변형 가능성 낮춤
  • 백업시스템을 통해 데이터 삭제시 복원 가능

최적화를 위한 효율적인 Collider 설정

⚠️문제 사항
→ 맵의 모든 개별 오브젝트 하나하나에 Collider를 설정함으로써 충돌 함수에 많은 연산 발생
 
🆕개선 방식
  • 가능한 분류할 수 있는 지형을 기준으로 Collider 전용 오브젝트를 생성하고 광범위한 Collider 설정
  • Collider의 밑(지하) 혹은 닿지 않는 부분은 Collider에서 제외
💫개선결과
  • 불필요한 연산량을 줄임으로써 최적화
🗣️
담당자: 김형중

캐릭터의 자유로운 이동과 스테이지 선택 : Waypoint 알고리즘

아이디어
  • 캐릭터가 정해진 경로 위에서 이동해야 함.
  • 스테이지 입구에 도달할 때마다 캐릭터가 멈출 수 있어야 함.
    • → Waypoint 알고리즘을 사용하여 구현.
⚠️ 문제 사항
  • 스테이지 선택씬이 열릴 때마다 캐릭터가 스폰되는 장소가 동일함.
    • 스테이지를 완료할 때마다 해당 스테이지 입구 앞에서 스폰되어야함.
    • → 게임의 흐름이 자연스럽지 않고 미완성적인 느낌을 줌.
 
🆕 개선 방식
  • Waypoint의 index값을 활용해 스폰되는 포인트를 지정 :
    • 스테이지 선택씬에 진입할 때 마다 현재 스테이지에 맞는 Waypoint의 index값을 지정해주어 해당 지점에서 스폰될 수 있도록 조정.
 
💫 개선 결과
  • 캐릭터가 정해진 경로 위에서 자유롭게 이동할 수 있음.
  • 스테이지 입구에 도착하면 OnCollisionEnter() 함수를 통해 움직임을 멈추어 스테이지에 도달할수 있음.
  • 스테이지가 끝나고 다시 스테이지 선택씬에 진입했을 때, 해당 스테이지의 입구에서 제대로 스폰됨.
🗣️
담당자: 박지원

상속과 오버라이딩으로 가독성과 효율성 향상 : Top View 고려한 Player 클래스의 개선

⚠️ 문제 사항
  • Top view 고려하여 기존의 방식과 다른 플레이어의 이동 방향 조정 필요.
  • Player 클래스에 오버로딩이나 조건문으로 문제 해결 시도.
    • Top view 여부 지속적 확인 필요.
    • → 단일 클래스에서 다양한 view에 따른 기능 추가로 가독성, 효율성 저하 우려.
 
🆕 개선 방식
  • TopViewPlayer 클래스 도입:
    • Player 클래스 상속, 메서드 오버라이딩으로 Top view에서만 다르게 동작하도록 조정.
 
💫 개선 결과
  • 코드 구조 명확화.
  • 가독성 및 효율성 향상.

모듈화를 통한 가독성 향상 : 이벤트 기반 코드 개선과 효율적인 오브젝트 처리

⚠️ 문제 사항
  • 특정 입력 이벤트가 발생할 때마다 직접 코드 호출.
  • 상호작용 가능한 오브젝트의 가까움 여부 조건문으로 확인.
    • → 코드의 모듈화 및 가독성 저하, 주기적인 조건 확인 필요.
 
🆕 개선 방식
  1. 이벤트 함수 도입:
      • 입력 부분에 이벤트 함수 적용
      • 입력 이벤트 발생 시 콜백 함수 실행으로 코드 모듈화.
  1. 상호작용 가능한 오브젝트 처리:
      • 가까운 오브젝트 상호작용을 조건문이 아닌 충돌 검사로 변경.
      • 오브젝트와 충돌 시에만 이벤트 함수에 연결.
 
💫 개선 결과
  • 코드 모듈화 및 가독성 향상.
  • 상호작용 가능한 오브젝트의 효율적인 처리.

충돌 최소화를 통한 효율적인 Raycast 활용 : 충돌 Layer 및 RaycastNonAlloc의 적용

⚠️ 문제 사항
  • RaycastAll을 사용하여 Laser의 방향에 있는 모든 물체 충돌 확인.
    • → 과도한 충돌 발생으로 인한 성능 저하 발생.
 
🆕 개선 방식
  1. 충돌 Layer 셋팅:
      • 충돌 체크 대상을 Layer로 설정하여 불필요한 오브젝트와의 충돌 체크 효율화.
  1. RaycastNonAlloc 사용:
      • RaycastAll 대신 RaycastNonAlloc을 사용하여 내부에서 생성되는 불필요한 메모리 할당 방지.
  1. 한 번에 하나의 Receiver만 충돌하도록 조정:
      • Laser의 각도를 조절하여 한 번에 하나의 Receiver만 충돌하도록 조정.
  1. 정답 후에는 Raycast 사용 중단:
      • 정답을 맞춘 이후에는 Raycast를 더 이상 사용하지 않도록 설정.
 
💫 개선 결과
  • 충돌 최소화 및 성능 향상.
  • 불필요한 Raycast 호출로 인한 오버헤드 감소.
  • RaycastNonAlloc 및 충돌 Layer 설정으로 메모리 할당 최소화 및 효율적인 충돌 체크.
🗣️
담당자: 정재훈

캐싱과 오브젝트 풀링으로 메모리 최적화 : CPU 부담 감소와 가독성 향상

⚠️ 문제 사항
  • 고드름 오브젝트가 떨어지면 즉시 파괴하고 정해진 위치에 다시 생성하는 방식으로 작성.
    • → 해당 방식은 스테이지가 끝날 때까지 파괴하고 다시 생성하므로 가비지가 지속적으로 생성되어 CPU 부담이 큼.
 
🆕 개선 방식
  • 캐싱과 오브젝트 풀링을 활용한 효율적인 구현:
    • 하나의 오브젝트로 작성하고 오브젝트 풀링과 코루틴을 이용하여 고드름이 바닥에 떨어질 때, 일정 시간이 지난 후 정해진 위치로 돌아오도록 구현.
    • 코루틴에서 사용되는 WaitForSeconds 객체를 미리 변수에 담아두고 사용하여 메모리 사용량을 최소화하고 코드의 효율성을 높임.
 
💫 개선 결과
  • 메모리와 성능의 효율을 높임.
  • 가비지 생성을 최소화하여 CPU 부담을 감소시킴.
  • 코드의 가독성과 유지보수성을 향상시킴.

스크립트 기반 초기화 도입으로 안정성 강화 : 값 빠짐 및 초기화 오류 문제 해결

⚠️ 문제 사항
  • 인스펙터 창에서 초기화.
    • → 중간에 값이 빠지거나 잘못 넣어지는 문제 발생.
 
🆕 개선 방식
  • 스크립트를 이용한 초기화 도입:
    • 자식 오브젝트를 받는 경우, 부모 오브젝트의 코드에서 GetChild()를 통해 안정적으로 초기화.
 
💫 개선 결과
  • 값 빠짐 및 잘못된 초기화 문제 안정적으로 해결.

코드의 명확성 강조 : 퍼즐 관리를 위한 단일 스크립트와 Static 변수의 도입

⚠️문제 사항
  • 각자의 클래스에 변수를 선언하여 퍼즐을 관리.
    • → 코드의 가독성 저하 및 관리 어려움.
 
🆕 개선 방식
  • 퍼즐 관리 스크립트 도입:
    • 하나의 스크립트에서 퍼즐을 관리.
    • Static 변수를 활용하여 다른 클래스에서 쉽게 접근 및 관리.
 
💫 개선 결과
  • 코드의 가독성 향상 및 관리 용이성 향상.

동적 태그 비교의 효율성 향상 : CompareTag() 메서드의 도입

⚠️ 문제 사항
  • 콜라이더의 태그를 판단할 때 == 연산자 사용.
    • → 정적 문자열 비교로 동적 태그 관리에 한계 존재.
 
🆕 개선 방식
  • CompareTag() 메서드 도입:
    • CompareTag() 메서드 활용하여 동적 태그 비교.
    • 동적할당 없이 더 효율적인 태그 비교 구현.
 
💫 개선 결과
  • 코드의 효율성 향상.
  • 동적 태그 관리에 용이성 증가.
 
✔ 개선 발전 가능성
  • 다음 프로젝트에서는 태그를 관리하는 변수(const)를 도입하여 가비지 생성을 최소화하고자 함.
🗣️
담당자: 이홍준

가상 메서드를 통한 코드의 재사용성 향상 및 관리성 개선

⚠️ 문제 사항
  • 기믹 스크립트에서 캐릭터와 기믹 오브젝트 둘 다 제어하여 단일성 부족
  • 기믹 개수가 늘어날수록 코드의 관리 난이도가 높아짐
 
🆕 개선 방식
  • 캐릭터 제어는 캐릭터 스크립트에서, 기믹 제어는 기믹 총괄 스크립트에서 제어하도록 분리
  • 기믹 총괄 스크립트는 가상 메서드로 구성하여 각 기믹 스크립트가 함수를 가져다 쓸 수 있도록 제작
  • 기믹 스크립트가 총괄 스크립트를 상속받아 사용하는 방법도 있지만 굳이 상속을 사용하지 않아도 함수를 가져다 쓰는데 지장이 없으며 오버라이딩을 통해 함수를 입맛에 맞게 바꿔쓸 수 있기 때문에 캡슐화에 지장을 줄 수 있는 상속을 사용하지 않음
 
💫 개선 결과
  • 코드의 과도한 중복 제거 (실제로 각 기믹 스크립트의 코드는 약 1500줄 → 400줄로 줄음)
  • 코드의 재사용성 및 관리성 향상

사용된 기술 스택

notion image
  • Visual Studio - 2022
  • Rider - 2023.2.1
  • Unity - 2022.3.2f1
  • GitHub
Design
  • Photoshop 2022
  • Maya 2020
Collaboration

클라이언트 구조

전체적인 구조

notion image

데이터 관리

notion image
DataPersistenceManager
각각의 저장슬롯에 ID를 부여하여 구별시켜줍니다. 그리고 NewGame, SaveGame, LoadGame 함수를 통해 전반적인 데이터 저장을 관리합니다.
GameData
게임에 저장할 변수들의 데이터를 담당하고 있습니다.
IDataPersistence
DataPersistenceManager의 interface로 LoadData, SaveData 함수를 통해 데이터 관리자와 저장할 변수를 연결시켜줍니다.
FileDataHandler
Json을 활용하여 게임 내 저장한 데이터와 로컬파일을 직렬화&역직렬화를 통해 연결시켜줍니다.

플레이어 관리

notion image
Player
플레이어의 이동, 회전에 대한 입력을 받고 그에 따른 움직임과 애니메이션을 처리함
TopViewPlayer
Player를 상속 받아 top view인 상황에서 플레이어의 이동, 회전에 대한 입력을 처리함
ForceReceiver
플레이어의 점프, 낙하와 관련된 처리, 땅에서와 공중에서의 애니메이션과 움직임을 처리함

스테이지 관리

notion image
GameManager
현재 스테이지 값, 클리어한 스테이지 데이터 저장
WaypointPath
캐릭터의 이동과 스테이지 접근
MoveSelect
스테이지 선택씬에서 캐릭터 이동에 따른 현재 접근 스테이지 정보
Stage2Manager
Stage2에 진입시 Floor1 실행, 진행 상황에 맞는 Floor 실행, 모든 Floor Clear시 Stage Clear로 판단해 StageSelectScene Load
 

기믹관리

PuzzlePattern
PuzzlePattern
LaserPattern
LaserPattern
Stage3GimmickManager
Stage3GimmickManager
PuzzleManager
퍼즐버튼 랜덤배치 및 퍼즐오브젝트 초기 세팅, 퍼즐 기믹의 성공여부 판단 후 다음 스테이지로 가는 오브젝트 실행
LaserPatternManager
레이저 랜덤 패턴 생성 및 초기 세팅, 모든 Laser 성공 여부 확인 및 패턴 성공시 CutScene 재생
Stage3GimmickManager
Stage3 의 모든 기믹에 사용되는 함수를 가상 메서드로 모아서 관리

코드 샘플 및 주석

김어진

정재훈

박지원

이홍준


 
사용자 의견
개선방안
분류
기믹 및 지형에 따라 들리는 소리가 달랐으면 좋겠습니다.
지형마다 collider를 사용해 AuioClip을 바꾸어주는 방식으로 소리가 다르게 나도록 패치하였습니다.
ALL
StartScene에서 키보드 클릭이 아닌 마우스 클릭도 있으면 좋겠어요.
EventSystem을 변경하여 키보드 클릭과 마우스클릭 모두 가능하게 변경
StartScene
Stage1의 낮은 잎에 닿으면 플레이어가 2단 점프를 하지 못합니다.
Player의 Jump 범위에 문제가 생기지 않게 오브젝트의 위치를 변경하였습니다. 이후에 Jump 메커니즘을 수정할 예정입니다.
Player
Stage1 나무토막이 바닥에 떨어졌을 때 무조건 캐릭터 리스폰을 해서 나무토막도 리스폰을 시켜야 아이템을 먹을 수 있는 부분이 아쉽습니다.
캐릭터 리스폰과 관계 없이 나무토막이 떨어진 후 7초가 지나면 원상태로 돌아가도록 수정하였습니다.
Stage1Scene
게임 플레이 도중 발판 블럭이 리스폰 안 되서 메인으로 나가서 다시 스테이지로 돌아왔는데 시야가 위로 고정되는 버그에 걸렸습니다.
Stage2 Manager의DonDestroyOnLoad함수를 제거 해줌으로써 Start의 카메라 세팅이 매번 작동되도록 수정하였습니다.
Stage2Scene
스테이지2 용암블럭 앞 얼음블럭이 떨어진 후 젠이 되지 않아 진행할 수 없었습니다.
몇 개의 얼음 블록은 지속적으로 생성되도록 설정하여 플레이어가 진행하는 데 어려움이 없도록 진행하였습니다.
Stage2Scene
Stage2-3에서 ESC 버튼이 안 먹습니다.
2-3 전용 캐릭터에 OptionInput스크립트를 넣어 Option창에 접근할 수 있도록 수정했습니다.
Stage2Scene
Stage2 고드름 바닥에 떨어졌을때 맞고 죽는 판정을 고쳐주시면 좋겠습니다.
고드름의 콜라이더를 이용하여 땅에 닿기 전까지는 플레이어가 닿으면 리스폰이 되고, 땅에 닿으면 콜라이더를 비활성화하여 닿아도 아무 효과도 적용되지 않도록 개선하였습니다.
Stage2Scene
Stage2 원근감 및 거리감이 불편합니다.
Stage2의 전반적인 y축의 높이를 재조정할 예정입니다.
Stage2Scene

팀원 구성 및 연락처

이름
태그
역할
MBTI
블로그 주소
Github주소
김어진
팀장
GameData,StartScene,Stage1Scene
ENTJ
정재훈
부팀장
Stage2Scene,Gimmick
ENFP
김형중
팀원
StageSelect,Option,Sound
INFP
박지원
팀원
Stage2Scene,Player,Gimmick
ISFP
이홍준
팀원
Stage3Scene,Gimmick
ISTP
 
 
Share article
Subscribe Newsletter
Stay connected for the latest news and insights.
RSSPowered by inblog