개발/유니티

[유니티] 자바에서 만든 프로젝트 유니티로 옮기기(1)

kimchangmin02 2025. 7. 22. 22:16

 

 

청사진 하나로 해결되는 자바방식

 

 

1

(기본적인 방법)

자바는, 스크립트(클래스 파일들을 적기만 하고, resource에 이미지만 있으면 되는 형식이엇지만)

유니티는 스크립트랑 게임 오브젝트랑 연결해야함

왜냐하면 자바는 기본적으로 게임을 위해서 만들어진게 아닌데

유니티는 계속 움직이는, 게임을 위해서 만들어진 툴이라서?

일종의 유니티 방식

 

왜 유니티 방식이 더 효율적인가?

사용자님께서 말씀하신 상황을 "중앙의 거대한 컨트롤러가 일일이 지시하는 방식"과 "각 객체가 알아서 역할을 수행하는 방식"으로 나누어 비교해 보겠습니다.

1. 예측 불가능한 변화에 대한 유연성

상황: "걸어 다니는 적"에게 "하늘을 나는 기능"을 추가하고 싶을 때

  • 중앙 지휘 방식 (자바 상속 구조의 한계):
    • Enemy라는 부모 클래스가 있고 WalkingEnemy가 이를 상속받았다고 가정해 봅시다. WalkingEnemy walk()라는 함수를 가지고 있습니다.
    • 여기에 날게 하려면 어떻게 해야 할까요? FlyingEnemy라는 새로운 클래스를 만들고 fly() 함수를 추가해야 합니다.
    • 만약 **"걸어 다니다가 날기도 하는 적"**을 만들고 싶다면 문제가 복잡해집니다. WalkingEnemy FlyingEnemy를 동시에 상속받을 수 없기 때문입니다(다중 상속 문제). 결국 코드가 중복되거나, 모든 기능을 다 가진 거대한 SuperEnemy 클래스를 만들어 필요 없는 기능까지 모두가 가지게 되는 비효율적인 구조가 되기 쉽습니다.
  • 유니티 컴포넌트 방식 (레고 블록 조립):
    • Enemy라는 게임 오브젝트가 있습니다. 여기에는 Movement 스크립트(컴포넌트)가 붙어있어 걸어 다닙니다.
    • 여기에 날게 하고 싶다면? 그저 Fly라는 기능의 스크립트(컴포넌트)를 추가로 붙여주기만 하면 끝입니다.
    • **"걸어 다니다가 날기도 하는 적"**은 Movement 컴포넌트와 Fly 컴포넌트를 둘 다 붙이면 됩니다. 기능의 추가와 제거가 부품을 붙였다 떼는 것처럼 자유롭고, 다른 코드에 영향을 주지 않습니다.

결론: 게임 개발에서는 예측 불가능한 기획 변경이 잦습니다. 컴포넌트 방식은 기능 단위로 부품화가 되어있어 이런 변화에 매우 유연하고 신속하게 대처할 수 있습니다.

2. 폭발적인 재사용성

상황: "플레이어가 쏜 총알"과 "적이 쏜 총알"을 만들 때

  • 중앙 지휘 방식:
    • 중앙 컨트롤러는 PlayerBullet EnemyBullet을 구분해서 관리해야 합니다. 만약 총알의 '직진하는 기능', '벽에 부딪히면 사라지는 기능'이 동일하더라도, 각각의 로직 안에서 별도로 코드를 작성하거나 복잡한 상속 구조를 만들어야 할 수 있습니다.
  • 유니티 컴포넌트 방식:
    • **'직진하는 기능'**을 가진 MoveForward 컴포넌트를 하나 만듭니다.
    • **'벽에 닿으면 터지는 기능'**을 가진 ExplodeOnImpact 컴포넌트를 하나 만듭니다.
    • 이제 PlayerBullet 프리팹을 만들고, 이 두 컴포넌트를 붙입니다.
    • EnemyBullet 프리팹을 만들고, 이 두 컴포넌트를 똑같이 붙입니다.
    • 만약 "적이 쏜 총알은 플레이어를 따라가게 만들고 싶다"면? EnemyBullet 프리팹에만 TrackPlayer라는 컴포넌트를 추가로 더 붙여주면 됩니다.
    •  MoveForward 컴포넌트는 총알뿐만 아니라, 직진하는 미사일, 앞으로 돌진하는 자동차 등 어디에나 재사용할 수 있습니다.

결론: 기능들이 독립된 부품(컴포넌트)으로 존재하기 때문에, 완전히 다른 종류의 오브젝트라도 필요한 기능을 가져다 붙여 손쉽게 재사용할 수 있습니다. 이는 개발 속도를 비약적으로 향상시킵니다.

 

 

 

 

 

 

 

  1. 하이어라키(Hierarchy) 창에서 마우스 오른쪽 클릭
    • 보여주신 스크린샷과 같이 메뉴를 엽니다.
  2. 2D Object > Sprites > Square 선택
    • Create Empty가 아니라, 그 아래 있는 2D Object 메뉴로 들어갑니다.
    • 오른쪽에 나오는 메뉴에서 Square를 선택합니다. (어떤 모양이든 상관없지만 Square가 가장 기본입니다.)
  3. 이름 변경
    • 하이어라키 창에 Square라는 이름의 오브젝트가 생성되었을 겁니다.
    • 이름을 Enemy 로 바꿔줍니다.
  4. 이미지 연결 (가장 중요한 단계)
    • 하이어라키에서 Enemy 오브젝트를 선택합니다.
    • 인스펙터(Inspector) 창을 보면 Sprite Renderer 라는 컴포넌트가 이미 붙어있을 겁니다.
    • Sprite 라고 쓰인 칸에, 이전에 Sprites 폴더로 가져왔던 적 이미지를 마우스로 끌어다 놓습니다.
    • 이제 씬(Scene) 뷰에 있던 하얀 네모가 적 이미지로 바뀝니다!
  5. 나머지 부품 조립
    • 이제 이미지가 보이는 오브젝트가 완성되었습니다. 여기에 이전 답변에서 설명드린 나머지 부품들을 조립하면 됩니다.
    • Enemy 오브젝트가 선택된 상태에서 Add Component 버튼을 눌러...
      • Enemy.cs (적 스크립트)
      • Rigidbody 2D (물리 기능)
      • Box Collider 2D (충돌 감지)
    • ...를 모두 추가하고, Gravity Scale = 0, Is Trigger = true 로 설정합니다.
  6. 프리팹으로 저장
    • 모든 조립과 설정이 끝난 Enemy 오브젝트를 하이어라키 창에서 프로젝트 창의 Prefabs 폴더로 드래그하여 Enemy.prefab 설계도를 만듭니다.
    • 이제 하이어라키의 Enemy는 지워도 됩니다.

 

 

 

 

 

 

 

 

2

 

왜 문제가 됫던거지데 

스프라이트에 이미지 드래그가 안되

 


Q

png임
근데 투명한건데 배경

 

A

문제없음

 

 

 

 

 

 

 

Q

png나 jpg중 둘중 하나는 뭐 안된다던데,
아 이건 투명 배경에[ 대한건가

 

A

PG (JPEG) - 투명 배경 절대 불가

  • JPG는 투명 배경을 지원하지 않습니다.
  • JPG는 사진을 저장하기 위해 만들어진 형식으로, 파일 용량을 줄이기 위해 이미지 데이터를 일부 손상시키는 '손실 압축' 방식을 사용합니다.
  • 이 형식의 설계 자체가 투명도 정보(알파 채널)를 포함하지 않기 때문에, 포토샵 같은 툴에서 배경을 투명하게 만들어 JPG로 저장하면 강제로 흰색이나 검은색 같은 단색 배경이 채워져서 저장됩니다.

PNG - 투명 배경 완벽 지원

  • PNG는 투명 배경(알파 채널)을 완벽하게 지원합니다.
  • 웹이나 게임의 그래픽(로고, 아이콘, 스프라이트 등)을 위해 만들어졌으며, 이미지 품질 저하가 없는 '비손실 압축'을 사용합니다.
  • 캐릭터나 아이템처럼 배경 없이 오브젝트의 모양만 깔끔하게 보여주고 싶을 때 사용하는 표준 파일 형식입니다.

유니티에서의 실제 사용 사례

  • PNG를 사용해야 할 때:
    • 플레이어 캐릭터, 몬스터, NPC
    • 총알, 이펙트, 아이템 아이콘
    • 버튼, 체력 바, 게임 창 등 모든 UI 요소
  • JPG를 사용해도 괜찮을 때:
    • 게임 시작 시의 타이틀 화면이나 스테이지의 전체 배경 이미지처럼 화면을 꽉 채워서 투명도가 전혀 필요 없는 경우 (파일 용량을 아낄 수 있다는 장점이 있습니다.)
    • 게임 내 액자 속 사진 등

 

 

 

 

 

 


Q

아 아까 이문제는, 압축을 안풀고, 드래그해서그럼
근데 압축 안풀어도, 이미지 더블클릭하면 보이긴하던데

 

A

압축을 풀지 않은 상태에서 이미지 파일을 더블클릭하면 이미지가 보이는 것은 운영체제(OS)가 임시 폴더에 파일을 풀어 잠시 보여주는 원리입니다.

하지만 유니티(Unity) 에디터에서 스프라이트로 사용하기 위해 드래그 앤 드롭을 시도하면 문제가 발생하는 것은 유니티의 에셋 관리 방식과 관련이 깊습니다.

결론부터 말하자면, 유니티는 프로젝트에 포함될 모든 에셋(Asset)에 대한 직접적인 파일 경로와 접근 권한이 필요하기 때문에 압축을 풀어야 합니다.

압축 해제가 중요한 이유

1. 유니티의 에셋 데이터베이스와 메타데이터

유니티는 프로젝트에 추가되는 모든 에셋을 'Assets' 폴더 안에서 관리합니다. 이미지, 사운드, 3D 모델 등 어떤 파일이든 프로젝트에 들어오면 유니티는 해당 에셋에 대한 고유한 메타데이터(.meta 파일)를 생성합니다. 이 메타데이터에는 임포트 설정, ID 등 에셋을 관리하는 데 필수적인 정보가 담겨있습니다.

압축 파일 안에 있는 이미지를 그대로 드래그하면, 유니티는 해당 파일의 정확한 경로를 확보할 수 없습니다. 압축 파일은 단일 파일이며 그 안의 내용물은 직접적인 경로를 가지지 않기 때문입니다. 따라서 유니티는 에셋을 프로젝트 데이터베이스에 정식으로 등록하고 메타파일을 생성하는 과정을 진행할 수 없습니다.[1]

2. 임시 파일과 영구적인 파일의 차이

압축 파일 속 이미지를 더블클릭해서 보는 것은, 마치 택배 상자를 열어 물건을 잠시 확인하는 것과 같습니다. 운영체제는 이 이미지를 임시 공간에 잠시 꺼내놓고 보여준 뒤, 창을 닫으면 임시 파일을 삭제합니다.

반면, 유니티로 이미지를 가져오는 것은 그 물건(이미지)을 내 방(프로젝트)의 정해진 위치(Assets 폴더)에 두고 계속 사용하겠다고 등록하는 절차와 같습니다. 따라서 언제든지 접근할 수 있는 영구적인 위치, 즉 압축이 풀린 실제 파일이 필요한 것입니다.[2]

3. 유니티의 자체 압축 및 처리 과정

유니티는 이미지를 프로젝트에 가져올 때, 단순히 원본을 복사하는 것에서 그치지 않습니다. 플랫폼(PC, 모바일 등)에 최적화하기 위해 자체적인 압축 포맷(예: Crunch, LZ4)을 적용하고 텍스처 설정을 관리합니다.[3][4][5] 예를 들어, 픽셀 아트의 경우 압축 설정을 잘못하면 색이 바래거나 깨져 보일 수 있어 별도의 설정이 필요하기도 합니다.[4][5]

이러한 유니티의 내부 처리 과정을 거치려면, 압축되지 않은 원본 이미지 파일이 반드시 필요합니다.

결론적으로, 압축 파일에서 직접 이미지를 드래그하는 것은 유니티의 에셋 관리 시스템이 정상적으로 작동하는 것을 방해합니다. 번거롭더라도 항상 압축을 해제한 후, 실제 이미지 파일을 유니티 프로젝트의 'Assets' 폴더로 가져와야 안정적인 개발 작업을 이어갈 수 있습니다.

 

 

 

 

 

 

 

 

 

 

3

근데 게임시작 버튼 누르니깐, 적들이 안나오고, 

스페이스바 눌러도 총알이 안날아감

이것도 무슨 연결이 필요한가
근데 우리 prefab은 만들엇잖아

아 이 prefab이 나오려면 어떤 이벤트가 이썽야하나

 

>

gamemanager게임 오브젝트랑

enemyspawner게임오브젝트를 하이아키에서 만든다음에

뭔가 연결을 해준건가

이렇게 하니깐 되는데

 

이전에는 왜 안 됐을까?

이전에는 '적 프리팹(Enemy Prefab)'이라는 설계도만 있었을 뿐, "언제, 어디서, 어떻게 적을 등장시켜라"라고 명령을 내리는 실행자(Manager/Spawner)가 게임 세상에 없었기 때문입니다.

 

Q

>근데 이전에도 코드는 있엇는데 왜 안된거지?

그게 유니티랑 연결이 안되엇던건가

아, 여기서 specialize Field에서 shot이랑 enemy를 연결해주고 있는건가

 

 

A

이전에도 코드는 존재했지만, 그 코드는 "어떤 프리팹을 써야 하는지" 전혀 모르는 상태였습니다. 코드와 유니티 에디터 상의 실제 에셋(프리팹 파일) 사이에 연결이 끊어져 있었던 것이죠.

사용자님께서 보신 인스펙터 창의 그 슬롯이 바로 그 연결을 만드는 '다리' 역할을 합니다.


레시피(코드)와 실제 재료(프리팹)의 비유

이 상황을 아주 쉽게 비유해 보겠습니다.

  1. 코드 = 요리 레시피 (public GameObject enemyPrefab;)
    • 스크립트 코드는 "적(Enemy)이라는 재료를 가져와 냄비에 넣으세요" 라고 적힌 레시피입니다.
    • 코드는 '적'이라는 재료가 필요하다는 사실은 알지만, 그 재료가 'A사에서 만든 적'인지, 'B사에서 만든 적'인지, 아니면 선반 어디에 있는지 구체적으로는 모릅니다. 그저 '적'이라는 이름표가 붙은 재료가 필요할 뿐입니다.
  2. 유니티 에디터 = 주방과 선반
    • 유니티의 프로젝트 창(Project Window)은 재료들이 보관된 선반입니다. 여기에는 Enemy.prefab, PlayerShot.prefab 등 다양한 재료(에셋)들이 있습니다.
  3. 인스펙터의 빈 슬롯 = "여기에 재료를 올려두세요"
    • public이나 [SerializeField] 키워드를 사용하면, 유니티는 인스펙터 창에 "이 레시피(코드)는 '적'이라는 재료가 필요하대요. 여기에 맞는 재료를 올려주세요" 라는 의미의 **빈 칸(슬롯)**을 만들어 줍니다.
    • 사용자님의 스크린샷에서 Enemy 풀과 PlayerShot 풀 아래에 있는 Prefab 슬롯이 바로 이 빈 칸입니다.
  4. 드래그 앤 드롭 = 실제 재료를 레시피에 지정해주는 행위
    • 사용자님께서 프로젝트 창(선반)에 있던 Enemy 프리팹을 인스펙터 창의 Prefab 슬롯(빈 칸)으로 드래그 앤 드롭하는 순간, 드디어 연결이 완성됩니다.
    • 이제 레시피(코드)는 막연히 '적'을 찾던 상태에서, "아하! 바로 선반에 있던 저 'Enemy.prefab'을 가져다 쓰라는 거구나!" 라고 명확하게 인지하게 됩니다.

public [SerializeField]의 역할

이 연결 다리를 놓아주는 키워드가 바로 public [SerializeField]입니다.

  • public GameObject enemyPrefab;
    • "이 enemyPrefab 변수는 외부에 공개할 거야. 다른 스크립트도 쓸 수 있고, 유니티 인스펙터 창에도 보여줘!" 라는 의미입니다.
  • [SerializeField] private GameObject enemyPrefab;
    • "SerializeField"는 "이 변수는 다른 스크립트에서는 못 쓰게 비공개(private)로 유지하되, 유니티 인스펙터 창에는 특별히 보여줘서 연결할 수 있게 해줘!" 라는 의미입니다. (더 안정적인 코드를 위해 권장되는 방식입니다.)

결론적으로, 코드를 작성하는 것은 필요한 변수라는 '그릇'을 만드는 행위이고, 인스펙터에서 드래그 앤 드롭으로 연결하는 것은 그 그릇에 실제 에셋이라는 '내용물'을 채워 넣는 행위입니다.

이전에는 내용물이 없는 빈 그릇(null 상태)이었기 때문에 코드가 아무것도 할 수 없었고, 이제는 그릇에 프리팹이라는 내용물을 채워주셨기 때문에 코드가 비로소 정상적으로 작동하게 된 것입니다. 이 '연결' 작업이야말로 유니티 개발의 가장 핵심적인 과정 중 하나입니다.

 

 

 

 

 

 

 

 

 

 

4

 

NullReferenceException: Object reference not set to an instance of an object

적이 안나오는 문제>

연결 문제인지,

코드문제읹지

 

 

범인과 범행 수법

  • 범인: poolDictionary 라는 변수 (오브젝트 풀들을 담아두는 거대한 사전)
  • 범행 수법: poolDictionary 텅 비어있습니다(Null).
  • 사건의 재구성:
    1. EnemySpawner ObjectPooler에게 "Enemy 태그 가진 놈 하나 줘!" 라고 요청했습니다.
    2. ObjectPooler poolDictionary 라는 사전에서 "Enemy" 항목을 찾으려고 했습니다.
    3. 하지만 poolDictionary 사전 자체가 존재하지 않아서(초기화되지 않아서) "어? 사전을 펼쳐야 하는데, 사전을 받은 기억이 없는데?" 라며 NullReferenceException 오류를 발생시킨 것입니다.

 poolDictionary가 비어있을까요?

poolDictionary ObjectPooler.cs Start() 함수 안에서 초기화됩니다.

Generated csharp

// ObjectPooler.cs
void Start()
{
    poolDictionary = new Dictionary<string, Queue<GameObject>>(); // ★ 바로 여기!

    foreach (Pool pool in pools)
    {
        // ... (이후 로직) ...
    }
}
 
Use code with caution.C#

이 오류가 발생했다는 것은, ObjectPooler Start() 함수가 EnemySpawner Start() 함수보다 늦게 호출되었거나, 아예 호출되지 않았다는 것을 의미합니다.

하지만 더 근본적인 문제는, 우리가 ObjectPooler의 핵심 로직을 Start()에 두었다는 것입니다. 다른 스크립트가 Start()에서 ObjectPooler를 사용하려고 할 때, 순서가 꼬이면 이런 문제가 발생할 수 있습니다.

>왜지


해결 방법: Start() Awake()로 변경하기

이 문제를 해결하는 가장 확실하고 표준적인 방법은, 초기화 로직을 Start()가 아닌 Awake() 함수로 옮기는 것입니다.

  • Awake(): 씬에 있는 모든 오브젝트가 로드된 직후, 다른 스크립트의 Start() 함수가 호출되기 **'이전'**에 항상 먼저 호출되는 것을 보장받는 함수입니다. 다른 스크립트들이 "일을 시작하기 전"에 "모든 준비를 마치는" 역할을 합니다.

[수정 방법]

  1. ObjectPooler.cs 스크립트 파일을 엽니다.
  2. Start() 함수의 이름을 Awake() 로 바꿔주기만 하면 됩니다.

 

 

 

 

 

 

 

 

 

5

 

 

 
NullReferenceException: Object reference not set to an instance of an object UnityEditor.GameObjectInspector.OnDisable () (at <916f8759030446de8f67b63248a8a6d1>:0) SerializedObjectNotCreatableException: Object at index 0 is null UnityEditor.Editor.CreateSerializedObject () (at <916f8759030446de8f67b63248a8a6d1>:0) UnityEditor.Editor.GetSerializedObjectInternal () (at <916f8759030446de8f67b63248a8a6d1>:0) UnityEditor.Editor.get_serializedObject () (at <916f8759030446de8f67b63248a8a6d1>:0) UnityEditor.Collider2DEditorBase.OnEnable () (at <916f8759030446de8f67b63248a8a6d1>:0) UnityEditor.BoxCollider2DEditor.OnEnable () (at <916f8759030446de8f67b63248a8a6d1>:0)
 
 

결론부터 말씀드리면, 이 문제는 여러분이 짠 게임 로직(코드)의 문제가 아닙니다. 이것은 유니티 에디터 자체가 "고장 난" 상태를 의미합니다.


 
Q
아니 뭐야 껏다키니깐 해결되네 왜지?
 

 

A

오류 메시지를 보면 핵심은 UnityEditor라는 단어에 있습니다.

  • NullReferenceException: ... UnityEditor.GameObjectInspector.OnDisable()
  • SerializedObjectNotCreatableException: ... UnityEditor.Editor.CreateSerializedObject()

이것은 사용자님이 작성하신 PlayerController.cs 같은 게임 로직 스크립트에서 발생한 오류가 아니라는 결정적인 증거입니다. 이 오류들은 모두 유니티 에디터의 내부 기능(인스펙터 창, 시리얼라이즈 기능 등)과 관련된 코드에서 발생했습니다.

왜 껐다 켜면 해결될까요? 컴퓨터 재부팅과 똑같습니다.

이 현상을 컴퓨터가 이상할 때 재부팅하는 것과 똑같은 원리로 이해하면 매우 쉽습니다.

  1. 정상 상태: 컴퓨터를 켜면 운영체제(Windows/Mac)가 메모리에 정상적으로 올라가고 모든 프로그램이 순서대로 잘 작동합니다. 유니티도 마찬가지로 에디터를 켜면 모든 내부 모듈(인스펙터, 씬 뷰, 콘솔 등)이 메모리에 정상적으로 자리를 잡습니다.
  2. 문제가 발생하는 순간: 컴퓨터를 오래 쓰다 보면 프로그램이 꼬이거나, 드라이버가 충돌하거나, 보이지 않는 임시 데이터가 쌓여 알 수 없는 오류가 생깁니다.
    마찬가지로, 유니티 에디터도 복잡한 프로그램이기 때문에 여러 작업을 반복하다 보면 내부 상태가 비정상적으로 꼬일 수 있습니다. 예를 들어,
    • 인스펙터 창을 여러 개 띄우거나 Lock을 걸었다 푸는 과정에서 참조가 꼬임[1][2]
    • 에셋을 임포트하거나 수정하는 과정에서 내부 데이터베이스가 일시적으로 불일치 상태가 됨
    • 특정 컴포넌트(예: 콜라이더)를 선택했을 때, 인스펙터 창이 보여줘야 할 대상 오브젝트 정보를 순간적으로 잃어버림 (이것이 바로 Object reference not set to an instance of an object, 즉 '빈 껍데기만 있고 실체가 없다'는 NullReferenceException의 원인입니다.)
  3. "껐다 켠다"는 것의 의미 (메모리 초기화):
    컴퓨터를 재부팅하면 메모리(RAM)에 있던 모든 복잡하게 꼬인 데이터가 깨끗하게 비워지고, 운영체제가 처음부터 다시 순서대로 로드됩니다.
    유니티 에디터를 껐다 켜는 것도 정확히 같은 역할을 합니다. 에디터를 종료하는 순간, 메모리에 올라와 있던 모든 에디터 관련 데이터(꼬여버린 인스펙터 창의 상태, 잘못된 에셋 참조 등)가 모두 사라집니다.
    그리고 다시 에디터를 실행하면, 유니티는 프로젝트 폴더의 데이터를 기반으로 가장 깨끗하고 안정적인 초기 상태로 내부 모듈들을 메모리에 다시 로드합니다. 일시적으로 꼬였던 내부 상태가 리셋되면서 문제가 해결되는 것입니다.[3][4]

결론: 왜 껐다 켜니 해결됐는가?

"사용자의 게임 코드가 아니라, 유니티 에디터 프로그램 자체의 내부 상태가 일시적으로 엉켰기 때문입니다. 에디터를 재시작하는 것은 이 엉킨 상태를 깨끗하게 초기화하는 가장 확실하고 빠른 방법입니다."

 
 
 
 
 
 
 
 
 
 
 
 
6
 
Q
근데 지금 화면이 너무ㅜ 작은데
난 모바일 말고, 컴퓨터로 플레이 할수있게 하고싶은데

자바에서는 jFrame을 써서 700*1600인가 1600*700인가 아무튼 거의 모니터 사이즈 크기가 되도록 햇는데

유니티에서는 그렇게 못하나
일단 기본적으로 실행화면이 작은데
 

 

 

 

 

A

PC 화면 크기(해상도)로 변경하는 방법

  1. Game 뷰 탭 찾기: 유니티 에디터에서 Scene 뷰 옆에 있는 Game 뷰 탭을 클릭합니다. (이미 보고 계신 그 창입니다.)
  2. 해상도 설정 드롭다운 메뉴 클릭: Game 뷰 탭 바로 아래에, 현재 ver (1080x1920) 이라고 표시된 버튼(드롭다운 메뉴)을 클릭합니다.
  3. 원하는 해상도 선택 또는 생성: 버튼을 누르면 여러 가지 선택지가 나타납니다.
    • 추천 (가로 비율 선택): 목록에서 16:9 또는 16:10 같은 가로 비율(Aspect Ratio)을 선택하세요. 16:9가 현재 대부분의 PC 모니터에서 사용하는 표준 비율입니다.
    • 직접 크기 지정 (JFrame처럼): 사용자님께서 원하시는 1600 * 900 같은 특정 크기를 직접 만들 수 있습니다.
      1. 드롭다운 메뉴의 맨 아래에 있는 + 버튼을 클릭합니다.
      2. 새로운 창이 뜨면 다음과 같이 설정합니다.
        • Label: "PC Screen" 이나 "1600x900" 처럼 알아보기 쉬운 이름을 입력합니다.
        • Type: Fixed Resolution (고정 해상도)으로 선택합니다.
        • Width & Height: 원하는 가로(Width)와 세로(Height) 크기를 입력합니다. (예: Width: 1600, Height: 900)
      3. OK 버튼을 누르면 목록에 방금 만든 해상도가 추가되고, 바로 적용됩니다.