---
# System prepended metadata

title: Unity Academy
tags: [수업기록, 유니티코드]

---


>  [강의 정보_홍동희](https://www.ofjeju.kr/communication/notifications.htm?category=2&act=view&seq=2051569)
 [책 공유_게임개발자가 알려주는 게임 제작 입문](https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=321115182)
[유니티 허브 다운로드](https://unity.com/kr/download)
[유니티 매뉴얼](https://docs.unity3d.com/kr/2023.2/Manual/GizmosMenu.html)
proonan29@gmail.com / naver.com

### 개론
* VR에서 언리얼, 유니티 활용. 애플비젼도 유니티 활용해서 만들어짐
* 유니티도 버전업이 많이 진행되다 보니 유니티 허브 활용해서 결려 있는 유니티를 골라서 들어갈 수 있도록 함
* 인공지능이 무엇일까. 프로그램으로 어떤 기능을 하는 것을 넘어서 길 찾기 처럼, 일반적으로 간단한 알고리즘을 풀 수 있지 않고, 학습해서 하는 일이라고 볼 수 있음. 
* 객체 지향 개념. 객체를 만들고 그걸 대리인으로 세워서 함. 존재를 인스턴스라고 하고 세무서처럼 법인격체에 해당됨
* 게임 개발에 있어서 블랜더, 마야 맥스 등을 활용해서 보통 오브젝트 만들고 디자인. 게임은 경제가 있어야 히트할 수 있음. QA, 기획자가 개발과 디자인을 할 수 없어도 할 수 있음. 목업, 스크래치 등 작업 할수 있음.
* 개발자의 방식: 일관성에 따라 사고하고 작업
* 게임에서 움직임은 실존 가상 세계에서 위치 변화. 실존하는 가상 세계는 메타버스. 게임을 하다가 현피를 뜨자고 하는 것처럼 형이상학적 세계여도 현실에 영향을 미치는 세계가 바로 실존하는 가상 세계 메타버스
* 가상 세계는 컴퓨터 램(주기억장치)에 있는 세계
* exe 실행 파일 : excute 실행하다 / 처형하다 처형파일. 컴파일해야 실행되고 데이터를 가져오면 실행됨
* 유니티, 언리얼 모두 특징, 기능이 다름. 엔진별로 다름.
* 브라운관 240 pixel. RT 3D VR AR 을 넘어 디지털 트윈 시대. 현실과 똑같은 세계로 대기업 공장에서 디지털 트윈 문의가 이어옴. 디지털 트윈 프레임도 수직 기본 60으로 게이밍 모니터 144, 120 모니터 자체 프레임수 높아짐. 컴퓨터마다 프레임이 다르기에 똑같이 균일화할 수 있음. 


### 기본 설정
* D:// 디드라이브 작업 폴더 설정
* 영문프로젝트명 0# 식으로 작성
* visual studio 설정
* 폴더명 앞대문자로 일관성으로 작업
* 스크립트 - C#으로 하고 스크립트 저장 


### 유니티 구성
* 왼쪽 hierarchy 위계, 계층 화면 : 게임 개발에는 부모 관계가 있고, 게임의 오브젝트가 여기 있음
* light 종류별로 있고, 디렉셔널 라이트 등
* 하단 메뉴에서 스크립트 폴더 설정해서 생성
* 오브젝트에 드래그해서 스크립트 연결. 스크립트에 오브젝트를 붙여서 사용하는 컴포넌트 방식. 유니티는 파일과 클래스 이름이 맞아야만 작동
* c# 언어
    * include, using, import 비슷한 걸로 씨언어부터 라이브러리 활용함
    * class 집합는 함수와 변수 표함. () 표시도 함수에 해당됨. class가 제공하는 함수는 메소드, 변수는 프로포티에 해당
    * 스타트, 업데이트로 가상함수. 스타트 업데이트는 상속 받은 함수라고 볼 수 있음. start 한번 뿐 update 매 프레임마다 실행 최소 60이상
* 마우스 마휠, 마우스 오른쪽 / 왼쪽 클릭에 따라 회전 작업
* 유니티 transform : 위치 변경으로 포지션값, 스케일, 로테이션으로 x,y,z 값 변환해서 진행. 좌표 x : 현실세계 좌우 y: 마이클잭슨 상하 z: 앞뒤 로테이션
* 프레임에서만 보고 결정. 멀티 스크래치는 불가능하지만, 유니티는 멀티가 가능.
* MonoBehaviour 
* 게임 기본 구성 : 좌우 이동, 상하 이동, 적의 이동 

#### 좌우 이동, 상하이동
* s = vt
* translate 이동하세요 뜻으로 평행이동
* deltaTime : 델타 타임으로 프레임과 프레임 사이의 시간. 프레임 사이 간격으로 두개의 차이값을 different 뜻으로 델타값으로 부르고 dx, dy로도 해서 쓰는 경우도 여기에 해당
* keydown 한번씩만 되기에 keydown, keyup으로 나눠서 작업. 리피티드 키 스토크 키보드일 경우에 분리를 해서 키가 눌러져 있다고 인식하기에 나눠서 작성해야 하고, 게임의 기본이자 메인 루프

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

public class Player : MonoBehaviour
{
    const float speed = 3.0f;
    bool bMoveLeft = false;
    bool bMoveRight = false;
    bool bMoveUp = false;
    bool bMoveDown = false;
    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        float d = Time.deltaTime * speed;
        if (Input.GetKeyDown(KeyCode.LeftArrow))
        {
            bMoveLeft = true;
        }
        if (Input.GetKeyUp(KeyCode.LeftArrow))
        {
            bMoveLeft = false;
        }
        if (bMoveLeft)
        {
            transform.Translate(new Vector3(d, 0, 0));
        }
        if (Input.GetKeyDown(KeyCode.RightArrow))
        {
            bMoveRight = true;
        }
        if (Input.GetKeyUp(KeyCode.RightArrow))
        {
            bMoveRight = false;
        }
        if (bMoveRight)
        {
            transform.Translate(new Vector3(-d, 0, 0));
        }
        if (Input.GetKeyDown(KeyCode.UpArrow))
        {
            bMoveUp = true;
        }
        if (Input.GetKeyUp(KeyCode.UpArrow))
        {
            bMoveUp = false;
        }
        if (bMoveUp)
        {
            transform.Translate(new Vector3(0, d, 0));
        }
        if (Input.GetKeyDown(KeyCode.DownArrow))
        {
            bMoveDown = true;
        }
        if (Input.GetKeyUp(KeyCode.DownArrow))
        {
            bMoveDown = false;
        }
        if (bMoveDown)
        {
            transform.Translate(new Vector3(0, -d, 0));
        }
    }
}
```

#### 적의 이동
* 항상 start, update 항상 나오고, 모든 오브젝트는 transform이 있음. 
* 프레임에서만 보고 결정. 변수 활용
* 싸인함수와 코싸인함수로 -1, 1 반복되도록 해서 할 수 있음
* enemy 스크립트: float x = Mathf.Sin(Time.time) * 3.0f (삼각함수 진폭)
* transform.position.y
* ; 세미콜론 : 한문장에 종결자 terminate 터미널과 같은 종점의 의미를 가짐. 파스칼 언어에는 맨 끝문장에서 세미콜론을 뺌. PT 마지막 구령를 하지 않는 것과 같은 작업. 파스칼에선 seperator 구분자에 해당함. 불편해서 이후에 다 넣게 됨
* enemy, player 든 따로 업데이트를 계속 할 수 있음.
* 랜덤 숫자를 넣어서 다르게 이루어지도록 함.
* 파이함수는 상수로 하기에 넣어짐. 속도는 직접 추가해야 함. 진폭과 차이가 있음
* 출발점을 다르게 하고, 초기화를 하지 않으면 0이 됨. 예약어를 제외하고 변수를 넣어도 됨. 시간의 진행을 느리게 하는 식으로 속도를 곱해줌. 진폭의 변화를 줄 수 있음
* 진자운동 미디어아트를 만들 수 있음.
* 정수 int / 실수 float : 부동소수점 * 2.0f, double : 대동소수점 * 2.0. 정수 4바이트 4기가 / 부동소수점은 지수와 가수를 나눠서 계산
```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy : MonoBehaviour
{
    const float speed = 5.0f;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        float x = Mathf.Cos(Time.time) * speed;
        transform.position = new Vector3(x, 0, 0);
    }
}
---
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        float x = Mathf.Sin(Time.time) * 6.0f;
        transform.position = new Vector3(x, transform.position.y, 0);
    }
}
---
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy : MonoBehaviour
{
    float r; // displacement 출발점을 바꿈
    float speed; // 속도
    float amp; // 진폭
    // Start is called before the first frame update
    void Start()
    {
        speed = Random.Range(0.5f, 3.0f);
        r = Random.Range(0, Mathf.PI * 2.0f);
        amp = Random.Range(1.0f, 5.0f);
    }

    // Update is called once per frame
    void Update()
    {
        float x = Mathf.Sin(Time.time * speed + r) * amp;
        transform.position = new Vector3(x, transform.position.y, 0);
    }
}

```

[진자운동]
(https://ko.khanacademy.org/computing/computer-programming/programming-natural-simulations/programming-oscillations/a/trig-and-forces-the-pendulum)

#### 랜덤 적 만들기

* 프리팹 : 붕어빵 틀을 만들어서 찍어내는 방식. 만들어놓고 여러개 쓰겠다는 방식. 개수 까지도 랜덤하게 만들어 보겠다고 하는 식. 클릭할 때마다 수두룩 하게 만드는 방식으로 할 수 있음. 건축 용어로 조립식 건물 벽체. 다이어몬드, 콘크리트는 경도는 세지만 강도는 약함.  
* 프리팹 Prefabs : Assets 폴더 생성 / enemy 오브젝트를 Prefab 폴더로 드래그 
* n 개 나올 수 있도록 게임매니저를 만들어서 메인루프를 만드는 것임. 스크립트 Manager 만듦. 오직 초기화를 위한 작업.
* hierarcy creat empty Manager - script 컴포넌트 - prefab 컴포넌트
* 전산학에도 작명에 일가견. 뭐하는 함수이고 변수인지 알 수 있도록 작명해야 함. 연관성 있게 지어야 함.
* 함수이름이 같아도 실제가 다른 함수가 있음. 오버라이딩 - 동명이인 함수. Random.Range(). 가상함수를 오버로딩이라고 함. 
* for 반복문 : #번 까지 반복하는 형태. = while 문
* c 언어를 만드는 사람. 이전에 명령이 많아서, for while 반복문/ if else switch 분기문 만 하면 됨. 이외에는 함수로 남이 만든 코드를 잘 쓰는 일이 필요. 기성품에 해당하는 소스를 쓰는 형태. 노출된 함수만 보이는 형태. 
* Instantiate : 빵을 잘 찍어내는 함수와 같이 생성이라는 뜻. instance 생성된 객체라고 볼 수 있음. 
* public / private / protected : 접근지정자. 접근권한에 따른 함수. 공개할 수 있는 함수가 public. 외부의 접근권한이 있느냐에 따라 다름.
```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Manager : MonoBehaviour
{
    public GameObject enemyPrefab;
    // Start is called before the first frame update
    void Start() //초기화
    {
        int num = Random.Range(1, 10);
        for (int i=0; i<num; i++)
        {
            GameObject enemy = Instantiate(enemyPrefab);
            enemy.transform.position = new Vector3(0, Random.Range(-3.0f, 3.0f), 0);
        }
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

```

---

### 게임 데이터 저장방법과 이해
* 오락실 기계에서 1위하면 이름을 넣어서 저장되도록 되는 것도 게임 데이터. 오락실 기계를 껐다 켜면 데이터가 날라가고 했음. 요즘은 게임 데이터가 남고 서버로 가서 기록됨. 서버로 저장이 되어야 함. 유니티와 서버연동을 어떻게 하느냐가 제일 중요. 
* 앱을 만든다고 하면 모형프로그램이라고 볼 수 있음. 컴퓨터에서 돌아가는 것도 다 앱이라고 함. 어플리케이션의 약자가 앱이라고 볼 수 있음. 유니티에서는 프론트만 작업하고, 서버에는 저장이 안되기에 백엔드 작업이 필요. 프론트엔드는 유저와 맞닿는 부분으로 대표적인 사례 웹페이지이라고 볼 수 있고, 백엔드는 눈에 보이지 않음. 
* 게임 데이터 : 언제 들어왔는지 시간, 얼마나 했는지 시간, 돈 얼마나 썼는지, 접속자 수 등 데이터가 많음
* 과거에는 TV광고 -> 현재 유튜브 광고를 많이 함. 우리가 검색한 기록에 맞춰서 마케팅광고가 이루어지는 것처럼 구글 네이버등에서 사용자의 검색데이터가 팔아서 광고로 이루어짐. 유튜브에 어떤 좋은 자료가 있다는 식의 파생 정보, 메타 데이터라고 함. 프로그래밍에서는 포인터라고 할 수 있음. 메타데이터에 대한 아이디어를 가지고 있어야 함. 메타데이터에 대한 메타데이터가 있을 수 있음. 
* 로컬로 1차 저장이 이루어짐. 
* 운영체제 Operating System는 프로세스를 관리하고 외부장치를 연결하기 위한 시스템이라고 볼 수 있음. CPU 램만 있으면 컴퓨터가 될 수 있지만, 저장을 하기 위함. 플로피디스크(자기기억장치) - 하드디스크 HDD - SDD / CD - DVD  이런 것들을 프로그래머가 일일히 지원할 수 없어서 인터페이싱을 함. 구글은 안드로이드 플랫폼를 무료로 하고, 구글 플레이 앱 결제하도록 함.운영체제는 각각 지원하지 않고 유니티처럼 상용지원을 할 수 있도록 함. 
* 미래사회에서는 프로그래밍에 대한 개념을 가지고 있어야 하고, 잘 살아가는 것이 필요함. 인공지능과 시스템을 만들 위한 일을 소수가 할 예정
* 저장은 스트림이라고 함. 동영상을 스트리밍 서비스라고 하듯이 시작과 끝이 있는 긴 서비스라고 볼 수 있음. 간단한 형태의 파일 txt 메모장으로 생성헤서만 글자만 남아 텍스트파일이 됨. 문자열만 남음.
* console : 개발자의 시각이라고 볼 수 있음
* UI 버전 : 텍스트 - save 변경. 버튼 on clik - manager 가져와서 연결 - save messsage
```
        string message = PlayerPrefs.GetString("message");
        Debug.Log("message" + message);
        
            public void SaveMessage()
    {
        PlayerPrefs.SetString("message", "Hello World");
    }
        
    

```

---

#### 자체 스터디
참고링크 : 골드메탈(유니티 관련 영상) 
https://www.youtube.com/watch?v=7plGPXkmnxQ&list=PLO-mt5Iu5TeYI4dbYwWP8JqZMC9iuUIW2
> Unity Hub 설치, Unity 계정 생성 : LTS Long Term Support System 장기지원 설치 또는 로케이트 가능.Preferred 디폴트로 되고, 최신 버전으로 다운로드 - 어느 플랫폼으로 릴리즈 베포에 따라 서포트 결정. 언어 결정해서 다운로드 완료
> Unity Hub - Create
> 기본 인터페이스 4가지 창 프로젝트 : 아래에 있는 창 : 게임 파일에 관련한 모든 프로젝트 창 / 왼쪽에 있는 계층구조 창: 오브젝트 생성 / 중앙에 있는 장면 창: 오브젝트 확인 / 오른쪽에 있는 인스펙터 창: 속성 확인
> 계층구조 마우스 오른쪽 버튼으로 오브젝트 생성. 
> 키보드 단축키 : Q키(뷰 이동), W키(기즈모 기준으로 이동), E키(선을 누르고 자유롭게 회전, 가운데 누르고 회전 가능), R키 (크기 조정, 가운데 누르고 크기 비율에 따라 크기 조정), D키 (사각툴 ED, UI에 쓰임),
> 카메라 : 마우스 오른쪽(카메라 회전) alt+마우스 왼쪽(카메라 축 이동), 키보드방향키(카메라 자유이동), 마우스 휠(카메라 이동,줌)
> 인스펙터 transform 활용해서 나만의 오브젝트 사용. 땅하나와 오브젝트 
> 게임 구조와 프로그래밍
> - 연극/게임 > 막/장면 > 인물&소품/오브젝트 > 대본/스크립트
> - 프로그래밍언어 : 컴퓨터 언어로 컴퓨터와 사람이 나누는 대화. 컴퓨터는 01로만 이루어진 언어. 사람에게 어려워서 나온 것이 프로그래밍 컴퓨터 언어. 유니티는 C# 사용
> 스크립트 
> - 프로젝트 창에 스크립트 생성, 인스팩터에 스크립트 미리보기, 파일 더블클릭 비쥬얼 스튜디오
> - 프로젝트 옆에 있는 콘솔 창 : Debug.Log() - 콘솔창에 메세지 출력, 프로그래밍 마침표 ;(세미클론), "Hello Unity"
> - Save 하기로 함. 스크립트 파일을 인스펙터에 드래그 하면 됨.  
> C# 기초문법 보고 오기 


유니티 관련 블로그 링크 
https://alpaca-code.tistory.com/category/%EC%9C%A0%EB%8B%88%ED%8B%B0

-----
Plane과 Quad : 주로 바닥을 담당하는 오브젝트

![](https://hackmd.io/_uploads/S1OjTNqoh.png)
plane

![](https://hackmd.io/_uploads/B1Ph6Ecsn.png)
quad

1. 공통점 : 둘 다 판의 형태
2. 차이점 
(1) 처음 생성할 때 각도가 다름
: Plane은 가로로 누워있고/ Quad는 세로로 누워 있음

(2) 크기 
: Plane은 Quad보다 삼각형을 훨씬 더 많이 사용한다.
: 퀄리티 Plane > Quad / 최적화 Plane < Quad
(3) 용도 (스프라이트 출력)
: 유니티에서는 스프라이트를 어딘가에 출력해야 할 일이 있다. 
: 휴대폰의 스크린처럼 무언가를 표시해야할 상황이 분명히 나타난다. 
: 이럴 때는 보통 Quad를 쓰고, Plane을 쓸 수 있지만 굳이 쓰지 않는다.

3.결론
- Quad를 돌려서 쓰는 게 렌더링할 삼각형이 적어지기 때문에 최적화 면에서 더 좋다. 



--

변수 : 데이터를 메모리에 저장하는 장소
- 변수의 종류 : int, float, String, bool
- int : 정수형 데이터 (단순한 숫자 데이터)
- float : 소수점까지 포함한 숫자형 데이터, float쓸 때는 뒤에 f를 꼭 붙여줘야 한다.
- String : 문자열 데이터 , 양 끝에 ""
- bool : 논리형 데이터, True of False

그룹형 변수 : 변수들을 묶은 하나의 장소
- string[] monsters = {"슬라임","사막뱀","악마"};

프로그래밍 흐름 : 선언 > 초기화 > 호출

---

#### 마우스 누르면 떠오르기 기능
> 모터쇼 신차 처럼 카탈로그 형태 보이고자 한 작업할 예정
> 가상세계의 좌표 : 월드 좌표. 마우스가 사용하는 좌표계 (x,y): 화면끝에서 끝까지만 작동 - 스크린 좌표계. 좌표계 변환
> OBJECT - SCALE X:5 Y:1 종잇장 z:5 
> Asset - create material - name
> Mesh Render - material
> GameMain
> 유한상태머신FSM 컴퓨터 : enum 상태 확인 - 열거형 사용
> 물건이 있는지 없는지 확인하는 것임. 원근법 시야처럼. 벡터를 쏴서 거리를 보듯이 카메라의 위치에서 자를 만들어서 당겨보세요. 줄자의 길이을 확인 하도록 함. 너무 길게 하면 안됨. out 으로 중간에 값을 건네 받는 함수.
> 매직 넘버 : 의미를 알 수 없는  숫자. 
> 물리 엔진을 할 때는 충돌 체크. 안 겹치게 하고 싶을 경우, 물리적 실체를 규명해줘야 함. 강체에 힘을 가해야 함. 강체를 모를 경우에 RIGIDBODY 활용
    > 물리 엔진 활용 : 큐브 - 컴포넌트 - 피직스 -  RIGIDBODY, 조금 올려서 하기 
    > 물리 순간적으로 속도 바뀔때 임펄스 한번에 순식간, 점점 바뀔 때 에드 포스 시간이 필요. 총의 경우, 마하 이하로 해서 임펄스 충격량으로 작성.
> 도미노, 볼링 게임 가능
> 
```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameMain : MonoBehaviour
{
    enum Direction {None, Left, Right}
    Direction bRotate = Direction.None;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if(Input.GetMouseButtonDown(0))
        {
            RaycastHit hit;

            //try raycast
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(ray, out hit, 100.0f))
            {
                Debug.Log("Time" + Time.time + " Detect=" + hit.transform.name);
                Rigidbody rb = hit.transform.GetComponent<Rigidbody>();
                if (rb != null)
                {
                    rb.AddForce(0, 10.0f, 0, ForceMode.Impulse);
                }
                else
                {
                    Movable mv = hit.transform.GetComponent<Movable>();
                    if (mv != null)
                    {
                        mv.FlipTarget();
                    }
                    else 
                    {
                        bRotate = Direction.Right;
                    }
                }
            }
        }
    }
}
```
> MOVABLE 스크립트 

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

public class Movable : MonoBehaviour
{
    public GameObject target;
    public Vector3 angleClose;
    public Vector3 angleOpen;

    bool bOpen = false;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
    public void FlipTarget()
    {
        if (target != null)
        {
            bOpen = !bOpen;

            if (bOpen)
            {
                target.transform.localRotation = Quaternion.Euler(angleOpen);
            }

            else
            {
                target.transform.localRotation = Quaternion.Euler(angleClose);
            }
        }
    }

}

```
> 스포츠카 문이 열리도록 하기 위해서 스크립트 
> 스포츠카 엔진후드 컴포넌트 - 엔진후드 타겟 / 오픈시 x 좌표 변화 
> physics - mesh coll
> 두번 명령이 될 경우는 컴퍼넌스 다른 곳에 있을 수 있음. 싱글 톤 디버깅 확인
> collider/body 다른 센서가 있을 경우 확인 필요
> 다른 오브젝트 눌러서 왼쪽 오른쪽 가능
```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameMain : MonoBehaviour
{
    enum Direction {None, Left, Right}
    Direction bRotate = Direction.None;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if(Input.GetMouseButtonDown(0))
        {
            RaycastHit hit;

            //try raycast
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(ray, out hit, 100.0f))
            {
                Debug.Log("Time" + Time.time + " Detect=" + hit.transform.name);
                Rigidbody rb = hit.transform.GetComponent<Rigidbody>();
                if (rb != null)
                {
                    rb.AddForce(0, 10.0f, 0, ForceMode.Impulse);
                }
                else
                {
                    Movable mv = hit.transform.GetComponent<Movable>();
                    if (mv != null)
                    {
                        mv.FlipTarget();
                    }
                    else 
                    {
                        bRotate = Direction.Right;
                    }
                }
            }
        }
        if (Input.GetMouseButtonDown(1))
        {
            bRotate = Direction.Left;
        }
        if (Input.GetMouseButtonUp(0) || Input.GetMouseButtonUp(1))
        {
            bRotate = Direction.None;
        }
        switch (bRotate)
        {
            case Direction.Right:
                // rotate main camera
                Camera.main.transform.RotateAround(Vector3.zero, Vector3.up, Time.deltaTime * 30f);
                break;
            case Direction.Left:
                // rotate main camera
                Camera.main.transform.RotateAround(Vector3.zero, Vector3.up, -Time.deltaTime * 30f);
                break;
        }
    }
}
```
```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Movable : MonoBehaviour
{
    public GameObject target;
    public Vector3 angleClose;
    public Vector3 angleOpen;

    bool bOpen = false;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
    public void FlipTarget()
    {
        if (target != null)
        {
            bOpen = !bOpen;

            if (bOpen)
            {
                target.transform.localRotation = Quaternion.Euler(angleOpen);
            }

            else
            {
                target.transform.localRotation = Quaternion.Euler(angleClose);
            }
        }
    }

}

```

![](https://hackmd.io/_uploads/B1xKS85s2.png)
![](https://hackmd.io/_uploads/S1GFSIcs2.png)
![](https://hackmd.io/_uploads/ryNFHIcih.png)

#### 스테이지 저장
> 플스 게임을 그래픽작업이 됨언리얼, 유니티로 만듦. 유니티는 캐주얼하고 모바일 게임을 많이 만듦
> 플랫폼은 승강장이라는 뜻을 가지고 있어서, 평대라는 형태. 플랫폼 게임은 마리오 계통 게임에 해당. 쿠키런은 런게임에 해당됨. 플랫폼 게임은 멈춰서 각을 재야하고 생각해야 함. 런게임은 절대 서지 않은 형태. 
> 2D - 에셋 : 골든메탈 스프라이트 platformer 심플 2D 플랫포머 에셋 팩 - download, import - DEMO : RIGIDBODY 작동
> 대문자, 소문자, 대문자 쓰는 방식은 카멜케이스 / 소문자 대문자 소문자 쓰는 방식 스몰케이스
> INTENTATION 들여쓰기 중요
> /* */ 각주처리 
> `player.GetComponent<Rigidbody2D>().AddForce(new Vector3(0, speed, 0), ForceMode2D.Impulse);//물리엔진 컴포넌트` 컴포넌트는 게임엔진에서 쓰는 걸로, 또 하나의 인스턴스가 생겨서 그 라이브러리를 쓰고 싶으면 겟 컴포넌트해줘야 함. 플레이어에 있는 rigidbody를 가져와요. ()는 함수로. 강체에다가 Addforce해야함. 
> GETCOMPONET는 시간이 걸림. 
> GameManager - 1단계 : 윗쪽 방향키 눌렀을 때 점프
------------------------------------------------
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Manager : MonoBehaviour
{
    public GameObject Player;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if(Input.GetKeyDown(KeyCode.UpArrow))
        {
            Jump();
        }
    }
    void Jump()
    {
        Player.GetComponent<Rigidbody2D>().AddForce(new Vector3(0, 10.0f, 0), ForceMode2D.Impulse);
    }
}


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

public class GameManager : MonoBehaviour
{
    public GameObject player; // 변수선언
    const float UP_SPEED = 5.0f;
    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.UpArrow))
        {
            Jump();
        }
        
    }

    void Jump() //함수 public 해도 됨
    {
        player.GetComponent<Rigidbody2D>().AddForce(new Vector3(0, UP_SPEED, 0), ForceMode2D.Impulse);//물리엔진 컴포넌트 
    }
}

```
>player / RIGIBODY null 경우 IF 보호함수 활용

```
if (player != null)
    {
        rb = player.GetComponent<Rigidbody2D>();
    }

if (rb != null)
        {
            rb.AddForce(new Vector3(0, UP_SPEED, 0), ForceMode2D.Impulse);//물리엔진 컴포넌트
        }
```

------------------------------------
>프리팹 폴더 만들기 : Prefebs - platforms/player/enemy/finish 
>프리팹 만들어주는게 하나로 묶어줄 수 있음. 기성품이라고 할 수 있음
> 화면 해상도를 정할 수 있음. FREE ASPECT
> 메인카메라를 플레이어의 자식으로 만들면 플레이어 카메라 모드
> 다른 스테이지 저장 : Scene이 스테이지에 해당함. 
> EditManager 삽입 - 스크립트 삽입 - PREFABS 넣으면 
> 리스트 배열 : `public List<GameObject> list Prefabs;` c++ 어레이, 벡터 / c# 리스트로 말함. 리스트는 용량 늘리고 줄일 수 있음. 프리펩을 다 집어넣으면 됨
> 게임오브젝트 : 
> Editer code : 스테이지 메뉴 생김`[ExecuteInEditMode]` 계속 수정 모드가 되고, `    [MenuItem("Stage/Save/Save as Txt")]` 저장이 되도록 할 수 있음. 툴을 만드는 사람들이 보통 사용. 
>  메뉴 만들기 
```
[MenuItem("Stage/Eunmi")]
    static void Eunmi()
    {
        Debug.Log("This is Mee");
    }
```
> stages 만들기 -  platforms / chars 폴더 만들기 - prefabs 분류 넣기. 움직이는 것과 움직이지 않는 것을 나눠서 작업
> 텍스트 형태 저장. JSON 저장 : API 사람도 기계도 읽기 편함. 화면이 어떤 구조인지 확인할 수 있음. Platforms, chars로 이루어짐. 각 좌표/ 스프라이트 / 오브젝트 이름이 잇기에 인티엔시 해서 할 수 있음. z는 2D까지 하기에 없음. 
> 프리팹을 만들어서 할 수 있음. 선언되어 있으면 됨. 
> 데이터 저장과 효율적으로 만들수 있는지에 따라서 다름.DB 쌓는 과정이 중요. 에디터 코드로 유니티를 활용할 수 있도록 함. 
> 파싱 : 스트링 문자열로 CR 캐리지 리턴 / LF 라이 피드 중앙으로 가세요. 다음 문자로 가세요도 들어가 있음. 어떻게 쪼개서 스프라이트로 만드는냐에 해당됨
> stage 폴더 잊지말자 


#### 데이터 로드
> Json {} 중괄호 으로 시작해서 블록으로 뜻함. 블록은 어떤 액션에 해당되는 내용. 반복 하는 내용. 폰노이만형 컴퓨터로 코드와 데이터를 프로그래밍을 다룸. 클래스 안에서는 함수, 변수 / 메소드와 프로포티에 해당됨. 
> " " 쓰는 내용 string 문자열로 인식자, 식별자의 이름에 해당. ,로 했을 경우에 같은 레벨에 해당됨. [ ] 어레이로 배열에 해당. 여러 블록이 들어 있는 배열이 온 내용.
> http://json.parser.online.fr/ : 웹 유틸리티로 파싱해서 문법에 맞게 함. 노드(자식)을 접음. 3개의 데이터 name, platform, chars. 그 아래의 데이터 갯수 확인함. 보통 목록형 데이터로 시퀄(SQL), 마리아 db, 오라클에 해당. NO 시퀄에 해당됨. 그때 그때 채워넣어서 편함. 시퀄은 계속 테이블이 바뀔 예정이지만, 개념없이 아무거나 쉽게 넣을 수 있어서 편안.포맷에만 맞춰서줄 수 있도록 하기에 
> tile Prefeb 지정 - Asset Resources 폴더 만들고 - 스프라이트 platforms 폴더로 이동
> loard txt - new stage 생성
> 인스펙터에 스테이지 체크를 하면 끄고 닫기 가능
> txt 파일에서 깃발을 스파이크로 바꿔서 로드 해보기
```
{"name":"Finish", "sprite":"Finish", "x":5.5, "y":0.5},
-> {"name":"Spike", "sprite":"Spike", "x":5.5, "y":0.5}
```
>  `[MenuItem("Stage/Save/Save as Txt")]` 함수가 있어야 하고, 저 메뉴 버튼이 작동하도록 함. 
>  `Static` void : 정전기라는 뜻으로 정적 변수에 해당. 인스턴스는 위계질서에 올라와 있을 경우에 메모리에 올라올 경우에 해당. C#는 뉴를 해야 메모리에 올라오는 것이라고 함. 정적 변수는 뉴를 하지 않아도 항상 메모리에 올라와 있음. 인스턴스는 많아도 공통으로 공유. 프리팹은 공유한다고 볼 수 있음. 어머니는 7남매로 인스턴스가 7개 있어도 공유한다고 볼 수 있음. 선산은 한개로 내가 있어도 없어도 계속 있는 형태. 이 클래스를 통털어서 하나 밖에 없음. 항상 접근이 가능한 것으로 public은 아니지만 edit manager 에서 할 수 있음. 메뉴 할때는 항상 static이 있어야 함.
>  save as 창이 모든 운영체제에 있음. 리눅스 - 안드로이드, OS도 있음.
>  path는 파일 페스가 있음. 페스의 길이 0이 아니면, stringfystage() 문자열화 해서 저장하세요.
>  load로 path를 해서 하나의 문자열로 다 받아 들을 수 있음. 문자열은 한줄짜리가 아니라 여러줄도 가능하고, 여러줄에 cr, lf 를 활용해서 그 다음줄로 만듦. jsonutility 활용해서 불러냄. 라이브러리가 json은 라이브러리를 c#에서 제공하지 않기에, nodeclass 형태로 파싱을 하도록 함. 
>  name 에는 항목에서 노드 클래스가 platform, chars가 있어야 함. 
>  1. name / 2. Platforms / 3. Chars
>  List형태 여러 개 읽을 수 있음. 대괄호가 있다. 

> RPG : 롤 플레잉 게임
> 어떤 게임을 만들어야 할까? 돈잘버는 게임
> 어떤 게임이 돈 잘버는 게임일까? RPG

> 스크립트 명령
%CHEST_CH1_2 : [아이템2]를 얻었다

> PNG 투명한 부분이 있다 // JPG 투명한 부분이 없다


(1) Scripts에서 <Player> 스크립트 Create-------------
```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{
    Rigidbody2D rb;
    // Start is called before the first frame update
    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.UpArrow))
        {
            rb.AddForce(new Vector3(0, 5.0f, 0), ForceMode2D.Impulse);
        }
        if (Input.GetKeyDown(KeyCode.LeftArrow))
        {
            Vector3 v = rb.velocity;
            v.x = -2.0f;
            rb.velocity = v;
        }
        if (Input.GetKeyDown(KeyCode.RightArrow))
        {
            Vector3 v = rb.velocity;
            v.x = 2.0f;
            rb.velocity = v;
        }

    }
}
```

(2) <Player>스크립트를 [Stage]-[Chars]-[Player] 안에 넣어준다.

    
**********************************
Hierachy - <Finish>
1. Add Component
2. Physics 2D
3. Box Collider 2D
4. Is Trigger 체크 ON
5. Finish 스크립트 추가
- Finish 스크립트를 <Finish>에 드래그
6. 코드입력
```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Finish : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        Debug.Log("Game Win!");
        
    }
}
```


6.Hierachy - CREAT - UI - Canvas
/-Hierachy - CREAT - UI - Legacy - TXT - <WinMessage>

7.
WinMessage 
: 화면을 Scene모드로 변경 - 
Font Size : 50 / Color : White 변경 - Horizontal Overflow / Vertical Overflow 모두 Overflow 설정

8. 코드 입력 - Finish
```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Finish : MonoBehaviour
{
    public GameObject winMessage;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
    private void OnTriggerEnter2D(Collider2D collision)
    {
        Debug.Log("Game Win!");
        winMessage.SetActive(true);
    }
}
```

9.<Finish>의 Inspector의 Finish스크립트의 Win Message를 WinMessage로 변경 
    
#### RPG게임 작업
> 게임기획자와 개발자가 구분되는 지점을 찾아 볼 수 있음. 게임기획자는 시스템, 스테이지, 여정, 시나리오까지 기획해서 진행.
> import pakage
> File - Build settings - 씬 추가
> scenes - start
> RESOURCE - SCRIPTS XML
> scenes - converation / ConvasConversation - Dialog - Next - On Click() : Runtime Only / TestScripts.Onclick_NextScript / Scripter 가져오기
> scenes - TilemapDungeon / resorces - images - gift 추가 / obj(gift) 이름 변경
> scenes - TilemapDungeon / ObjectManager - Obj List : obj(gift)
- scenes - TilemapDungeon / Action Item - Label Action : / Sprite Renderer : 그림 삽입 / Physics 2D - Polygon Collider 2D - Is Trigger
> Prefabs - Slot - Image : mainmenu44 / Script : Iteminfo/ Transform 60, 60 / Rotate Pic(Script) - Image : Standingimg(img)
> XML Script 파일 위치 대문자, 소문자, 다르면 달라짐. TBD.  
> test script : 필요에 의해 만들어진 문법 - 스크립트를 만들 수 있음. XML 체제 안에서 이루어질 수 있음. 파싱이 잘 됨. 
  <label name="move(RedBrick)">
    <!-- 던전에서 벽돌 스테이지로 -->
    <loadscene name="TilemapDemoComplete" entry="entry-right"/>
    <end/>
  </label>
  <label name="obj(gift)">
    <talksmall>선물상자를 얻었다.</talksmall>
    <Item id="obj(ift)" collect="1" delete="1" image="images/gift.png"/>
    <end/>
  </label>
 <label name="testTalk">
    <insert mode="2" time="1.0">portraits.png</insert>
    <talk>안녕하세요? 프로그램은 어렵나요?</talk>
    <talk>원래 고생 좀 하는 것입니다.</talk>
    <talk>^^^^^^;;;;;</talk>
    <hide all="0"/>
  </label>
</script_data>
    
#### 게임 작업 
> 포켓몬의 전투 시스템 : 공격 애니메이션과 공격 행동을 하고, hq가 줄어드는 형태로 이루어짐. 간단한 산수 놀이에 해당됨. 슈팅게임과 다른 RPG 게임에 해당하기에 만들기 쉬운 편
> 자동차 예제에서 문이 천천히 닫히게 하기 위해선, 열리는 각도와 닫히는 각도를 알기에 매 프레임마다 가져가도록 함. 프레임 delta.time 활용해서 진행. 속도보다 닫히는 시간을 가지고, 토탈 초를 알면 얼만큼을 하도록 할지 계산함.
> 부드러움이 중요한 요소. 트랜스머, 아이언맨처럼 부드럽게 움직이는 것으로 상태값 enum 활용해서 함. 
> 모든 머신과 프로그래밍은 유한 상태라고 볼 수 있음. enum Door state. easy function 그래프처럼 하기 위함. 
> 프로그래머는 모든 걸 표, 연결 상태로 봄. A에서 B로 가는 걸 고민.
> 삶의 시간처럼 0~duration 까지 시간적 위치값. 0~1.0 Lerp를 쓸 수 있으니, duration으로 나눠서 활용. CLAMp으로 최대값 넘지 않도록 함. 
> Movable
```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Movable : MonoBehaviour
{
    enum DoorState { Closed, Closing, Opened, Opening}
    DoorState doorState = DoorState.Closed; //변수 만듦,초기값
    public GameObject target;
    public Vector3 angleClose;
    public Vector3 angleOpen;
    public float duration; // 소요 시간
    float currentPosition; // 0~duration 까지 시간적 위치값


    bool bOpen = false;

    // Start is called before the first frame update
    void Start()
    {
        currentPosition = 0;
    }

    // 각도
    void SetRotation()
    {
        Vector3 currentRotation = Vector3.Lerp(angleClose, angleOpen, currentPosition / duration);
        target.transform.localRotation = Quaternion.Euler(currentRotation);
    }

    // Update is called once per frame
    void Update()
    {
        if (doorState == DoorState.Opening)
        {
            currentPosition += Time.deltaTime;
            currentPosition = Mathf.Clamp(currentPosition, 0, duration);
            if (currentPosition >= duration)
            {
                doorState = DoorState.Opened;
            }
            SetRotation();
        }
        else if (doorState == DoorState.Closing)
        {
            currentPosition -= Time.deltaTime;
            currentPosition = Mathf.Clamp(currentPosition, 0, duration);
            if (currentPosition <= 0)
            {
                doorState = DoorState.Closed;
            }
            SetRotation();
        }
    }

    public void FlipTargetSmooth()
    {
        if (doorState == DoorState.Opening || doorState == DoorState.Opened)
        {
            doorState = DoorState.Closing;
        }
        else
        {
            doorState = DoorState.Opening;
        }
    }

    public void FlipTarget()
    {
        if (target != null)
        {
            bOpen = !bOpen;

            if (bOpen)
            {
                target.transform.localRotation = Quaternion.Euler(angleOpen);
            }

            else
            {
                target.transform.localRotation = Quaternion.Euler(angleClose);
            }
        }
    }

}


```
> Game Main : fliptarget -> fliptargetsmooth  mv.FlipTargetSmooth(); //변경필요
> enginhood - duration 3 입력 
> 우리는 타자연습을 하는 게 아니다. 옆에 드롭다운이 되면 사용하고, 빠르게 입력한다. 별표가 있으면 저장이 안된거다. 

#### 파이어베이스
> 유니티에서 프로젝트를 열때는 폴더를 누르고 열기를 한다. 
    
Firebase
> 파이어베이스는 모바일 앱웹 개발. 앱 개발용 API 제공하는 서비스로 구글의 일원. 파이어베이스를 백엔드를 할 수 있음.앱을 만들때 필요한 백엔드 서비스- 서버를 필요로 하는 거의 모든 기능을 제공
> 사용자 인증, 사용자 데이터 처리, 앱과 백엔드 서버간의 안전한 데이터 통신, 앱기능의 간편한 관리를 위한 Config 관리
> 사용자 로그인을 처리하기 위해 인증서버+DB 필요. 대체 로그인 간편 인증을 많이 함. 인증하는 걸 OAUTH2.0를 이용한 인증(구글,페북, 네이버, 카톡 등 SNS로그인)
> 키를 주지 않고, 암호를 보내고 또 암호를 다시 보내고 할 수 있도록 하는 식으로 주고 받아서 접근할 수 있음.
> 사용자가 남기는 정보의 처리 DB 또는 Storage 필요, 채팅/문자 메시지, 댓글(DB), 사진 및동영상의 자료 처리(Storage)
> my sql 시퀄로 이뤄져서 키값을 일일히 만들어야 함. json, xml 노시퀄로 키값으로 알아서 들어가는 형태.
> API 구성을 위한 서버리스(파이어베이스 평션)
    
    
벡엔드를 구현하기 위한 기존 방식
>1. 서버 임대 - 2. OS 설치 - 3.API제공을 위한 WEB 솔루션 설치 (PHP, NodeJS) 4.DBMS를 탑재 ()

파이어베이스의 연동작업 
> 파이어베이스 프로젝트 생성 - 라이브러리모듈 추가해서 하면 됨. 
> 폴더 자체로 열어주세요. 
    
파이어베이스
> 구글 독스와 다르게 페이지 링크가 있지만, 키값이 나온다 https://networkbackend-cea90-default-rtdb.firebaseio.com/
> 사용자 인증 시스템을 시작하기를 한다\
> 파이어베이스 / asset json 설치, 다른 파일도 설치 , 콘솔 이동    

유니티
> 유니티 빌드 세팅에서 안드로이드, ios 가능한지 확인이 필요\
> 유니티 마크가 있으면 이미 스위치 됨
> 빌드 세팅 - 플레이어 /playername, platformname 넣고
> 파이어베이스 / asset json 설치, 다른 파일도 설치 , 콘솔 이동