유니티 맛보기

주 강사님의 코드 교육을 들어가기 전에 유니티를 다뤄보는 시간을 가졌다.

유니티의 화면 구성부터 간단한 컴포넌트를 다뤄보았다.

 

Scene : 플레이 화면의 객체를 조작할 수 있는 세계

Hierarchy : 씬의 객체를 배치하는 곳(주인공들)

Inspector : 객체의 상태를 나타내는 탭

Project : 프로젝트의 파일들(실제 폴더) 

유니티 화면 구성

 

주 강사님 수업(자료형부터 객체지향까지)

 

유니티의 생명 주기

Awake()

<- OnEnable

Start() - 한번만 불림

Update() - 프레임당 한번씩 불림(사양에 따라 달라질 수 있음)

<- TriggerEnter

<- CollisionEnter

<- OnDisable

(대략적으로 이렇게 된다고 한다.)

유니티 생명주기 Docs

 

 

자료형

 

변수 : 메모리에 할당(적재)

ex) 숫자, 문자, 문자열, bool, 텍스처, 게임오브젝트(class)

 

변수이름 xx ~만큼(size)

사이즈 명시 = 자료형

 

ex) (int) (hp) = (1);

(자료형) (변수명) = (값);

자료형 : 어떤 식으로 적재 할거다(크기 포함)

1바이트 = 8비트

1비트는 (0과1) 2개 표현

1바이트는 2의 8승 256개 표현 가능

signed(음수까지 표현)

u~ unsigned(0부터 양수 표현)

 

 

리터럴 – 따로 선언 안 하고 그냥 숫자 사용 ex) a = 15; (여기서 a가 상수 15가 리터럴)

 

 

게임프로그래밍에서..

변수 -> 명사

함수 -> 동사

ex) FPS 게임

총을 쏴서 적군을 맞춘다.

명사 – 총, 적군

동사 – 쏴서 맞춘다.

 

 

숫자 – 정수형, 실수형

 

int와 long

ex) 귀찮아서 long으로 쓰면 하나 당 8바이트가 1000개 있으면 FPS가 30이라고 쳤으면 8000*30 = 240000 너무 커짐 ** 주의

 

nint

nuint

32bit os 64bit os

runtime(운영체제에 따라 달라짐) word

 

게임 만들 때 자료형보다 큰 숫자로 넘어간다면 overflow로 다시 최소값부터 시작

underflow는 자료형보다 작은 숫자가 될 때 => 웬만하면 int

 

cf) 네트워크를 들어갈 때 opcode일 때 byte 사용할 때가 있음

 

 

값 참조 vs 주소 참조

값을 참조할 때는 값만 복사해서 대상과 독립적으로 사용하는 경우고

주소를 참조할 때는 같은 대상의 주소를 담아서 직접 사용하는 경우다.

 

 

부동소수점 / 고정소수점

부동 – float(부유하다, 떠다니다) => 지수를 안 정함

- 부호비트 +-

- 32비트 1비트에서 최상위 비트 - 부호비트

- 가수에서 쓸 만큼만 쓰고 나머지를 소숫점을 표현하는 데 씀 => 경계가 떠다님

오차가 생길 수 있음

 

 

고정 – fixed => 지수를 정하고 감

가수x밑수(지수 – 제곱표현)

 

특징)

가수가 커지면 지수가 작아짐(정확도 내려감)

지수가 커지면 가수로 표현할 부분이 줄어듬(정확도 올라감)

용량이 큼(메모리 잡아먹음)

 

ex) 10진수 4.123

가수 4123

밑수 10

지수 –3

4123x10(-3)

 

 

float(4바이트) vs double(8바이트)

지수를 표현하는 부분이 float과 double이 다름

비트를 사용하는 부분이 다르기 때문

 

 

소수를 비교할 때 a == b 등 등치 비교는 잘 안 함

=> 오차 범위를 지정하거나 문자열화 시켜서 비교(얼추 맞을 수 있음)

 

 

소수점 어떻게 표현?

- IEEE 754 표준

 

 

암시적 자료형 var

var 쓰는 이유

- 변수를 선언하는데 숏코딩을 위해 사용

 

특징

- 지역변수로만 사용 가능

- 숫자 타입은 var 지양(형변환 문제 때문에)

- 가독성 문제

  

ex)

int a = 3; // var a = 3;

float b = 1.23f; // var b = 1.23f;

char c = ‘h’; // var c = ‘h’;

 

 

문자형 / 문자열

char / string

‘’ / “”

string은 char의 배열

string은 내장 클래스도 있음

 

 

bool형 : 참과 거짓을 위한 자료형

c#에서 true와 false 아니면 값 안 받음

 ex) bool isTrue = true;

 

 

배열

– 같은 자료형 + 이름 + 메모리 상에 순차 저장

ex) int[5] arrayHp = new int[5];

0번부터 시작 int라면 4바이트 크기만큼 담기고 그 다음으로

 

c# .NET Framework Array라는 클래스 사용 – 내장함수 포함

List

Collection

IEnumerable – 순회

 

c#

int[ ][ ] 가변길이 배열

int[ , ] 다차원 배열

 

 

연산자

 

산술연산자 

+, -, *, /, %

 

 

복합대입 연산자

+=, -=, *=, /=, %= 등등

 

 

증감연산자

++, --

전위 연산자

ex) ++i, --i

후위 연산자

ex) i++,i--

 

 

비교 연산자

==, >=, >, <=, <

 

 

논리연산자

&&, &, ||, |, !, ^

ex) Instanciate(“Enemy”) == null

 

중요! 많이 나오는 실수

&&를 쓰면 앞에서 false일시 뒤의 나머지 부분을 스킵하는데

&를 쓰면 조건문에서 앞에가 false여도 조건 부분은 실행됨

||를 쓰면 조건문에서 앞에가 true일시 나머지 부분을 스킵하는데

|를 쓰면 조건문에서 앞에가 true여도 조건 부분을 다 실행함

 

ex) bool a = true;

a &= false;

a = false && a;

a |= false

 

연산자 우선순위(Microsoft Docs)

 

 

형변환(캐스트 : 형태에 맞춰서 본을 뜸)

 

암시적 형변환

- 담을 형태 변수 = 담길 변수;

- int를 float에 담는 것은 가능

- float -> double 괜찮음

 

명시적 형변환

- 담을 형태 변수 = (담을 형태와 같은 바꿀 형태)담길 변수;

- float을 int에 담는 것은 불가능(상실되는 부분이 많으면 명시적)

- double(8바이트) -> float(4바이트)은 X

- 명시적으로 = 뒤 부분에 (double)을 붙여줘야 됨

 

ex)

float a = 5f;

a = 5; // 암시적 형변환

float b = (int)a; // 명시적 형변환

 

 

예약어

사용자 변수를 선언할 때 예약어는 쓰면 안 됨

C#예약어(Microsoft Docs)

 

 

코드 표기법

 

파스칼 케이스 : 단어들이 연속적으로 이어질 때 각 단어의 첫글자를 대문자로 사용

ex) PlayerName

카멜 케이스 : 단어들이 연속적으로 이어질 때 첫 단어를 제외하고 각 단어의 첫글자를 대문자로 사용

ex) playerName

- 회사마다 가이드가 다름(미리 숙지를 하면 좋음)

 

 

코딩 컨벤션(표준)

- 변수이름 설정하는 게 중요

 

 

조건문

if (조건)

{

    // 실행문

}

 

 

반복문

for문

for (var i = 0; i < 5; i++)

{
Debug.Log(i);

}

 

 

Coroutine

yield return

 

 

7.4 (월) 수업 내용 요약

변수 => 데이터형을 메모리에 올리는 것

배열 – int[] student = new int[5];

배열만으로 다루기 어려움

=> 클래스를 만들자

클래스 : 어떤 문제를 해결하기 위한 데이터를 만들기 위해 추상화(쓰고자 하는 내용)

ex) 챔피언의 hp mp status를 필요한 것만 빼놓은 것

캐릭터 A(name)가 공격(Attack)을 하면 메소드 {데미지(명사) 10이 박힌다(동사)} .

이런 개념이 합쳐지면 클래스가 됨

 
 

 

메서드

형식

public void Move () {}

접근한정자 반환형(리턴형) 메서드이름 매개변수 {뭐할지}

 

ex)

public int Add(int a, int b)

{

        return a + b;

}

int a = 1;

int b = 3;

int result = a + b;

debug.Log(result);

int newResult = Add(1, 3);

debug.Log(newResult);

 

- 반환형 void – 반환 값이 없음 (return 안 써줘도 됨)

- 반환형 나머지(int, string , , ,) 맞는 형이 return에 나와야 됨

- 매개변수 – 받을 땐 형식 명시 줄 땐 그냥 형식에 맞춰서 보내면 됨

- 함수를 래핑도 가능 Debug.Log(string str);를 시간을 찍히게 MyLog(string str);로 만들 수 있음

 

 

클래스

Champion champ = new Champion();

클래스 변수명 = new한정자 클래스 생성자 ;

 

ex)

class Champion

{

        int hp;

        int mp;

        int Add(int a, int b)

        {

                return a + b;

        }

}

 

ex) int[] arr = new int[]4;

- new는 클래스 new 한정자이다. 자료형과는 다르게 참조형 자료형이다.

- int, string 등등은 값형 자료형

 

 

 

오버로딩

함수 이름은 같은데 매개변수의 타입이 다름

- 오버로딩으로 구현하면 같은 함수를 작성했을 때(Add를 썼을 때 위아래 방향키를 눌러서 다른 함수를 선택할 수 있음 => 개발 편의성)

 

ex)

public float Add(float a, float b)

{

return a + b;

}

// 매개변수가 같고 반환 값이 다른 경우는 에러 뜸

 

 

한정자

ex)

class System

{

        int hp;

        int lv;

        public int GetHp()

        {

               return hp;

        }

        private void SetLvUp()

        {

               lv++;

        }

}

 

class Program

{

        static void Main(string[] args)

        {

                System system = new System();

                int hp_ = system.GetHp();

                // system.SetLvUp(); 에러 – private라서

        }

}

 

유니티에서 inspector에서 접근하고 싶을 때 코드 상으로는 private여야 한다면 무지성 public말고

[SerializedField]

private int hp = 0; 이런 식으로 선언해야 한다.

 

 

생성자

 

ex)

Champion champ = new Champion();

champ.hp = 500;

Champion champ = new Champion();

champ.hp = 600;

Champion champ = new Champion();

champ.hp = 700; 일 때 항상 넣기 힘드니까

 

class Champion

{

        int _hp;

        int _mp;

 

        // 외부에서 접근하니까 public
        public Champion(int hp, int mp)

        {

               _hp = hp;

               _mp = mp;

        }

}

 

 

소멸자

ex)

~Champion()

{

        Debug.Log(“Free”);

        _hp = 0;

        _mp = 0;

}

 

 

프로퍼티(property)

ex)

public int HP

{

        // champ.HP => get을 호출

        // 무조건 return을 써줘야됨

        get

        {

               return _hp;

        }

        // champ.HP = -100; => set을 호출

        // 무조건 value라는 값을 써줘야됨

        set

        {

                if (value < 0)

                {

                        value = 0;

                }

                _hp = value;

        }

}

 

// 다른 클래스에서

int A = champ.HP; => get

champ.HP = -100; => set

 

// HP 값 자체에는 접근 가능, 받아올 수 있음

public int HP { get; set; }

// 가져오는 건 가능한데 넣는 건 작업을 막을 수 있음

public int MP { get; private set; }

 

 

값 자료형, 참조 자료형, 클래스 자료형

 

값 자료형

ex)

int a = 20;

TestValue(a);

Debug.Log(a); // 출력 값 20

 

void TestValue(int a)

{

        a = 10;

}

 

 

참조 자료형

ex)

int[] a = new int[1]{ 20 };

TestValue(a);

Debug.Log(a[0]); // 10 출력

 

void TestValue(int[] a)

{
        a[0] = 10;

}

 

 

클래스 자료형

ex)

class TestValueClass

{

        public int value = 0;

}

 

void TestValue(TestValueClass t)

{

        t.value = 10;

}

 

// 다른 클래스에서

TestValueClass tvClass1 = new TestValueClass();

tvClass1.value = 20;

TestValue(tvClass1);

Debug.Log(tvClass1.value);

 

string a = “Test”;

Debug.Log(a);

TestValue(a);

Debug.Log(a);

 

TestValue(string a)

{

        a = “Test2”;

}

 

 

상속 

부모로부터 자식이 속성이나 특성을 물려받음

 

// 챔피언 아칼리 아리 아무무

// 속력 2 3 4

// Move(); SkillQ,W,E,R 챔피언마다 조건이 다름

public class Champion

{

        public int _lv = 1;

        public int _hp = 650;

        public int _mp = 0;

 

        public void Move()

        {

                Debug.Log(“Move”);

        }

 

        public virtual void SkillQ()

        {

                Debug.Log(“SkillQ”);

        }

 

        public virtual void SkillW()

        {

               Debug.Log(“SkillW”);

        }

 

        public virtual void SkillE()

        {

                Debug.Log(“SkillE”);

        }

 

        public virtual void SkillR()

        {

                Debug.Log(“SkillR”);

        }

}

// 다른 클래스

public void new Move()

{
        Debug.Log(“Move”);

}

 

 

가상 함수

virtual – 부모 객체의 함수를 자식들을 통해서 변화를 줄 수 있음

 

 

한정자

base 한정자 - 부모

new 한정자 – 덮어씀

 

 

접근 한정자

public – 외부 접근 가능

protected – 자식(파생 클래스)에서 접근 가능

private -  같은 클래스 내에서 접근 가능

 

 

 

외의 개념들

 

모듈화 : 기능적인 기본 사양을 공유하는 그룹핑을 지은 unit

 

상속 : 이미 부모에서 구현된 거에서 갖다 쓰는 것

 

라이브러리 : using을 통하여 갖다 씀

 

[Serializable] - 클래스 위에 쓰여서 인스펙터에 정보가 뜨게 함

 

 

이번 주 과제들

 

배열 안의 회색 값 찾기
롤 챔피언 과제(Json의 텍스트 파일의 정보를 가져오기)
롤 챔피언 과제(로그 띄우기)

 

 

한 주 후기

 드디어 개발교육 첫 주차가 끝났다. 이번 주 수업은 C#과 관련된 수업으로 진행하였고 부족했던 부분을 다시 공부할 수 있는 시간이었다. 강사님이 수업이 끝나고 유니티를 같이 다뤄보면서 진행할 수 있는 과제를 내주셨는데 배열부분에서 코드를 이해하는데 조금 걸렸지만 끝까지 해낼 수 있었다.

 개발 교육을 들으면서 질문이 여럿 생겼는데 enum의 선언 부분이나 접근 한정자 부분에서 이해하는데 꽤나 걸렸던 것 같다. 클래스 안에서 선언 되었는지와 클래스 밖에서 선언 되었는지에 따라 enum변수에 접근할 수 있는지가 달라지는 것을 배웠다. enum 선언에서 클래스 밖에서 선언될 때(namespace레벨)는 private와 protected는 쓰이지 않고(class도 internal과 public만 쓰임) 기본적으로 아무것도 안 쓰면 internal이라 같은 어셈블리 안이면 어디든 사용 가능하고 클래스 안에서 선언될 때는 선언하려는 변수의 한정자보다 범위가 같거나 넓은 한정자로 enum을 선언해야한다는 것을 배웠다.

 원래는 이런 것들이 왜 이렇게 되는지에 대해서 의문을 가지지 않고 그냥 되는 길을 찾아서 생각없이 진행했다면 이번처럼 질문을 통해서 이해를 하는 방향으로 가야지 기억에 더 잘 남는다는 것을 알게 되었다. 특히나 이번엔 친절하게 설명해주시는 강사님이 계셔서 조금이라도 이해가 가지 않으면 물어보고 개념을 확실히 잡고 가야겠다고 생각했다.

 아직 내가 직접 뭔가를 만들기엔 조금 부족한 것 같다. 그리고 정답지를 안 보고도 끝까지 만들어보는 습관을 들어야 겠다고 생각했다. 이러한 연습을 통해 스스로 생각한 것을 구현할 수 있을 것이라고 생각한다.

 이번 주 마지막 과제에서 살을 붙이는 작업이 이후의 과제들이라는데 내가 한 과제들이 이어진다는게 재밌을 것 같다. 다음 주도 열심히 해야겠다. 파이팅!!

 

유데미코리아 바로가기

본 포스팅은 유데미-웅진씽크빅 취업 부트캠프 유니티 1기 과정 후기로 작성되었습니다.

+ Recent posts