Skip to content

Instantly share code, notes, and snippets.

@Curookie
Last active November 20, 2023 08:21
Show Gist options
  • Save Curookie/d29cd2e774128766591ebed6f201fe0f to your computer and use it in GitHub Desktop.
Save Curookie/d29cd2e774128766591ebed6f201fe0f to your computer and use it in GitHub Desktop.
유니티 공부 (Unity3D Study)

목차

  1. 기본 개념 및 세팅 노하우, 단축키
  2. 컴포넌트 설명
  3. 충돌체(콜리더와 트리거)
  4. 카메라
  5. UI
  6. 애니메이션
  7. 기본적인 스크립트
  8. 오디오
  9. 게임 데이터 저장 (PlayerPrefs)
  10. 씬 전환
  11. 지형 생성 (Terrain)
  12. 네트워크

기본 개념 및 세팅 노하우, 단축키

기본 개념

최초 유니티 제작자들은 파이널 컷에 영향을 많이 받아서 전체적인 툴 UI가 파이널 컷(=동영상 편집 프로그램)과 매우 흡사하다.

구성

프로젝트(Project) 1개 < 씬(Scene) 여러개 < 게임 오브젝트(GameObject) 여러개 < 컴포넌트(Component) 여러개

프로젝트 뷰(Project View) = 파일(소스관리) 창

  • 게임에 사용되는 에셋들을 관리하는 창
  • 윈도우의 탐색기, 맥의 파인더와 비슷한 역할
  • 다양한 검색 기능
  • 폴더 생성 및 파일을 불러오는 곳

하이어라키 뷰(Hierarchy View) = 사용중인 오브젝트 리스트 창

  • 현재 씬에 사용되는 게임 오브젝트를 관리하는 뷰
  • 새로운 게임 오브젝트를 생성/삭제
  • 계층 구조 설정

인스펙터 뷰(Inspector View) = 편집창

  • 현재 선택한 게임 오브젝트 혹은 애셋의 정보를 보여주는 뷰
  • 컴포넌트 추가/삭제/변경
  • 게임 오브젝트 이름, 태그, 레이어 변경

씬 뷰(Scene View) = 게임내 세트장

  • 우리가 실질적으로 게임을 제작하는 공간
  • 게임 오브젝트들을 배치하는 곳
  • 씬 뷰 툴바 (Q-핸드 W-포지셔닝 E-로테이션 R-스케일링 T-렉)

게임 뷰(Game View) = 실제 보이는 스크린(메인 카메라의 모습)

  • 현재 씬이 실제로 작동하는 모습을 보여주는 뷰
  • 다양한 해상도 테스트와 게임을 플레이 해보는 곳
  • 게임 뷰 툴바(Ctrl+P-실행, Ctrl+Shift+P-일시정지, Ctrl+Alt+P-다음프레임)

왼손 비유 = 기즈모
오른쪽 - 회전
Alt + 오른쪽 확대/축소
축 중심 회전

프리팹(Prefab)은 데이터를 재사용하거나 한번에 모두 수정하기 위해 그룹핑한 것

프리팹은
= 파란색 정육면체 아이콘. Hierarchy에서 파란색 글씨.
= 유니티의 핵심 개념(에펙의 컴포지션 같은 개념)
= 개발을 위해 만든 오브젝트(리소스+컴포넌트들)들을 묶어 재사용을 통해 프로그래밍, 아트의 작업효율을 높이기 위해 사용한다.
= 수정작업이 필요 시 원본인 프리팹을 수정하면 씬에서 사용된 모든 프리팹이 일괄 수정된다. (이 부분을 주의하고 잘 사용 시 작업효율 높아짐)
= 만드는 방법은 그냥 Hierarchy에서 Project로 프리팹화 할 오브젝트를 끌어다 놓으면 됨.
= 프리팹 원본은 Project에 있는거다.
= 수정하는 방법은 원본을 수정하면 모두 바뀌고, 인스턴스(Hierarchy에 있는 애)를 바꾸고 Inspector윗 부분에 Apply 누르면 원본에 적용되 모두 바뀌지만 누르지 않는다면 그 인스턴스 하나만 수정된 상태로 있는다. Select는 연결된 프리팹 보여주고, Revert는 변경사항을 원본의 상태로 초기화한다.
= 제거하는 방법은 원본을 제거하면 사라지고 Hieratchy의 빨간색은 원본과 연결이 끊겨서 발생하는 경고인데 신경쓰이면 메뉴에 GameObject>Break Prefab Instance를 누르면 된다.

세팅 노하우

가로형 게임일 경우 Layout 2by3 으로 두고 작업하고 세로형 모바일이면 Game View를 세로로 둬서 작업하는게 좋음

폴더 정리는 반드시 하자!

제작 리소스가 많아지면 UI에서 드래그로 작업해야하는 엔진 특성상 작업효율이 상당히 떨어질 수 있다.
따라서 프로젝트 폴더명 정리는 필수적이다. (정리의 중요성은 게임이 영상보다 더 심하다!)
ex)
01Scene
02Script
03Prefab
04Image
05Audio
06Animation
07Material
08Particle
09Font
10Shader

디자이너와의 소통

디자이너는 흰색 버튼만 만들면 다른 색이나 투명도를 고민할 필요없다.
유니티 내에서 제작 가능하다는 점을 상기시켜주자!

유용한 단축키

ctrl+d 복제
ctrl+p 게임 시작/중지
ctrl+9 에셋스토어 창

3D할 때는 Q-핸드 W-포지셔닝 2D, UI할 때는 T-렉 (T키로 Rect Tool 활성화 하면 UI 조정할 때 씬 뷰에서 외곽선 볼 수 있다.) V키 - 특정 오브젝트를 특정 위치에 붙일 수 있는 기능
하이라키에서 오브젝트 더블클릭 - 오브젝트 시점으로 전환(오브젝트 찾아줌)


컴포넌트 설명

유니티에서 속성을 이루는 가장 작은 단위라고 생각하면 된다. 오브젝트에 컴포넌트(속성)를 붙여서 프로젝트를 진행하는 것이다. 모든 컴포넌트는 인스펙터 뷰(GUI수정) 또한 스크립트(코딩수정)로 컨트롤 가능하기 때문에 꼭 숙지해둬야한다.

1. Transform

모든 오브젝트에 있는 컴포넌트 (단, UI 오브젝트 에선 Transform을 상위호환인 Rect Transform을 가지고 있다.)

3가지 옵션이 있다.
position(위치정보) x,y,z
rotation(회전정보) x,y,z
scale(크기정보) x,y,z

왜 모든 오브젝트에 있어야만 하는 컴포넌트(속성)인지 10초만 고민해본다면 이해할 수 있을 것이다.

2. SpriteRenderer

2D 이미지(Sprite)를 보여주기 위한 컴포넌트
sprite에 이미지를 넣으면 된다.

옵션 sprite

3. Rigidbody( 2D)

물리속성(이동, 중력, 저항, 무게 등)을 쉽게 구현하기 위해 제공하는 컴포넌트
Rigidbody는 3D
Rigidbody 2D는 동일한 기능 2D를 위한 컴포넌트다.

2D라고 Rigidbody를 사용해서 작동 안하는 건 아니지만 3D형태로 연산이 되니까 리소스 낭비가 될 것이다.

옵션
mass : 질량
drag : 힘에의해 공기저항
angular drag : 회전할때 공기저항

리지드바디 y 막고 x,z 막고 평면이동 할 때 물리 Constraints Freeze Y 해주면된다.


충돌체(콜리더와 트리거)

콜리젼은 두 물체가 부딪히는 현상, 트리거는 두 물체가 범위안에 들어온 현상
유니티는 NVidia의 PhyxsX 물리엔진을 사용한다.

필요한 컴포넌트 ???? Collider (2D) 컴포넌트 - 물리적용을 위한 충돌체 범위(콜리젼)나 이벤트를 위한 범위(트리거)를 지정하기 위해 사용하는 컴포넌트 Rigidbody(2D) 컴포넌트 - 물리적용 컴포넌트

Collision 충돌

  1. 두 물체 모두 Collider(2D)를 가지고 있다.
  2. 둘 중 적어도 하나는 Rigidbody(2D)를 가지고 있다.

Trigger 충돌

  1. 두 물체 모두 Collider(2D)를 가지고 있다.
  2. 둘 중 적어도 하나는 Rigidbody(2D)를 가지고 있다.
  3. 둘 중 적어도 하나는 IsTrigger 옵션이 체크되어 있다.

Layer와 Edit > Project Settings > Physics로 충돌을 없앨 수 있다.


카메라

넘나 중요할 수 밖에 없는게 실제 보이는 연출을 담당하기 때문이다.

Isometric View 2.5D라고 함 = 원근감 없는 3D라 생각하면 됨 isometric 만들기 camara Orthographic 뷰로 설정하면 Isometric 만들 수 있다.

하늘 추가하기

Window > Rendering > Lighting에서 Skybox추가할 수 있다.


UI

사실 많은 변화가 일어나고 있고, 여러 디자인적 개념이 들어가 쉽지 않을 수 있는 파트이다. 잡 기술이나 팁도 많은 편이다.

uGUI (unity Graphic User Interface)
요즘은 이걸로 쓰자. 미래성도 있음.
nGUI 유료 에셋이고 예전에 유행했던 방식

UI는 Transform 대신 Rect Transform을 사용하고
Position값은 앵커와 피벗에 대한 Position값으로 수정된다.

앵커(Anchor) - 흰색 화살표4개 (퍼센트 값 0-1)
UI의 부모에 대한 고정 오프셋
부모 사각형의 폭과 높이에 대한 비율로 정의

피벗(Pivot) - 파란색 가운데 빈 동그라미
이동/회전/크기 조절하는 중심 축이다.

  1. Canvas - UI를 그리는 공간, 모든 UI는 canvas의 자식오브젝트이다.

RenderMode 그리는 방식을 정함

  1. Screen Space - Overlay 포지션을 옮길 수 없고 그냥 어떤 카메라든 상관없이 보이는 카메라 위에 덮어 씌워진다.
  2. Screen Space - Camera 특정 카메라에 위에 덮어 씌우는 것
  • Plane Distance - 카메라와 떨어져있는 (z)거리
  • SortingLayer - UI 전체의 레이어 순서
  1. World Space 캔버스의 위치를 실제 위치에 적용해 주는 방식.

Canvas Scaler 컴포넌트는 보이는 크기의 비율을 세팅하기 위해 사용하는 컴포넌트
UI Sacle Mode

  1. Scale With Screen Size로 세팅해두는 걸 추천
    Reference Resolution 모바일 1920 * 1080(16 * 9) 이나 2220 * 1080(18.5 * 9) 적절한 타겟을 정해서 하는게 좋음
    Match - Width나 Height에 맞추는 편이 좋음. 가로게임이냐 세로게임이냐에 따라 적절한 것을 선택하는게 좋음.
  1. Image - Sprite를 사용하는 이미지 UI오브젝트 생성, Image Type이 중요!
    Source Image - 이미지 Sprite
    Color - 이미지 대상으로 색을 정하기 때문에 다양한 색을 원한다면 흰색으로 해두고 변경하는걸 추천!
    Raycast Target - 클릭 가능여부 정하는 것

Image Type

  1. Simple 그냥 표시
  2. Sliced 잘라진 Sprite Editor에서 초록색 선으로 테두리 빼고 지정할 수 있다. (원하는 크기 이미지 별로 안깨져 보이게 수정가능 - 테두리가 안 깨지므로)
  3. Tiled 테두리 지정 유지한 채로 바둑판식 체우는 것 가능
  4. Filled 스킬 도는 것이나 체력 체워지는 것 할 때 사용할 수 있다.

Preserve Aspect - 이미지 크기 그대로 지정(비율이 유지된 채로 최대 크기로 지정 됨.)

  1. Text - 화면에 텍스트를 표시, 폰트, 크기, 정렬, 텍스트가 사각 영역 너비/높이 보다 클 경우 옵션 선택
    Text - 텍스트 내용 ( <태그> 형 문법 사용가능 rich 문법이라고 함)
    FontSize - 텍스트 크기
    Horizontal Overflow - 가로 넘치면 어떻게 할건가 Overflow로 해두는거 추천 (넘어도 짤리거나 표시 안 되는거 방지)
    Vertical Overflow - 세로 넘치면 어떻게 할건가 Overflow로 해두는거 추천 (넘어도 짤리거나 표시 안 되는거 방지)
    BestFit - 사각형에 딱 표시할 수 있는 최대 사이즈로 바꿔준다.

  2. Outline - 테두리를 넣을 수 있다.

  3. Shadow - 그림자도 넣을 수 있다.

  4. Button - 버튼
    Interactable - Enable/Disable 상태 정하기

Transition - 4가지 상태별로 어떤 식으로 표현할 지

  1. Normal - 기본
  2. Highlighted - 마우스 갔다댈 때
  3. Pressed - 마우스(터치) 클릭할 때
  4. Disabled - 클릭(터치) 못하게 막을 때

OnClick() - 버튼 클릭 시(터치) 이벤트 발생 설정 (아래 괄호는 스크립트일 경우 설명)

  1. 어떤 오브젝트의 (스크립트 시 보통 자기 자신)
  2. 어떤 컴포넌트의 (보통 자기 자신에 달린 스크립트)
  3. 어떤 값을 (스크립트 안에 public으로 생성된 함수)
  4. 어떻게 바꾸겠다. (매개변수가 있으면 입력 없으면 이 부분 생략됨)
  1. Scroll View - 스크롤 뷰
    Scroll View의 Vertical을 꺼주면 가로만 되게 설정할 수 있음.
    Viewport - Scroll View의 크기에 따르는데 Mask로 안보이게 하는 것
    Content - 아래에 내용을 넣으면 됨

(Vertical, Horizontal) Layout Group 컴포넌트 사용하면 오브젝트 간의 정렬 사용할 수 있음. (자동화 - 효율, 유지보수 향상)

  1. Input Field - 입력 창
    Placeholder - 도움말 가이드 텍스트
    Text - 실제 입력 내용
    OnValueChanged(String) - 바뀔 때마다 작동하는 이벤트
    OnEndEdit(String) - 입력이 끝날 때 작동하는 이벤트

[필수 팁]

  1. Rect 툴(T키)을 사용하면 UI 수정하는데 유용하다.
  2. UI 생성하면 EventSystem 자동으로 생성되는데 UI클릭이나 터치등을 처리하는 오브젝트가 자동으로 붙는거니까 그대로 둬라.
  3. 반응형이나 다양한 비율을 잡아줄려면 빈 패널들로 레이아웃을 잡아놓고 그 안에 배치하는게 좋다.
  4. Rect Transform > Anchor Presets(아이콘 눌러서 나오는 팝업)에서 Alt와 Shift 누르면 Anchor Point 설정할 때 옵션이 달라진다.
  5. 스크립트 부분에서 UI컴포넌트를 GetComponent하려하면 using UnityEngine.UI; 을 적어줘야한다.
  6. 레이어 순서 개념 이해해두면 좋다.
  7. 버튼은 Raycast 클릭되는 범위는 투명한 영역과 상관없이 파란색 범위는 다 클릭이 된다.
  8. UI의 Image는 none시에 흰색 불투명한 배경, SpriteRenderer는 none시에 투명한 배경이 세팅된다.

애니메이션

레거시 애니메이션 - 예전 유니티 코드로 애니메이션 컨트롤 하는 기술을 의미
메카님 에니메이션 - 애니메이터와 스테이트 개념이 적용되 GUI로 컨트롤 하는 기술을 의미

[매카님 에니메이션]

에니메이션은 트랜지션과 파라미터를 알고 있어야한다.

  1. Animation 컴포넌트로 애니메이션을 지정하는 방법
  • Animation컴포넌트를 넣고 Animation뷰에서 Add 하면 Clip이 만들어지고 그 안에 넣어진다.
  • 간단한 애니메이션을 표현해야할 때 사용한다.
  • Animation 뷰에서 녹화 버튼(빨간색)을 누르고 키프레임마다 물체를 변경해서 애니메이션을 만드는 형태로 작업하면 편하다. 디테일 한부분은 프레임 값을 넣어서 지정하면되며 Samples가 1초당 프레임 수 이므로 이걸 바꾸면 초당 프레임수를 다르게 적용할 수 있다.
  • Animation 뷰에서 애니메이션 제목 클릭하면 New Animation있는데 이걸로 해당 오브젝트 새로운 애니메이션 추가 가능.
  • Animation에서 Position을 움직이는 동작을 하면 다른 물리나 코드에서 Position이 변경되는 것이 무효화 된다!
    => 이 부분을 해결하고자 빈 게임 오브젝트를 만들어서 그 안에 내용을 넣어두고 빈 오브젝트에 애니메이션을 달아 수정하거나 이런식으로 하기도 함.
  1. Animator 컴포넌트로 상태에 따른 애니메이션 지정하는 방법
  • Animator컴포넌트를 사용하며 Animator Controller 상태를 관리하는 애셋이 장착 되어야한다.
  • Animation뷰와 Animator뷰를 사용해서 작업한다.
  • 오브젝트를 선택한다음 Animation뷰에서 Add 해서 Clip을 만들면 자동으로 그 오브젝트 이름으로 Animator Controller가 생성되어 오브젝트에 장착 됨.
    (Animator에서 애니메이션 추가할 경우 모든 Animation Clip은 자동적으로 Loop옵션이 체크되어있다. 한번만 작동하게하려면 Clip선택해 Loop를 꺼야한다.)
  • State(동작)들로 이뤄져있고 Transition(선)들로 이동
  • Entry는 시작 시에 작동할 상태와 연결, Any State는 모든 상황에서 작동할 수 있는 State, Exit는 Entity로 돌아갈 수 있도록 끝낼 때
  • 디폴트 상태는 주황색, 각 트랜지션(선)마다 파라미터(조건)을 지정할 수 있다.
  • State의 Motion에 들어가는 건 Animation Clip(재생할 하나의 동작), Speed - 재생 속도
  • Animation Clip의 옵션은 State 아이콘을 더블클릭하면 나오며 Loop Time(반복할거냐, 안할거냐), Loop Pose(3D에서 자연스러운 전환), Loop Offset(시작점 수정)
  • Parameters에 보면 조건을 추가할 수 있다. 코드에서 Set/GetTrigger, Set/GetBool, Set/GetInt .. 등 이런 함수들을 가지고 설정한다.
  • HasExitTime (체크되면 조건이 만족되어도 나가는 시간을 만족 해야만 나간다. 바로 나가고 싶으면 체크를 풀어야한다.)
  • Transition Duration (자연스러운 변환시간 2D에선 대체적으로 0)
  1. Playable Director 컴포넌트로 요즘 뜨고 있는 Timeline을 사용해서 애니메이션을 지정하는 방법 세가지로 볼 수 있다.
  • 오브젝트 클릭하고 Timeline뷰에서 Add하면 Playable애셋이 장착되고 애니메이션 클립을 잔득 안만들어도 되어서 좋다. (Playable안에 자동저장됨)
  • 기존 애니메이션 뷰로도 편집할 수 있음.
  • 마치 동영상 프로그램같이 Track으로 관리되며 더욱 직관적이고 코드와 결합도 쉬워졌다.
  • 시네마틱 콘텐츠, 게임플레이 시퀀스, 오디오 시퀀스, 복합 파티클 효과에서 사용하면 좋다.

[레거시 애니메이션의 예]

[System.Serializable]
public class Anim
{
    public AnimationClip idle;
    public AnimationClip runForward;
    public AnimationClip runBackward;
    public AnimationClip runRight;
    public AnimationClip runLeft;
}
본클래스 {
    public Anim anim;
    public Animation _animation; -> PlayerModel(Animation)
}
    void Start()
    {
        tr = GetComponent<Transform>();

        _animation = GetComponentInChildren<Animation>();
        _animation.clip = anim.idle;
        _animation.Play();
    }

    // Update is called once per frame
    void Update () {
        h = Input.GetAxis("Horizontal");
        v = Input.GetAxis("Vertical");
        Vector3 moveDir = (Vector3.forward * v) + (Vector3.right * h);
        tr.Translate(moveDir * Time.deltaTime * moveSpeed, Space.Self);
        tr.Rotate(Vector3.up * Time.deltaTime * rotSpeed * Input.GetAxis("Mouse X"));
        //        Debug.Log("H = " + h.ToString());
        //        Debug.Log("V = " + v.ToString());

        //키보드 입력값을 기준으로 동작할 애니메이션 수행
        if (v >= 0.1f)
        {
            //전진 애니메이션
            _animation.CrossFade(anim.runForward.name, 0.3f);
        }
        else if (v <= -0.1f)
        {
            //후진 애니메이션
            _animation.CrossFade(anim.runBackward.name, 0.3f);
        }
        else if (h >= 0.1f)
        {
            //오른쪽 이동 애니메이션
            _animation.CrossFade(anim.runRight.name, 0.3f);
        }
        else if (h <= -0.1f)
        {
            //왼쪽 이동 애니메이션
            _animation.CrossFade(anim.runLeft.name, 0.3f);
        }
        else
        {
            //정지시 idle애니메이션
            _animation.CrossFade(anim.idle.name, 0.3f);
        }
    }

기본적인 스크립트

우리가 원하는 컴포넌트를 만들기 위해서, 더 나아가서 에디터를 수정하기 위해서 알아야한다.
언어는 C#

using ~~ -> 사용할 도구를 불러오는 부분

public(누구나 사용해라) class(스크립트 컴포넌트) ~~ (컴포넌트 이름) : MonoBehaviour(유니티의 기본기능을 사용하겠다.) {
여기에 내용(코드)을 적으면 됨.
// 주석은 코드에 영향을 주지 않는 설명할 때 사용한다. 한줄 주석임(//)
// 코드는 절차적으로 실행 윗줄에서 아래줄으로
}

이벤트 함수호출 순서

이걸 왜 알아야할까? 가장 중요함!! 다 외워두는걸 추천 게임의 시간 흐름에 적절하게 코딩을 할 수 있음. 적절한 흐름에서 코딩할 줄 모르면 에러가 날 수도 있고(코드로 컴포넌트를 가져 와야하는데 없는 상황 등...), 코드를 비효율적이게 짤 수도 있다.

  1. Reset() - 스크립트를 인지했을 때 실행
  2. Awake() - 최초 실행(오브젝트가 생성됬을 때)
  3. OnEnable() - Awake와 Start사이(말 그대로 Enable 체크 됬을 때)
  4. Start() - 한번만 실행하는 코드를 넣기 위해 실행
  5. FixedUpdate() - 고정된 프레임 시간에 실행된다. 가장 먼저 업데이트 되는 코드.(랙이 걸려도 상관없이 적용되어야 하는 코드를 넣는다. 물리관련 업데이트 코드를 넣으면 좋다.)
  6. yield WaitForFixedUpdate() - 코루틴에서 FixedUpdate후에 실행되는 yield
  7. OnTriggerXXX() - 트리거 먼저 실행
  8. OnCollisionXXX() - 충돌 실행
  9. OnMouseXXX() - 마우스 클릭 이벤트 실행
  10. Update() - 매 프레임 마다 실행(랙에 따라 지연될 수도 있다.)
  11. yield null() - 코루틴에서 Update후에 실행되는 yield
  12. yield WaitForSeconds()
  13. yield WWW()
  14. yield StartCoroutine()
  15. LateUpdate()
  16. OnRender~~~ () 렌더링 ~~
  17. OnGUI()
  18. yield WaitForEndOfFrame()
  19. OnApplicationPause()
  20. OnDisable()
  21. OnApplicationQuit()
  22. OnDestroy()

기본적인 함수/프로퍼티

  1. Debug.Log(string); Debug.Log(int); Debug.Log(float);
    출력 체크용 함수 - 보통 버그 잡을 때 사용

  2. Destroy(GameObject); Destroy(GameObject, float);
    게임 오브젝트 제거, 몇 초 뒤에 제거

  3. transform.Translate(Vector3);
    transform 컴포넌트를 사용해서 해당 게임 오브젝트 이동(코드로 이동 - 순간 이동)
    보통은 update에 넣어서 완전히 단순히 이동시킬 때 사용
    Vector3.right(1f,0,0), up(0,1f,0), forward(0,0,1f) .. 등 Vector3의 상수를 사용가능

  4. transform.Rotate(Vector3);
    transform 컴포넌트를 사용해서 해당 게임 오브젝트 이동(코드로 회전 - 순간 회전)
    보통은 update에 넣어서 완전히 단순히 회전시킬 때 사용
    Vector3.right(1f,0,0), up(0,1f,0), forward(0,0,1f) .. 등 Vector3의 상수를 사용가능

  5. Input.GetKeyDown(KeyCode);
    특정 키가 눌리는 순간 true를 반환한다. (조건문하고 같이 사용해야함!)
    KeyCode.Space, KeyCode.Enter.. 등 KeyCode의 상수 이용하면 됨

  6. Instantiate(GameObject); Instantiate(GameObject, ); Instantiate(GameObject);
    괄호 안에 게임 오브젝트를 복제(새롭게 코드로 생성)할 때 사용한다. (많이 씀, 프리팹하고 연동해서) 그냥 생성하는 건 안쓰고, 위치와 회전값을 지정해주는 형태로 주로 사용한다.

  7. gameObject.GetComponent();
    컴포넌트 이름을 <제너릭> 표현안에 넣으면 게임 오브젝트의 그 컴포넌트를 가져올 수 있다. (가장 많이 씀)
    가져 온 다음 그 컴포넌트의 기능/값을 코드로 수정하면 됨.
    한번 만 가져와서 변수에 캐싱해서 사용해라.

  8. rigidbodyComponent.AddForce(Vector3);
    rigidbody컴포넌트에 힘을 줘서 움직이게 하는 코드 (코드로 일시적 힘을 줄 수 있다. - 자연스러운 움직임 가능)

  9. gameObject.SetActive(bool);
    게임 오브젝트를 Enable/Disable 할 수 있다. 특정 상황에서 키거나 끌때 또는 생성하지 않고 재활용할 때도 사용한다. (오브젝트 풀에서도 사용)

  10. transform.right; //right 대신 원하는 Vector3 키워드 사용가능
    transform의 특정 방향만 가져오거나 세팅할 때 사용하는 프로퍼티

Input관련(키 입력 값 별) 스크립트

  1. Input.GetKey(키코드) : 해당 키를 눌렀을 때 true
  2. Input.GetKeyDown(키코드) : 해당 키를 누르기만 했을 때 true
  3. Input.GetKeyUp(키코드) : 해당 키를 눌렀다가 뗐을 때 true
  4. Input.GetButton(정의된_키) : 해당 키를 눌렀을 때 true
  5. Input.GetButtonDown(정의된_키) : 해당 키를 누르기만 했을 때 true
  6. Input.GetButtonUp(정의된_키) : 해당 키를 눌렀다가 뗐을 때 true

즉, GetKey = GetKeyDown + GetKeyUp, GetButton = GetButtonDown + GetButtonUp 이다. (눌리고 있는 동안 true)

Input.GetAxis("정의된 키워드"); 그 키워드(행동)가 실행됬을 때(플랫폼 상관없이 true)

이동(Translate) 코드

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

public class PlayerCtrl : MonoBehaviour {
    private float h = 0.0f;
    private float v = 0.0f;

    private Transform tr;

    [SerializeField] [Range(0,100)] public float moveSpeed = 10.0f;
   
    void Start()
    {
        tr = GetComponent<Transform>();    
    }

    // Update is called once per frame
    void Update () {
        h = Input.GetAxis("Horizontal");
        v = Input.GetAxis("Vertical");
        Vector3 moveDir = (Vector3.forward * v) + (Vector3.right * h);
        tr.Translate(moveDir * Time.deltaTime * moveSpeed, Space.Self); // Space.Self 로컬방식/ World.Self 글로벌방식  
//        Debug.Log("H = " + h.ToString());
//        Debug.Log("V = " + v.ToString());
	}
}

마우스 카메라 회전 코드

  1. 플레이어에 메인카메라 넣기
tr.Rotate(Vector3.up * Time.deltaTime * rotSpeed * Input.GetAxis("Mouse X"));
  1. 카메라에 코드 넣기
  public Transform Player;
    Vector3 Offset;

	// Use this for initialization
	void Start () {
        Offset = transform.position - Player.position;
	}
	
	// Update is called once per frame
	void Update () {
        Vector3 Playerpos = Player.position + Offset;
        transform.position = Vector3.Slerp(transform.position, Playerpos, Time.deltaTime * 10.0f)
	}

c# 접근 한정자

프로그래밍적인 개념이긴한데 중요함. 범위를 한정함으로서 보안적, 효율적으로 코드를 구조화 할 수 있다. 함수나 변수 맨 앞에 붙이는 수식어임.

  1. public 모든 곳 - public으로 선언된 변수는 엔진에서 수정이 가능하다. (인스펙터 뷰에 보이게 됨)
    ex) 보통 게임오브젝트나 프리팹을 선언된 변수에 끌어다 놓아 캐싱해서 사용하는 식으로 코드를 짜면 된다.
  2. [default] private 클래스 내부 - 아무것도 안 적으면 기본으로 이걸로 됨. (다른 클래스에서 참조 불가)
  3. protected 파생 클래스 - 상속 받은 클래스, 인터페이스까지만 사용가능
  4. internal 어셈블리 내부 - 말 그대로 어셈블리 단에서만 추가적으로 사용가능
  5. protected internal 같은 어셈블리 내부 & 파생 클래스

형 변환

값은 그대로이지만 다른 자료형으로 변환시키는 방법.

암시적 형변환 - 자동으로 바꿔주는 것
ex) int -> float float i = 10;
ex) string + int string s = "a"+100;

★ 명시적 형변환 - 직접 해줘야하는 형변환
ex) float -> int int i = (int) 1.3f; //버림 함 1.3f -> 1 ex) string -> int int.Parse("100"); ex) int -> string 100.ToString();
ToString("format") 포맷을 정해서 출력하게 할 수 있는데 알아두면 유용함.
ToString("N0") 1000의 자리 숫자마다 , 넣어주기 123,456 이런식으로
ToString("N3") 3자리 수로 앞에 없으면 0 넣어주기 001 002 003 이런식으로

Lerf, Slerp 따라가는 식

Trail Render 뒤에 이미지가 따라오는 것

[옵션]

  1. Tag는 한번에 여러 가지 오브젝트를 컨트롤 하는 작업을 할 때 사용.

  2. Layer는 특정 부분에 (효과,빛)을 주고싶을 때 사용하는 것이다.

  3. RequireComponent 유니티에서 컴포넌트를 스트립트 상에서 추가하는 옵션이다. 보통 클래스 밖에 쓴다. ex) [RequireComponent(typeof(Rigidbody))] 꼭 필요한 컴포넌트가 없는 상태로 실행되는것을 막을 수 있다.

[Tip] edit> player Settings > input(axis)

ai로 타겟을 찾아가는 nav mesh라는 기능

트리거 콜린더 탐지할 수 있게 하는 기능

FindGameObjectWithTag 로 태그단위로 컨트롤 할 수 있다. ex) GameObject.FindGameObjectWithTag("태그명").transform;

컴포넌트 참조는 GetComponent<컴포넌트명>(); 으로 참조할 수 있다.

canvas는 화면의 비율을 유지

canvas group은

sublimecodeintel 코드 인텔리전스 기능 유니티는 unity completions를 설치해야한다.

coroutine은 동시성을 표현하기 위한 방법 update 와 비슷, ienumerator를 사용해서 시간을 조정, 원하는 때에 키고 끌 수 있다. yield 같이 쓴다. lerp 중간값을 구하는 함수

LookAtConstraint AR에서 특정 시점을 바라보게 할 수 있는 것 Transform.LookAt 메소드도 있다. Application.Quit(); 어플 종료 Quaternion 회전 FixedJoint 움직이는 WandController Vive VR 툴 Steam VR 써야함

ctrl+alt+c 주석척리

OnCollisionEnter(Collision hit) OnTriggerEnter(Collider hit) Instantiate 는 객체 생성하는것 Instantiate (ball, transform.position, Quaternion.identity) as GameObject; Object는 GameObject 형변환 시켜야한다.

리셋 씬 SceneManager.LoadScene("Scene_Name"); 유니티 Reference 페이지를 잘 활용해야한다.

canvas grup alpha를 가질 수 있도록 지원하고 다른 기능 소유 alt + 캔버스 폼 클릭하면 크기를 꽉 체울수 있다. mask로 맞출수 있다. ray

rigidbody의 Gravity 구동원리를 이해 못하고 있다.

콘솔 창에서 체크 할 수 있는 기법 Debug.Log ("텍스트"); 현재 오브젝트의 이름을 this.GameObject.name로 알 수 있다. 유니티에서 CSV 불러올려면 CSVParser.cs 같은 클래스 파일을 만든다음 불러오는 방법을 사용한다. 리스트 : List<제너릭> 변수명 = new List<제너릭>(); 리스트에 추가 : 리스트.Add(?); 지정 인덱스 리스트에서 삭제 : 리스트.RemoveAt(0); 3번째에 저장되어 있는 리스트 값 사용 : 리스트[2]; 지정된 인덱스에 삽입 : 리스트.insert(1, ?); 다양한 형을 집어 넣을 수 있는 리스트 : ArrayList 변수명 = new ArrayList(); String > Float로 형변환 : float.Parse(String); 유니티 파일 불러오기 : Resources.Load(파일명/위치);

애니메이션 Loop Time 체크 끄면 한번만 작동하게 할 수 있다. Instantiate 로 생성하면 (clone) 이 붙는데 이거 없애려면 생성한 거 Gameobject.name = 원래오브젝트.name; 해주면 됨 Fade API가 많이 있고, UI API도 Asset Store에 많이 있다.

Window -> Lighting -> Lightmap Tab -> Disable Continuous Baking -> Press Build to bake the lighting once manually. Window > Lighting > Other Settings. Turn off Auto and press Build. Reload 할 때 조명깨지는거 방지할 수 있음.

디자인 Materials -> Albedo 왼쪽 박스에 끌어넣기 Albedo 칼라 바꾸면서 저녁/낮 효과 normalMap -> 씌우면 입체효과, 값 수정 더 심하게 할 수 있다.

UI 카메라를 따로 두고, 완전 멀리 두고 Depth only로 두면 겹쳐보이게 할 수 있고, Culling Mask 를 UI로 설정하면 된다. 두개 렌더링 시키는 방식

오디오

최적화하는데 주의 해야한다.

  1. Audio Source - 소리의 셋
  2. Audio Clip - 소리 내용
  3. Audio Listener - 듣는 곳

Mute - 음소거
BypassReverbZones - (동굴효과 이펙트)
PlayOnAwake - 시작할 때 자동으로 시작할 거냐
Loop - 반복재생
Priority - 우선순위

스크립트 GetComponent().Play, Stop, Pause, UnPause 등

Audio Listener는 MainCamera에 자동으로 추가되어있고, 씬에 하나만 있어야한다.

게임 케릭터가 어디에 가까워지면 소리 크고 멀어지면 줄이고 싶으면 Audio Listener를 게임 케릭터에 달고
AudioSource에서 Spatial Blend 최대로 주고, 3D Sound Settings 범위를 늘려줘야한다. Min, Max 세팅. 원 크기 직접 늘려도 됨


게임 데이터 저장 (PlayerPrefs)

데이터를 간단하게 저장할 수 있게 해주는 클래스
key값과 데이터를 넣어 저장할 수 있고 , 반대로 key값을 넣어 데이터를 꺼낼 수도 있다.
저장 가능한 데이터 타입
int , float , string

데이터 세팅 방법
PlayerPrefs.SetInt("hero_hp",10); // hero_hp 라는 key 값으로 10의 정수형 데이터를 집어 넣음

이런식으로 SetFloat, SetString 으로 float 와 String 의 값을 넣으면 된다.

데이터 얻어오는 방법
PlayerPrefs.GetInt("hero_hp"); // hero_hp key에 대응하는 값을 돌려준다. key 가 없을경우 기본값을 돌려준다. ( 0 )

마찬가지로 GetFloat , GetString 도 해주면 된다.

데이터 삭제
ㄱ PlayerPrefs.DeleteKey("hero_hp"); // key값을 넣어 해당 key값을 가진 값을 삭제
ㄴ PlayerPrefs.DeleteAll(); // 모든 데이터를 삭제

데이터의 유무 체크
PlayerPrefs.HasKey("hero_hp");

key값이 존재한다면 true를 반환, 없다면 false 반환

저장 방법
PlayerPrefs.Save();를 호출하면 된다.

저장되는 공간
ㄱ Mac일 경우 :
~/Library/Preferences 폴더에 unity.[company name].[product name].plist 이름으로 저장된다.

ㄴ Windows일 경우 :
HKCU\Software[company name][product name] 레지스트리에 저장된다.

ㄷ Mac , Web일 경우
~/Library/Preferences/Unity/WebPlayerPrefs 바이너리 파일 아래에 저장된다.

ㄹ Windows , Web일 경우
%APPDATA%\Unity\WebPlayerPrefs 에 저장된다.

Web 에서는 1mb의 용량제한이 있고 웹 플레이어 URL당 하나의 파일을 사용할 수 있다.
제한이 초과될 경우 PlayerPrefsException 을 던진다.

보안 문제
다른 플랫폼은 테스트해보지 못했으나 맥에선 해당 plist를 열어볼 수 있다. ( 수정은 불가능하지만 )
일단 열어볼 수 있다는 것 하나만으로 보안이 그렇게 높은건 같지 않고, 정 사용하려면 key 값과 데이터를 암호화 해서 사용하는게 좋을듯 하다.

씬 전환

Build Settings 에서 실제 사용할 Scene을 드래그 앤 드롭 하면 씬 이름과 번호가 적용된다.

스크립트에서
using UnityEngine.SceneManagement;

SceneManager.LoadScene(씬 이름or씬 번호);
로 전환 가능

지형 생성 (Terrain)

Plugin - Terrain Toolbox 설치한 후
Asset Store에서 Terrain Tools Sample Asset Pack를 받는다.
다양한 브러쉬를 사용하기 위해서다.(대부분의 작업은 브러쉬로만 함)
작업하기 전에 Lighting 들어가서 Auto Generate를 꺼둔다.(작업 후 킨다)
Window > Terrain Toolbox 탭을 켜서 작업하면 된다. Create해서 Terrain을 생성하고 작업하면된다.
Brush 클릭해서 작업하면 됨.
지형을 만들고 나서 색을 입히고 싶으면 Layer Add한다음 Texture, NormalMap, MaskMap 씌우면 됨.
브러쉬로 일부 지역에만 입힐 수도 있다.
raw파일로 Highmap을 불러와서 지형을 생성할 수도 있다. 브러쉬로 나무와 잔디&꽃을 생성할 수 있다.
설정에서 Distance 250까지 두면 디테일 보이는 거리를 조정할 수 있다.

팁(Tip)

  1. 인스펙터 뷰에서 바로 아래쪽 아이콘을 클릭해 아이콘 설정으로 빈 오브젝트를 씬 뷰에서 특정 아이콘으로 보이게(클릭 되게) 할 수 있다.
  2. 인스펙터 뷰에서 무한대 값(최댓 값) 입력 시 inf 엔터 > Infinity 입력됨
  3. 형 변환 as로 할 수 있다. EX) Resources.Load (file) as TextAsset
  4. 유니티에서 지원하는 Attribute(속성)이 있는데 그 중에 [SerializeField]는 인스펙터 UI상에서 컨트롤 할 수 있게 해주는 옵션이다. (private을 에디터상에서 보이게할 때 사용)
    ex) [SerializeField] [Range(0,180)] private float m_CautiousMaxAngle = 50f;
    50기본값으로한 UI로 0~180까지 수정할 수 있게 나타난다.
  5. ToString("format") 포맷을 정해서 출력하게 할 수 있는데 알아두면 유용함.
    ex) ToString("N0") 1000의 자리 숫자마다 , 넣어주기 123,456 이런식으로
    ex) ToString("D3") 3자리 수로 앞에 없으면 0 넣어주기 001 002 003 이런식으로
  6. Sprite Editor에서 초록색 선은 테두리 제외해서 잡아주면 Sprite - Sliced 타입으로 크기에 상관없이 내용물하고 테두리를 분리해서 크기 조정 가능.
  7. Unity Ads
    Simple Ads - 유저의 의도와 관계없이 출력, 스킵 가능, 수익성 낮음
    Reward Ads - 유저가 원해서 시청, 스킵 불가능, 수익성 높음
    Services 에서 Ads On해서 13세 이상인지 아닌지 체크하고, 스크립트 2개 불러오기
    유니티에즈는 테스트가 쉬움 실제 기기 아니여도 됨.
  8. PlayerSettings> Other Settings > BundleVersionCode는 새로 빌드할때마다 1씩 늘려줘야한다.

네트워크

서버의 종류

  1. Host-Client 서버 방식 Host 클라이언트가 서버를 열고 처리하는 방식 TCP/IP LAN

  2. 데디케이트 서버 방식 중앙 Server를 두고 클라이언트가 접속하는 방법 오버워치

구현 방법

  1. 쉬움 유니티 기본 지원 UNet 사용 Network Manager 컴포넌트 + Multiplayer 사용 https://gist.github.com/Curookie/55cd06cb807dde4bcfd0a967dcd05959
  2. 강추 Mirror 무료 에셋 사용한다.

용어

Migration 란 Host가 연결이 끊길때 다른 Client에게 Host를 옮기고 연결을 수정하는 것을 말함.

게임장르

FPS, 레이싱 (데이터량 많음) 턴제 ,카드 (데이터 적음) RTS (데이터량 매우 많음) -> LockStep 기술을 사용해서 구현

  1. Unity Hub를 설치한다.
  2. 유니티 계정 만들고, 유니티 베타가 아닌 최신버전을 받아둔다. 설치 옵션에 원하는 개발 Visual Code 쓸꺼면 Visual Studio 체크 끄고, Android 체크(안드로이드 개발 할거면)
  3. 유니티 킨 후 오른쪽 상단의 Layout -> 2 by 3으로 바꾼다.
  4. Project View를 Hierarchy View 아래에 놓는다.
  5. 개인적으로 Project View 메뉴 아이콘을 클릭해서 One Column Layout으로 둔다.
  6. Edit -> External Tools -> External Script Editor -> Visual Code 설치된 경로로가서 exe 변경 경로 경로 : %localappdata%Programs\Microsoft VS Code\Code.exe
  7. SDK Download 눌러서 안드로이드 스튜디오 다운로드 한다. 스튜디오를 다 다운받고 실행시켜야 SDK를 받을 수 있다. 창이 뜨고 Start a new Andriod Studio project 가 보이면 아래쪽에 Configure > SDK Manager에 들어간다. 여기서 SDK추가 설치가능 SDK Location 복붙하거나 Browse 누르면 자동으로 잡아준다. 중요한건 SDK 인데 용량이 엄청나니 부족할거같으면 SDK경로를 D:/SDK 이렇게 놓거나 하는게 좋다. 나중에 계속 버전 추가하면 거진 10기가-20기가는 먹을거임 ㅎㅎ SDK경로 기본세팅은 C:\Users????\AppData\Local\Android\Sdk = %localappdata%Android\Sdk 인거
  8. JDK Download 눌러서 [JAVA SE 최신 버전 Development Kit 8u201] 이런거 Accept License Agreement클릭하고 JDK 윈도우 x64 버전으로(윈도우 일경우) 알아서 받으셈. 받고나서 Browse 누르면 바로 잡힐거임. 경로는 Program Files\Java에 있음
  • NDK는 안해도 빌드 되는데 안드로이드 IL2PP 백엔드로 빌드를 하려면 NDK도 추가로 설정을 해줘야한다.
  1. Visual Code에서 플러그인 설치 ext명령어
  • C#, C# Extensions, C# FixFormat, Unity tools, Debugger for Unity, Unity Code Snippets 6가지 설치하면 됨. .NET SDK 에러뜨면 링크 가서 받은다음 하라는대로 따라하면 됨.
@Curookie
Copy link
Author

Curookie commented Feb 3, 2018

@Curookie
Copy link
Author

Curookie commented Feb 24, 2018

http://grayt.tistory.com/71
싱글톤 과 start awake 함수 차이

@Curookie
Copy link
Author

Destroy 함수와 DestroyImmediate 함수 차이
https://fetchinist.com/blogs/?p=308

@Curookie
Copy link
Author

Curookie commented Feb 27, 2018

IEnumerator를 자주써서 프로세스를 분할 시키는 게 좋다.
예를 들어서 사운드 페이드로 키고 끄는것도 구현가능하다.
아래는 페이드 키고 끄는 소스
->

public void FadeIn()
{
    if (PlayerPrefs.GetInt("music_on") == 1)
    {
        StartCoroutine(FadeAudio(1.0f, Fade.In));
    }
}

public void FadeOut()
{
    if (PlayerPrefs.GetInt("music_on") == 1)
    {
        StartCoroutine(FadeAudio(1.0f, Fade.Out));
    }
}

private enum Fade
{
    In,
    Out
}

private IEnumerator FadeAudio(float time, Fade fadeType)
{
    var start = fadeType == Fade.In ? 0.0f : 1.0f;
    var end = fadeType == Fade.In ? 1.0f : 0.0f;
    var i = 0.0f;
    var step = 1.0f / time;

    while (i <= 1.0f) 
    {
        i += step * Time.deltaTime;
        m_audioSource.volume = Mathf.Lerp(start, end, i);
        yield return new WaitForSeconds(step * Time.deltaTime);
    }
}

@Curookie
Copy link
Author

Lerp() 함수에 대한 자세한 설명
http://iygames.tistory.com/6
한줄 요약해주자면
사용법은 Vector3 Mathf.Lerp(위치1, 위치2, 0-1 사이의 숫자); 이렇게 사용하고 3번째 인자가 중요한데 0이면 위치1, 0.5면 중간점, 1이면 위치2 이걸 잘 활용해서 그냥 fade나 Easy-in out 효과도 낼수 있다.
https://developers.google.com/web/fundamentals/design-and-ux/animations/the-basics-of-easing?hl=ko

@Curookie
Copy link
Author

스마트폰 처럼 터치가능하게 하려면 EventSystem에다 Touch Input Module 컴포넌트 추가하면 됨 script Base Input 자동추가됨

@Curookie
Copy link
Author

Curookie commented Feb 27, 2018

1422
1423

스마트폰 가로 게임앱 개발 캔버스 UI 설정 / 카메라 설정

@Curookie
Copy link
Author

게임 분석 중
게임 화면 UI
파티클 캔버스를 따로 두는 모습을 보임( Background )
ex) Canvas (팝업창이나 버튼들을 담아둠) 와 Canvas-Background ( 파티클, 배경 이펙트 등)

@Curookie
Copy link
Author

Curookie commented Feb 27, 2018

씬 바꾸는 스크립트를 만들어두고, 재사용하는 식으로 사용하는 것 좋은방법이다.
Ex) public으로 선언해서 에디터에서 수정하는 식으로

public class SceneTransition : MonoBehaviour
{
    public string scene = "<Insert scene name>";
    public float duration = 1.0f;
    public Color color = Color.black;
    
    public void PerformTransition()
    {
        Transition.LoadLevel(scene, duration, color);
    }
}

@Curookie
Copy link
Author

Curookie commented Feb 27, 2018

어플 내 팝업도 따로 스크립트를 만들어서 각 팝업 프리팹을 불러오는 식으로 하면 좋다. 만약 누를때 뭔가 값을 가져와야하는 동작이 필요할 경우만 상속받아서 사용한다.
그리고 이건 팁인데 ***을 띄우는경우 알파값으로 처리하면 애니메이션 문제도 상관없이 간단하게 처리할 수 있다.

팝업 스크립트 예제

  1. PopupOpener.cs
using UnityEngine;

// This class is responsible for creating and opening a popup of the given prefab and add
// it to the UI canvas of the current scene.
public class PopupOpener : MonoBehaviour
{
    public GameObject popupPrefab;

    protected Canvas m_canvas;

    protected void Start()
    {
        m_canvas = GameObject.Find("Canvas").GetComponent<Canvas>();
    }

    public virtual void OpenPopup()
    {
        var popup = Instantiate(popupPrefab) as GameObject;
        popup.SetActive(true);
        popup.transform.localScale = Vector3.zero;

        // BEGIN_MECANIM_HACK
        // This works around a Mecanim bug present in Unity 5.2.1 where
        // the animation does not start until a frame after the prefab
        // has been instantiated. See:
        // http://forum.unity3d.com/threads/unity-5-2-mecanim-transitions-not-working-the-same-as-5-1.353815
#if UNITY_5_2_1
        var animator = popup.GetComponent<Animator>();
        animator.Update(0.01f);
#endif
        // END_MECANIM_HACK

        popup.transform.SetParent(m_canvas.transform, false);
        popup.GetComponent<Popup>().Open();
    }
}
  1. PlayPopupOpener.cs
using UnityEngine;

// Specialized version of the PopupOpener class that opens the PlayPopup popup
// and sets an appropriate number of stars (that can be configured from within the
// editor).
public class PlayPopupOpener : PopupOpener
{
    public int starsObtained = 0;

    public override void OpenPopup()
    {
        var popup = Instantiate(popupPrefab) as GameObject;
        popup.SetActive(true);
        popup.transform.localScale = Vector3.zero;
        popup.transform.SetParent(m_canvas.transform, false);

        var playPopup = popup.GetComponent<PlayPopup>();
        playPopup.Open();
        playPopup.SetAchievedStars(starsObtained);
    }
}
  1. Popup.cs
using System.Collections;
using UnityEngine;
using UnityEngine.UI;

// This class is responsible for popup management. Popups follow the traditional behavior of
// automatically blocking the input on elements behind it and adding a background texture.
public class Popup : MonoBehaviour
{
    public Color backgroundColor = new Color(10.0f / 255.0f, 10.0f / 255.0f, 10.0f / 255.0f, 0.6f);

    private GameObject m_background;

    public void Open()
    {
        AddBackground();
    }

    public void Close()
    {
        var animator = GetComponent<Animator>();
        if (animator.GetCurrentAnimatorStateInfo(0).IsName("Open"))
            animator.Play("Close");

        RemoveBackground();
        StartCoroutine(RunPopupDestroy());
    }

    // We destroy the popup automatically 0.5 seconds after closing it.
    // The destruction is performed asynchronously via a coroutine. If you
    // want to destroy the popup at the exact time its closing animation is
    // finished, you can use an animation event instead.
    private IEnumerator RunPopupDestroy()
    {
        yield return new WaitForSeconds(0.5f);
        Destroy(m_background);
        Destroy(gameObject);
    }

    private void AddBackground()
    {
        var bgTex = new Texture2D(1, 1);
        bgTex.SetPixel(0, 0, backgroundColor);
        bgTex.Apply();

        m_background = new GameObject("PopupBackground");
        var image = m_background.AddComponent<Image>();
        var rect = new Rect(0, 0, bgTex.width, bgTex.height);
        var sprite = Sprite.Create(bgTex, rect, new Vector2(0.5f, 0.5f), 1);
        image.material.mainTexture = bgTex;
        image.sprite = sprite;
        var newColor = image.color;
        image.color = newColor;
        image.canvasRenderer.SetAlpha(0.0f);
        image.CrossFadeAlpha(1.0f, 0.4f, false);

        var canvas = GameObject.Find("Canvas");
        m_background.transform.localScale = new Vector3(1, 1, 1);
        m_background.GetComponent<RectTransform>().sizeDelta = canvas.GetComponent<RectTransform>().sizeDelta;
        m_background.transform.SetParent(canvas.transform, false);
        m_background.transform.SetSiblingIndex(transform.GetSiblingIndex());
    }

    private void RemoveBackground()
    {
        var image = m_background.GetComponent<Image>();
        if (image != null)
            image.CrossFadeAlpha(0.0f, 0.2f, false);
    }
}
  1. PlayPopup.cs
using UnityEngine;
using UnityEngine.UI;

// Specialized behavior for the popup that opens before selecting a level to play in
// the demo. It showcases how to create a specialized popup with custom behavior: in this
// case, one to three stars can be displayed depending on the player score on that particular
// level.
public class PlayPopup : Popup
{
    public Color enabledColor;
    public Color disabledColor;

    public Image leftStarImage;
    public Image middleStarImage;
    public Image rightStarImage;

    public void SetAchievedStars(int starsObtained)
    {
        if (starsObtained == 0)
        {
            leftStarImage.color = disabledColor;
            middleStarImage.color = disabledColor;
            rightStarImage.color = disabledColor;
        }
        else if (starsObtained == 1)
        {
            leftStarImage.color = enabledColor;
            middleStarImage.color = disabledColor;
            rightStarImage.color = disabledColor;
        }
        else if (starsObtained == 2)
        {
            leftStarImage.color = enabledColor;
            middleStarImage.color = enabledColor;
            rightStarImage.color = disabledColor;
        }
        else if (starsObtained == 3)
        {
            leftStarImage.color = enabledColor;
            middleStarImage.color = enabledColor;
            rightStarImage.color = enabledColor;
        }
    }
}

@Curookie
Copy link
Author

패턴이나 배경 만들기 위해 사용하는 Texture2D
SetPixel 후에는 최종 Apply적용을 해야한다.

ex)

var bgTex = new Texture2D(1, 1);
bgTex.SetPixel(0, 0, backgroundColor);
bgTex.Apply();

@Curookie
Copy link
Author

런타임 도중에 인스턴스 형태로 빈오브젝트를 생성하려면
ex)

private GameObject m_background;
...
m_background = new GameObject("PopupBackground");

이런식으로 해도 된다.

@Curookie
Copy link
Author

이미지 컴포넌트.canvasRenderer.SetAlpha(투명도)로 투명도 조정 가능
이미지 컴포넌트.CrossFadeAlpha(투명도, 초, 시간크기무시할건가) 로 페이드 효과를 간단하게 줄수있다니... 사기야

image.canvasRenderer.SetAlpha(0.0f);
image.CrossFadeAlpha(1.0f, 0.4f, false);

@Curookie
Copy link
Author

localScale, localPosition, localRotate 는 모두 부모오브젝트를 기준으로 잡는 크기 위치 회전을 의미한다.

@Curookie
Copy link
Author

Curookie commented Feb 27, 2018

RectTransform의
sizeDelta는 Anchor와 RectWidth/Height 사이의 길이를 의미한다. 크기 지정할 때 주로 쓴다.

sizeDelta.x = UIElementRectangle.width - AnchorsRectangle.width;
sizeDelta.y = UIElementRectangle.height - AnchorsRectangle.height;

예를 들어
rectTransform.sizeDelta = new Vector2(width, height); 로 RectTransform객체의 사이즈를 지정할 수 있다

@Curookie
Copy link
Author

부모 위치를 지정하는 건
transform.SetParent(canvas.transform, 월드위치유지여부 디폴트false);

부모안에 집어넣는데 만약 레이어를 맨위로 가게 해선 안될경우(덮어씌우지 않고 뒤로 보내야할 경우)
인덱스 순서는 0 (하이라키에서 가장 위, 즉 가장 뒤) -> 높아질수록 앞으로 나온다.
배경.transform.SetSiblingIndex(transform.GetSiblingIndex()); 요런식으로 인덱싱으로 처리할 수 있다. 이 코드 같은경우는 현재 인덱스에 배경이 위치하게 하는 것이므로 배경이 현재 객체의 바로 뒤로 온다. 그럼 현재부터 그 앞에있는 객체들의 인덱스는 한칸씩 밀리겠죠~

@Curookie
Copy link
Author

Curookie commented Feb 27, 2018

애니메이션 특정 이름과 실행 중인 애니메이션 파악하는 방법과 특정 애니메이션 실행하는 방법

var animator = GetComponent<Animator>();
if (animator.GetCurrentAnimatorStateInfo(0).IsName("Open"))
    animator.Play("Close");

만약 끝났는지 확인하려면 현재 상태에 애니메이션 이름 EventEndAnimationName 을 확인하고 normalizedTime 시간으로 플레이가 다 됬는지 확인.

이때 애니메이션은 Loop를 풀어놓아야 한다.

bool EndAnimationDone()
    {
        return PlayAnimator.GetCurrentAnimatorStateInfo(0).IsName(EventEndAnimationName) && 
            PlayAnimator.GetCurrentAnimatorStateInfo(0).normalizedTime >= 0.99f;
    }

이런식으로 하면 애니메이션 파라미터 없이도 컨트롤 가능

@Curookie
Copy link
Author

Curookie commented Aug 22, 2018

Unity3D에서 uGUI Button 을 동적으로 생성할 때, 클릭 이벤트 추가 하는 방법

_spawnedButton.GetComponent().onClick.AddListener(delegate() { 게임오브젝트.GetComponent<컴포넌트 클래스 이름>().실행할 함수(); });

참고로 인스펙터 상으로는 보이지 않으니 주의하세요!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment