2019년 5월 29일 수요일

국비 교육 : 게임 프로그래밍 057일

57일 차 교육 내용 메모를 옮겨 본다.
A* 구현의 풀이와 관련된 내용이 메모로 작성되어 있다.


재귀 : 타고 내려가기에 상위값을 바꿀 수 없다.
while() : 타고 들어가다 상위 값을 수정할 수 있다.

열린목록 : 할일, 예정, 어떤 사각형을 검색해야 되는지
닫힌목록 : 결과, 완료, 저장되어 있는 사각형

A STAR : 길찾기
FSM : 몬스터 인공지능

이동 검색 시 개각이 없으려면 8방향이 아닌 4방향으로 검색을 수행하면 된다.
열린목록에 대각선 방향의 검색을 끌 경우(list 추가를 안할 경우) 4-way 길찾기로 동작한다.


이와 같은 내용이 메모로 작성되어 있고, A*알고리즘에 대한 상세한 설명은 아마도 풀이를 한 프로젝트의 소스에 주석으로 작성되어 있다고 생각 된다.

2019년 5월 28일 화요일

국비 교육 : 게임 프로그래밍 056일

56일 차 교육 내용 메모를 옮겨 본다.
경로 탐색 A*에 대한 메모가 작성되어 있다.


시작점과 경로와의 거리
경로와 목적지까지의 최단 거리

타일맵에 2개의 기능을 추가해 본다.
1. 클릭할 때 장애물 생성하기
2. 시작점, 도착지점을 제어할 수 있게 하기


A*에 대한 교육은 인터넷 올라와 있는 자료를 중심으로 소개를 하고, 이를 실제 제작해 보는 실습과 숙제로 이어진 것 같다.

2019년 5월 27일 월요일

국비 교육 : 게임 프로그래밍 055일

55일 차 교육 내용 메모를 옮겨 본다.
마우스 좌표 획득에 대한 메모가 작성되어 있다.


마우스의 좌표는 WM_MOUSE 이벤트를 받아서 GET_X_LPARAM(lp)로 좌표를 얻는다.

그리는 영역이 보이지 않는 영역을 항시 그리고 있지 않도록 소스를 구성해야 한다.

카메라 좌표의 플레이어 캐릭터 좌표, 마우스 포인터 좌표에 대한 관리 요소가 중요하다.


이처럼 짧은 메모 내용으로 작성되어 있고, 아마도 어제 있었던 Tile Map 과 관련된 풀이 형식으로 하루 교육이 진행된 것으로 생각된다.

국비 교육 : 게임 프로그래밍 054일

54일 차 교육 내용 메모를 옮겨 본다.
타일맵 구현에 대한 메모가 작성되어 있다.


2D에서의 Tile Map 구현
- Tile을 재사용함으로써 용량의 이점이 있다.
- 배열적 접근이 이루어질 수 있다.

화면에 그려지는 속도 = 픽셀수
- GPU의 연산때문에 큰 그림이 느릴 수 있다.

TileMap을 그리는 프로젝트를 실습해 본다.
1. line을 이용해 Tile의 Grid를 생성한다.
2. 그려진 각 Tile의 내부에 X, Y 좌표를 출력한다.
3. 마우스 커서 이동 시 어느 타일에 있는지 정보를 표시한다.
4. Tile이 스크롤 되도록 화면을 제어한다.


이와 같은 내용으로 Tile Map을 구현하는 실습이 교육된 것으로 생각 된다.

국비 교육 : 게임 프로그래밍 053일

53일 차 교육 내용 메모를 옮겨 본다.
맵 스크롤 기능을 구현하는 데 도움이 되는 내용이 메모로 작성되어 있다.


배열의 크기를 동적으로 늘리거나 줄일 경우에는 ±1씩 증가시키는 것이 아니라 일정한 단위를 지정해 늘리거나 줄여야 한다. (±1씩은 너무 비효율적이다.)

offset의 연산으로 화면이 돌아간다.
- 이동시킬 width 크기를 지정한다.

카메라의 좌표를 가지고 각 개체들의 상대좌표를 계산해 render의 좌표를 설정한다.


수업시간에 맵 스크롤 기능을 구현해 보는 프로젝트를 진행 한것 같다.
그리고 진행하는 중에 도움이 될만한 내용을 메모로 기록해 둔 것으로 보인다.

Unity C# AES 암호화/복호화

유니티에서 C#에서 지원해주는 암호화 기능을 사용해 데이터를 숨기는 기능
로컬에 JSON 형식(string 형식)으로 데이터의 저장 시 정보를 숨기는데 적용이 가능
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;

public class AESCrypto : MonoBehaviour
{
    // 키로 사용하기 위한 암호 정의
    private static readonly string PASSWORD = "3ds1s334e4dcc7c4yz4554e732983h";

    // 인증키 정의
    private static readonly string KEY = PASSWORD.Substring(0, 128 / 8);

    // 암호화
    public static string AESEncrypt128(string plain)
    {
        byte[] plainBytes = Encoding.UTF8.GetBytes(plain);

        RijndaelManaged myRijndael = new RijndaelManaged();
        myRijndael.Mode = CipherMode.CBC;
        myRijndael.Padding = PaddingMode.PKCS7;
        myRijndael.KeySize = 128;

        MemoryStream memoryStream = new MemoryStream();

        ICryptoTransform encryptor = myRijndael.CreateEncryptor(Encoding.UTF8.GetBytes(KEY), Encoding.UTF8.GetBytes(KEY));

        CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
        cryptoStream.Write(plainBytes, 0, plainBytes.Length);
        cryptoStream.FlushFinalBlock();

        byte[] encryptBytes = memoryStream.ToArray();

        string encryptString = Convert.ToBase64String(encryptBytes);

        cryptoStream.Close();
        memoryStream.Close();

        return encryptString;
    }

    // 복호화
    public static string AESDecrypt128(string encrypt)
    {
        byte[] encryptBytes = Convert.FromBase64String(encrypt);

        RijndaelManaged myRijndael = new RijndaelManaged();
        myRijndael.Mode = CipherMode.CBC;
        myRijndael.Padding = PaddingMode.PKCS7;
        myRijndael.KeySize = 128;

        MemoryStream memoryStream = new MemoryStream(encryptBytes);

        ICryptoTransform decryptor = myRijndael.CreateDecryptor(Encoding.UTF8.GetBytes(KEY), Encoding.UTF8.GetBytes(KEY));

        CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);

        byte[] plainBytes = new byte[encryptBytes.Length];

        int plainCount = cryptoStream.Read(plainBytes, 0, plainBytes.Length);

        string plainString = Encoding.UTF8.GetString(plainBytes, 0, plainCount);

        cryptoStream.Close();
        memoryStream.Close();

        return plainString;
    }

    // 적용 예제
    void Start()
    {
        string str = "원본 문자 정보";
        Debug.Log("plain : " + str1);

        string str1 = AESEncrypt128(str1);
        Debug.Log("AES128 encrypted : " + str1);

        string str2 = AESDecrypt128(str2);
        Debug.Log("AES128 decrypted : " + str2);
    }
}

2019년 5월 26일 일요일

국비 교육 : 게임 프로그래밍 052일

52일 차 교육 내용 메모를 옮겨 본다.
이미지의 애니메이션 그리기 방식에 대한 메모가 작성되어 있다.


- 매니저는 생성하고 삭제를 관리하기 위해 만드는 것이다.


Ani 출력 "스프라이트"를 이용
- 이미지를 자를 출력단위로 frame 당 경과 시간으로 출력한다.
- 이에 대한 전용 클래스를 제작해 관리하도록 한다.


그리고 맵스크롤에 자습을 진행했다.


아마도 실습으로 Ani 출력에 대해서 진행한 것 같다.
그리고 남은 시간 맵스크롤에 대해서 찾아보는 자습으로 진행한 것 같다.

국비 교육 : 게임 프로그래밍 051일

51일 차 교육 내용 메모를 옮겨 본다.
이미지의 투명 그리기 방식이 주로 메모로 작성되어 있다.


- 포인터 해제 시 복사 생성자의 관리 부분을 신경 써라.
- 글자의 뒤쪽에서 앞으로 검색한다.
- 메모리 구역의 코드, 전역, 스택은 프로그램마다 자동으로 설정된다.


투명 그리기
1. 빈 종이 A를 준비
2. A에다 기존 화면을 그린다.
3. 백버퍼를 A에도 그린다.
4. A에다 transblt로 칼라 키 값을 제외한다.
5. 백버퍼에다 A를 alpha를 먹여 그린다.


아마도 기존 그리기 방식에 추가적으로 TransparentBlt(), GdiTransparentBlt() 등을 이용해 정의한 RGB 칼라를 제외하여 투명 그리기를 처리하는 예제를 진행한 하루였던 것 같다.
실습한 프로젝트의 코드상에 자세한 정보가 있을 것 같다.

국비 교육 : 게임 프로그래밍 050일

50일 차 교육 내용 메모를 옮겨 본다.
클래스에 대한 내용과 자습 내용으로 메모가 작성되어 있다.


클래스 상속의 Overriding : 재정의

namespace 정의가 없는데 겹치는 경우 원 함수의 namespace 정의


자습
- stretchblt, gdi transform 등의 이미지 그리기 함수를 추가 학습
- 이미지 매니저를 만들어 이미지 이름으로 관리하도록 파싱 기능을 추가되도록 구현
- 맵 스크롤에 대해서 알아 보기


이와 같은 내용이 작성되었다.
윈도우 API를 시작한 이후부터 메모 내용이 현저히 적어졌다.

2019년 5월 22일 수요일

국비 교육 : 게임 프로그래밍 049일

49일 차 교육 내용 메모를 옮겨 본다.
어제에 이어서 Tree에 대한 내용이 메모로 작성되어 있다.


Tree 삭제
- 양쪽 자식이 모두 살아 있는 경우
 왼쪽 노드의 가장 큰 값
 오른쪽 노드의 가장 작은 값


Tree = STL의 Map 으로 키(key)와 데이터(data)로 구성된다.
- 키(key)는 유일값으로 중복되지 않는다.

Tree가 한쪽으로 치우치는 상태 = 편향 = AVL 알고리즘으로 해결

재귀함수의 경우 값이 계속 갱신 되도록 구조를 잡아야 한다.
- 부모의 값 = 자식의 값 또는 연산 값


Map Set을 알아본다.

Map, pair 구조체를 이용해 값을 넣는다.
- Map 의 " [ ] " 연산자의 사용이 가능하지만 안 하는 것을 추천한다.


list와 vector의 삭제 시, erase() 구문은 2개 타입밖에 없다.
map, erase는 키 값과 반복자를 이용해 삭제할 수 있다.


자료구조 매니저 제작 시
- Vector 는 index가 index로 0부터 순차적으로 증가 된다.
- Map은 key가 index로 순차적이지 않아도 된다.

Map은 넣을 때 고민할 필요가 없어서 데이터 관리에 효율적이다.


이상과 같은 내용이 교육되었고, Tree구조를 제작해 검색과 삭제가 되는 프로젝트 실습을 진행한 것 같다.

국비 교육 : 게임 프로그래밍 048일

48일 차 교육 내용 메모를 옮겨 본다.
Tree 자료구조에 대한 내용이 메모로 작성되어 있다.


Tree 자료 구조
- Root : 노드의 시작(출발)
- Leaf : 노드의 끝, 자식 노드가 없을 시
- 선(링크)을 가지고 있는 포인터 변수


이진트리
- 차수가 2개로 고정된 트리
- 근본 개념은 다르지만, STL에서는 Map이라고 불린다.













- 순회 방법
 전위(중→좌→우) : 1→2→4→5→3→6→7
 중위(좌→중→우) : 4→2→5→1→6→3→7
 후위(좌→우→중) : 4→5→2→6→7→3→1


BST
- 이진탐색트리
- 찾고자 하는 값이 leaf 노드에 도달할 때까지 없으면 없다고 판단한다.
- 검색에 특화되어 있다.
- 삽입/삭제가 용이하다.


ALV
- 균형을 맞추는 트리
- 차수의 기울어짐을 막아주기 위한 트리


이상과 같이 Tree에 대한 내용을 학습한 것으로 생각된다.

국비 교육 : 게임 프로그래밍 047일

47일 차 교육 내용 메모를 옮겨 본다.
FMOD와 MCI에 관한 내용이 메모로 작성되어 있다.


FMOD
- 사운드 전문 엔진, 사용이 쉽다.
- 별도의 라이브러리가 필요

MCI
- 미디어 컨트롤 인터페이스 (멀티 미디어)
- 윈도우 라이브러리, 별도 라이브러리 필요 없음
- 귀찮고 사용이 불편하다.


FMOD의 함수 중
- playsound(~) 라는 함수는 외부 함수로 감싸면 링크 에러가 발생 될 수 있다.

정의 : 실제로 생성한다. 정의는 1회만 가능
선언 : 다른 곳의 정의를 소개한다. 가져다 사용하기 위한 목적으로 n회 가능

FMOD
- sound 리소스의 관리
- 채널(재생 정보) 관리, 사운드 제어를 하기 위한 주체
- system 초기화 작업
- sound manager의 역할로 singleton으로 제작해 사용


이상과 같은 내용이 교육되었고, FMOD를 이용한 프로젝트를 실습한 것 같다.

2019년 5월 21일 화요일

국비 교육 : 게임 프로그래밍 046일

46일 차 교육 내용 메모를 옮겨 본다.
프레임의 개념과 클래스 전방선언에 대한 내용이 메모로 작성되어 있다.


프레임 기준의 계산이 아닌 경과 시간으로 계산하도록 코드가 구성되어야 한다.
- 이는 프레임의 단위당 조건 체크가 이루어질 경우, 조건이 스킵 될 수 있다.
- 결과 시간당 처리를 하는 경우 밀린 시간 값의 처리를 몰아서라도 할 수 있다.

거리 = 이동량 * 경과시간
속도 = 거리 / 시간


고해상도 타이머를 제작해 프로그램의 계산이 시간을 기준으로 처리될 수 있도록 한다.


헤더에 많은 정보를 담지 말아라
헤더에 클래스의 전방선언을 할 수 있다.
- 단 전방선언된 클래스를 포인터 사용할 경우에만 사용한다.


이와 같은 내용이 교육되었다.

2019년 5월 20일 월요일

국비 교육 : 게임 프로그래밍 045일

45일 차 교육 내용 메모를 옮겨 본다.
윈도우 프로그래밍에서 그리기와 관련된 내용이 메모로 작성되어 있다.


Peekmessage 큐에 보고 오는 함수
- 메시지의 존재 유/무를 확인하는 함수
- 메시지가 있으면 true
- 메시지가 없으면 false

기준시간과 현재 시간을 계산하여 60FPS가 되도록 갱신 시점을 지정할 수 있다.
코드상에서 갱신 시점의 Delay를 강제하여 설정한다.

Gettickcount() 함수
- 1초에 1000번 확인을 하지 않는다.
- 정밀하지 못함1, 16, 32 의 시간 틱 단위로 자체 타이밍을 가지고 있다.

Timegetime() 함수
- 정밀한 1/1000 초 시간 제어를 하기 위해 사용하는 함수다.
- 사용 전 Timebeginperiod() 와 Timeendperiod() 를 이용해 틱 주기 시간을 설정할 수 있다.


이상과 같이 FPS를 제어하는 윈도우 그리기 기능에 대한 프로젝트 교육이 진행되었다.

국비 교육 : 게임 프로그래밍 044일

44일 차 교육 내용 메모를 옮겨 본다.
이상하게도 별로 작성된 내용이 없다.

이전에 진행하던 이미지 프로젝트에 대한 실습이 계속 진행된 하루였나 보다.

순수 가상함수 virtual void Func() = 0; 선언에 대한 내용이 한 줄 작성되어 있다.


2019년 5월 17일 금요일

Unity에서 List 의 FindAll() 을 이용한 데이터 취합

Unity에서 List의 FinaAll()을 이용해 데이터를 취합하는 방법이다.
List에 저장되어 있는 데이터를 이용해 취합하려는 조건을 설정 할 수 있다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NumGroup
{
    public int     index;
    public string  name;

    public NumGroup(int index, string name)
    {
        this.index = index;
        this.name = name;
    }
}

public class LinqExample : MonoBehaviour
{
    List numbersA = new List();
    List numbersB = new List();

    List numGroupA = new List();
    List numGroupB = new List();

    void Start()
    {
        // numbersA : 1,2,5,8
        numbersA.Add(1);
        numbersA.Add(2);
        numbersA.Add(5);
        numbersA.Add(8);

        // numbersB : 1,3,5,7,9
        numbersB.Add(1);
        numbersB.Add(3);
        numbersB.Add(5);
        numbersB.Add(7);
        numbersB.Add(9);

        // FindAll 메서드
        // list 에 저장되어 있는 int 값 n 을 이용해 n % 2 == 0 연산이 옳으면 저장 한다.
        List findallA = numbersA.FindAll(n => n % 2 == 0);
        // 결과 : 2, 8

        // FindAll 메서드
        // list 에 저장되어 있는 int 값 n 을 이용해 n != numbersB[0] 연산이 옳으면 저장 한다.
        List findallB = numbersA.FindAll(n => n != numbersB[0]);
        // 결과 : 2, 5, 8


        ///
        /// class 형식의 데이터 연산
        ///
        
        // numbersA : 1 "가나다" , 2 "마바사" , 5 "아자차" , 8 "파타하"
        numGroupA.Add(new NumGroup(1, "가나다"));
        numGroupA.Add(new NumGroup(2, "마바사"));
        numGroupA.Add(new NumGroup(5, "아자차"));
        numGroupA.Add(new NumGroup(6, "파타하"));

        // numbersB : 1 "AAA" , 3 "BBB" , 5 "CCC" , 7 "DDD" , 9 "EEE"
        numGroupB.Add(new NumGroup(1, "AAA"));
        numGroupB.Add(new NumGroup(3, "BBB"));
        numGroupB.Add(new NumGroup(5, "CCC"));
        numGroupB.Add(new NumGroup(7, "DDD"));
        numGroupB.Add(new NumGroup(9, "EEE"));

        // FindAll 메서드
        // list 에 저장되어 있는 NumGroup 클래스 n(numGroupA) 을 이용해 n.index % 2 == 0 연산이 옳으면 저장 한다. 
        List findallGroupA = numGroupA.FindAll(n => n.index % 2 == 0);
        // 결과 : 2 "마바사" , 8 "파타하"
        
        // FindAll 메서드
        // list 에 저장되어 있는 NumGroup 클래스 n(numGroupA) 을 이용해 n.index != numGroupB[0].index 연산이 옳으면 저장 한다. 
        List findallGroupB = numGroupA.FindAll(n => n.index == numGroupB[0].index);
        // 결과 : 1 "가나다"


        // FindAll 메서드
        List findallGroupC = new List();

        // List의 AddRange()는 한번에 다수의 데이터(데이터 목록)를 추가 할 수 있다. (IEnumerable 인터페스를 구현한 컬렉션 객체의 추가가 가능하다.)
        // list 에 저장되어 있는 NumGroup 클래스 n(numGroupA) 을 이용해 n.index != numGroupB[i].index 연산이 옳으면 더한다.
        for (int i = 0; i < numGroupB.Count; i++)
        {
            findallGroupC.AddRange(numGroupA.FindAll(n => n.index == numGroupB[i].index));
        }
        // 결과 : 1 "가나다" , 5 "아자차"

    }
}

Unity에서 LINQ를 이용한 List 연산

Unity에서 Linq를 이용해 List를 연산하는 방법이다.
LINQ란 자주 사용 되는 정보의 선택/열거 작업을 다루기 위한 기존 문법의 확장이다.
사용법은 SQL 쿼리구문과 유사하다.

Unity서 List로 관리되는 데이터는 LINQ의 문법으로 연산이 가능 하다.
LINQ로 교집합, 차집합, 합집합 연산을 아래와 같이 간단히 할 수 있다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// Linq를 사용 한다고 선언
using System.Linq;

public class LinqExample : MonoBehaviour
{
    List numbersA = new List();
    List numbersB = new List();
    
    void Start()
    {
        // numbersA : 1,2,5,8
        numbersA.Add(1);
        numbersA.Add(2);
        numbersA.Add(5);
        numbersA.Add(8);

        // numbersB : 1,3,5,7,9
        numbersB.Add(1);
        numbersB.Add(3);
        numbersB.Add(5);
        numbersB.Add(7);
        numbersB.Add(9);

        // 차집합 : numbersA 에서 numbersB가 중복되면 제외 한다. 
        // 결과 : 2, 8
        List except = numbersA.Except(numbersB).ToList();

        // 교집합 : numbersA 에서 numbersB가 중복되면 저장 한다.
        // 결과 : 1, 5
        List intersect = numbersA.Intersect(numbersB).ToList();

        // 합집합 : numbersA 와 numbersB를 중복을 하나로 처리 하여 모두 저장한다.
        // 결과 : 1, 2, 5, 8, 3, 7, 9
        List union = numbersA.Union(numbersB).ToList();
    }
}

2019년 5월 16일 목요일

국비 교육 : 게임 프로그래밍 043일

43일 차 교육 내용 메모를 옮겨 본다.
윈도우 프로그래밍에서 그리기와 관련된 실습한 내용이 메모로 작성되어 있다.


1. 이미지 출력 기능을 클래스로 만들기

2. PeekMessage에 대한 사용법 익히기

3. 원하는 Frame으로 출력을 강제 하는 기능

4. 이미지 애니메이션


이와 같은 내용을 실습 프로젝트로 진행한 것 같다.

국비 교육 : 게임 프로그래밍 042일

42일 차 교육 내용 메모를 옮겨 본다.
윈도우 프로그래밍 중 그리기와 관련된 내용이 메모로 작성되어 있다.


BitBlt
- DC간의 영역 간에 고속 복사를 수행

StretchBlt
- 크기가 변동되는 그리기

transparentBlt
- 지정된 색을 빼고 출력

GdiAlphaBlend
- 알파값을 빼고 그리는 함수


4가지의 bmp 파일 포맷을 그리는 함수
WinAPI를 이용한 기본 그리기


설명된 기능을 이용해 Window에서 bmp, png 이미지 파일을 출력하는 프로젝트를 실습한 것 같다.

국비 교육 : 게임 프로그래밍 041일

41일 차 교육 내용 메모를 옮겨 본다.
키 입력을 재활용할 수 있는 클래스 화 시키는 방법에 대해 메모가 되어있다.


키 입력 함수를 클래스로 변경
- 클래스 사용 목적 : 객체 생성 1 ~ 무한대
- 객체가 프로젝트에서 1개만 필요할 경우 ? (1개로 제한)
 (관리자 기능과 같이 1개만 있어야 하는 상황)
- 현재는 1개의 객체만을 허용하지만, 필요한 경우 객체 생성을 가능하도록 변경이 쉬운 형태
- 1개의 객체 = 전역변수 + 함수
 (선언 및 사용 시 문제 : 여러 객체 생성으로 변경할 수 없다.)
- 여러 객체 = 클래스화
 (1객체만 사용한다는 보장이 없다.)


즉, 다음과 같은 제한이 필요하다.
1. 클래스로 만든다.
2. 객체 생성을 하면 안 된다.
3. 객체 생성을 못 하지만, 1개는 있어야 한다.


Static 정적 변수 키워드
- 선언될 때 생성되어 프로그램이 종료될 때 소멸한다.

static 멤버 변수 : 정적 전역 변수
static 멤버 함수
- 함수가 this call에서 일반 함수로 변경된다.
- 객체 선언 없이 호출할 수 있다.
- this 사용 못 함 : 멤버 접근이 안 됨


싱글톤
- 매니저 기능이 필요할 경우 주로 사용
- 1개를 쓰고 필요하면 늘릴 수 있다.
- 1곳에서의 연산 및 판단이 필요할 경우 사용


이상과 같이 싱글톤 매니저를 생성하고, 관리하는 방법에 대한 교육이 이루어졌다.

국비 교육 : 게임 프로그래밍 040일

40일 차 교육 내용 메모를 옮겨 본다.
HDC 와 화면 버퍼링, 키 입력에 대한 내용이 메모에 작성되어 있다.


HDC 란
- H : 핸들
- DC : 그리기에 필요한 모든 정보를 가진 데이터 구조체
 (DC의 내부 정보 종류로는 HPEN, HBRUSH, HFONT 등...)

화면 깜박임
- invalidaterect() 함수
- 무효화 영역 강제 발생
- WM_PAINT 강제 호출
- 매개변수 = HWND , RECT , ERASE
- ERASE : 이전 기록의 유지 유/무 , true 시 캔버스를 초기화
- 함수의 ERASE 가 true 라서 발생

근본적인 원인
- 그리는 사이사이의 캔버스가 화면에 그대로 노출되어 있기에


해결책
- 1번만 그리면 된다.
- 다른 HBITMAP에 그린 이후에 이 HBITMAP을 1회 화면에 그린다.


더블 버퍼링  or 백 버퍼링
- 임시 버퍼를 생성하여, 해당 버퍼에 렌더링 작업을 모두 진행한 이후 실제 버퍼로 데이터를 일제히 이동시켜 나타내는 방법

백 버퍼링 방법
1. 임시 종이 : HBITMAP
2. 임시 종이 정보를 다 그린다.
3. 임시 종이를 앞 종이에 옮겨 그린다.

문제 : HBITMAP에 직접 그리는 방법이 존재하지 않는다.

해결책
1. 기존 HDC와 동일한 HDC를 하나 더 만든다.
2. HBITMAP을 만든다.
3. 새로 만든 HDC에 새로 만든 HBITMAP을 넣는다.
4. DC간 고속 복사 함수로 HBITMAP을 복사한다.
5. HBITMAP 과 HDC를 지운다.


키 상태 체크
- GetKeyState 반환값
 최상위 1bit = 현재 눌렸는가
 최하위 1bit = 토글

- GetASyncKeyState
 최상위 1bit = 현재 눌렀는가
 최하위 1bit= 이전에 눌렀었는가

- 두 함수의 차이점
 GetKeyState : 메시지 큐에서 눌림을 확인한다.
 GetASyncKeyState : 함수 확인 시점에서의 눌린 상태를 확인한다.


교육된 키 입력 방식을 토대로 Key 입력의 stay, once_down , once_up , toggle 의 4가지 상태를 함수로 구현해 보는 과제를 줬다.

국비 교육 : 게임 프로그래밍 039일

38일 차 교육 내용 메모를 옮겨 본다.
2D 각 계산 및 충돌에 대한 내용이 메모에 작성되어 있다.


피타고라스 a² + b² = c²
- sinθ = b / c
- cosθ = a / c


데카르트 좌표계










- cosθ = x / 1 = x / r  →   x = cosθ * r
- sinθ = y / 1 = y / r  →  y = sinθ * r


각도의 표현
- 360도 문법 = 1바퀴
- π 호도법 = 원주율
 2πr을 가지고 각을 표시하는 법

호도법을 통한 각 계산
- 360º == 2πr
- 1º == πr / 180 == 1라디안

좌표 이동
- x = cosθ * r  ,  y = sinθ * r
- r 은 speed로 길면(크면) 빠르게 이동


그리고 이를 이용해 각을 계산해 벽에 물체가 충돌했을 때 반사되어 나오는 예제 프로젝트를 진행했다.

2019년 5월 15일 수요일

국비 교육 : 게임 프로그래밍 038일

38일 차 교육 내용 메모를 옮겨 본다.
메모 내용을 보니 STL에 대한 강의가 이루어졌다.


컨테이너 요소 삭제
- vector 의 삭제 : pop_back
- list의 삭제 : pop_front , pop_back

컨테이너 공용 삭제 도구 : erase
컨테이너 공용 삽입 도구 : insert

무효화 현상
- 어떤 상태가 없던 상태로 되돌리는 것
- 컨테이너의 삽입, 삭제에 의해서 이미 할당받은 반복자의 기능이 무효화 되는 현상
- 내부 메모리 관리에 의해서 데이터의 주소를 잃어버리는 현상

erase 함수는 지운 다음의 반복자를 반환한다.

vector에서는 반복자 앞의 데이터를 샂게할 경우 뒤의 처리에서 문제가 발생 된다.
(해당 반복자보다 이전 원소를 삭제할 때)


vector의 무효화 현상
- 삽입 : 삽입을 했는데 허용량을 확장 하면서 삽입이 이루어질 때
- 삭제 : 해당 반복자의 이전 원소로 삭제 할 때, 해당 반복자(자신)을 삭제 할 때

list의 무효화 현상
- 삽입 : 무효화 현상 없음, front나 back등의 원소 위치는 변할 수 있음
- 삭제 : 문제없음, 주변 원소의 삭제에 의한 무효화는 없다.


이와 같은 내용으로 강의가 이루어졌다.

국비 교육 : 게임 프로그래밍 037일

37일 차 교육 내용 메모를 작성해 본다.
윈도우 프로그래밍과 STL에 대한 내용이 메모로 작성되어 있다.


실습으로 winMain 을 세부 class로 분할해 재활용성을 높이는 구조화 시키기를 진행했다.


STL (Standard Template Library)
- 제작 목적 : 자주 사용되는 것에 대한 기능 모음
- 종류 : 함수자, 알고리즘, 컨테이너, 반복자

함수자
- 객체가 함수인척 ()멤버 연산자
- A(num); 같이 만드는 연산자로 클래스의 객체

알고리즘
- 문제 해결 방법
- 데이터를 다루기 위한 일련의 함수

컨테이너
- 자료구조들 , vector, list, stack ...
- 템플릿으로 만들어둔 자료 저장소

반복자
- 컨테이너에 저장된 요소를 순회하기 위해 사용한다.
- 컨테이너 내부 원소의 포인터 역할을 수행하는 클래스


이와 같은 내용이 교육되었다.

2019년 5월 14일 화요일

Unity Console 창 메시지 삭제 함수

DebugInfo 메서드 실행 시 Unity의 Console Window 의 메시지 들을 삭제한 뒤 Debug.Log() 처리가 이루어 진다.

using System.Reflection;

public void DebugInfo()
{
    var assembly = Assembly.GetAssembly(typeof(UnityEditor.Editor));
    var type = assembly.GetType("UnityEditor.LogEntries");
    var method = type.GetMethod("Clear");
    method.Invoke(new object(), null);

    Debug.Log("Debug Message");
}

국비 교육 : 게임 프로그래밍 036일

36일 차 교육 내용 메모를 작성해 본다.
윈도우 띄우기와 그리기에 대한 내용이 메모로 작성되어 있다.


윈도우 띄우기
1. 윈도우 클래스 정보입력 및 등록
2. 윈도우 창 생성 : create window
3. 화면 띄우기 : show window
4. 메시지 루프 : 콜백 함수 : 메시지가 발생 되면 처리를 한다.

핸들
- 장치를 윈도우가 구분하기 위한 정수값
- 윈도우가 부여해 주는 32bit의 정수로 'H' 접두가 붙는다.


HDC
- 그리기에 필요한 정보를 가지고 있는 구조체
1. 무효화 영역 : 순간적으로 다시 그려지지 않는 영역, WM_Paint 메시지
2. 갱신 처리 Set_Timer 콜백


GDI (Graphics Device Interface)
- GDI 객체 화면에 그림을 그리거나 문자를 출력할 때 사용 하는 객체
- GDI 객체의 클래스를 변경하여 생성하며, 이를 DC에 넣고 이 DB를 이용해 그림을 그린다.

그리기
1. GDI 객체 생성 : GDI 객체 클래스의 creat() 계열 함수 사용
2. 객체를 DC에 등록 : selectobject() 함수 이용
 (DC를 쓰고 난 다음 원상태로 복원하기 위해 기존에 설정된 객체를 포인터로 저장해둠)
3. DC를 이용해 그래픽을 출력
4. 이전 객체로 되돌림 : DC를 원 상태로 복원
5. 객체를 삭제  : GDI 객체 클래스의 deleteobject() 함수 이용


이와 같은 내용을 토대로 윈도우를 생성하고 점, 선, 사각형 등을 그려 제어하는 프로젝트 실습을 한 것으로 생각된다.

국비 교육 : 게임 프로그래밍 035일

35일 차 교육 내용 메모를 작성해 본다.
강의 내용이 윈도우 프로그래밍으로 완전히 변경됐다.


모달형
- 자식 윈도우가 있을 경우 포커싱이 자식에게만 된다.
- 부모의 윈도우로 포커싱이 안된다.

모달리스
- 부모와 자식이 모두 포커싱을 가질 수 있다.


HDC(Handle to a Device Context)
- Device Context 핸들
- 그리기에 필요한 모든 정보를 가진 데이터 구조체

화면에 선하나 그리기
- 선 속성 : 시작점, 끝점, 선색, 선 두께 등..
- 선에 필요한 속성은 크게 변화되지 않는다.
- 시작점, 끝점만 알고 속성을 부여한 선이 그려진다.


무효화 영역
- 화면에 숨겨져 있어 그리지 않는 부분.

WM_Paint
- 무효화 영역이 있으면 호출된다.
- 다시 그려야 될 상황에서 사용된다.


윈도우 프로그래밍은 "메시지"를 받아들여 동작한다.


이렇게 윈도우 프로그래밍과 관련된 내용을 학습했다.
윈도우 프로그래밍도 별도의 교재 없이 강사님의 설명과 프로젝트 실습으로 교육됐다.

2019년 5월 13일 월요일

unity GameObject의 모든 자식 GameObject들을 삭제 하기

현재 GameObject의 자식으로 등록된 GameObject를 모두 삭제 하는 메서드이다.

public void DeleteChilds()
{
    // child 에는 부모와 자식이 함께 설정 된다.
    var child = this.GetComponentsInChildren();

    foreach (var iter in child)
    {
        // 부모(this.gameObject)는 삭제 하지 않기 위한 처리
        if(iter != this.transform)
        {
            Destroy(iter.gameObject);
        }
    }
}

Unity Generics Singleton을 이용한 Manager 생성

Generics 타입의 Singleton 패턴을 이용해 DataManager 클래스를 생성한다.
그리고 생성한 DataManager 클래스의 변수 및 메서드는 어느 클래스에서도 접근할 수 있다.

Generics 타입으로 Singleton을 상속받아 재활용할 수 있다.
Awake() 메서드를 통해 Singleton에 맞게 GameObject가 중복으로 생성되지 않도록 처리되며,
Manager로 사용하기 위해, Scene 이동 시 삭제되지 않도록 처리되었다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Singleton : MonoBehaviour where T : MonoBehaviour
{
    // Singleton Instance 선언
    static T m_instance;

    // Singleton Instance에 접근하기 위한 프로퍼티
    public static T Instance
    {
        get
        {
            if (m_instance == null)
            {
                // T 라는 오브젝트의 형(컴포넌트의 형)을 검색해 가장 처음 오브젝트를 반환 한다.
                m_instance = GameObject.FindObjectOfType();

                // instance 가 없을 경우 GameObject를 생성해 선언한다.
                if (m_instance == null)
                {
                    // T 컴포넌트 의 이름으로 생성 한다.
                    GameObject singleton = new GameObject(typeof(T).Name);
                    m_instance = singleton.AddComponent();
                }
            }

            return m_instance;
        }
    }

    public virtual void Awake()
    {
        if (m_instance == null)
        {
            m_instance = this as T;
            DontDestroyOnLoad(this.gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }
}

// Singleton 의 파생으로 Manager 클래스 생성
public class DataManager : Singleton
{
    // Manager 클래스용 데이터 설정
    public bool isWrite = false;
    public int itemCount = 0;

    // DataManager에서 Awake 메서드 사용 시 선언
    public override void Awake()
    {
        base.Awake();
    }
}

public class DataUpdate
{
    void SetItem()
    {
        // DataManager 클래스에 접근이 가능 하다.
        DataManager.Instance.itemCount = 10;
    }
}

Unity Singleton을 이용한 Manager 생성

Singleton 패턴을 이용해 GameManager 클래스를 생성한다.
그리고 생성한 GamaManager 클래스의 변수 및 메서드는 어느 클래스에서도 접근할 수 있다.

Awake() 메서드를 통해 Singleton에 맞게 GameObject가 중복 생성되지 않도록 처리되며,
Manager로 사용하기 위해, Scene 이동 시 삭제되지 않도록 처리되었다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameManager : MonoBehaviour
{
    //  Singleton Instance 선언
    private static GameManager instance = null;

    // Singleton Instance에 접근하기 위한 프로퍼티
    public static GameManager Instance
    {
        get
        {
            return instance;
        }
    }

    // GameManager 에서 사용 하는 데이터
    public bool isPause = false;
    public int score = 0;

    void Awake()
    {
        // Scene에 이미 인스턴스가 존재 하는지 확인 후 처리
        if(instance)
        {
            Destroy(this.gameObject);
            return;
        }

        // instance를 유일 오브젝트로 만든다
        instance = this;

        // Scene 이동 시 삭제 되지 않도록 처리
        DontDestroyOnLoad(this.gameObject);
    }
}

public class GameContorl
{
    public void IsPause()
    {
        GameManager.Instance.isPause = true;
    }
}

2019년 5월 11일 토요일

국비 교육 : 게임 프로그래밍 001 ~ 034일 | C++ , STL, 알고리즘, 자료구조 강의

1일부터 34일까지의 C++ 강의 내용을 되돌아본다.


C++ 은 학원에서 제공되는 교재를 기반으로 강의 되었다.
교재는 400여 쪽의 얇은 교제였던 걸로 기억하고, 아마도 C++ 11 이전 내용의 표준 문법이 서술되어 있던 교재였던 것 같다.

하여간, 교재를 이용해 C++의 강의 및 예제 풀이가 진행되었다.
그리고 교재에 없는 C++ 11에 대한 내용은 강사의 설명 및 예제 프로젝트로 가볍게 설명되고, 자체 학습으로 교육된 것으로 기억된다.


STL, 알고리즘, 자료구조에 대한 강의는 교재가 없이 강사의 설명으로 진행됐다.
계속 프로그래밍을 공부하고, 여러 학습 방법을 돌이켜보면 너무 짧은 시간에 훅하고 교육됐다고 생각된다.

자습 및 숙제로 많은 부분이 커버 되고, 강의 시간의 프로젝트 실습과 질문 시간을 가지는 방식으로 교육되었다. 저 세 개의 공부할 내용은 각 항목당 책 한 권으로 설명되는 내용이다. 그런데 교육 내용을 돌이켜 보면, C++ 의 기본 문법 강의 시간보다 매우 적은 시간이 할애 되어 교육되었다.


이게 교육 시작 전 원생의 능력에 맞추어 교육 일정이 잡혀서 나온 결과인 것인지 이제는 판단이 안 된다.


이제는 과거의 많은 게임 국비 교육 중 하나의 과정으로 34일이라는 교육 시간, 실제 교육 기간으로 약 2개월에 해당하는 기간에 강의가 이렇게 진행되었다고 직접 경험한 기록을 남기고자 글을 작성해 본다.


국비 교육 : 게임 프로그래밍 034일

34일 차 교육 내용 메모를 작성해 본다.
C++ 문법에 대한 내용과 WinAPI 에 대한 강의가 이루어졌다.


함수 포인터(콜백), 함수자(멤버 연산자), 람다식(무명함수) 에 대한 설명
자료구조 중 트리에 대한 설명

STL (Standard Template Library) 디자인 패턴에 대한 소개


Win32 API
- 응용프로그램 : OS 기반으로 그 위에서 동작하는 프로그램
- 인터페이스
 : 두개체간의 상호작용을 위한 매개체
 : 유저와 OS 사이의 매개체
- API를 리팩토링한 UWP라는 신규 개발 플랫폼이 윈도우 8이후 적용됨

핸들
- 윈도우 내에서 자동으로 할당되는 구분번호
- 자료형에 'H' 접두가 붙는다.
- int 하나 있는 구조체로 되어 있다. (번호용)

VS에서 프로젝트 생성 시 '윈도우 응용프로그램'으로 선택해 빈 프로젝트를 생성한다.

기본 프로그래밍 단위
1. 윈도우 구조체 정의 ┐ 1. 윈도우 구조체 정의 및 등록
2. 윈도우 구조체 등록 ┘
3. 윈도우 생성      ┐ 2. 윈도우 생성 및 화면 띄우기
4. 윈도우 출력      ┘
5. 메시지 루프     ─ 3. 메시지 루프


이상과 같은 내용이 강의 되었음.
이날 강의로 윈도우 프로그래밍이 시작되어 화면에 윈도우를 띄우는 프로젝트 실습이 진행되었다.

국비 교육 : 게임 프로그래밍 033일

33일 차 교육 내용 메모를 작성해 본다.
이날 교육은 리스트에 대한 설명 및 구현에 대한 강의가 이루어졌다.


선형 리스트
- vector , 동적배열 , DArray
- 데이터가 물리적으로 연결되어 있다.
- 임의 접근이 중요할 경우 사용

연결 리스트
- 삽입, 삭제가 중요한 경우 사용
- 내부 구현은 비선형, 데이터의 구성은 선형
- '노드'라는 단위구조를 가짐 (데이터, 연결부(다음 노드 정보) )
- 단방향 연결 리스트, 양방향 연결 리스트, 원형 연결 리스트


그리고 단방향, 양방향 연결 리스트를 실제로 구현해 보는 실습 시간을 가졌다.

국비 교육 : 게임 프로그래밍 032일

32일 차 교육 시 작성된 메모를 작성해 본다.

충돌 알고리즘, 자료구조, 선형보간에 대한 내용이 메모되어 있다.


기초 충돌
- 점 ↔ 사각형
 (left < x && x < right) && (top  < y && y < bottom)
- 사각형 ↔ 사각형
 (left < right`  && left` < right) && (top  < bottom` && top`  < bottom)
- 점 ↔ 원
 Length = sqrt( pow(x-x`,2) + pow(y-y`,2) );
 Radius = (right - left) / 2;
 Length < Radius
- 원 ↔ 원
 Length = sqrt( pow(x-x`,2) + pow(y-y`,2) );
 Radius1 = (right  - left ) / 2;
 Radius2 = (right` - left`) / 2;
 Length < Radius1 + Radius2


자료구조
- 자료를 효율적으로 이용할 수 있도록 컴퓨터에 저장하는 방법

- 스택(LIFO) : 구현이 쉬우며 최신 데이터를 사용하는데 적용
- 큐(FIFO) : 최신 데이터가 나중에 사용하는데 적용
- deck : 양방향 삭제 가능
- 선형 리스트
- 연결 리스트


선형보간법
- 시작점, 끝점을 기준으로 중간값을 예측하는 알고리즘의 일종










- 예측하는 보간 방식이 선형이기 때문에 선형 보간법
- 시작점 * ( 1- 진행 비율) + 끝점 * 진행 비율


이상과 같은 내용이 메모되어 있다.
되돌아 보니 이 날은 하루에 참 많은 내용이 교육 된 것 같다.

국비 교육 : 게임 프로그래밍 031일

31일 차 교육 내용 메모를 옮겨 본다.
다양한 정렬 알고리즘에 대한 설명과 예제 구현에 대한 교육이었던 것 같다.

- 무작위의 n개 숫자를 선정하기
- 선정된 숫자를 오름(내림)차순으로 정렬하기


위 내용에 대한 예제 프로젝트를 진행한 것으로 판단된다.
돌이켜 보니 정렬 알고리즘에 대한 강의가 이리 짧게 끝났나 싶기도 하다.

2019년 5월 10일 금요일

국비 교육 : 게임 프로그래밍 030일

30일 차 교육 내용 메모를 옮겨 본다.
메모 내용을 보니 템플릿에 대한 강의가 이루어졌다.


템플릿 : template<>로 선언한다
- template<typename T>
- template 문법을 사용하여 함수 오버로딩을 컴파일러에 위임하는 방법


함수 템플릿
- 함수명<float>( ~ );  ← 형태로 선언해 사용할 수 있다
- 위 선언은 template의 매개변수 type을 float로 강제해 사용한다.

클래스 템플릿
template<typename T>
class abc
{
     public :
     T a = 0;  ← 멤버 변수를 템플릿 화 시킴
}


메모한 내용은 적지만 아마도 실습 프로젝트오 템플릿에 대한 설명이 이루어진 것 같다.
그리고 다양한 정렬이 어떤 알고리즘으로 어떤 구현 방식과 효율이 있는지에 대한 조사가 숙제로 나왔다.

국비 교육 : 게임 프로그래밍 029일

29일 차 교육 내용 메모를 옮겨 본다.
콘솔상에서의 출력 하는 기능과 이전 내용에 대한 강의가 이루어 졌다.

#include <iomanip> 선언을 통한 iostream cout시 기능들

setw(최소자릿수)
- cout << setw(최소자릿수) << 1 << endl;
- 자릿수로 5을 입력한 경우 : பபபப1 형태로 빈공간을 포함해 출력
- setw() 의 경우 선언 뒤쪽 1개만 영향을 준다.

- cout<<left<<.. 등을 이용해 문자 정렬이 가능하다.
- 정렬은 left , right , internal 세가지가 있다.

setfill('문자')
- 공란을 대체할 문자를 입력해 출력 되도록 한다.

showbase
- 숫자 출력시 진법 접두어(0 , 0x)를 표시 한다.

setprecision(자리수)
- 끝자리를 반올림 하여 출력 한다.

cin.clear()
- 에러가 있다는 사실을 지운다.

cin.ignore(글자수, 타겟);
- 글자수 : 버리기 위해 읽어드릴 문자의 개수 또는 버릴 문자의 수
 (글자 수 만큼 입력 시 버퍼가 비워진다.)
- 타겟 : 타겟 된 글자가 입력 되면 버퍼를 비운다.
 (입력되는 글자 중 타겟이 있는 경우 버퍼는 버려진다.)

                               

멤버 이니셜라이저
- 상수, 레퍼런스 변수, 인자 있는 부모 생성자, 자신의 다른 생성자

함수 오버라이딩
- 부모의 멤버함수를 재정의 하는 문법
- [반환 타입] [함수명](매개변수)가 모두 동일해야 된다.

부모의 클래스 포인터는 일괄 관리를 위해 사용 된다.
- 부모 클래스 포인터에 자식 클래스를 넣어 배열로 사용 할 수도 있다.

가상함수는 부모에 붙인다.
               오버라이딩 되어있어야 된다.
               virtual 키워드를 사용 한다.

가상함수와 순가상함수 두 종류가 존재 한다.

다형성(동일한 멤버함수)
- 동일한 인터페이스(결합부, 매개체)를 사용하여 다른 기능을 발휘
- 상호작용을 위해 두 개체간 의사소통이 가능하도록 하는 매개체

다형성 구현시 포인트
1. 초기 설계 중요(객체간의 관계 구축)
2. 부모 클래스 포인터를 활용하여 코드 구성
3. 부모 클래스 포인터에 객체 주소를 변경하는 코드 필요


이와 같이 iomanip 을 이용한 출력과 이전 강의 복습으로 교육이 진행 됬다.
숙제로 함수 포인터, 함수자, 람다식 에 대해 공부해 오라고 했다.

국비 교육 : 게임 프로그래밍 028일

28일 차 교육 내용 메모를 옮겨 본다.

왠일인지 작성된 내용이 거의 없다. 


클래스 상속, 동적 생성을 이용한 예제 프로그램 작성을 자습한 것으로 파악 된다.

그래서 메모 내용을 옮기는 것으로는 쓸 내용이 없다.



2019년 5월 9일 목요일

국비 교육 : 게임 프로그래밍 027일

27일 차 교육 내용 메모를 옮겨 본다.
함수 선언과 클래스 상속에 대한 내용이 작성되어 있다. 

함수 선언(프로토타입)을 신경 쓰자
전역 함수로 선언한 녀석들을 헤더에 선언을 해줘야 문제없이 돌아간다.

클래스 상속
- 문법 2개, 기능 1개의 상속 관련 전용 기능이 있다.
- 기존의 클래스로 새로운 클래스를 만드는 문법

상속 방법
class 클래스 명 : public 클래스 명
{
}


1. 상속에서의 접근제어 지정
- 상속받는 멤버의 최소 접근 제어
- public : 부모의 최소가 public
- protected : 부모의 최소가 protected
- private : 부모의 최소가 private
- 일반적으로 public으로 선언하며 마지막 상속의 경우만 private로 선언

상속의 종류
- 연속 상속 : A ← B ← C ← D
- 다중 상속 : A ←┐
        ┠ C
      B ←┘

상속의 사용의미
- 재활용
 1) 의미의 확장
 2) 의미의 세분화


2. 오버라이딩
- 클래스 상속 시 똑같은 함수를 선언해 사용하는 것을 의미
- 부모와 같은 함수(프로토타입이 동일)를 자식도 만들어 사용하는 것
 (재정의해 만드는 것)
- 클래스 상속 간에서 부모 클래스의 멤버 함수를 자식 클래스가 재정의하는 것
 (같은 프로토타입인데 기능이 다르다)


3. 부모 포인터 변수
- 자식 개체의 주소를 저장할 수 있다.

부모 포인터 변수 활용
- 여러 자식 클래스의 객체를 하나의 자료형으로 관리
- 부모 포인터 변수로 모든 자식 객체의 저장 가능
 예) 몬스터 *p = 고블린, 오크, 트롤...

문제
- 포인터는 자신의 자료형으로 주소의 형태를 파악한다.
- 포인터는 자신의 주소가 내 자료형일 것이라 짐작한다.
- 즉, 부모 메모리를 가리킨다.

필요한 것
- 부모의 포인터 변수에서 자식의 함수를 호출하는 방법이 필요하다.


4. 바인딩
- 함수의 선언과 정의를 결합하는 과정
- 컴파일 시점에서 고정되는 것을 정적 바인딩
- 호출 시점에 호출 위치를 파악하는 것을 동적 바인딩

vitual 키워드
- 동적 바인딩으로 함수를 구성하게 하는 키워드
- 클래스 내에 가상함수가 있는 경우 가상 함수 테이블이라는 함수 위치 저장소가 생성
 1) 부모의 함수에 virtual 키워드를 추가
 2) 부모의 가상함수를 자식이 오버라이딩
 3) 부모 포인터로 가상함수 호출 시 자식 함수 호출

순 가상함수
- virtual void Func() = 0;
- 함수 선언 뒤에 "= 0 "을 붙인 것
- 순 가상함수가 있으면 해당 클래스를 이용한 변수 선언이 안 된다.
- 자식 클래스에서 해당 함수의 오버라이딩을 강제한다.


이상과 같이 클래스 상속과 관련된 메모된 내용을 옮겨 보았다.
함수의 선언보다 클래스 상속에 대한 내용이 주를 이룬 것으로 보아, 함수 선언은 짧게 훑고 지나 간듯하다.

Unity - Firebase 연동 (Analytics, AdMob)

버전 : firebase_unity_sdk_6.5.0.zip 게임에서 통계 측정 및 광고 추적을 위해 Firebase 을 연동한다. 앞서 [Unity - GPGS 와 Admob 연동 및 배포 준비 작업]  연동 이후에 작업을 진행 한다. 유니...