
[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 설치 (나머지는 필요할 때 설치)
- 추가 컴포넌트 설정
- Unity 2019.1 버전 다운로드 (강의 기준 버전, Officaial Releases 에서 찾아서 받으면 됨)
새 프로젝트 생성 + 인터페이스 살펴보기
- 새 프로젝트 생성
- Projects - New
- Project name
- Unity Version (설치된 Unity Editor 버전이 2개 이상일 경우)
- Location
- Template (미리 셋업된 설정을 사용, 프로젝트 도중 변경 가능)
- Projects - New
- 인터페이스 초기 세팅
- (menu) Window > Layout - 2 by 3로 설정
- (menu) Window > General > Console 추가 (Ctrl+Shift+C)
- 인터페이스 설명 (왼쪽 상단부터 시계 방향으로)
- Scene
- Unity는 하나의 게임 월드를 Scene이라는 단위로 관리
- 1 Scene : 1 (게임월드, 게임맵, 게임레벨에 대응)
- 현재 활성화된 Scene을 시각적으로 편집하는 창
- Unity는 하나의 게임 월드를 Scene이라는 단위로 관리
- Hierarchy
- 계층, 현재 Scene에 존재하는 모든 게임 오브젝트를 리스트로 표시
- Inspector
- 현재 선택한 게임 오브젝트나 에셋 정보를 표시
- 게임 오브젝트 : 게임 세상 속에 존재하는 물건이나 사물
- 컴포넌트 : 해당 게임 오브젝트가 실제로 동작할 수 있는 기능을 부여하는 부품
- Console
- 유니티 에디터가 개발자에게 유용한 정보를 텍스트로 표시해주는 곳
- 일반적인 기록 로그, 경고나 권고사항, 에러 등
- 유니티 에디터가 개발자에게 유용한 정보를 텍스트로 표시해주는 곳
- Project
- 현재 프로젝트에서 사용할 모든 에셋(Asset)과 패키지(Package)를 표시
- Asset
- 프로젝트에서 사용할 모든 형태의 파일(이미지, 음악, 비디오, 3D모션, 애니메이션 등)
- drag & drop, (menu) Assets > Import New Asstet...
- Package
- 패키지 매니저를 통해 추가된 외부 모듈
- Project View 우측 하단에 아이콘 크기 설정 가능(최소화해서 리스트 뷰로 사용하는 것이 용이)
- Game
- 다른 비율의 화면에서 게임이 어떻게 보일지 미리 파악할 수 있도록 게임창 제공
- 플레이어가 실제로 보게될 화면에는 영향을 주지 않음
- Scene
플레이 버튼
- 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를 해제한 상태에서 추가할 것)
- Play 버튼 실행 시
트랜스폼 툴 + Toggle Tool Handle Position + 씬 탐색
- 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
- 현재 Scene 창이 표시되는 방식을 표시
- Pivot (추천) : 오브젝트의 위치를 기준으로 오브젝트 위에 씬 도구들을 표시
- Center : 오브젝트의 위치와 상관 없이 오브젝트 형태의 중앙점을 기준으로 씬 도구들을 표시
- Local (추천) : 오브젝트의 좌표를 기준으로 씬 도구들을 표시 (사용)
- Global : 오브젝트의 좌표와 상관없이 글로벌 좌표계를 기준으로 표시
- 현재 Scene 창이 표시되는 방식을 표시
- 씬 탐색
- 씬을 쳐다보고 있는 가상의 카메라를 움직이기
- 씬 포커스 사용
- 게임 오브젝트 더블 클릭 시 씬 창의 해당 오브젝트 포커스
- 마우스 스크롤로 줌인 / 줌아웃 가능
- 트랜스폼 툴 사용
- 마우스 휠 스크롤 버튼 누르고 있을 경우 '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 → Visual Studio Code)
- VSCode 설치
- 공식 사이트에서 다운로드하여 기본 설정 그대로 설치
- VSCode를 유니티 에디터에서 사용할 코드 에디터로 등록
- Unity > (상단 메뉴바) Edit > Preferences > External Tools > External Script Editor의 드롭다운 메뉴에서 사용할 에디터(VSCode)의 경로를 찾아 실행 파일 등록
- Mac : VSCode.app
- Windows : VSCode.exe / Code.exe
- Unity > (상단 메뉴바) Edit > Preferences > External Tools > External Script Editor의 드롭다운 메뉴에서 사용할 에디터(VSCode)의 경로를 찾아 실행 파일 등록
- VSCode - 유니티 연동에 필요한 의존 라이브러리 설치
- VSCode의 C# 플러그인 설치
- 마지막으로 VSCode를 실행하고 전용 C# 플러그인을 설치 (Ctrl+Shift+X > C# > Install)
- 여기까지 완료하였다면 이제 유니티에서 C# 스크립트를 만들고 실행할 때 VSCose로 열림
게임 엔진의 원리
게임 오브젝트와 컴포넌트
- 게임 엔진을 사용하는 이유
- 도구를 만드는 것이 아닌 도구를 어떻게 사용할 지 정의 (게임 로직)
- 이미 만들어진 기반(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 is B
- 완벽하게 순수한 base class를 만드는 것은 힘듬
- 상속 시스템의 이해
- 게임 오브젝트-컴포넌트 방식 / 컴포넌트 패턴 / 컴포지션 패턴 (상속 시스템 대안 방법 )
- A has B,C,D...
- 비어있는 컨테이너(게임 오브젝트)를 만들어 놓고 선택적으로 기능(컴포넌트)들을 골라서 붙이는 방식
- 게임 오브젝트
- 단순 홀더(Holder), 빈 껍데기
- 컴포넌트를 붙일 수 있음
- 컴포넌트
- 미리 만들어진 부품으로 각자 대표 기능을 가짐 (스스로 동작하는 독립 부품)
- 게임 오브젝트에 붙일 수 있음
- 유연한 재사용 / 기획자의 프로그래머 의존도가 낮아짐 / 독립성 덕분에 추가와 삭제가 쉬움
- ex1) Transform Component : 게임 오브젝트에게 위치 크기 회전을 가질 수 있는 기능을 부여
- ex2) Ridgidbody Componet에 로직(스크립트작성)을 추가하여 기능을 부여
- 컴포넌트 덕에 바닥부터 만드는 것이 아닌, 이미 존재하는 다양한 부품들에 로직만 추가하여 조립하는 형태
- A has B,C,D...
메시지와 브로드캐스팅
- 컴포넌트 : 자신의 기능을 스스로 내부에서 완성시킨 독립적인 개체
- 외부의 간섭을 받지 않는 각각의 컴포넌트들이 어떻게 스스로를 동작 시킬까?
- 컴포넌트의 구조
- MonoBehaviour를 상속 + 컴포넌트 고유의 기능
- MonoBehaviour (컴포넌트로서 필요한 필수 기능들이 존재)
- 컴포넌트로서 게임 오브젝트에 추가될 수 있음
- 유니티의 통제를 받음
- 유니티 이벤트 메시지를 감지할 수 있게 됨
- 메시지
- 보내는 쪽은 누가 받는지 신경쓰지 않음
- 받는 쪽은 누가 보냈는지 신경쓰지 않음
- 메시지에 명시된 기능을 가지고 있으면 실행, 없으면 무시
- 브로드캐스팅
- 메시지를 무차별적으로 많이 보내는 것
- 유니티는 실행해야 될 기능이 있으면 해당 기능을 메시지에 담아서 게임 오브젝트 전체에 브로드캐스팅을 보냄
- 이 방법 덕분에 유니티 엔진은 이곳 저곳을 거쳐서 원하는 오브젝트를 겨우 찾아 간 다음, 원하는 기능을 쓰는 수고를 하지 않아도 됨. 그저 메세지를 게임 세상에 뿌리면 됨. 이 때문에 컴포넌트들이 서로 얽혀 있을 필요가 없어 컴포넌트들은 자유롭게 게임 오브젝트에 독립적으로 붙이고 떼어낼 수 있음.
- 메시지를 무차별적으로 많이 보내는 것
- 메시지
- 유니티 이벤트 메서드
- 이름만 맞춰 구현하면, 해당 타이밍에 자동으로 실행
- Start, Update, OntriggerEnter...
- 유니티 이벤트 메시지를 감지할 수 있게 됨
- 유니티의 통제를 받음
- 컴포넌트로서 게임 오브젝트에 추가될 수 있음
- 메시지/브래드캐스팅 시스템
- 복잡한 참조 관계를 끊고 각각의 게임 오브젝트들이 라이프 싸이클을 스스로 관리할 수 있게함
- 정리
- 유니티의 모든 컴포넌트는 MonoBehaviour 기반
- 컴포넌트는 메시지를 받을 수 있음
- 메시지에 해당하는 기능을 가지고 있으면 실행
- 이벤트 기반 메서드는 메시지를 통해 "실행되야 할 타이밍에" 자동 실행
C# 프로그래밍 : 기본
변수와 함수의 이해
- 변수(Variable)
- 값(Value)이 할당되는 이름 (가리키는)
- 변수에 할당된 데이터는 런타임(게임 도중)에 얼마든지 접근하여 수정 가능
- 타입(Type)을 지정할 수 있음 (몇몇 데이터 타입은 특정한 값 서식을 요구)
- int : 정수, float : 실수, bool : 참거짓, string : 단어나 문장 등...
- int gold = 9; string itemName = "sword";
- 값(Value)이 할당되는 이름 (가리키는)
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) 작성해서 사용해보기
- Assets > Create > C# 스크립트 생성 (HelloFunction)
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가 함수여서 문제가 안됨
- 전역변수 - 전역에서 관측 가능한 변수
- 지역변수 - 해당 지역에서만 유효한 변수
- 변수는 유효 범위 내에서 중복적으로 선언해서 사용할 수 없음
- 변수의 유효 범위(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'를 만나야 분기문 코드가 종료된다.
- switch를 통해 작성한 코드는 if/else if/else를 통해 똑같이 작성할 수 있다.
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 (맵 평형 바닥)
- 오브젝트에 컴포넌트 추가
- Plane
- Material (물체 표면의 컬러를 결정) 추가
- Project > Main > Create > Material (물체 표면의 컬러를 결정) > (이름변경, F2) Plane
- Inspector > Plane > Main Maps > Albedo > 색 지정
- Smoothness > 낮게 설정 (반사율 높으면 거울 처럼, 낮으면 플라스틱 처럼 보임)
- Scene > Plane에 drag&drop
- Project > Main > Create > Material (물체 표면의 컬러를 결정) > (이름변경, F2) Plane
- Material (물체 표면의 컬러를 결정) 추가
- 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하여 동작 테스트
- Player 컴포넌트에 AddForce 기능 추가 테스트 (void Start() 함수 안에 작성)
- Project > Assets > (C# 스크립트) Player 생성하여 아래 코드 작성 후 Player 오브젝트에 작성한 스크립트(컴포넌트)를 drag&drop으로 추가
- Rigidbody에 힘을 주라라는 스크립트를 추가
- Player > (Inspector) Add Component > Physics > Rigidbody (물리기능추가)
- (Inspector) Sphere Collider
- 물체의 표면에 물리적인 표면을 만들어 줌
- Plane/Player 둘다 적용되어 있어서 Player가 공중에서 떨어져도 Plane 아래로 떨어지지 않음
- Plane
- 접근지시자
- public 외부 접근 가능, Inspector 에서 접근하여 편집 가능
- private (기본, 명시하지 않는 경우) 외부에서 접근 불가
- 카멜명명법 (협의된 약속)
- 클래스 이름 첫 글자는 대문자
- 함수 이름 첫 글자는 대문자
- 변수 이름 첫 글자는 소문자
- 단어와 단어 사이는 대문자로 구분
플레이어 조작
- 유니티는 메시지를 사용
- Start ()
- 게임이 처음 시작되었을때 한번 실행
- Update ()
- 화면이 한번 깜빡일때 한번 실행
- 게임이 지속적으로 갱신되게 함
- 테스트 : Debug.Log("화면이 한번 깜빡임!");
- 화면이 한번 깜빡일때 한번 실행
- Start ()
- 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 오브젝트 하위(자식)로 옮기기
- Position X(0) Y(0) Z(0)
- Hierarchy > Create > Create Empty(빈 게임 오브젝트 생성) > "Level"
- Play 버튼으로 생성한 Level(Map) 오브젝트 테스트하기
- Player를 조작(wasd)하여 계획대로 벽을 못 뚫고 지나가는지 테스트
- Wall(Cube) 오브젝트에는 이미 Collider 기능을 갖고 있어 물체의 물리적인 표면을 만들어줘서 물체가 뚫고 지나가지 못함
- Player를 조작(wasd)하여 계획대로 벽을 못 뚫고 지나가는지 테스트
- Cube 오브젝트 생성 (벽으로 사용, 이름 Wall로 변경)
- 아이템 박스 만들기 (옮길 박스)
- 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에 적용
- Assets > Create > Material > 이름 변경 "ItemBox"
- 물리능력 적용
- Add COmponent > Physics > Rigidbody (물리기능 추가)
- 아이템박스가 밀릴 때 회전하지 않게 하기
- Rigidbody > Constraints
- Freeze Position : Y축 선택(Y축 잠금)
- Freeze Rotation : XYZ축 선택(회전 못하도록 잠금)
- Player 오브젝트도 'Freeze Position - Y축 잠금' 설정
- Rigidbody > Constraints
- Prefab으로 아이템 박스 오브젝트 복사하기
- ItemBox 오브젝트를 Drag&Drop으로 Assets에 옮김
- Assets에 생성된 Prefab을 Hierarchy 창에 Drag&Drop으로 옮김
- 총 3개의 아이템 박스 오브젝트를 만듬(기존1 Prefab으로 2개 생성)
- Cube 오브젝트 생성 > 이름 변경 "ItemBox"
- 골인 지점 만들기
- 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 > 색상 지정
- Claer Flags - 아무것도 비추어지지 않는 영역을 어떻게 표현할 것인가
오브젝트 회전 + 시간 간격
- 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)
- 스크립트 코드 작성
- GameManager 스크립트 생성
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 비율로 대응되게 생성됨
- Hierarchy (오른쪽 클릭) > UI > Text
- UI 배치하기
- Text 클릭 > Scene (2D) > 이동 > 마우스로 배치
- Anchor Presets 사용
- 자주 사용하는 배치 UI를 제공, 이를 선택하여 설정 가능 (Alt키를 누르면 Snapping 옵션이 활성화되어 배치됨)
- 내용 입력 및 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 파일
- File > Build Settings
- 스페이스바를 누르면 게임 재시작이 가능하도록 하기
- GameManager 스크립트에 로직 코드 작성
- 게임 세상(Scene) 최종 출력물에 등록하기
// 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
- 프로젝트가 아닌 경로에 파일 저장 (꼬일 수 있음)
반응형