본문 바로가기
  • 식초 한잔 할래..?
공부/게임 공부

Unity로 가상 공간을 만들어 보자.

by 돼지피그푸곰 2025. 10. 28.

이번에 만들어볼건 Zep처럼 가상의 공간을 만들어서 Player의 이동, 간단한 상호작용, 거기에서 할 수 있는 미니게임등을 만들어 보는 시간입니다.

 

필수로 만들어야 하는 기능들로는

  • 캐릭터 이동 및 맵 탐색
  • 맵 설계 및 상호작용 역역
  • 미니게임 실행
  • 점수 시스템
  • 게임 종료 및 복귀
  • 카메라 추적 기능

입니다.

 

위의 필수 기능들은 전부 다 만들 자신이 있었기 때문에, 초기 설계에서 도전 기능들까지도 생각했습니다.

NPC대화 기능, 미니게임 추가, 탈 것 추가, 캐릭터 커스터마이징 추가, 리더보드 시스템 등.

이 도전 기능들 또한 다 구현할 자신이 있었기 때문에, 기능에 대한 생각은 하지 않고, 일단은 원래 계획했던 2DGTA형식을 만들어보려고 했습니다.

 

그 중 가장 넣고 싶었던 기능이 오브젝트를 잡고 던지는 기능이었습니다.

잡고, 던지고, 파괴하고, 이로 인해 지나갈 수 없는 길도 파괴가 되는 등의 스케치를 짰고,

파괴한 오브젝트가 많으만 많아질 수록 업적이 쌓이고, 능력이 증가하는 스케치를 짰습니다.

거기에 더해 BattleZone을 만들어서, NPC에게 말을 걸면 현재 있는 지역에 다양한 오브젝트, 몬스터들이 떨어지게 하여, 내 Player가 물건을 잡고 던져서 헤치우는 스케치를 했습니다.

 

즉 저는 캐릭터의 움직임, 잡고 던져서 오브젝트 파괴, 업적시스템, NPC의 상호작용, BattleZone이라는 미니게임이 기본이 되는 구조였기 때문에 이와 관련된 스켈레톤 코드를 먼저 짰습니다.

 

스켈레톤 구조를 짜는데 까지는 하루가 걸렸고, 이 정도 속도라면 그 다음날 맵만 만들고, Player에게 이미지만 씌우고, 오브젝트들에게 이미지만 씌우면 현재 제가 생각한 이것 저것 부시는 GTA2D는 완성될 전망이 보였습니다.

 

과제 나온게 21일. 스켈레톤과 씌울 이미지 구한게 22일, 때문에 23일이면 기능 구현이 얼추 끝나고, 거기에 필수 기능인 점수와, 과제에서 요구한 미니게임 하나 붙이면 되는 상태였습니다.

 

여기서부터 문제가 발생합니다. 

 

맨 위의 사진과 같이

 

 

구조를 새롭게 짰습니다.

 

컨셉은 이렇습니다.

 

현 세대에 살고 있는 주인공에게 이세계 포털을 열어주는 NPC들이 생겨, 완전히 다른 지형의 세계로 가서 미션을 클리어 하고 오면 힘이 쌓이면서 점점 강해집니다. 여기서 NPC3명의 모든 미션을 여러번 클리어하면 업적이 쌓이며 능력치가 강해지고, 숨겨진 NPC가 등장합니다. 이는 정석 엔딩이고, 만약 Player가 NPC3명을 다 죽이면 BadEnding으로 연결하는 NPC가 나오게 되는 구조입니다.

 

이미 NPC를 통해 Scene을 전환하는 방법은 스켈레톤에 구현을 해 놓았고, 엔딩Scene도 따로 만들어 놨습니다.(간단하게 텍스트만 나옴)

 

일단 여기까지는 아무런 문제가 없었기 때문에 맵을 전부 다 만들었습니다.

 

 

위의 사진이 기본 현대 맵입니다. 잘 찾아보면 NPC도 3명 있고, Player는 자유롭게 움직일 수 있습니다.

초록색 영역은 몬스터, 오브젝트가 생성되는 공간입니다. 지금은 R버튼을 누르면 리셋되게 했는데, 추후에 맵에 있는 오브젝트의 갯수를 체크해서 시간마다 자동적으로 생성되게 바꾸려고 했습니다.

 

여기는 배틀씬입니다.

Player가 등장하면 Wave마다 일정 수의 몬스터가 등장하며, Player와 싸우게 되지요. 이미지와 애니매이션은 3종류를 구했기 때문에 근거리, 원거리, 돌진형 느낌으로 준비했지만 시간문제상 하나의 종류로 wave3까지만 깨면 클리어 되게 해 놨습니다.

 

여기는 스윔씬입니다.

개인과제에서 주어진 것 중 하나가 비행기인데, 저는 수영으로 대체했습니다.

이유는 그냥..이미지 사이트 돌아다니다가 바다속 이미지가 있길래 이걸로 했습니다.

때문에 비행기와 달리 부력 시스템을 만들어야 합니다.

 

마지막으로 마리오씬입니다.

마리오 짝퉁같은 이미지들을 발견해서, 예전에 고양이 마리오처럼 함정을 좀 만들어 두고,

빠르게 골인 지점에 도달해야 하는 형식으로 만들었습니다.

 

이렇게 맵 4개를 만들고 엔딩씬과 배드엔딩씬을 텍스트로 만들었습니다.

 

이제 이걸 구현할 일만 남았습니다.

 




미니게임 Scene전환 트러블 슈팅

🧩 문제 발생

가장 중요시 여겼던 시스템은 업적 시스템. 이를 유지하기 위해, 그리고 컨셉을 유지하기 위헤 Player를 MainScene에 유지하고 이후의 미니게임들Scene에 들어갈 때는 MainPlayer를 새롭게 Respawn하려는 구조로 설계 이때 DontDestroyOnLoad를 사용해서 MainPlayer가 각 Scene들끼리 충

 

-> 이로 인해 Player가 각 미니게임마다 다르게 적용하는 물리법칙에 위배, 각 씬이 몬스터로서 인식, 중력, 부력 등을 설정하니 MainScene의 Player에게도 적용되는 문제 발생

 

🧠 해결 방향

각 미니게임을 독립적인 Scene으로 전환하기.

Player가 미니게임에 들어가면 미니게임이 원래 있던 오브젝트를 Player가 조종할 수 있게 하고, 게임에 대한 결과값만 MainScene의 리더보드 시스템 혹은 Player의 업적 시스템에 반영하기.

 

-> 이 부분에 대해서는 처음부터 알고 있었지만, 마치 Player와 컷신 사이의 괴리감처럼, 자연스러운 Scene전환과, 실시간으로 능력이 업그레이드 되는 것을 원했기 때문에, (해결할 수 있을 줄 알았기 때문에) 알면서도 시도를 안한채로 해결 방안 모색.

 

결과

모든 부분에서 충돌이 났지만 제출시간이 다가와 해결 실패. 다음엔 그냥 독릭개채의 Scene으로서 만들고 결과값만 가져오기로 결정.

 

 

던지기 & 파괴 트러블 슈팅

 

🧩 문제 발생

1. 오브젝트의 종류에 따라 Layer, Trigger문제 발생

처음에 오브젝트와 스켈레톤 코드를 구현할 때, BreakableObject와 ThrowableObject를 분리.

이유: 파괴되는건 몬스터이고, 던지는건 물건으로 생각.

 

나중에 생각 변경한 점: 오브젝트도 던지면 파괴되어야 하고, 몬스터도 작은 애들은 던지는게 재미있다고 생각.

때문에 며칠 전에 만들어 둔 Layer와 Trigger를 다시 탐색. => 제대로 정리 안해둔 것이 발단.

 

추가로 잡고 던지기 기능 외에 punch기능도 구현. 그런데 잡을 수 있는 오브젝트에서 마우스 왼클릭을 하면 punch대신 잡아버리는 문제 발생. 이는 처음에 punch기능을 넣을 생각이 없었기 때문에 벌어진 일이므로, 코드 변경. 조건문 추가 -> 던지기 입력 분리

 

🧠 해결 방향

모든 파괴 가능한 오브젝트들의 Layer를 Destructible로 지정.

마찬가지로 던질 수 있는 오브젝트들도 Throwable로 지정.

지나치게 많은 Layer가 생성되어 있었던 것을 정리.

 




 

BattleMonster의 알고리즘

🧩 문제 발생

배틀씬에서 몬스터를 소환 후 Player를 공격해야 하지만, 이와 관련된 알고리즘을 구상하지 않았음.

이는 위의 트러블 슈팅들에서 야기된 문제로 Trigger, MainScene에서 불러온 Player가 제대로 태그처리되지 않았으며, 몬스터가 Player를 대상으로 인식하지 않은 문제 발생.

추가로 몬스터에 Destrutible레이어를 붙이니, 지들끼리 부딪혔을 때도 파괴.(오브젝트에 맞았을 때 파괴되어야 하는데)

몬스터와 플레이어의 콜라이더 크기가 실제 이미지하고 안맞음

 

🧠 해결 방향

Attack 태그 추가 및 코드 수정. 

오브젝트들끼리 부딪혔을 때 알아서 파괴가 되기 때문에, Player의 던져진 물체에 맞았을 때만 파괴되도록 코드 수정.

애니매이션의 프레임별 HitboxPrefab를 추가. => 평소 필요 없는 Collider 제거

 




그 외 힘들었던 점
  • 편할려고 미니게임 Scene을 분리했는데, 오히려 불편해짐. 차라리 Scene 분리 말고, 구역을 만들어서, 해당 구역에 들어가면 물리 법칙이 달라지게끔 했으면 더 좋았을 것 같다.
  • Player의 애니매이션에 맞춘 펀치 및 타격지점. -> 범위가 생각보다 작고, Player의 Collider 때문에 사실상 범위 밖에서 때리는데 맞는 듯한 느낌.
  • Tile문제: 강의 영상에서는 각 타일마다, Image마다 Slice하는 방법이나, 이미 완벽히 준비된 소스 활용. 하지만 실제로 Image를 구해보니 자르는 방법에 따라 다르고, 잘라진 파일도 있지만 잘라지지 않은 파일도 있어서 알아서 자르라는 곳도 많으며, Auto로 할 경우 꽤나 부정확한 경우게 많다. 거기에 직사각형의 전체 타일을 Slice후 TileMap에 적용하지 정사각형으로 바뀌어 매우 알아보기 어렵게 되는 문제 발생. 이 부분 분명 더 쉬운 방법이 있을 터. 좀 더 알아볼 부분이다.
  • 오브젝트가 파괴 되었을 때, 파편이 튀는 Particle효과를 넣었지만, 좀 짜쳐보인다. 더 나은 방법 필히 있을 거라 생각. 모색 예정
  • Github에 업로드 할 때, 캐시안에 100메가가 넘는 파일이 있어 퍼블리싱이 불가능 했다. 하지만 이미 파일 내의 변화를 감지한 깃허브데스크탑 때문에, 파일 안의 캐시를 전부 다 지워도 퍼블리싱이 안되는 문제 발생. 파일 갯수가 3만개가 넘어갔기 때문에 하나씩 찾는 것도 불가능. 검색도 불가능. 때문에 새로운 리포지토리를 만들고. gitignore도 만들었지만 어째서인지 ignore안되는 일 발생. 결국 수동으로 싹 다 지우고 퍼블리싱 완료.
  • 하나를 고치니 다른 부분들에게도 전부 다 영행을 줌. TextRPG에서는 각 코드, 클래스를 캡슐화하는 것이 가능했는데, Unity에서는 어떤 식으로 캡슐화 하는지 궁금.
  • 마찬가지로 카메라 움직임이 BattleScene으로 들어가니 캐릭터에 따라 안움직여짐. 원인으로는 캐릭터가 리스폰 되기 전에 카메라가 캐릭터를 찾아서 일 수도 있고, 강제로 카메라를 고정시키는게 있을 수 있고.
  • 코드가 많아지고, 영향주는게 많아지면서 점차 무얼 바꿔야 할지 조차도 힘들어지는 경지에 도달. -> 새로 만드는게 빠를 듯

 

 

이렇게 다사다난한 개인과제 5일을 마무리 합니다.

마지막 이틀은 수정만 했던 터라 그냥 싹 다 갈아엎는게 정답일 것 같은 느낌을 받았지만...그게 맞는 것 같기도 하고.

 

마찬가지로 수치 조정도 Inspector에서 해결할 수 있게 코드를 짰는데, 오히려 그것 때문에 후반으로 갈수록 힘들어 지는 경향이 있었습니다.

 

현재 제가 만든 구조는 하나를 만들고, 거기에 추가해서 수정하고, 거기에 더해서 만들고 등등 하고 있다 보니 서로가 직접적으로 참조를 하고 있는 상태입니다.

 

마찬가지로 인터페이스도 없기 때문에 최대한 비슷하게 만들었지만 애초에 이미 너무 넓게 퍼져버린 것들을 주워담기가 힘든 상태. 

그러니 이걸 캡슐화 시켜서 인터페이스를 만들고, 데이터도 private로 제한하고, 각 클래스들을 Manager를 통해 조정하고, 독립단위로 테스트하게 만들어야 합니다.

 

사실 저는 후자를 더 선호하는데, 하나씩 만들다 보니 저도 모르는 사이에 어느새 모든게 결합되어 있더군요. 이래서 기획이 중요한거구나 싶었습니다.