[Unity] 유니티 입문 하기_C# 프로그래밍 기본_첫 게임 제작하기

류명운

·

2021. 9. 12. 19:36

반응형

* 유니티 입문 하기_공부하면서 복습겸 자료 정리해봄

* udemy _ retr0의 유니티 (Unity C#) 게임 프로그래밍 에센스 강의 수강 내용 위주로 정리

* 추가 참고 사이트 유니티 공식 사용자 매뉴얼(2019.1버전 기준)

 

유니티 준비하기

Unity Hub와 Unity Editor 설치

  • 공식 홈페이지
    • 계정 생성 (이메일 인증까지)
    • Unity Hub 다운로드 및 설치
      • Unity Hub는 Unity용 Launcher임
      • 라이선스 설정 및 동의
        • Unity Plus or Pro - 연매출 $10만 이상 혹은 조직/단체 (유료)
        • Unity Personal - 연매출 $10만 이하 개인 (무료)
      • 버전 정보
        • a - 알파버전, b - 베타버전, f - 정식버전
        • LTS (Long Term Support) - 장기지원버전으로 오랜기간 오류를 수정하고 보완해 안정화된 버전
    • Unity Editor 설치
      • Projects - 최근 프로젝트
      • Learn - 활용할 수 있는 무료 교육/학습 링크들
      • Installs - 원하는 버전의 Unity Editor 설치 (버전 여러개 설치 가능)
        • Unity 2019.1 버전 다운로드 (강의 기준 버전, Officaial Releases 에서 찾아서 받으면 됨)
          • 추가 컴포넌트 설정
            • Dev Tool_Visual Studio 설치 (나머지는 필요할 때 설치)

새 프로젝트 생성 + 인터페이스 살펴보기

  • 새 프로젝트 생성
    • Projects - New
      • Project name
      • Unity Version (설치된 Unity Editor 버전이 2개 이상일 경우)
      • Location
      • Template (미리 셋업된 설정을 사용, 프로젝트 도중 변경 가능)
  • 인터페이스 초기 세팅
    • (menu) Window > Layout - 2 by 3로 설정
    • (menu) Window > General > Console 추가 (Ctrl+Shift+C)

Unity Editor 인터페이스 초기 세팅 완료 화면

  • 인터페이스 설명 (왼쪽 상단부터 시계 방향으로)
    • Scene 
      • Unity는 하나의 게임 월드를 Scene이라는 단위로 관리
        • 1 Scene :  1 (게임월드, 게임맵, 게임레벨에 대응)
        • 현재 활성화된 Scene을 시각적으로 편집하는 창
    • Hierarchy
      • 계층, 현재 Scene에 존재하는 모든 게임 오브젝트를 리스트로 표시
    • Inspector
      • 현재 선택한 게임 오브젝트나 에셋 정보를 표시
      • 게임 오브젝트 : 게임 세상 속에 존재하는 물건이나 사물
      • 컴포넌트 : 해당 게임 오브젝트가 실제로 동작할 수 있는 기능을 부여하는 부품
    • Console
      • 유니티 에디터가 개발자에게 유용한 정보를 텍스트로 표시해주는 곳
        • 일반적인 기록 로그, 경고나 권고사항, 에러 등 
    • Project
      • 현재 프로젝트에서 사용할 모든 에셋(Asset)과 패키지(Package)를 표시
      • Asset
        • 프로젝트에서 사용할 모든 형태의 파일(이미지, 음악, 비디오, 3D모션, 애니메이션 등)
        • drag & drop, (menu) Assets > Import New Asstet...
      • Package
        • 패키지 매니저를 통해 추가된 외부 모듈
      • Project View 우측 하단에 아이콘 크기 설정 가능(최소화해서 리스트 뷰로 사용하는 것이 용이)
    • Game
      • 다른 비율의 화면에서 게임이 어떻게 보일지 미리 파악할 수 있도록 게임창 제공
      • 플레이어가 실제로 보게될 화면에는 영향을 주지 않음

플레이 버튼

Unity Editor 상단중앙에 위치한 플레이버튼 (Play, Pause, Step)

  • Play
    • Play 버튼 실행 시
      • 유니티 에디터 플레이모드로 전환
      • Scens 실행 (Scens을 테스트할 때 활용)
    • ex) 큐브(Hierarchy, 게임 오브젝트)를 하나 생성하고 중력의 영향을 받아 아래로 떨어지는 행동(Inspector, 컴포넌트)을 추가하여 실행해보기
      • 게임 오브젝트 생성
        • Hierarchy > Create > 3D > Cube
      • 중력의 영향을 받아 아래로 떨어지는 행동 추가
        • Cube 오브젝트 선택 > Inspector > Add Component > Physics > Rigidbody 컴포넌트 추가
      • 실행 (Play 버튼 클릭하여 플레이모드로 전환)
        • Scens 화면의 Cube 오브젝트 아래로 떨어지는 것 확인
      • 중지 (Pause, 일시정지)
      • 단계별 진행 (Step, 한번에 한프레임씩 진행)
    • Play mode 에서 생성한 게임 오브젝트는 Play mode 종료 시 삭제 됨 (Scens의 중요한 변경 사항은 Play mode를 해제한 상태에서 추가할 것)

트랜스폼 툴 + Toggle Tool Handle Position + 씬 탐색

Unity Editor 좌측 상단에 위치한 트랜스폼 톨

  • Transform Tools 사용해보기 (단축키: q w e r t y)
    • Hand Tool
    • Move Tool (평행이동 툴)
      • 평행이동 툴의 화살표를 드래그하면 해당 방향으로 오브젝트를 평행이동 함
      • X축-빨간색, Y축-초록색, Z축-파란색 
    • Rotate Tool (회전 툴)
      • 회전 축을 드래그하여 축 기준으로 회전
    • Scale Tool
      • 오브젝트의 크기를 조절 가능 (중앙 축을 드래그하면 XY 동시에)
    • Rect Tool
      • 선택한 오브젝트의 직사각형을 편집(가로, 세로)
      • 2D 게임 오브젝트나 UI 게임 오브젝트를 주로 편집할 때 사용
    • Move, Rotate or Scale selected objects (Transform Tool)
      • 3가지 툴을 합친 것
    • Available Custom Editor Tools
      • 사용자 정의 툴

Toggle Tool Handle Position

  • Toggle Tool Handle Position
    • 현재 Scene 창이 표시되는 방식을 표시
      • Pivot (추천) : 오브젝트의 위치를 기준으로 오브젝트 위에 씬 도구들을 표시
      • Center : 오브젝트의 위치와 상관 없이 오브젝트 형태의 중앙점을 기준으로 씬 도구들을 표시
      • Local (추천) : 오브젝트의 좌표를 기준으로 씬 도구들을 표시 (사용)
      • Global : 오브젝트의 좌표와 상관없이 글로벌 좌표계를 기준으로 표시
  • 씬 탐색
    • 씬을 쳐다보고 있는 가상의 카메라를 움직이기
      • 씬 포커스 사용
        • 게임 오브젝트 더블 클릭 시 씬 창의 해당 오브젝트 포커스
        • 마우스 스크롤로 줌인 / 줌아웃 가능
      • 트랜스폼 툴 사용
        • 마우스 휠 스크롤 버튼 누르고 있을 경우 'Hand Tool' 활성화
        • 마우스 오른쪽 버튼 누르고 있을 경우 FPS 게임처럼 씬을 돌아다닐 수 있는 'Flythrough Mode' 활성화
          • WASD로 조작 가능
        • 윈도우(Alt), Mac(옵션키) 누른 채로 마우스 움직이면 '공전 모드' 활성화

기즈모 + 씬 기즈모

  • 기즈모(Gizmo)
    • 씬 편집을 쉽게하기 위해 씬 창에 표시되는 그래픽 도구들
      • 기즈모 드롭 다운 메뉴를 통해 씬 창에 표시되는 것 설정
      • 실제 게임에는 표시되지 않고 개발자의 편의를 위해 씬 창에서만 보임
  • 씬 기즈모
    • 씬 창의 우측 상단 모서리에 위치
      • 씬 카메라의 방향과 시점을 즉시 파악하고, 즉시 변경할 수 있도록 도와줌
      • 씬 기즈모의 원뿔형 암들은 씬 카메라의 방향과 일치함
      • 원뿔형 암들을 클릭하면 즉시 카레마 방향을 해당 방향으로 회전할 수 있음
      • 씬 기즈모 중앙에 있는 큐브는 원근감이 있는 Persp View와 원근감이 없는 Iso View로 즉시 변경 가능

기즈모와 씬 기즈모


씬 애셋 (Scene Asset)

  • 씬 저장 : (윈도우) Ctrl+S, (맥) Command+S
  • 새로운 씬 생성 : (윈도우) Ctrl+N, (맥) Command+N
  • Scene은 Assets 폴더 내에 저장 함
    • Project View에서 확인 및 선택 가능

프로젝트 폴더 구조와 필수 폴더들

  • 생성한 프로젝트 폴더를 열어보면 많은 폴더와 파일들이 존재함
    • 대부분의 폴더와 파일들은 프로젝트를 실행하기 위한 임시 폴더와 파일들
    • 필수 폴더들
      • Assets, Packages, ProjectSettings

유니티 에디터를 위한 3가지 코드 에디터

  • 윈도우 유저는 유니터 에디터 기본 값 그대로 설치 시 비주얼 스튜디오가 함께 설치된다. 다른 코드 에디터가 취향에 맞는 경우에만 전환하면 된다.
  • 맥 유저는 비주얼 스튜디오 코드로 전환하는 것을 적극 추천
  • 코드 에디터와 IDE
    • 유니티에서 코드는 어떠한 텍스트 프로그램으로 작성해도 상관 없음 (메모장 가능)
      • 실제 코드의 처리(컴파일과 빌드)는 유니티 에디터에서 실행되기 때문
    • 편의를 위해 IDE 또는 코드 에디터를 사용
      • 코드 에디터 - 코드를 편집하는데 유용한 강조기능, 자동완성, 여러 확장 기능을 제공하는 개발용 텍스트 편집기
      • IDE - 코드 에디터에 컴파일러와 디버거, 프로젝트 관리 도구 등 개발에 필요한 여러 도구까지 합쳐 제공하는 프로그램
  • 유니티 커뮤니티에서 개발용으로 많이 추천되는 3가지 코드 에디터
    • 비주얼 스튜디오 (Visual Studio)
      • 유니티 개발에서 가장 기본적인 코드 에디터 선택
      • 윈도우 사용자라면 이것을 그대로 사용하는 것을 추천
    • 비주얼 스튜디오 코드 (Visual Studio Code) - 대부분 이거 많이 사용함
      • 다양한 운영체제를 지원하며, 최고로 가볍고 빠름
      • 모든데 갖추어진 IDE가 아닌, 코드 에디터로 별도의 환경 설정이 필요
      • 다양한 오픈소스 확장 플로그인을 통해 마음껏 커스터마이즈 가능
      • 맥 사용자라면 비주얼 스튜디오 코드를 사용하는 것을 추천
    • 젯브레인의 라이더 (JetBrains Rider) - 유료(1년 $139)
      • 다양한 운영체제를 지원하며, 매우 강력한 리팩토링 기능을 제공, 조금 무거움
      • 수없이 많은 단축기능, 자동완성, 자동화 기능을 제공
      • 유니티 공식 지원

유니티 에디터에서 사용할 코드 에디터를 변경하기(Visual Studio → Visual Studio Code)

  • VSCode 설치
  • VSCode를 유니티 에디터에서 사용할 코드 에디터로 등록
    • Unity > (상단 메뉴바) Edit > Preferences > External Tools > External Script Editor의 드롭다운 메뉴에서 사용할 에디터(VSCode)의 경로를 찾아 실행 파일 등록
      • Mac : VSCode.app
      • Windows : VSCode.exe / Code.exe
  • VSCode - 유니티 연동에 필요한 의존 라이브러리 설치
    • , 닷넷코어, 모노
      • 각 링크타고 들어가서 기본 설정 그대로 설치
      • 닷넷코어의 경우 최초 예제 프로젝트를 한번이라도 빌드해야 정상적으로 동작함
        • 명령프롬프트(CMD) 실행 후 아래 커맨드 입력 및 실행
          • (설치확인) > dotnet 
          • (예제 앱 만들기) > dotnet new console -o myApp
          • (예제 앱 디렉터리로 이동) > cd myApp
          • (예제 앱 빌드 실행) > dotnet run
  • VSCode의 C# 플러그인 설치
    • 마지막으로 VSCode를 실행하고 전용 C# 플러그인을 설치 (Ctrl+Shift+X > C# > Install)
    • 여기까지 완료하였다면 이제 유니티에서 C# 스크립트를 만들고 실행할 때 VSCose로 열림

VSCode Extensions > C# > Install


게임 엔진의 원리

게임 오브젝트와 컴포넌트

  • 게임 엔진을 사용하는 이유
    • 도구를 만드는 것이 아닌 도구를 어떻게 사용할 지 정의 (게임 로직) 
    • 이미 만들어진 기반(API, 컴포넌트 등)의 재사용
  • 기존 상속 (inheritance) 시스템의 한계
    • 상속 시스템의 이해
      • 이미 만들어진 클래스를 기반으로 기능을 덧 붙여서 새로운 클래스를 만드는 방법  
      • base class (기반이 되는 부모 클래스)
      • derived class (부모 클래스를 확장해서 만든 자식/확장 클래스)
        • 부모 클래스를 가진 채로 자신 만의 코드를 덧 붙여서 만들어짐
          • 부모 클래스에 작성된 코드를 다시 작성할 필요가 없음
      • ex1) class Monster → class Orc : Monster → class OrcChieftan : Orc
      • ex2) class Character → class Player : Character, class NPC : Character, class Monster : Character 
    • 상속이 항상 잘 동작하는 것은 아님
      • 완벽하게 순수한 base class를 만드는 것은 힘듬
        • A is B
          • 자식 클래스는 선택적으로 상속할 수 없음 (자식 클래스가 필요로 하지 않는 기능도 상속하게 됨)
          • 미래에 사용될 "최소 필수 집합"을 미리 예상하는 것은 힘듬
          • 상속에만 너무 의존하면 오히려 코드를 재사용하기 어려운 상황이 발생
          • 기획자가 프로그래머에게 의존하게 됨
  • 게임 오브젝트-컴포넌트 방식 / 컴포넌트 패턴 / 컴포지션 패턴 (상속 시스템 대안 방법 )
    • A has B,C,D...
      • 비어있는 컨테이너(게임 오브젝트)를 만들어 놓고 선택적으로 기능(컴포넌트)들을 골라서 붙이는 방식
    • 게임 오브젝트
      • 단순 홀더(Holder), 빈 껍데기
      • 컴포넌트를 붙일 수 있음
    • 컴포넌트
      • 미리 만들어진 부품으로 각자 대표 기능을 가짐 (스스로 동작하는 독립 부품)
      • 게임 오브젝트에 붙일 수 있음
      • 유연한 재사용 / 기획자의 프로그래머 의존도가 낮아짐 / 독립성 덕분에 추가와 삭제가 쉬움
      • ex1) Transform Component : 게임 오브젝트에게 위치 크기 회전을 가질 수 있는 기능을 부여
      • ex2) Ridgidbody Componet에 로직(스크립트작성)을 추가하여 기능을 부여
        • 컴포넌트 덕에 바닥부터 만드는 것이 아닌, 이미 존재하는 다양한 부품들에 로직만 추가하여 조립하는 형태

메시지와 브로드캐스팅

  • 컴포넌트 : 자신의 기능을 스스로 내부에서 완성시킨 독립적인 개체
    • 외부의 간섭을 받지 않는 각각의 컴포넌트들이 어떻게 스스로를 동작 시킬까?
  • 컴포넌트의 구조
    • MonoBehaviour를 상속 + 컴포넌트 고유의 기능
    • MonoBehaviour (컴포넌트로서 필요한 필수 기능들이 존재)
      • 컴포넌트로서 게임 오브젝트에 추가될 수 있음
        • 유니티의 통제를 받음
          • 유니티 이벤트 메시지를 감지할 수 있게 됨 
            • 메시지
              • 보내는 쪽은 누가 받는지 신경쓰지 않음
              • 받는 쪽은 누가 보냈는지 신경쓰지 않음
              • 메시지에 명시된 기능을 가지고 있으면 실행, 없으면 무시
            • 브로드캐스팅
              • 메시지를 무차별적으로 많이 보내는 것
                • 유니티는 실행해야 될 기능이 있으면 해당 기능을 메시지에 담아서 게임 오브젝트 전체에 브로드캐스팅을 보냄
              • 이 방법 덕분에 유니티 엔진은 이곳 저곳을 거쳐서 원하는 오브젝트를 겨우 찾아 간 다음, 원하는 기능을 쓰는 수고를 하지 않아도 됨. 그저 메세지를 게임 세상에 뿌리면 됨. 이 때문에 컴포넌트들이 서로 얽혀 있을 필요가 없어 컴포넌트들은 자유롭게 게임 오브젝트에 독립적으로 붙이고 떼어낼 수 있음.
          • 유니티 이벤트 메서드
            • 이름만 맞춰 구현하면, 해당 타이밍에 자동으로 실행
            • Start, Update, OntriggerEnter...
  • 메시지/브래드캐스팅 시스템
    • 복잡한 참조 관계를 끊고 각각의 게임 오브젝트들이 라이프 싸이클을 스스로 관리할 수 있게함
  • 정리
    • 유니티의 모든 컴포넌트는 MonoBehaviour 기반
    • 컴포넌트는 메시지를 받을 수 있음
    • 메시지에 해당하는 기능을 가지고 있으면 실행
    • 이벤트 기반 메서드는 메시지를 통해 "실행되야 할 타이밍에" 자동 실행

C# 프로그래밍 : 기본

변수와 함수의 이해

  • 변수(Variable)
    • 값(Value)이 할당되는 이름 (가리키는)
      • 변수에 할당된 데이터는 런타임(게임 도중)에 얼마든지 접근하여 수정 가능
    • 타입(Type)을 지정할 수 있음 (몇몇 데이터 타입은 특정한 값 서식을 요구)
      • int : 정수, float : 실수, bool : 참거짓, string : 단어나 문장 등...
      • int gold = 9; string itemName = "sword";
type variableName;
type variableName = value;
  •  함수(Function) 혹은 매서드
    • 미리 정해진 동작을 수행하는 코드 묶음
      • 여러번 중복되는 코드를 간결하게 묶어 사용하고 싶을때 마다 불러서 씀
    • y = f(x); 입력을 받아 처리할 수도 있음
    • y = f(x) = x + 5; 
      • y = f( ) = 5; 입력이 없어도 됨
    • 결과를 주지 않거나(void), 결과로 어떤 값을 줄수도 있음
type FunctionName(type inputName) { }

콘솔 출력 + C# 기본 변수

  • 스크립트(C#) 파일 생성
    • Project > Assets > Create > C# Script > 파일명입력(HelloUnity)
  • 콘솔 출력
    • 생성한 스크립트 파일 열기 (더블클릭)
    • Debug.Log("Hello World!"); 콘솔 출력 코드를 삽입. 해당 스크립트를 게임 오브젝트에서 사용 (Play)
      • 콘솔 출력 확인 → Hello World!
      • Clear : 이전 로그 정리
      • Clear on Play : 플레이를 할 때마다 이전 로그 정리
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class HelloUnity : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
    	// 주석, 컴퓨터가 처리하지 않는 라인 - 메모로 사용
        
        /*
            여러줄을 걸친
            주석을
            남길수 있다.
        */
        
        // 콘솔 출력
        Debug.Log("Hello World!"); 
        
        // (윈도우)Ctrl+S 저장

        // 숫자형 변수
        // int 는 소수점이 없는 정수
        int age = 23;
        int money = -1000;
        // floating point - float: 소수점을 가지는 실수: 32비트
        // 소수점 아래 7자리까지만 정확, 그 이상을 넘어가면 근사값으로 처리
        float height = 169.1234567f;
        // double은 float의 두배의 메모리를 사용: 64비트 (성능에 불리함)
        // 소수점 아래 15자리 까지만 정확, 그 이상을 넘어가면 근사값으로 처리
        double pi = 3.14159265359;
        // boolean(bool)은 참(true) 혹은 거짓(false)
        bool isBoy = true;
        bool isGirl = false;
        // 문자형 변수
        // character(char)는 한 문자
        char grade = 'A';
        //string은 문장 (치즈 스트링처럼 문장을 늘여놨다고 해서 스트링)
        string movieTitle = "아바타";

        Debug.Log("내 나이는!: " + age);
        Debug.Log("내가 가진 돈은!: " + money);
        Debug.Log("내 키는!: " + height);
        Debug.Log("원주율은!: " + pi);
        Debug.Log("내 성적은!: " + grade);
        Debug.Log("명작 영화!: " + movieTitle);
        Debug.Log("나는 남자인가? " + isBOy);

        // var는 할당하는 값을 기준으로 타입을 결정
        // variable type name이 너무 길어서 타이핑하기 귀찮아서 var 사용
        var myNme = "R_Myeongun";
        // 눈으로 보기에는 var이지만 컴퓨터 내부에서는 string으로 인식
        var myAge = 23;
        // int myAge = 23;

        Debug.Log("명운의 닉네임: " + myName);
    }
}

사칙 연산 + 복합 연산자

int a = 5;
int b = 7;
// 더하기
int sum = a + b;
Debug.Log(sum);
// 뺴기
sum = a - b;
Debug.Log(sum);
// 곱하기
Debug.Log(a*b);
// 나누기
Debug.Log(a/b);
Debug.Log(b/a);
// 나머지
Debug.Log(a%b);

int i = 0;
Debug.log(i); // 0
i++; // i = i + 1;
Debug.log(i); // 1
Debug.log(i++); // 1출력하고 i값은 2으로 변경
Debug.log(++i); // i값 3으로 변경하고 3출력

// 복합연산자 (귀찮아서 짧게 쓰는 방식)
i += 1; // i = i + 1;
i -= 1; // i = i - 1;
i *= 1; // i = i * 1;
i /= 1; // i = i / 1;
i %= 1; // i = i % 1;

함수 + 스코프

  • 함수 (Function)
    • Assets > Create > C# 스크립트 생성 (HelloFunction)
      • 함수는 반복적인 코드를 미리 만들어서 쓰고 싶을 때마다 불러서 사용
    • ex) 반지름 가져다 주는 함수(GetRadius) 작성해서 사용해보기
void Start ()
{
    float sizeOfCircle = 30f;
    float radius = GetRadius(sizeOfCircle); // 반지름 구하는 함수 사용
    
    Debug.Log("원의 사이즈: " + sizeOfCircle + " 원의 반지름 : " + radius);
}

float GetRadius (float size)
{
    float pi = 3.14f;
    float tmp = size/pi; // 임시 저장용 변수
    
    // Mathf(UnityEngine에 이미 포함)라는 수학 관련 함수 집합의 Square root(제곱근 반환) 함수 사용
    float radius = Mathf.Sqrt(tmp);
    
    return radius; // 결과값 반환
}
  • 스코프
    • 변수의 유효 범위(Scope)가 존재
      • 변수는 유효 범위 내에서 중복적으로 선언해서 사용할 수 없음
        • 위 함수 예제 코드에서 radius가 중복 선언되어 사용됐지만, 각 변수의 scope가 함수여서 문제가 안됨
      • 전역변수 - 전역에서 관측 가능한 변수
      • 지역변수 - 해당 지역에서만 유효한 변수

형변환 + 조건문

  • 형변환 (캐스팅, Casting)
    • 서로 다른 데이터 타입끼리 변환을 통해서 값을 주고 받을 수 있음
      • 자동으로 될 때도 있고, 명시적으로 캐스팅 해야 할 때도 있음
// 형변환 캐스팅
int height = 170;
float heightDetail = 170.3f;

// 자동 형변환 (잃어버리는 정보가 없으면)
heightDetail = height; // 가능
height = heightDetail; // 에러 : 소수점이 없는 변수에 소수점이 있는 변수를 캐스팅하려니 

// 직접 명시해야 하는 경우 (잃어버리는 정보가 있으면)
height = (int)heightDetail; // 소수점이 없는 int를 명시해줌 : 170.3f에서 .3f이 짤리고 170이 height에 대입
  • 조건문 (if)
    • 조건에 따라서 처리가 필요할 경우
// 조건문 if문
int age = 5;

if(age == 5) {} // true나 false가 명확하게 지정이 되는 조건이 들어가야 함
else if(age < 5) {} // if에서 지정한 조건이 'true'가 아닐 경우 else if 조건 순차적으로 확인
elft if(age > 5) {} // age가 5가 아니고, 5보다 크지 않고, 5보다 작을 경우
else {} // 위 조건이 모두 'true'가 아닐 경우

// a == b (a와 b가 같으면 'true')
// a != b (a와 b가 다르면 'true')
// a < b (a가 b보다 작으면 'true')
// a > b (a가 b보다 크면 'true)
// a <= b (a가 b와 같거나 작으면 'true')
// a >= b (a가 b와 같거나 크면 'true)
// a >= 1 || a <= 5 ('||'는 다중 조건에서 OR 연산자로 사용, a가 1이상이거나 5이하이면 'true')

bool isBoy = true;
if(isBoy) {} // isBoy가 'true'일 경우
if(!isBoy) {} // isBoy가 'false'일 경우

분기문 + 반복문

  • 분기문 (Switch)
    • switch를 통해 작성한 코드는 if/else if/else를 통해 똑같이 작성할 수 있다.
      • 다만 switch 문을 통해 작성하면 보다 작업이 간편하다.
    • 'break'를 만나야 분기문 코드가 종료된다.
int year = 2012;

switch (year)
{
	case 2012:
    	Debug.Log("레미제라블");
        break;
        
	case 2016:
    	Debug.Log("곡성");
        break;
        
	case 2017:
    	Debug.Log("트랜스포터5");
        break;
        
    default:
    	Debug.Log("년도가 해당사항 없음");
        break;
}
  •  반복문 (루프문, Loop)
// for 문
// 초기화; 조건; 업데이트
// 순번을 계속 넘김
// i > 0,1,2,3,4,5,6,7,8,9
for(int i=0; i<10; i++)
{
    Debug.Log("현재 순번: " + i);
}
Debug.Log("루프 끝");

// while 문
// 조건이 'true' 경우 반복
bool isShot = false;
int j = 0;
while(isShot == false)
{	
    if(j==3)
    {
    	isShot == true;
    }
    else {}
}

// do while 문
// 조건에 상관 없이 do를 최초 한번은 실행
// 조건이 'true' 경우 반복
do
{
    Debug.Log("Do-While");
}while(isShot == false);

배열

  • 값을 연속적으로 할당하는 공간
// 여러개의 값을 하나의 변수로 다루게 해준다
// '[]'를 통해 배열임을 명시해준다.
// ex) 10명의 학생 점수를 저장하는 배열, 0번째 방부터 시작
int[] scores = new int[10];
// scores[0][1][2][3][4][5][6][7][8][9]
scores[0] = 89;
scores[1] = 22;
scores[2] = 76;
scores[3] = 57;
scores[4] = 48;
scores[5] = 90;
scores[6] = 11;
scores[7] = 66;
scores[8] = 42;
scores[9] = 10;
// Array index is out of index
scores[10] = 30;

Debug.Log(scorea[3]); // 57

for(int i = 0; i < 10; i++)
{
    Debug.Log("학생 " + i + "번째의 점수: " + scores[i]);
}

// 배열 방을 새로 늘리고 싶을 때
scores = new int[20]; // 기존 배열 방(값포함)들은 다 날라감

클래스와 오브젝트

컴퓨터는 사람의 사고 방식을 반영하는 기계가 되어야 한다.
- 스티븐잡스 -
  • OOP (Object-oriented Programming)
    • 객체지향프로그래밍은 모든 프로그래밍의 기반이 되는 사상
      • OOP를 이해한다면, 현대 프로그래밍 언어를 이해하는데 장벽이 낮아질 것임
      • OOP를 이해하는데 가장 큰 적은 컴퓨터(기계)처럼 사고하여 이해하려고 애쓴다는 것이다.
    • OOP는 고대 그리스에서 왔음 (실제 클래스와 오브젝트라는 개념은 고대 그리스의 이데아에서 옴)
      • 이데아 - 레플리카
        • 이상적인 세계(이데아, 추상적인 완벽한 원본, CLASS)에 존재하는 책상을 본따서 현실에 구체화시켜 책상을 만듬(레플리카, 복제본, OBJECT)
        • 이데아 (이상적인 세계) → CLASS
        • 레플리카 (이데아를 실존하는 세계에 구현) → OBJECT
목수가 책상을 만들 때에는 목수의 머릿속에는 가장 이상적이고 완벽한 책상이 하나 존재한다. 목수가 현실의 책상을 만들 때에는 그 이상적인 책상을 본따서 만든다.
- 플라톤 -
  • 클래스 (CLASS)
    • 이상적인 세계에 존재하는 단 하나의 기준 (원형) (사람의 머릿속에 추상적)
      • 실제로는 존재하지 않는다.
      • 가장 중요한 특성만 개략적으로 알려준다.
      • 구체적인 수치가 없다.
  • 오브젝트 (OBJECT)
    • 실존하는 세계에 클래스를 원형으로 찍어낸 존재
      • 같은 원형 클래스를 갖고 있지만, 각각은 서로 독립적이고 구별되는 존재
        • 자기 자신을 스스로 챙길 수 있다.
        • 하나의 온전한 단위로 존재한다. (사람=클래스, 명우니=오브젝트)
        • 실존하는 세상에 산다.
        • 하나의 원본에서 파생되어도, 서로 구분 가능하다.
public class HelloCLass : MonoBehaviour
{
    void Start ()
    {
    	// Animal 틀(Class)을 이용해 서로 다른 오브젝트를 생성
        // 각각의 오브젝트는 서로 독립적이고 구분되어 사용됨
    	Animal jack = new Animal();
        jack.name = "JACK";
        jack.sount = "Bark";
        jack.weight = 4.5;
        
        Animal nate = new Animal();
        nate.name = "NATE";
        nate.sount = "Nyaa";
        nate.weight = 1.2;
        
        Animal annie = new Animal();
        annie.name = "ANNIE";
        annie.sount = "Wee";
        annie.weight = 0.8;
        
        // jact이 갖고 있는 정보를 nate에 덮어씌우는 것이 아닌,
        // jact이 가리키는 Animal의 주소를 nate도 가리키게됨
        // Animal jack = new Animal(); 당시 생성한 Animal의 주소를 공유함        
        nate = jact;
        Debug.Log(nate.name); // "JACK"
        Debug.Log(jact.name); // "JACK"
        nate.name = "JIMMY";
        // 하나의 실제 존재하는 오브젝트 Animal을 2개의 변수 jact, nate가 가리키기 때문에 동일한 값 출력
        Debug.Log(nate.name); // "JIMMY"
        Debug.Log(jact.name); // "JIMMY"               
    }
}

// Animal 이라는 새로운 틀을 만듬
public class Animal
{
    public string name; // 이름, 외부에서 접근 가능하도록 public scope 설정
    public string sound; // 소리
    public float weight; // 몸무게
}
  • nate가 jact이 가리키는 오브젝트를 따라 가리킴에 따라 기존 오브젝트는 미아가 됨
    • 미아(어떠한 변수도 가리키지 않음)가 된 오브젝트는 그 누구도 접근할 수 없게 됨
    • 가비지컬렉션
      • C#이나 JAVA같은 언어는 미아가 된 오브젝트(메모리)를 주기적으로 갈아 엎어서 없애버림
  • Call by Reference
    • 가져와서 쓴다. 변수는 실존하는 오브젝트를 가리키는 참고자 (Referance)
    • 유니티는 어떠한 기능들을 가진 컴포넌트를 조립한 다음, 미리 만들어진 컴포넌트를 가져와서 쓰는 개념
      • 변수를 통해 원하는 컴포넌트를 가져와서 해당 컴포넌트의 내장 기능을 사용하면 실존하는 오브젝트가 사용된다는 개념

게임 제작 : 소코반 (창고지기)

  • 간단한 게임 제작해보기, 소코반 (지정된 장소로 상자들을 전부 밀면 승리하는 게임)
    • 트랜스폼, 컴포넌트를 어떻게 가져오는지
    • 여러가지 컴포넌트들, 회전, 위치변경 등 물리처리
    • 게임을 빌드하는 법을 익힘으로 실제 게임을 완성해보기

초기 씬 구성

  • 새 프로젝트 생성 (3D, Sokovan)
  • 게임 오브젝트 생성 (Plane, Player)
    • Plane (맵 평형 바닥)
      • Hierarchy > Create > 3D > Plane (맵 평형 바닥)
    • Player (공)
      • Hierarchy > Create > 3D > Sphere > (이름변경) Player
  • 오브젝트에 컴포넌트 추가
    • Plane
      • Material (물체 표면의 컬러를 결정) 추가
        • Project > Main > Create > Material (물체 표면의 컬러를 결정) > (이름변경, F2) Plane
          • Inspector > Plane > Main Maps > Albedo > 색 지정
          • Smoothness > 낮게 설정 (반사율 높으면 거울 처럼, 낮으면 플라스틱 처럼 보임)
        • Scene > Plane에 drag&drop
    • Player
      • Plane과 Playser가 곂치지 않도록 Plane의 Y 값 조정
      • (Hierarchy) Plane > (Inspector)Transform Position Y > '-0.5'
      • 물리처리 기능 추가 (중력의 영향을 받고 힘을 줄 수 있게)
        • Player > (Inspector) Add Component > Physics > Rigidbody (물리기능추가)
          • Rigidbody에 힘을 주라라는 스크립트를 추가
            • Project > Assets > (C# 스크립트) Player 생성하여 아래 코드 작성 후 Player 오브젝트에 작성한 스크립트(컴포넌트)를 drag&drop으로 추가
              • public float speed = 10f;
              • public Rigidbody playerRigidbody;
            • (Inspector) Rigidbody 컴포넌트 Player(스크립트) 컴포넌트의 playerRigidbody에 drag&drop으로 추가
              • Player 컴포넌트에 AddForce 기능 추가 테스트 (void Start() 함수 안에 작성)
                • playerRigidbody.AddForce(0,1000,0);
                • Play하여 동작 테스트
    • (Inspector) Sphere Collider
      • 물체의 표면에 물리적인 표면을 만들어 줌
      • Plane/Player 둘다 적용되어 있어서 Player가 공중에서 떨어져도 Plane 아래로 떨어지지 않음
  • 접근지시자
    • public 외부 접근 가능, Inspector 에서 접근하여 편집 가능
    • private (기본, 명시하지 않는 경우) 외부에서 접근 불가
  • 카멜명명법 (협의된 약속)
    • 클래스 이름 첫 글자는 대문자
    • 함수 이름 첫 글자는 대문자
    • 변수 이름 첫 글자는 소문자
    • 단어와 단어 사이는 대문자로 구분

플레이어 조작

  • 유니티는 메시지를 사용
    • Start ()
      • 게임이 처음 시작되었을때 한번 실행
    • Update ()
      • 화면이 한번 깜빡일때 한번 실행
        • 게임이 지속적으로 갱신되게 함
      • 테스트 : Debug.Log("화면이 한번 깜빡임!");
  • Player 오브젝트가 유저 입력(WASD)을 받아 움직이도록 처리
void Update()
{
    // 1초에 대략 60번 단, 사양에 따라 다름
    // 몇 번 실행되는지는 정해져 있지 않음
    // 유저 입력 받기
    if(Input.GetKey(KeyCode.W)) // w 전진
        playerRigidbody.AddForce(0,0,speed);
    if(Input.GetKey(KeyCode.A)) // A 좌측
        playerRigidbody.AddForce(-speed,0,0);
    if(Input.GetKey(KeyCode.S)) // S 후진
        playerRigidbody.AddForce(0,0,-speed);
    if(Input.GetKey(KeyCode.D)) // D 우측
        playerRigidbody.AddForce(speed, 0,0);
}
  • Player 오브젝트가 유저 입력(유니티 제공 함수 사용)을 받아 움직이도록 처리
public class Player : MonoBehaviour
{
    public float speed = 10f;
    // 유니티 에디터 Inspector에서 다중 사용자가 수정하다가
    // 문제가 생길 수 있음(왠만하면 public이 아닌 private로 할 것)
    private Rigidbody playerRigidbody;

    void Start()
    {
        // GetComponent는 <> 안에 있는 기능을 게임 오브젝트 안에서 찾아줌
        // Inspector에서 drag&drop 하는 것보다 더 관리가 쉬움(문제 방지)
        playerRigidbody = GetComponent<Rigidbody>();
    }

    void Update()
    {
        // "Horizontal" : 키보드(+조이스틱) 수평 방향에 대응되는 키가 맵핑되있음
        // A <-       -> D : 키 값을 수정할 필요가 없음
        // -1.0   0   +1.0 : -1 ~ +1 값을 받음 (조이스틱을 살살 미는 정도를 알기 위해)
        float inputX = Input.GetAxis("Horizontal");
        
        // "Vertical" : 키보드(+조이스틱) 수직 방향에 대응되는 키가 맵핑되있음
        // S  v       ^  W  
        // -1.0   0   +1.0
        float inputZ = Input.GetAxis("Vertical");

        // playerRigidbody에 힘(AddForce)을 넣어 줌 (관성 +힘에 의해 속도가 정해짐)
        // playerRigidbody.AddForce(inputX * speed, 0, inputZ);

        // playerRigidbody가 중력에 의해 떨어지는 속도
        float fallSpeed = playerRigidbody.velocity.y;

        // Vector3 = x,y,z 값을 가지는 집합
        Vector3 velocity = new Vector3(inputX, 0, inputZ); //x,y,z 값
        // (inputX * speed, fallSpeed * speed, inputZ * speed)
        velocity = velocity * speed;
        velocity.y = fallSpeed;
        // playerRigidbody에 속도(velocity) 지정
        playerRigidbody.velocity = velocity;
    }
}

레벨 디자인 (맵 디자인)

  • 맵 디자인하기
    • Cube 오브젝트 생성 (벽으로 사용, 이름 Wall로 변경)
      • Scale X(5) Y(1) Z(0)
      • Gizmos -> Y축 정렬
        • 평행이동 툴을 선택한 후 Windows(Ctrl) / Mac(Command)를 누른 채 마우스로 드래그하여 Wall의 좌표를 옮기면 1씩 좌표 값이 옮겨 짐
        • Position X(-2.5) Y(0) Z(4.5)로 이동 후 이름 "HorizontalWall"로 변경
      • "HorizontalWall" 오브젝트 복사하여 "VerticallWall" 생성
    • 위 방법 반복하여 레벨 디자인 배치 완성하기
    • 여러개의 "Wall" 오브젝트로 번잡해진 Hirarchy 창을 정리하기 위해 하나의 게임 오브젝트로 묶어주기
      • Hierarchy > Create > Create Empty(빈 게임 오브젝트 생성) > "Level"
        • Position X(0) Y(0) Z(0)
          • Wall 오브젝트들 Shift키 누른 상태로 멀티클릭하여 Level 오브젝트 하위(자식)로 옮기기
    • Play 버튼으로 생성한 Level(Map) 오브젝트 테스트하기
      • Player를 조작(wasd)하여 계획대로 벽을 못 뚫고 지나가는지 테스트
        • Wall(Cube) 오브젝트에는 이미 Collider 기능을 갖고 있어 물체의 물리적인 표면을 만들어줘서 물체가 뚫고 지나가지 못함

레벨 (맵) 디자인

  • 아이템 박스 만들기 (옮길 박스)
    • Cube 오브젝트 생성 > 이름 변경 "ItemBox"
      • Transform > Reset
      • 사이즈 및 좌표 설정
        • Position X(-1.5) Y(0) Z(-1.5) 
        • Scale X(0.9) Y(0.9) Z(0.9)
      • 색상 넣기
        • Assets > Create > Material > 이름 변경 "ItemBox"
          • Albedo > 색상 선택 (주황색)
          • Smmothness > 0 (값이 크면 반들반들해져보임)
        • 생성한 Material Drag&Drop으로 ItemBox에 적용
      • 물리능력 적용
        • Add COmponent > Physics > Rigidbody (물리기능 추가)
        • 아이템박스가 밀릴 때 회전하지 않게 하기
          • Rigidbody > Constraints
            • Freeze Position : Y축 선택(Y축 잠금)
            • Freeze Rotation : XYZ축 선택(회전 못하도록 잠금)
          • Player 오브젝트도 'Freeze Position - Y축 잠금' 설정
    • Prefab으로 아이템 박스 오브젝트 복사하기
      • ItemBox 오브젝트를 Drag&Drop으로 Assets에 옮김
      • Assets에 생성된 Prefab을 Hierarchy 창에 Drag&Drop으로 옮김
      • 총 3개의 아이템 박스 오브젝트를 만듬(기존1 Prefab으로 2개 생성)
  • 골인 지점 만들기
    • Cube 오브젝트 생성 > 이름 변경 "EndPoint"
    • 사이즈 및 좌표 설정
      • Position > X(2.5) Y(0) Z(3.5)
      • Rotation > X(60) Y(60) Z(60)
      • Scale > X(0.5) Y(0.5) Z(0.5)
    • 색성 넣기
      • Assets > Create > Material > 이름 변경 "EndPoint"
      • Drag&Drop으로 EndPoint 오브젝트에 적용
    • Prefab으로 골인 지점(EndPoint) 오브젝트 복사하기
      • 총 3개의 골인 지점 오브젝트를 만듬(기존1 Prefab으로 2개 생성)
    • Player가 통과 가능하도록 설정
      • EndPoint 오브젝트 > Box Collider > Is Trigger > 체크 > Apply (Prefab으로 생성한 다른 골인 지점 오브젝트들도 변경사항 함께 적용 됨)
  • Player 색상 적용하기
    • Assets > Create > Material > "Player" > 색상 설정 / Smoothness 0 > 오브젝트에 적용 
  • Main Camera
    • Claer Flags - 아무것도 비추어지지 않는 영역을 어떻게 표현할 것인가
      • Solid Color > Brackground > 색상 지정


오브젝트 회전 + 시간 간격

  • EndPoint가 회전하도록 만들기 (60도씩)
    • Assets > Create > C# Script > Rotator
// Update는 대략 1초에 60번 실행
void Update()
{
    // 소문자 'transform'은 오브젝트 자기 자신의 'Transform' 컴포넌트를 참조함
    // XYZ축 60도 회전
    // Time.deltaTime 은 화면이 한번 깜빡이는 시간 (한 프레임의 시간)
    // 화면을 60번 깜빡이면 (초당 60프레임) 1/60
    // 60/60 * 60 = 1초에 60도 회전
    transform.Rotate(60 * Time.deltaTime,60 * Time.deltaTime ,60 * Time.deltaTime); 
}
  • 모든 게임 오브젝트는 Transform 컴포넌트를 가지고 있음
    • 자기 자신의 Transform을 스크립트에서 사용하고 싶으면 transform(소문자)으로 참조하여 사용할 수 있음
  • Time.deltaTime
    • 시간 간격이 들어옴

충돌처리

  • Tag 사용하여 충돌처리
    • Tag는 게임 오브젝트를 분류하여 식별하는데 사용
    • 'EndPoint' > Inspector > Tag > Add Tag > Tags + > 'EndPoint' > Save
      • Tag > 'EndPoint' 선택
      • 다른 Prefab으로 만든 EndPoint 오브젝트에도 적용되도록 'Apply'
    • ItemBox가 너무 쉽게 밀리니 마찰력을 추가
      • ItemBox > Inspector > Rigidbody > Drag > '10'
    • ItemBox가 충돌을 감지할 수 있는 기능을 추가
      • ItemBox > Inspector > Add Component > "ItemBox (New Script)"
public class ItemBox : MonoBehaviour
{

    // 아이템박스 Renderer를 담을 변수 선언
    private Renderer myRenderer;
    // 컬러 색상을 담을 변수 선언
    public Color touchColor; // public이어서 Unity Inspector에서 편집 가능 (파란색으로 설정)
    private Color originalColor; // 기존 색상 정보를 담을 변수 선언

    void Start()
    {
        // 게임이 시작됐을 때 나 자신의 Renderer를 가져오기
        myRenderer = GetComponent<Renderer>();
        // 기존 색상 정보 담기
        originalColor = myRenderer.material.color;
    }

    // 오브젝트가 Trigger(뚫고 지나갈 수 있는 오브젝트)인 Collider와 충돌했을 때 유니티가 자동으로 호출
    // Enter 충돌을 한 그 순간 호출
    void OnTriggerEnter(Collider other)
    {
        // other(충돌한 Collider 오브젝트)의 Tag가 "EndPoint" 인 경우
        if(other.tag == "EndPoint")
        {
            // 아이템박스의 Renderer 컴포넌트의 materials 색상 변경하기
            myRenderer.material.color = touchColor;
        }
    }
    
    // Stay 붙어있는 동안 호출
    void OnTriggerStay(Collider other)
    {
        if(other.tag == "EndPoint")
        {
            myRenderer.material.color = touchColor;
        }
    }

    // Exit 충돌했다가 떼어질 떄 호출
    void OnTriggerExit(Collider other)
    {
        if(other.tag == "EndPoint")
        {
            // 색상 기존 색상으로 다시 변경하기
            myRenderer.material.color = originalColor;
        }
    }
}

게임 매니저와 승리 조건

  • ItemBox 스크립트에 새로운 변수(isOveraped) 선언 (ItemBox가 EndPoint에 충돌 했는 지 체크)
public bool isOveraped = false;
  • Trigger와 충돌했을 경우 변수 값 변경
// Enter & Stay 
isOveraped = true;
// Exit
isOveraped = false;
  • 모든 ItemBox(3개)가 EndPoint에 충돌했을 때 승리했다는 로직을 추가
    • GameManager 스크립트 생성
      • Assets > Create > C# Script > GameManager
    • GameManager 스크립트를 적용할 Empty GameManager 오브젝트 생성
      • Hierarchy > Create Empty > GameManager
    • 생성한 GameManager 오브젝트에 GameManager 스크립트 적용 (Drag & Drop)
    • 스크립트 코드 작성
public class GameManager : MonoBehaviour
{
    // 모든 ItemBox(3) 정보를 담을 배열 생성
    // GameManager 오브젝트 > Inspector > itemBoxes > Size 설정(3)
    // 추가된 3개의 Element에 ItemBox 3개를 Drag & Drop으로 넣어줌
    public ItemBox[] itemBoxes;

    // 게임이 종료됐는지 알려주는 변수 선언
    public bool isGameOver;

    void Start()
    {
        // 게임 시작 시 isGameOver 초기값 설정
        isGameOver = false;
    }

    void Update()
    {
        // 게임이 종료(승리)되었을 경우 함수(Update) 종료(return)
        if(isGameOver == true)
        {
            return;
        }

        // ItemBox가 EntPoint에 몇개 도달했는지 정보를 담을 변수
        int count = 0;
        
        // ItemBox 오브젝트가 EndPoint에 도달했는지 체크
        for(int i=0; i<3; i++)
        {
            if(itemBoxes[i].isOveraped == true)
            {
                count++;
            }
        }
        
        // ItemBox 전부(3개)가 EndPoint를 모두 도달했을 경우
        if(count >= 3)
        {
            Debug.Log("승리");
            isGameOver = true;
        }        
    }
}

승리 UI 조건

  • UI 오브젝트 추가
    • Hierarchy (오른쪽 클릭) > UI > Text
      • Canvas > Text (이름변경 "WinUI")
    • Canvas 게임 세상과 1:1 비율로 대응되게 생성됨
  • UI 배치하기
    • Text 클릭 > Scene (2D) > 이동 > 마우스로 배치
    • Anchor Presets 사용
      • 자주 사용하는 배치 UI를 제공, 이를 선택하여 설정 가능 (Alt키를 누르면 Snapping 옵션이 활성화되어 배치됨) 

Anchor Presets 사용하기

  • 내용 입력 및 UI 설정
    • Text : "You Win!"
    • Font Size : 81
    • Paragraph
      • Horizontal Overflow : Overflow (글이 글상자를 넘어가면 넘치게 해줌)
      • Vertical Overflow : Overflow
    • Alignment : 중앙 / 중앙 정렬
    • Color : 색상 변경 (초록색)
    • 그림차 추가
      • Add Component > Shadow
    • 보유한 폰트 파일로 변경하고 싶을 경우
      • Assets 에 폰트파일 Drag&Drop > 오브젝트 컴포넌트 Font에 Drag&Drop
  • UI 숨겨놨다가 게임 승리 시 나타내기
    • Inspector > WInUI > (좌측체크박스) 해제
// WinUI 오브젝트를 가져올 변수 선언
// 게임매니저 오브젝트 스크립트 컴포넌트에 추가된 winUI에 WinUI 오브젝트 Drag & Drop으로 넣어줌
public GameObject winUI;

// 게임 승리시 승리 UI 오브젝트인 WinUI 오브젝트 표시
winUI.SetActive(true);
  • 게임 재시작 기능 추가하기
    • 게임 세상(Scene) 최종 출력물에 등록하기
      • File > Build Settings
        • Scenes In Build에 게임 세상 추가하기 : (Assets) Main 파일
    • 스페이스바를 누르면 게임 재시작이 가능하도록 하기
      • GameManager 스크립트에 로직 코드 작성
// Scene을 관리할 수 있는 기능들을 사용하기 위해 using 선언
using UnityEngine.SceneManagement;

// Update() 함수에 아래 내용추가
// GetKeyDown : 키보드를 누르는 한 순간만 호출(GetKey는 누르고 있는 동안)
// 스페이스바를 누를 경우 게임 재시작
if(Input.GetKeyDown(KeyCode.Space))
{
    // Scene의 이름이나 순번(Build Settings > Scenes In Build에 추가한)을 넣어주면 해당 Scene으로 점프함
    // 자기 자신의 Scene을 호출하면 게임 재시작
    SceneManager.LoadScene("Main");
}
  • 게임 종료 시 Player 못 움직이게 하기 (Player 스크립트 수정)
// 게임매니저를 가져옴
// Player 컴포넌트 Player 스크립트의 Game Manager 변수에 GameManager 오브젝트 적용 (Drag&Drop)
public GameManager gameManager;

// Update() 함수에 추가
// 게임 종료시 업데이트 함수 종료
if(gameManager.isGameOver == true)
{
    return;
}

배경 음악 추가하기

  • 음악파일 Assets에 추가
  • Hierarchy에 빈 오브젝트 생성 및 오디오 컴포넌트 추가
    • Create Empty > 이름 변경 "BGM"
    • Add Component > Audio Source
      • Assets에 추가한 음악파일 AudioClip에 추가 (Drag&Drop)
      • Play On Awake 체크 (게임 시작 시 음악 재생)
      • Loop 체크 (반복 재생)

최종 빌드

  • File > Build Settings (Scene In Build에 만든 게임 세상(Scene > Main)이 잘 포함되어 있는지 확인)
    • Platform 지정
    • Build And Run
      • 프로젝트가 아닌 경로에 파일 저장 (꼬일 수 있음)

최종 빌드되어 생성된 파일들
게임 실행 로드 화면
게임 시작시
게임 승리시 "You Win!" UI 출력 / Player 못 움직임

 

반응형