유니티는 레거시 애니메이션과 메카님 애니메이션이라는 두가지 유형의 애니메이션을 지원한다.

  • 레거시 애니메이션 : 하위 호환성을 고려한 애니메이션, 소스코드로 컨트롤 함. 가볍지만 새로 만든다면 메카님을 추천
  • 메카님 애니메이션 : 모션 캡쳐 애니메이션, 애니메이션을 재사용하는 Retargeting 가능. 

주인공 캐릭터는 애니메이션 타입으로 구현하고 적 캐릭터는 메카님 애니메이션을 적용해보자 

Resorces/Anmations 폴더에서 PlayerAnimation 패키지를 임포트한다.

임포트후 생성된 폴더는 07.Animations폴더로 옮긴다.

프로젝트뷰 Model/Player폴더내의 Player모델을 선택 인스펙터뷰의 위쪽  Rig탭을 선택하고 Animation Type을 Leagacy로 설정한다.

프로퍼티:기능:

Animation Type 애니메이션 타입을 지정합니다.
  None 애니메이션이 없습니다.
  Legacy 레거시 애니메이션 시스템을 사용합니다. Unity 3.x 및 이전 버전과 동일하게 애니메이션을 임포트하고 사용합니다.
  Generic 릭이 비휴머노이드(네 발 달린 생물 또는 애니메이션화할 엔티티)인 경우 제니릭 애니메이션 시스템을 사용합니다. Unity가 루트 노드를 선택하지만, 루트 노드(Root node) 로 사용할 다른 뼈대를 대신 식별할 수 있습니다.
  Humanoid 릭이 휴머노이드(두 다리와 두 팔과 머리가 있음)인 경우 휴머노이드 애니메이션 시스템을 사용합니다. 일반적으로 Unity가 골격을 감지하고 아바타에 올바르게 매핑합니다. 경우에 따라 아바타 정의(Avatar Definition) 변경사항을 설정하고 매핑을 수동으로 설정(Configure) 해야 할 수 있습니다.

하이라키뷰에서 Player의 Inspector를 보면 Animation컴포넌트가 추가되어 있다 이는 레거시타입으로 설정된 모델을 의미한다.  Animator가 추가되어 있다면 메카님 애니메이션이다.

애니메이션 클립

애니메이션 클립은 캐릭터의 동작을 기록한 파일입니다. 애니메이션 컴포넌트는 클립에 기록된 관절의 위치와 회전값을 프레임 단위로 재생시키는 역할을 한다.

3D 모델링 툴에서 제작한 애니메이션 클립을 애니메이션 파일로 만드는 방법에는 3가지가 있다.

  • 모든 애니메이션이 하나의 애니메이션 파일에 들어 있고가 있는데 분리 해야하는 경우
  • 모든 애니메이션 클립이 하나의 애니메이션 파일에 들어가 있지만 미리 분리된 경우
  • 애니메이션 클립들이 동작별로 분리해 별도의 파일로 생성하는 방식

애니메이션 적용

애니메이션폴더의 idel을 클릭해서 Inspector뷰를 보면 다음과 같이 아무것도 없다.

씬뷰나 프로젝트뷰의 모델 Player를 끌어다 idel Inspector뷰 맨아리 프리뷰에 끌어다 놓으면 모델이 보인다.

Zoom과 클릭후 Move해서 보기좋게 한후 Play를 누르면 프리뷰를 볼 수 있다.

Player Animation Clip폴더에서 Idel, RunB, RunF, RunL, RunR의 클립만 사용할텐데 Wrap Mode를 Loop로 지정한다. 한꺼번에 할수 없어 개별로 하나씩 해야한다.

하이라키의 Player를 선택한후 자물쇠를 잠구고 Animation Clip폴더에서 Idel, RunB, RunF, RunL, RunR 개를 전부 골라 끌어다 인스펙터의 Animations에 끌어다 놓는다 그럼 오른쪽 숫자가 0에서 5로 바뀐다. 열어보면 5개의 클립이 잘 적용되여 있다. 

이제 처음 실행시킬 Idle 애니메이션을 인스펙터의 Animation에 끌어다 놓으면 None이 Idle로 바뀐다.

설정완료후는 우상쪽 Lock을 푼다. Play해보면 Player가 Idel클립을 반복한다. 한번만 하고 끝난다면 아까 Wrap Mode를Loop로 설정 안한거다.

Player Inspector뷰의 Play Automatically속성은 실행했을때 기본 애니메이션 클립을 자동으로 실행해주는 옵션인데 해제한다. 이러면 play해도 아무런 동작도 하지 않는다.

스크립트를 통해 직접 컨트롤 해보겠다. PlayerCtrl스크립트를 다음과 같이 수정한다.

 

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

public class PlayerCtrl : MonoBehaviour {
    // Start is called before the first frame update
    Transform tr;
    private float moveSpeed;
    private float turnSpeed;
    private Animation anim;
    void Start() {

        tr = GetComponent<Transform>();
        moveSpeed = 10f;
        turnSpeed = 500f;
        anim = GetComponent<Animation>();  //추가된 코드
        anim.Play();
    }

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

        float h = Input.GetAxis("Horizontal");  //AD 입력 좌우
        float v = Input.GetAxis("Vertical");  //WS 입력 전후
        float r = Input.GetAxis("Mouse X");  //마우스 x축 입력
        Vector3 dir = Vector3.right* h + Vector3.forward* v;
        tr.Translate(dir.normalized * moveSpeed * Time.deltaTime);
        tr.Rotate(Vector3.up * turnSpeed * Time.deltaTime * r);
    }
}

Play해 보면게임뷰에서 캐릭터가 Idle동작을 반복해준다.

이제 키보드 동작에 맞춰 애니매이션을 바꿔가면 플레이해보겠다.

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

public class PlayerCtrl : MonoBehaviour {
    // Start is called before the first frame update
    Transform tr;
    private float moveSpeed;
    private float turnSpeed;
    private Animation anim;
    void Start() {
        tr = GetComponent<Transform>();
        moveSpeed = 10f;
        turnSpeed = 500f;
        anim = GetComponent<Animation>();  //추가된 코드
        anim.Play();
    }

    // Update is called once per frame
    void Update() {
        float h = Input.GetAxis("Horizontal");  //AD 입력 좌우
        float v = Input.GetAxis("Vertical");  //WS 입력 전후
        if (Mathf.Abs(h) > float.Epsilon || Mathf.Abs(v) > float.Epsilon) {  //움직임이 없다면 불필요한 동작을 안한다.
            Vector3 dir = Vector3.right * h + Vector3.forward * v;
            tr.Translate(dir.normalized * moveSpeed * Time.deltaTime);
            PlayerAnim(h, v);
        }
        float r = Input.GetAxis("Mouse X");  //마우스 x축 입력 
        tr.Rotate(Vector3.up * turnSpeed * Time.deltaTime * r);

    }
    void PlayerAnim(float h, float v) {
        Debug.Log("Move");
        if (v >= 0.1f) {
            anim.Play("RunF");
        } else if(v <= -0.1f) {
            anim.Play("RunB");
        } else if(h >= 0.1f) {
            anim.Play("RunR");
        } else if (h <= -0.1f) {
            anim.Play("RunL");
        } else {
            anim.Play("Idle");
        }
    }
}

너무 잘된다. 현재도 문제없지만 유니티는 애니메이션사이의 전환을 부드럽게 만들어주는 CroffFade라는 함수를 준비해놓왔다. 사용법은 

CrossFace("클립명", 전환시간);

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

public class PlayerCtrl : MonoBehaviour {
    // Start is called before the first frame update
    Transform tr;
    private float moveSpeed;
    private float turnSpeed;
    private Animation anim;
    void Start() {
        tr = GetComponent<Transform>();
        moveSpeed = 10f;
        turnSpeed = 500f;
        anim = GetComponent<Animation>();  //추가된 코드
        anim.Play();
    }

    // Update is called once per frame
    void Update() {
        float h = Input.GetAxis("Horizontal");  //AD 입력 좌우
        float v = Input.GetAxis("Vertical");  //WS 입력 전후
        if (Mathf.Abs(h) > float.Epsilon || Mathf.Abs(v) > float.Epsilon) {  //움직임이 없다면 불필요한 동작을 안한다.
            Vector3 dir = Vector3.right * h + Vector3.forward * v;
            tr.Translate(dir.normalized * moveSpeed * Time.deltaTime);
            PlayerAnim(h, v);
        }
        float r = Input.GetAxis("Mouse X");  //마우스 x축 입력 
        tr.Rotate(Vector3.up * turnSpeed * Time.deltaTime * r);

    }
    void PlayerAnim(float h, float v) {
        Debug.Log("Move");
        if (v >= 0.1f) {
            anim.CrossFade("RunF",0.25f);
        } else if(v <= -0.1f) {
            anim.CrossFade("RunB", 0.25f);
        } else if(h >= 0.1f) {
            anim.CrossFade("RunR", 0.25f);
        } else if (h <= -0.1f) {
            anim.CrossFade("RunL", 0.25f);
        } else {
            anim.CrossFade("Idle", 0.25f);
        }
    }
}

실행해보면 큰차이를 모르겠지만 동작간 차이가 클 경우 필요할 듯하다.

 

#유니티 #Animation

'유니티게임강좌 > 주인공 캐릭터 제작' 카테고리의 다른 글

[Player제작] 그림자  (0) 2023.02.26
[Player제작] 무기장착  (0) 2023.02.26
[Player제작] 캐릭터 회전 - Rotate  (0) 2023.02.25
Assembly  (0) 2023.02.25
[Player제작] 접근제한자  (0) 2023.02.25

게임오브젝트를 회전시킬 때는 Transform.rotation 속성값을 변경하거나 Rotate계열의 함수를 사용할 수 있다. 

다음은 오브젝트를 y축으로 30도 회전시키는 예이다.

tr.Rotate(new Vector3(0.0f, 30.f, 0.0f);
tr.Rotate(0.0f, 30.0f, 0.0f);
tr.Rotate(Vector3.up * 30f);

마우스입력을 받아 캐릭터가 회전하게 해보겠다. 마우스 움직임이 작기 때문에 스피드가 빨라야 한다.

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

public class PlayerCtrl : MonoBehaviour {
    // Start is called before the first frame update
    Transform tr;
    private float moveSpeed;
    private float turnSpeed;
    void Start() {
        tr = GetComponent<Transform>();
        moveSpeed = 10f;
        turnSpeed = 500f;
    }

    // Update is called once per frame
    void Update() {
        float h = Input.GetAxis("Horizontal");  //AD 입력 좌우
        float v = Input.GetAxis("Vertical");  //WS 입력 전후
        float r = Input.GetAxis("Mouse X");  //마우스 x축 입력
        Vector3 dir = Vector3.right* h + Vector3.forward* v;
        tr.Translate(dir.normalized * moveSpeed * Time.deltaTime);
        tr.Rotate(Vector3.up * turnSpeed * Time.deltaTime * r);
    }
}

씬뷰에서 가상 카메라 이동

씬뷰와 게임뷰를 동시에 표시하고

하이라키에서 Player를 클릭한후 Shift-F를 누르면  Play해보면 씬뷰의 카메라는 Player에 Lock된다.

'유니티게임강좌 > 주인공 캐릭터 제작' 카테고리의 다른 글

[Player제작] 무기장착  (0) 2023.02.26
[Player제작] 애니메이션  (1) 2023.02.26
Assembly  (0) 2023.02.25
[Player제작] 접근제한자  (0) 2023.02.25
[Player제작] 캐릭터의 이동  (0) 2023.02.25

접급제한자 internal을 공부하다가 어셈블리가 나와 유니티 매뉴얼을 보니 같은 라이브러리 같습니다. 유니티는 어셈블리를 관리하는 메뉴가 있네요. 초보분들은 그냥 넘어가는게 나을듯 합니다.

어셈블리 정의

어셈블리 정의 및 어셈블리 레퍼런스는 스크립트를 어셈블리로 구성할 수 있는 에셋입니다.

어셈블리는 스크립트에 의해 정의되고 다른 어셈블리에 대한 레퍼런스도 정의하는 컴파일된 클래스와 구조체가 들어 있는 C# 코드 라이브러리입니다. C#의 어셈블리에 대한 일반적인 정보는 .NET의 어셈블리를 참조하십시오.

기본적으로 Unity는 거의 모든 게임 스크립트를 사전 정의된 어셈블리인 Assembly-CSharp.dll로 컴파일합니다. (또한 Unity는 [몇 가지 더 작고 전문화된 사전 정의 어셈블리]도 생성합니다.)

이 배열은 소규모 프로젝트에 적합하지만, 프로젝트에 코드를 더 추가할 경우 몇 가지 단점이 있습니다.

  • 하나의 스크립트를 변경할 때마다 Unity는 다른 모든 스크립트를 다시 컴파일해야 하므로 반복적 코드 변경을 위한 전체 컴파일 시간이 늘어납니다.
  • 모든 스크립트는 다른 스크립트에서 정의된 타입에 직접 액세스할 수 있으므로 코드를 리팩터링하고 개선하기가 더 어려울 수 있습니다.
  • 모든 스크립트는 모든 플랫폼에 대해 컴파일됩니다.

어셈블리를 정의하면 코드를 구성하여 모듈성과 재사용성을 높일 수 있습니다. 프로젝트에 대해 정의하는 어셈블리의 스크립트는 더 이상 기본 어셈블리에 추가되지 않으며, 지정하는 다른 어셈블리의 스크립트에만 액세스할 수 있습니다.

위 다이어그램은 프로젝트의 코드를 여러 어셈블리로 분할하는 방법을 보여줍니다. Main은 Stuff를 참조하고 그 반대로는 참조하지 않기 때문에 Main의 코드 변경 사항은 Stuff의 코드에 영향을 주지 않습니다. 마찬가지로 Library는 다른 어셈블리에 의존하지 않으므로 다른 프로젝트의 Library에 있는 코드를 더 쉽게 재사용할 수 있습니다.

이 섹션에서는 어셈블리 정의 및 어셈블리 레퍼런스 에셋을 만들고 설정하여 프로젝트에 대해 어셈블리를 정의하는 방법에 대해 설명합니다.

어셈블리 정의

프로젝트 코드를 어셈블리로 구성하려면 원하는 각 어셈블리에 대한 폴더를 생성하고, 각 어셈블리에 속해야 하는 스크립트를 관련 폴더로 옮겨야 합니다. 그런 다음 [어셈블리 정의 에셋을 생성]하여 어셈블리 프로퍼티를 지정하십시오.

Unity는 어셈블리 정의 에셋이 포함된 폴더의 모든 스크립트를 가져온 후 에셋에 정의된 이름 및 기타 설정을 사용하여 어셈블리로 컴파일합니다. 또한 Unity는 자식 폴더에 자체 어셈블리 정의 또는 어셈블리 레퍼런스 에셋이 없는 경우 동일한 어셈블리의 모든 자식 폴더에도 스크립트를 포함합니다.

기존 어셈블리에 자식이 아닌 폴더의 스크립트를 포함하려면 자식이 아닌 폴더에 어셈블리 레퍼런스 에셋을 생성하고, 타겟 어셈블리를 정의하는 어셈블리 정의 에셋을 참조하도록 설정하십시오. 예를 들어 해당 폴더의 위치에 관계없이 프로젝트에 있는 모든 에디터 폴더의 스크립트를 자체 어셈블리에 결합할 수 있습니다.

Unity는 종속성에 의해 결정된 순서대로 어셈블리를 컴파일합니다. 컴파일이 수행되는 순서는 지정할 수 없습니다.

 

레퍼런스 및 종속성

한 타입(예: 클래스 또는 구조체)이 다른 타입을 사용하는 경우 첫 번째 타입은 두 번째 타입에 종속됩니다. Unity가 스크립트를 컴파일할 때 스크립트가 종속되는 모든 타입 또는 기타 코드에 액세스할 수 있어야 합니다. 마찬가지로, 컴파일된 코드가 실행될 때 컴파일된 버전의 종속성에 액세스할 수 있어야 합니다. 두 타입이 서로 다른 어셈블리에 있는 경우 종속 타입을 포함하는 어셈블리는 종속되는 타입을 포함하는 어셈블리에 대한 레퍼런스를 선언해야 합니다.

어셈블리 정의 옵션을 사용하여 프로젝트에 사용된 어셈블리 간의 레퍼런스를 제어할 수 있습니다. 어셈블리 정의 설정에는 다음이 포함됩니다.

  • [Auto Referenced] – 사전 정의된 어셈블리가 어셈블리를 참조하는지 여부
  • [Assembly Definition References] – 어셈블리 정의를 사용하여 생성된 다른 프로젝트 어셈블리에 대한 레퍼런스
  • [Override References] + [Assembly References] – 사전 컴파일된 (플러그인) 어셈블리에 대한 레퍼런스
  • [No Engine References] – UnityEngine 어셈블리에 대한 레퍼런스

참고: 어셈블리 정의를 사용하여 생성된 어셈블리의 클래스는 사전 정의된 어셈블리에서 정의된 타입을 사용할 수 없습니다.

 

기본 레퍼런스

기본적으로 사전 정의된 어셈블리는 어셈블리 정의를 사용하여 생성된 어셈블리(1), 프로젝트에 플러그인으로 추가된 사전 컴파일된 어셈블리(2)를 비롯한 다른 모든 어셈블리를 참조합니다. 또한 어셈블리 정의 에셋을 사용하여 생성된 어셈블리는 모든 사전 컴파일된 어셈블리(3)를 자동으로 참조합니다.

기본 설정의 경우 사전 정의된 어셈블리의 클래스는 프로젝트의 다른 어셈블리에서 정의된 모든 타입을 사용할 수 있습니다. 마찬가지로, 어셈블리 정의 에셋을 사용하여 생성된 어셈블리는 사전 컴파일된 (플러그인) 어셈블리에서 정의된 모든 타입을 사용할 수 있습니다.

어셈블리 정의 에셋에 대한 인스펙터에서 [Auto Referenced 옵션]을 비활성화하여 사전 정의된 어셈블리에서 어셈블리를 참조하지 못하도록 막을 수 있습니다. Auto Referenced 옵션을 비활성화하면 어셈블리에서 코드를 변경할 때 사전 정의된 어셈블리가 다시 컴파일되지 않지만, 사전 정의된 어셈블리가 이 어셈블리의 코드를 직접 사용할 수 없습니다. [어셈블리 정의 프로퍼티]를 참조하십시오.

마찬가지로, 플러그인 에셋에 대한 플러그인 인스펙터에서 Auto Referenced 프로퍼티를 비활성화하여 플러그인 어셈블리가 자동으로 참조되지 못하게 막을 수 있습니다. 이는 사전 정의된 어셈블리, 그리고 어셈블리 정의를 사용하여 생성된 어셈블리 모두에 영향을 미칩니다. 자세한 내용은 플러그인 인스펙터를 참조하십시오.

플러그인 에 대한 Auto Referenced 를 비활성화하면 인스펙터에서 어셈블리 정의 에셋에 대해 명시적으로 레퍼런스를 설정할 수 있습니다. 에셋의 [Override References] 옵션을 활성화하고 플러그인 에 대한 레퍼런스를 추가하십시오. Assembly Definition 프로퍼티를 참조하십시오.

참고: 사전 컴파일된 어셈블리에 대한 명시적 레퍼런스는 선언할 수 없습니다. 사전 정의된 어셈블리는 자동 참조된 어셈블리의 코드만 사용할 수 있습니다.

 

순환 레퍼런스

순환 어셈블리 레퍼런스는 한 어셈블리 레퍼런스가 두 번째 어셈블리를 참조하고, 두 번째 어셈블리는 다시 첫 번째 어셈블리를 참조할 때 존재합니다. 어셈블리 간의 이러한 순환 레퍼런스는 허용되지 않으며, “순환 레퍼런스가 포함된 어셈블리가 감지되었습니다”라는 오류 메시지와 함께 보고됩니다.

일반적으로 어셈블리 간의 이러한 순환 레퍼런스는 어셈블리에서 정의된 클래스 내의 순환 레퍼런스로 인해 발생합니다. 동일한 어셈블리에 있는 클래스 간의 순환 레퍼런스에 대해 기술적으로 유효하지 않은 점은 없지만, 다른 어셈블리의 클래스 간 순환 레퍼런스는 허용되지 않습니다. 순환 레퍼런스 오류가 발생하면 코드를 리팩터링하여 순환 레퍼런스를 제거하거나 상호 참조하는 리팩터링 클래스를 동일한 어셈블리에 배치해야 합니다.

 

어셈블리 정의 에셋 생성

어셈블리 정의 에셋을 만들려면 다음 단계를 따르십시오.

  1. Project 창에서 어셈블리에 포함할 스크립트가 있는 폴더를 찾습니다.
  2. 폴더(메뉴: Assets > Create > Assembly Definition)에 어셈블리 정의 에셋을 생성합니다.
  3. 에셋에 이름을 지정합니다. 기본적으로 어셈블리 파일은 에셋에 할당되는 이름을 사용하지만, Inspector 창에서 이름을 변경할 수 있습니다.

Unity는 프로젝트의 스크립트를 다시 컴파일하여 새로운 어셈블리를 생성합니다. 작업이 완료되면 새로운 어셈블리 정의에 대한 설정을 변경할 수 있습니다.

자식 폴더의 스크립트를 포함하여 어셈블리 정의가 포함된 폴더의 스크립트는 (해당 폴더에 자체 어셈블리 정의 또는 레퍼런스 에셋이 없는 경우) 새로운 어셈블리로 컴파일되고 이전 어셈블리에서 제거됩니다.

 

어셈블리 정의 레퍼런스 에셋 생성

어셈블리 정의 레퍼런스 에셋을 생성하려면 다음 단계를 따르십시오.

  1. Project 창에서 참조된 어셈블리에 포함할 스크립트가 있는 폴더를 찾습니다.
  2. 폴더(메뉴: Assets > Create > Assembly Definition Reference)에 어셈블리 레퍼런스 에셋을 생성합니다.
  3. 에셋에 이름을 할당합니다.
  4. Unity는 프로젝트의 스크립트를 다시 컴파일하여 새로운 어셈블리를 생성합니다. 작업이 완료되면 새로운 어셈블리 정의 레퍼런스에 대한 설정을 변경할 수 있습니다.
  5. 새로운 어셈블리 정의 레퍼런스 에셋을 선택하여 인스펙터 에서 해당 프로퍼티를 확인합니다.
  6. 타겟 어셈블리 정의 에셋을 참조하도록 Assembly Definition 프로퍼티를 설정합니다.
  7. Apply 를 클릭합니다.

자식 폴더의 스크립트를 포함하여 어셈블리 정의 레퍼런스 에셋이 포함된 폴더의 스크립트는 (해당 폴더에 자체 어셈블리 정의 또는 레퍼런스 에셋이 없는 경우) 참조된 어셈블리로 컴파일되고 이전 어셈블리에서 제거됩니다.

 

플랫폼별 어셈블리 생성

특정 플랫폼에 대한 어셈블리를 생성하려면 다음 단계를 따르십시오.

  1. 어셈블리 정의 에셋을 생성합니다.
  2. 새로운 어셈블리 정의 레퍼런스 에셋을 선택하여 인스펙터 에서 해당 프로퍼티를 확인합니다.
  3. Any Platform 옵션을 선택하고 제외할 특정 플랫폼을 선택합니다. 또는 Any Platform을 선택 해제하고 포함할 특정 플랫폼을 선택할 수도 있습니다.
  4. Apply 를 클릭합니다.

플랫폼용 프로젝트를 빌드할 때 어셈블리는 선택된 플랫폼에 따라 포함되거나 제외됩니다.

 

에디터 코드용 어셈블리 생성

에디터 어셈블리를 사용하면 Editor라는 최상위 폴더뿐만 아니라 프로젝트의 모든 위치에 에디터 스크립트를 배치할 수 있습니다.

프로젝트에서 에디터 코드가 포함된 어셈블리를 생성하려면 다음 단계를 따르십시오.

  1. 에디터 스크립트가 포함된 폴더에 [플랫폼별 어셈블리를 생성]합니다.
  2. 에디터 플랫폼만 포함합니다.
  3. 에디터 스크립트가 포함된 추가 폴더가 있는 경우 해당 폴더에 [어셈블리 정의 레퍼런스 에셋을 생성]한 후 이 어셈블리 정의를 참조하도록 설정합니다.

 

테스트 어셈블리 생성

테스트 어셈블리를 사용하면 테스트를 작성하고 Unity TestRunner로 실행할 수 있으며, 테스트 코드를 애플리케이션과 함께 제공하는 코드와 별도로 유지할 수 있습니다. Unity는 테스트 프레임워크 패키지의 일부로 TestRunner를 제공합니다. 테스트 프레임워크 패키지를 설치하고 테스트 어셈블리를 생성하기 위한 지침은 테스트 프레임워크 문서를 참조하십시오.

 

다른 어셈블리 참조

다른 어셈블리의 일부인 C# 타입과 함수를 사용하려면 어셈블리 정의 에셋에서 해당 어셈블리에 대한 레퍼런스를 생성해야 합니다.

어셈블리 레퍼런스를 생성하려면 다음 단계를 따르십시오.

  1. 인스펙터 에서 프로퍼티를 확인하기 위해 레퍼런스가 필요한 어셈블리의 어셈블리 정의를 선택합니다.
  2. Assembly Definition References 섹션에서 + 버튼을 클릭하여 새 레퍼런스를 추가합니다.
  3. 레퍼런스 리스트의 새로 생성된 슬롯에 어셈블리 정의 에셋을 할당합니다.

Use GUIDs 옵션을 활성화하면 새로운 이름을 반영하기 위해 다른 어셈블리 정의의 레퍼런스를 업데이트하지 않고도 참조된 어셈블리 정의 에셋의 파일 이름을 변경할 수 있습니다. (에셋 파일의 메타데이터 파일이 삭제되었거나, Unity 에디터 외부로 파일을 이동할 때 해당 메타데이터 파일을 함께 옮기지 않은 경우 GUID를 초기화해야 합니다.)

 

사전 컴파일된 플러그인 어셈블리 참조

기본적으로 어셈블리 정의를 사용하여 생성된 프로젝트의 모든 어셈블리는 사전 컴파일된 모든 어셈블리를 자동으로 참조합니다. 이러한 자동 참조는 어셈블리의 코드가 사용되지 않더라도 사전 컴파일된 어셈블리 중 하나를 업데이트할 때 Unity가 모든 어셈블리를 다시 컴파일해야 함을 의미합니다. 이러한 추가 오버헤드를 방지하려면 자동 참조를 오버라이드하고 어셈블리가 실제로 사용하는 사전 컴파일된 라이브러리에 대한 참조만 지정하십시오.

  1. 인스펙터 에서 프로퍼티를 확인하기 위해 레퍼런스가 필요한 어셈블리의 어셈블리 정의를 선택합니다.
  2. General 섹션에서 Override References 옵션을 활성화합니다.Override References 를 선택하면 인스펙터  Assembly References 섹션을 이용할 수 있습니다.
  3. Assembly References 섹션에서 + 버튼을 클릭하여 새 레퍼런스를 추가합니다.
  4. 빈 슬롯의 드롭다운 리스트를 사용하여 사전 컴파일된 어셈블리에 레퍼런스를 할당합니다. 리스트에는 프로젝트 빌드 설정에 현재 설정된 플랫폼에 대한 프로젝트의 사전 컴파일된 어셈블리가 모두 표시됩니다. (플러그인 인스펙터에서 사전 컴파일된 어셈블리에 대한 플랫폼 호환성을 설정하십시오.)
  5. Apply 를 클릭합니다.
  6. 프로젝트를 빌드할 각 플랫폼에 대해 이 단계를 반복합니다.

 

조건부 어셈블리 포함

프리 프로세서 심볼을 사용하면 어셈블리가 컴파일되고 게임 또는 애플리케이션의 빌드에 포함되는지 여부를 제어할 수 있습니다(에디터의 플레이 모드 포함). 어셈블리 정의 옵션의 Define Constraints 리스트에서 사용하려는 어셈블리에 대해 정의해야 할 심볼을 지정할 수 있습니다.

  1. 인스펙터 에서 프로퍼티를 확인할 어셈블리의 어셈블리 정의를 선택합니다.
  2. Define Constraints 섹션에서 + 버튼을 클릭하여 제약 리스트에 새로운 심볼을 추가합니다.
  3. 심볼 이름을 입력합니다.
  4. 이름 앞에 느낌표를 붙여서 심볼을 “무효화”할 수 있습니다. 예를 들어 UNITY_WEBGL이 정의되지 않은 경우 !UNITY_WEBGL 제약은 어셈블리를 포함할 수 있습니다.
  5. Apply 를 클릭합니다.

다음 심볼을 제약으로 사용할 수 있습니다.

  • [Scripting Define Symbols] 설정에서 정의된 심볼. 이 심볼은 Project Settings  Player 섹션에서 찾을 수 있습니다. 단, Scripting Define Symbols 는 프로젝트 빌드 설정에서 현재 설정된 플랫폼에만 적용됩니다. 여러 플랫폼에 대한 심볼을 정의하려면 각 플랫폼으로 전환한 후 Scripting Define Symbols 필드를 개별적으로 수정하십시오.
  • Unity에서 정의한 심볼. [플랫폼별 컴파일]을 참조하십시오.
  • 어셈블리 정의 에셋의 [Version Defines] 섹션을 사용하여 정의된 심볼.

스크립트에서 정의된 심볼은 제약이 충족되었는지 판단할 때 고려되지 않습니다.

자세한 내용은 [제약 정의]를 참조하십시오.

 

Unity 및 프로젝트 패키지 버전에 기반하여 기호 정의

프로젝트가 특정한 Unity 버전이나 패키지 버전을 사용하는지에 따라 어셈블리에 다른 코드를 컴파일해야 하는 경우, Version Defines 리스트에 항목을 추가할 수 있습니다. 이 리스트는 기호가 정의되어야 하는 때에 대한 규칙을 지정합니다. 버전 번호에 대해 특정 버전이나 여러 버전으로 평가되는 논리적 표현식을 지정할 수 있습니다.

심볼을 조건부로 정의하려면 다음 단계를 따르십시오.

  1. Inspector 에서 프로퍼티를 볼 어셈블리의 어셈블리 정의 에셋을 선택합니다.
  2. Version Defines 섹션에서 + 버튼을 클릭하여 리스트에 항목을 추가합니다.
  3. 다음 프로퍼티를 설정합니다.
    • Resource: 이 기호를 정의하기 위해 설치해야 하는 패키지나 모듈 또는 Unity 를 선택합니다.
    • Define: 심볼 이름입니다.
    • Expression: 특정 버전 또는 버전 범위로 평가되는 표현식입니다. 규칙은 버전 정의 표현식을 참조하십시오.
    Expression outcome 은 표현식이 어느 버전으로 평가되는지 나타냅니다. 결과에 Invalid 가 표시되면 표현식 구문이 틀린 것입니다.
  4. 다음 예에서는 프로젝트가 Timeline 1.3을 사용하는 경우 USE_TIMELINE_1_3 기호를 정의하며, 프로젝트를 Unity 2021.2.0a7 이상에서 열면 USE_NEW_APIS를 정의합니다.
  5. Apply 를 클릭합니다.

어셈블리 정의에서 정의된 심볼은 해당 정의에 대해 생성된 어셈블리의 스크립트 범위 내에만 있습니다.

Version Defines 리스트를 Define Constraints 로 사용하여 정의된 기호를 사용할 수 있습니다. 따라서 특정 패키지의 특정 버전이 프로젝트에 설치된 경우에만 어셈블리를 사용해야 함을 지정할 수 있습니다.

 

버전 정의 표현식

표현식을 사용하여 정확한 버전이나 여러 버전을 지정할 수 있습니다. Version Define 표현식은 수학적인 범위 표기법을 사용합니다.

대괄호 “[]”는 범위가 엔드포인트를 포함함을 지정합니다.

[1.3,3.4.1]은 1.3.0 <= x <= 3.4.1로 평가됩니다

괄호 “()”는 범위가 엔드포인트를 제외함을 의미합니다.

(1.3.0,3.4)는 1.3.0 < x < 3.4.0으로 평가됩니다

단일 표현식에서 범위 타입을 혼합할 수 있습니다.

[1.1,3.4)는 1.1.0 <= x < 3.4.0으로 평가됩니다

(0.2.4,5.6.2-preview.2]는 0.2.4 < x <= 5.6.2.-preview.2로 평가됩니다

대괄호 안에 단일 버전 지정자를 사용하여 정확한 버전을 지정할 수 있습니다.

[2.4.5]는 x = 2.4.5로 평가됩니다

좀 더 빠른 방법으로는 범위 대괄호 없이 단일 버전을 입력하여 표현식에 해당 버전 이상이 포함되어 있음을 나타낼 수 있습니다.

2.1.0-preview.7은 x >= 2.1.0-preview.7로 평가됩니다

참고: 표현식에서는 공백이 허용되지 않습니다. 와일드카드 문자는 지원되지 않습니다.

Unity 버전 번호

Unity의 현재 버전(및 어셈블리 정의를 지원하는 모든 버전)은 MAJOR.MINOR.REVISION의 세 부분으로 나뉜 버전 지정자(예: 2017.4.25f1, 2018.4.29f1, 2019.4.7f1)를 사용합니다.

  • MAJOR 버전은 타겟 출시년도입니다(예: 2017년, 2021년).
  • MINOR 버전은 타겟 출시 사분기(예: 1분기, 2분기, 3분기, 4분기)입니다.
  • REVISION 지정자는 세 부분으로 나뉘며, 형식은 RRzNN입니다.
    • RR은 1자리 또는 2자리의 개정 번호입니다.
    • z는 출시 유형을 지정하는 글자입니다.
      • a = 알파 출시
      • b = 베타 출시
      • f = 일반 공개 출시
      • c = 중국 출시 버전(f와 동등)
      • p = 패치 출시
      • x = 실험적 출시
    • NN은 1자리 또는 2자리의 번호로, 나중 출시일수록 커집니다.

출시 유형 지정자의 비교 관계는 다음과 같습니다.

a < b < f = c < p < x

즉, 알파 출시는 베타 출시보다 빠르며, 베타 출시는 일반(f) 출시 또는 중국(c) 출시보다 빠릅니다. 패치 출시는 항상 개정 번호가 같은 일반 출시나 중국 출시보다 늦으며, 실험적 개정 번호는 여타 출시 유형보다 늦습니다. 실험 출시는 끝에 나중 출시일수록 커지는 번호를 사용하지 않습니다.

Unity 버전 번호는 REVISION 컴포넌트 뒤에 2019.3.0f11-Sunflower와 같은 접미사 사용이 허용됩니다. 버전 비교 시 접미사는 무시됩니다.

예를 들어, 다음 표현식은 Unity의 모든 2017 또는 2018 버전을 포함하지만, 2019 이상 버전은 일체 포함하지 않습니다.

[2017,2019)

패키지 및 모듈 버전 번호

패키지 및 모듈 버전 지정자는 MAJOR.MINOR.PATCH-LABEL의 유의적 버전 형식을 따르는 네 부분으로 나뉩니다. 처음 세 부분은 항상 숫자이지만, 레이블은 스트링입니다. 프리뷰 상태의 Unity 패키지는 preview 또는 preview.n이라는 스트링을 사용하며, 여기서 n > 0입니다. 패키지 버전 번호에 대한 자세한 내용은 패키지 버전을 참조하십시오.

예를 들어, 다음 표현식은 MAJOR.MINOR 버전이 3.2 - 6.1(포함)인 모든 패키지 버전을 포함합니다.

[3.2,6.1]

 

스크립트가 속한 어셈블리 찾기

C# 스크립트 중 하나가 컴파일되는 어셈블리를 식별하려면 다음 단계를 따르십시오.

  1. Unity Project 창에서 C# 스크립트 파일을 선택하여 Inspector 창에서 해당 프로퍼티를 확인합니다.
  2. 어셈블리 파일 이름과 어셈블리 정의(존재하는 경우)는 Inspector  Assembly Information 섹션에 표시됩니다.

이 예제에서 선택한 스크립트는 Unity.Timeline.Editor 어셈블리 정의 에셋에서 정의된 라이브러리 파일인 Unity.Timeline.Editor.dll로 컴파일됩니다.

 

특수 폴더

Unity는 폴더 내에서 특정한 특수 이름이 지정된 스크립트를 다른 폴더의 스크립트와 다르게 취급합니다. 단, 이러한 폴더는 해당 폴더 내 또는 상위 폴더에 어셈블리 정의 에셋을 생성하면 더 이상 다르게 취급되지 않습니다. 이와 같은 변화는 Editor 폴더를 사용할 때 가장 잘 알아볼 수 있는데, 이러한 Editor 폴더는 보통 코드 정리 방식 과 사용하는 에셋 스토어 패키지에 따라 프로젝트 전체에 걸쳐 분산되어 있습니다.

보통 Unity는 이름이 Editor인 폴더의 모든 스크립트를 이러한 스크립트의 위치와는 상관없이 사전 정의된 Assembly-CSharp-Editor 어셈블리에 컴파일합니다. 단, 하위 폴더 중 Editor 폴더가 있는 폴더에 어셈블리 정의 에셋을 생성하면 해당 에디터 스크립트가 사전 정의된 에디터 어셈블리가 아닌 어셈블리 정의에 의해 생성된 새로운 어셈블리로 전송됩니다. 이 위치는 잘못된 위치입니다. Editor 폴더를 관리하기 위해 각 Editor 폴더에서 어셈블리 정의 또는 레퍼런스 에셋을 생성하고 해당 스크립트를 하나 이상의 에디터 어셈블리에 배치할 수 있습니다. [에디터 코드용 어셈블리 생성]을 참조하십시오.

 

어셈블리 속성 설정

어셈블리 속성을 사용하여 어셈블리에 대한 메타데이터 프로퍼티를 설정할 수 있습니다. 일반적으로 어셈블리 속성 문은 AssemblyInfo.cs 파일에 저장됩니다.

예를 들어 다음 어셈블리 속성은 몇 가지 .NET 어셈블리 메타데이터 값, InternalsVisibleTo 속성(테스트 작업 시 유용), 그리고 프로젝트를 빌드할 때 미사용 코드를 제거하는 방식에 영향을 주는 Unity 정의 [Preserve 속성]을 지정합니다.

[assembly: System.Reflection.AssemblyCompany("Bee Corp.")]
[assembly: System.Reflection.AssemblyTitle("Bee's Assembly")]
[assembly: System.Reflection.AssemblyCopyright("Copyright 2020.")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("UnitTestAssembly")]
[assembly: UnityEngine.Scripting.Preserve]

 

빌드 스크립트에서 어셈블리 정보 가져오기

UnityEditor.Compilation 네임스페이스에서 CompilationPipeline 클래스를 사용하면 Unity가 프로젝트를 위해 빌드한 모든 어셈블리에 대한 정보를 검색해서 가져올 수 있습니다. 여기에는 어셈블리 정의 에셋에 기반하여 생성된 어셈블리도 포함됩니다.

예를 들어 다음 스크립트는 CompilationPipeline 클래스를 사용하여 프로젝트의 모든 현재 플레이어 어셈블리를 나열합니다.

using UnityEditor;
using UnityEditor.Compilation;
public static class AssemblyLister
{
    [MenuItem("Tools/List Player Assemblies in Console")]
    public static void PrintAssemblyNames()
    {
        UnityEngine.Debug.Log("== Player Assemblies ==");
        Assembly[] playerAssemblies =
            CompilationPipeline.GetAssemblies(AssembliesType.Player);

        foreach (var assembly in playerAssemblies)
        {
            UnityEngine.Debug.Log(assembly.name);
        }
    }
}

C# 클래스나 변수를 선언할때 다음과 같은 접근 제한자가 있다.

  • public : 외부클래스(스크립트)에서 접근가능, 인스펙터에 노출됨
  • private : 동일클래스에서만 접근가능. 외부접근 불가, 인스펙터에 노출안됨
  • protected: private과 동일하게 외부접근 불가능하고 상속받은 파생 클래스에서만 접근가능
  • internal : 같은 어셈블리에서만 접근가능. class의 경우 접근제한자를 생략하면 internal이 기본값으로 설정

액세스 한정자는 멤버 또는 형식의 선언된 접근성을 지정하는데 사용되는 키워드

키워드 접근성
public 제한 없음
protected 포함 및 파생
internal 동일 어셈블리로 제한
protected internal 동일 어셈블리 또는 다른 어셈블리여도 포함하는 클래스에서 파생된 형식
private 포함
private protected 포함 or 동일 어셈블리 내의 포함하는 클래스의 파생 ( C# 7.2 이상 )

* 네임 스페이스에는 액세스 한정자가 허용되지 않음 

public class A { }
// 동일 어셈블리에서는 internal만 사용할 경우 public과 접근 제어 수준이 동일함
internal class B { } 

// protected, protected internal, private, private protected는 namespace에는 허용되지 않기 때문에 에러
protected class C { }

* 멤버 선언이 발생한 구문에 따라 특정 액세스 한정자만 허용

- 멤버가 다른 형식 내에 중첩되면 해당 엑세스 가능 영역은 엑세스 가능성 수준 및 한 수준 위 형식의 엑세스 가능 영역에 의해 결정됨

public class A{
    private class AA {
		public int x;
    }
}

public class B {
    void Test() {
        // AA Class가 private 이기 때문에 AA.x가 public 이여도 외부에서 접근할 수 없음
        A.AA aa = new A.AA();
    }
}

* 기본 멤버 액세스 가능성 및 멤버의 허용된 액세스 가능성

구문 기본 멤버 엑세스 멤버의 허용된 액세스
enum public none
class  private  public / protected / internal / private / protected internal, private protected
interface public public / protected / internal / *private ( 기본 구현 필요 ) / protected internal, private protected
struct private 상속이 안되기 때문에 protected는 제외됨

public / internal / private 

* protected

class A
{
    protected int x = 1;
}

class B : A
{
    void Start()
    {
        A a = new A();
        B b = new B();

        // x에 접근할 수 없기 때문에 에러
        a.x = 1;

        // x에 접근할 수 있기 때문에 정상
        x = 2;
    }
}

* internal

// EveryDayDevup-Framework 어셈블리
// 같은 어셈블리에서는 접근이 가능
internal class A {
    public static int x = 1;
}

class C{
    void Test() {
		A.x = 2;
    }
}


// Assembly-CSharp
class B {
    void Start() {
    	// 어셈블리가 다르기 때문에 A에 접근할 수 없음 
        A.x = 3;
    }
}
// internal class를 public으로 변경하고 멤버를 internal로 변경
public class A
{
	internal static int x = 1;
}

class C
{
	void Test()
    {
		A.x = 2;
    }
}


class B : 
{
    void Start()
    {
        A a = new A();
    	// 인스턴스 생성은 가능하지만
        // internal로 설정한 x에 접근할 수 없음 
        a.x = 2;
    }
 }

* protected internal

// EveryDayDevup-Framework
// 같은 어셈블리에 있는 C는 A.x의 접근할 수 있음
public class A
{
	internal int x = 1;
}

public class C 
{
	void Test()
    {
		x = 3;
    }
}

// Assembly-CSharp
// 다른 어셈블리에 있는 B클래스는 상속을 해도 A.x의 접근할 수 없음
class B : A
{
    void Start()
    {
        x = 2;
    }
}
// EveryDayDevup-Framework
// protected internal을 사용하면 다른 어셈블리의 파생 클래스에서 x의 접근이 가능
// protected internal은 멤버에만 사용할 수 있음
public class A
{
	protected internal int x = 1;
}

// Assembly-CSharp
class B : A
{
    void Start()
    {
     	// protected internal은 상속 시 다른 어셈블리에서 접근이 가능
        x = 2;
    }
}

* private

class A
{
    private int x;
    
    public int GetX() {
    	return x;
    }
}

class B
{
    void Test()
    {
        A a = new A();
        // private는 선언된 클래스 또는 구조체의 본문에서만 접근 가능
        // a.x의 접근할 수 없기 때문에 에러
        a.x;
        
        // A에서 x를 접근할 수 있도록 해줘야함
        a.GetX();
    }
}

* private protected

// EveryDayDevup-Framework
// 동일 어셈블리의 파생 클래스에서는 접근이 가능
public class A {
	private protected int x = 1;
}

public class C : A{
	void Test() {
		x = 2;
    }
}

// Assembly-CSharp
class B : A {
    void Test(){
    	// 다른 어셈블리에서는 상속을 받아도 x에 접근할 수 없음 
        x = 3;
    }
}

 

'유니티게임강좌 > 주인공 캐릭터 제작' 카테고리의 다른 글

[Player제작] 캐릭터 회전 - Rotate  (0) 2023.02.25
Assembly  (0) 2023.02.25
[Player제작] 캐릭터의 이동  (0) 2023.02.25
[Player제작] InputManager  (2) 2023.02.25
[Player제작] 유니티 Class 종류  (0) 2023.02.25

Vector3는 UnityEngine 구조체이다

쉽게 생각하면 다음과 같다  물론 실제는 좀더 복잡하다.

public struct Vector3 :IEquatable<Vector3>, IFormattable{
    public float x;
    public float y;
    public float z;
    public static Vector3 right {get;}
    public static Vector3 left {get;}
    public static Vector3 up {get;}
    public static Vector3 down {get;}
    public static Vector3 foward {get;}
    public static Vector3 back {get;}
}
 

이 구조는 Unity 전체에서 3D 위치와 방향을 전달하는 데 사용됩니다. 또한 일반적인 벡터 연산을 수행하기 위한 함수도 포함되어 있습니다.

아래 나열된 함수 외에도 다른 클래스를 사용하여 벡터와 점을 조작할 수도 있습니다. 예를 들어 Quaternion 및 Matrix4x4 클래스는 벡터와 점을 회전하거나 변환하는 데 유용합니다.

 

정적 변수

back Vector3(0, 0, -1) 작성에 대한 약어.
down Vector3(0, -1, 0) 작성에 대한 약어.
forward Vector3(0, 0, 1) 작성에 대한 약어.
left Vector3(-1, 0, 0) 작성에 대한 약어.
negativeInfinity Vector3( float.NegativeInfinity , float.NegativeInfinity , float.NegativeInfinity )
one Vector3(1, 1, 1) 작성에 대한 약어.
positiveInfinity Vector3( float.PositiveInfinity , float.PositiveInfinity , float.PositiveInfinity )
right Vector3(1, 0, 0) 작성에 대한 약어.
up Vector3(0, 1, 0) 작성에 대한 약어.
zero Vector3(0, 0, 0) 작성에 대한 약어.

변수

magnitude 이 벡터의 길이를 반환합니다(읽기 전용).
normalized 크기가 1인 이 벡터를 반환합니다(읽기 전용).
sqrMagnitude 이 벡터의 제곱 길이를 반환합니다(읽기 전용).
this[int] 각각 [0], [1], [2]를 사용하여 x, y, z 구성 요소에 액세스합니다.
x 벡터의 X 구성요소.
y 벡터의 Y 구성 요소입니다.
z 벡터의 Z 구성 요소입니다.

생성자

Vector3 지정된 x, y, z 구성 요소로 새 벡터를 만듭니다.

Public 함수

Equals 주어진 벡터가 이 벡터와 정확히 같으면 true를 반환합니다.
Set 기존 Vector3의 x, y 및 z 구성요소를 설정합니다.
ToString 이 벡터에 대해 형식이 지정된 문자열을 반환합니다.

Static 함수

Angle 및에서 벡터 사이의 각도를 계산합니다.
ClampMagnitude maxLength 로 고정된 벡터의 복사본을 반환합니다 .
Cross 두 벡터의 외적.
Distance a와 b 사이의 거리를 반환합니다.
Dot 두 벡터의 내적.
Lerp 두 점 사이를 선형 보간합니다.
LerpUnclamped 두 벡터 사이를 선형 보간합니다.
Max 두 벡터의 가장 큰 구성 요소로 만들어진 벡터를 반환합니다.
Min 두 벡터의 가장 작은 구성 요소로 만들어진 벡터를 반환합니다.
MoveTowards maxDistanceDelta 로 지정된 거리보다 더 멀리 이동하지 않고 현재 및 대상으로 지정된 점 사이의 위치를 계산합니다 .
Normalize 이 벡터의 크기를 1로 만듭니다.
OrthoNormalize 벡터를 정규화하고 서로 직교하도록 만듭니다.
Project 벡터를 다른 벡터에 투영합니다.
ProjectOnPlane 평면에 수직인 법선으로 정의된 평면에 벡터를 투영합니다.
Reflect 법선에 의해 정의된 평면에서 벡터를 반사합니다.
RotateTowards 대상을 향해 벡터 전류를 회전합니다.
Scale 두 벡터를 구성요소별로 곱합니다.
SignedAngle 축을 기준으로 시작과 끝 벡터 사이의 부호 있는 각도를 계산합니다.
Slerp 두 벡터 사이를 구면으로 보간합니다.
SlerpUnclamped 두 벡터 사이를 구면으로 보간합니다.
SmoothDamp 시간이 지남에 따라 원하는 목표를 향해 벡터를 점차적으로 변경합니다.

operator - 한 벡터에서 다른 벡터를 뺍니다.
operator != 벡터가 다른 경우 true를 반환합니다.
operator * 벡터에 숫자를 곱합니다.
operator / 벡터를 숫자로 나눕니다.
operator + 두 벡터를 더합니다.
operator == 두 벡터가 거의 같으면 true를 반환합니다.

 

'유니티스크립팅 > 유니티매뉴얼' 카테고리의 다른 글

카메라 - 유니티  (0) 2023.03.03
마우스좌표를 월드좌표로 - 2D  (0) 2023.03.02
[유니티매뉴얼] Unity의 회전 및 방향  (0) 2023.02.28
변수와 함수  (0) 2023.02.25
Scripts as Behaviour Components  (0) 2023.02.25

유니티에서 객체를 이동시키거나 회전시키는 방법은 2가지가 있다. 

1. 모든 객체에 있는 Transform컴포넌트의 position, rotation 속성을 지속해서 변경하는 것이다.

2. 내장된 물리엔진을 이용해 물리적인 힘(Force)또는 회전력(Torque)을 가해 변경시키는 것이다. 

 

애니메이션으로도 이동및 회전을 할 수 있지만, 이건 Transform컴포넌트의 속성값을 연속적으로 기록한 것을 재생하는 것이기 때문에  Transform컴포넌트를 이용하는 방법이다.

 

하이라키의 Player Object을 선택한후 인스펙터뷰에서 Add Component에서 new Script를 선택하고 PlayerCtrl로 한다. 

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

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

    // Update is called once per frame
    void Update()
    {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        transform.position += new Vector3(h, 0f, v);
    }
}

h,v를 입력 받아 Vector3 구조체를 만들어 transform.position에 "+=" 연산해준다.

h,v의 범위는 WASD나 화살표키에 따라 -1f~1f의 범위를 갖기 때문에 Player는 전후좌우로 잘 움직인다.

주의할건 Vector3(h,v,0f)가 아니라 Vector(h,0f,v)라는 거다 유니티는 3차원 좌표시스템인데 y는 위아래를 뜻한다. 따라서 x는 좌우 z는 전후를 뜻한다.

Play해보면 무지하게 빠르지만 잘 움직인다. 왜냐하면 Update()함수는 컴퓨터마다 다르자만 1초에 대략 60번 정도는 호출되기 때문이다. 그리고 이렇게 자주 호출되기때문에 되도록이면 무거운 처리를 피해야한다.

다음과 같이 자주호출될 Transform의 참조를 tr에 저장해놓고 사용하면 좀 가벼워진다. 이걸 컴포넌트캐시라고 한다.

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

public class PlayerCtrl : MonoBehaviour
{
    // Start is called before the first frame update
    Transform tf;
    void Start(){
        tf = GetComponent<Transform>();
    }

    // Update is called once per frame
    void Update(){
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        tf.position += new Vector3(h, 0f, v);
    }
}

tf.position += new Vector3(h, 0f, v);를 처리해주는 Translate()라는 함수가 있다

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

public class PlayerCtrl : MonoBehaviour
{
    // Start is called before the first frame update
    Transform tf;
    void Start(){
        tf = GetComponent<Transform>();
    }

    // Update is called once per frame
    void Update(){
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        tf.Translate(new Vector3(h, 0f, v));
    }
}

현재 움직임이 너무 빠르다. 왜냐하면 매프레임 호출되기 때문이다. 따라서 움직임을 작게하면 되지만 그렇게 되면 컴퓨터의 성능에 따라 속도차이가 나게 된다. 따라서 매 프레임의 시간간격을 곱해주면 컴퓨터의 성능에 관계없이 움직임 속도가 일정하게 된다. 성능이 나쁜 컴퓨터는 시간간격이 크기 때문에 그만큼 많이 움직이기 때문이다.

d(거리) = v1*t1 = v2*t2 , 컴퓨터 성능에 속도는 비례하지만 프레임간시간간격은 반비례한다.

간단하게 빠른 컴퓨터는 조금 움직이게 해주는거다.

 

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

public class PlayerCtrl : MonoBehaviour
{
    // Start is called before the first frame update
    Transform tf;
    void Start(){
        tf = GetComponent<Transform>();
    }

    // Update is called once per frame
    void Update(){
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        tf.Translate(Time.deltaTime * new Vector3(h, 0f, v));
    }
}

단위벡터를 이용해 이동 벡터를 만들수 있다.

Vector3 dir = Vector3.right*x + Vector3.forward*v;

단위벡터와 단위벡터의 합은 √2가 될수 있으므로 스칼라값을 1로 만들기 위해 단위벡터로 만들려면 dir.normalized를 사용해야한다. 

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

public class PlayerCtrl : MonoBehaviour {
    // Start is called before the first frame update
    Transform tf;
    private float speed;
    void Start() {
        tf = GetComponent<Transform>();
        speed = 8f;
    }

    // Update is called once per frame
    void Update() {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        Vector3 dir = Vector3.right* h + Vector3.forward* v;
        tf.Translate(dir.normalized * speed * Time.deltaTime);
    }
}

 

'유니티게임강좌 > 주인공 캐릭터 제작' 카테고리의 다른 글

Assembly  (0) 2023.02.25
[Player제작] 접근제한자  (0) 2023.02.25
[Player제작] InputManager  (2) 2023.02.25
[Player제작] 유니티 Class 종류  (0) 2023.02.25
[Player제작] 스크립트  (0) 2023.02.25

 Input은 외부에서 들어오는 입력값을 관리하는 클래스다. 최근에 추가된 InputSystem도 있지만 다음에 설명하겠다.

유니티는 자주 사용하는 키보드, 마우스, 조이스틱 입력에 대한 조합을 미리 정의해 놓왔고 InputManager에서 관리한다.

입력 관리자

Input Manager 창에서 프로젝트에 대한 입력 축 및 축과 관련된 행동을 정의할 수 있습니다. 액세스하려면 Unity의 메인 메뉴에서 Edit > Project Settings로 이동한 후 오른쪽 내비게이션에서 Input Manager를 선택합니다.

입력 관리자는 다음 타입의 컨트롤을 사용합니다.

  • 는 W 키, Shift 키, 스페이스바 등과 같은 물리적 키보드의 모든 키를 의미합니다.
  • 버튼은 리모콘의 X 버튼처럼 물리적 컨트롤러(예: 게임패드)에 있는 버튼을 가리킵니다.
  • 가상 축(복수형: )은 버튼, 키 등과 같은 컨트롤에 매핑됩니다. 사용자가 컨트롤을 활성화하면 축은 [–1..1] 범위의 값을 수신합니다. 이 값은 스크립트에서 사용할 수 있습니다. Horizontal, Vertical, Fire1, Fire2, Mouse X와 같은 추상적인 개념의 이름으로 정의되어 있다.

 

Input.GetKey("a")와 같이 위에 명시된 명명 규칙을 사용하여 특정 키 또는 버튼에 대한 입력을 쿼리할 수도 있습니다. 예를 들면 다음과 같습니다.

스크립트에서 가상 축 사용
스크립트에서 가상 축에 액세스하기 위해 축 이름을 사용할 수 있습니다.
예를 들어 Horizontal 축의 현재 값을 쿼리하고 변수에 저장하려면 다음과 같이 Input.GetAxis를 사용할 수 있습니다.

Input.GetAxis("Input Manager Axes 이름")으로 값을 얻어 올수 있다.

Input.GetAxis는 -1.0f~1.0f의 변화하는 값을 얻어오는데, 누루고 있으면 0f에서 -1f나 1f로 가속되는 값이 리턴된다.

Input.GetAxisRaw -1.0f, 0f, 1.0f의 3개중 하나의 값이 전달된다.

움직임이 아니라 이벤트(예: 게임 내에서 무기 발사)를 설명하는 축의 경우에는 대신에 Input.GetButtonDown을 사용하십시오.

두 개 이상의 축이 동일한 이름을 사용하는 경우 쿼리는 절대값이 가장 큰 축을 반환합니다. 따라서 축 이름에 두 개 이상의 입력 기기를 할당할 수 있습니다.

예를 들어 Horizontal이라는 이름으로 두 개의 축을 만든 후 하나는 키보드 입력에 할당하고 다른 하나는 조이스틱 입력에 할당할 수 있습니다. 사용자가 조이스틱을 사용하는 경우 입력은 조이스틱에서 수신되고 키보드 입력은 null입니다. 그렇지 않으면 입력은 키보드에서 수신되고 조이스틱 입력은 null입니다. 이를 통해 여러 컨트롤러의 입력을 처리하는 단일 스크립트를 작성할 수 있습니다.

예제

Horizontal  Vertical 축의 입력과 transform.Translate 메서드를 사용하여 XZ 공간(전방, 후방, 왼쪽, 오른쪽)에서 게임 오브젝트를 움직일 수 있습니다. 움직이려는 게임 오브젝트에 연결된 스크립트의 update() 메서드에 다음 코드를 추가하십시오.

float moveSpeed = 10;
//Define the speed at which the object moves.

float horizontalInput = Input.GetAxis("Horizontal");
//Get the value of the Horizontal input axis.

float verticalInput = Input.GetAxis("Vertical");
//Get the value of the Vertical input axis.

transform.Translate(new Vector3(horizontalInput, verticalInput, 0) * moveSpeed * Time.deltaTime);
//Move the object to XYZ coordinates defined as horizontalInput, 0, and verticalInput respectively.

Time.deltaTime은 마지막 프레임 이후 경과한 시간을 나타냅니다. moveSpeed 변수를 Time.deltaTime과 곱하면 게임 오브젝트가 프레임마다 일정한 속도로 움직입니다.

 

Input class는 다음과 같은 함수들을 지원하면 눌렸을때 눌리고 있을때 떨어졌을때를 구별할 수 있습니다.

GetAccelerationEvent Returns specific acceleration measurement which occurred during last frame. (Does not allocate temporary variables).
GetAxis Returns the value of the virtual axis identified by axisName.
GetAxisRaw Returns the value of the virtual axis identified by axisName with no smoothing filtering applied.
GetButton Returns true while the virtual button identified by buttonName is held down.
GetButtonDown Returns true during the frame the user pressed down the virtual button identified by buttonName.
GetButtonUp Returns true the first frame the user releases the virtual button identified by buttonName.
GetJoystickNames Retrieves a list of input device names corresponding to the index of an Axis configured within Input Manager.
GetKey Returns true while the user holds down the key identified by name.
GetKeyDown Returns true during the frame the user starts pressing down the key identified by name.
GetKeyUp Returns true during the frame the user releases the key identified by name.
GetMouseButton Returns whether the given mouse button is held down.
GetMouseButtonDown Returns true during the frame the user pressed the given mouse button.
GetMouseButtonUp Returns true during the frame the user releases the given mouse button.
GetTouch Call Input.GetTouch to obtain a Touch struct.
IsJoystickPreconfigured Determine whether a particular joystick model has been preconfigured by Unity. (Linux-only).
ResetInputAxes Resets all input. After ResetInputAxes all axes return to 0 and all buttons return to 0 for one frame.

이 섹션에서는 스크립팅 시 사용할 수 있는 Unity에서 가장 자주 사용되고 중요한 빌트인 클래스에 대한 간략한 정보를 제공합니다.

이 페이지는 Unity에서 스크립팅 기본 사항을 발견하기 위한 시작점 역할을 하며 Unity의 모든 클래스를 다루지 않습니다. 이는 여기서 다루는 클래스의 모든 멤버도 마찬가지입니다.

빌트인 클래스와 사용 가능한 모든 멤버에 대한 보다 온전한 레퍼런스는 스크립트 레퍼런스를 참조하십시오.

  • GameObject: 씬에 존재할 수 있는 오브젝트의 타입을 나타냅니다.
  • MonoBehaviour: 기본적으로 모든 Unity 스크립트가 파생되는 기본 클래스입니다.
  • Object: Unity가 에디터에서 참조할 수 있는 모든 오브젝트의 기본 클래스입니다.
  • Transform: 스크립트를 통한 게임 오브젝트의 포지션, 회전 및 스케일뿐만 아니라 부모 및 자식 게임 오브젝트의 계층적 관계에 대한 다양한 작업 방법을 제공합니다.
  • Vectors: 2D, 3D, 4D 포인트, 라인 및 방향을 표현하고 조작하는 클래스입니다.
  • Quaternion: 절대 또는 상대 회전을 나타내는 클래스이며, 이를 생성하고 조작하는 방법을 제공합니다.
  • ScriptableObject: 많은 양의 데이터를 저장하는 데 사용할 수 있는 데이터 컨테이너입니다.
  • Time (and framerate management): Time 클래스를 사용하면 시간을 측정 및 제어하고 프로젝트의 프레임 속도를 관리할 수 ​​있습니다.
  • Mathf: 게임 및 앱 개발에 일반적으로 필요한 삼각 함수, 로그 함수, 기타 함수를 비롯한 일반적인 수학 함수 컬렉션을 제공합니다.
  • Random: 흔히 요구되는 다양한 타입의 랜덤 값을 쉽게 생성할 수 있는 방법을 제공합니다.
  • Debug: 프로젝트가 실행되는 동안 어떤 일이 일어나고 있는지 파악하거나 조사하는 데 도움이 되는 정보를 에디터에서 시각화할 수 있습니다.
  • Gizmos and Handles: 씬 뷰와 게임 뷰에 라인과 모양뿐만 아니라 인터랙티브 핸들과 컨트롤도 그릴 수 있습니다.

C# 스크립트

유니티엔진의 코어 부분은 C++로 제작됐다. 유티는 스크립트언어로 C#을 지원한다. C++와 비슷해서 어렵지 않다. 객체지향 다형화에 대해 선지식이 필요하다.

 

여기서는 C#을 사용하는 법에 대해서는 다른곳에서 많이 다루었기 때문에 자세히 설명하지 않겠다. 책이나 다른 사이트를 참조해주시기 바란다.

 

유니티의 주요 이벤트 함수

프로젝트뷰에서 Scripts폴더를 하나만들고 우클릭을 하고 Create>Script를 하고 Ex란 이름으로 Scripts폴더에 저장하자.

더블클릭하면 지정된 에디터가 열리면서 자동생성된 코드가 보인다.

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

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

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

Ex로 저장된 스크립터에는 공교롭게 Ex라는 class가 만들어져 있다. 

Ex라는 class는 MonoBehaviour라는 class에서 상속되었다.

MonoBehaviour 클래스는 기본적으로 모든 Unity 스크립트가 파생되는 기본 클래스입니다. Unity의 프로젝트 창에서 C# 스크립트를 생성하면 MonoBehaviour에서 자동으로 상속되며, 템플릿 스크립트를 제공합니다. MonoBehaviour 클래스는 에디터에서 게임 오브젝트에 스크립트를 연결할 수 있는 프레임워크를 제공할 뿐만 아니라, 시작  업데이트 등과 같은 유용한 이벤트에 대한 연결을 제공합니다.

MonoBehaviour 클래스를 사용하면 코루틴을 시작, 중지 및 관리할 수 ​​있습니다. 코루틴은 특정 시간 동안 기다리거나 특정 작업이 완료될 때까지 기다리면서 다른 코드가 계속 실행되도록 해주는 비동기 코드 작성 방식입니다.

Ex class는 내부에 Start()와 Update()라는 이벤트 함수가 보인다. 이벤트 함수란 특정 상화에서 유니티엔진이 자동으로 호출해주는 함수이다.

이벤트

MonoBehaviour 클래스는 대규모 이벤트 메시지 컬렉션에 대한 액세스를 제공하며, 이를 통해 현재 프로젝트에서 발생하는 상황에 따라 코드를 실행할 수 있습니다. 다음은 일반적인 몇 가지 예입니다. 전체 리스트는 MonoBehaviour 스크립트 레퍼런스 페이지 Messages 섹션을 참조하십시오.

Start - 게임 오브젝트가 존재하기 시작할 때 호출됩니다(씬이 로드될 때 또는 게임 오브젝트가 인스턴스화될 때 호출).

Update - 프레임마다 호출됩니다.

FixedUpdate - 물리 타임스텝마다 호출됩니다.

OnBecameVisible  OnBecameInvisible - 게임 오브젝트의 렌더러가 카메라의 뷰에 들어오거나 나갈 때 호출됩니다.

OnCollisionEnter  OnTriggerEnter - 물리 충돌 또는 트리거가 발생할 때 호출됩니다.

OnDestroy - 게임 오브젝트가 파괴될 때 호출됩니다.

좀더 자세한 생명주기는 다음과 같은데 지금은 어렵고 나중에 필요할때 읽어도 될것 같다.

스크립트 라이프사이클 플로우차트

참고: 일부 브라우저에서는 SVG 이미지 파일을 지원하지 않습니다. 위 이미지가 올바르게 표시되지 않는 경우(예를 들어 텍스트가 보이지 않는 경우) Google Chrome 또는 Mozilla Firefox 등 다른 브라우저를 사용해 보십시오.

 

첫 번째 씬 로드

다음 함수는 씬이 시작할 때(씬에서 오브젝트마다 한 번) 호출됩니다.

  • Awake: 이 함수는 항상 Start 함수 전에 호출되며 프리팹이 인스턴스화 된 직후에 호출됩니다. 게임 오브젝트가 시작하는 동안 비활성 상태인 경우 Awake 함수는 활성화될 때까지 호출되지 않습니다.
  • OnEnable: (오브젝트가 활성화된 경우에만): 오브젝트 활성화 직후 이 함수를 호출합니다. 레벨이 로드되거나 스크립트 컴포넌트를 포함한 게임 오브젝트가 인스턴스화될 때와 같이 MonoBehaviour를 생성할 때 이렇게 할 수 있습니다.

씬에 추가된 모든 오브젝트에 대해 Start, Update 등 이전에 호출된 모든 스크립트를 위한 Awake 및 OnEnable 함수가 호출됩니다. 따라서 게임플레이 도중 오브젝트를 인스턴스화될 때는 실행되지 않습니다.

 

에디터

  • Reset: 오브젝트에 처음 연결하거나 Reset 커맨드를 사용할 때 스크립트의 프로퍼티를 초기화하기 위해 Reset을 호출합니다.
  • OnValidate: OnValidate는 오브젝트가 역직렬화될 때를 포함하여 스크립트의 프로퍼티가 설정될 때마다 호출되며, 이는 에디터에서 씬을 열 때와 도메인을 다시 로드한 후와 같이 다양한 시기에 발생할 수 있습니다.

 

첫 번째 프레임 업데이트 전에

  • Start: 스크립트 인스턴스가 활성화된 경우에만 첫 번째 프레임 업데이트 전에 호출됩니다.

씬 에셋에 포함된 모든 오브젝트에 대해 Update 등 이전에 호출된 모든 스크립트를 위한 Start 함수가 호출됩니다. 따라서 게임플레이 도중 오브젝트를 인스턴스화될 때는 실행되지 않습니다.

 

프레임 사이

  • OnApplicationPause: 이 함수는 일시 정지가 감지된 프레임의 끝, 실질적으로는 일반 프레임 업데이트 사이에 호출됩니다. 게임에 일시정지 상태를 가리키는 그래픽스를 표시하도록 OnApplicationPause 가 호출된 후에 한 프레임이 추가로 실행됩니다.

 

업데이트 순서

게임 로직, 상호작용, 애니메이션, 카메라 포지션의 트랙을 유지할 때, 사용 가능한 몇몇 다른 이벤트가 존재합니다. 일반적인 패턴은 Update 함수에 대부분의 작업을 수행하는 것이지만, 사용할 수 있는 다른 함수도 있습니다.

  • FixedUpdate: FixedUpdate 는 종종 Update 보다 더 자주 호출됩니다. 프레임 속도가 낮은 경우 프레임당 여러 번 호출될 수 있으며 프레임 속도가 높은 경우 프레임 사이에 호출되지 않을 수 있습니다. 모든 물리 계산 및 업데이트는 FixedUpdate 후 즉시 발생합니다. FixedUpdate 의 움직임 계산을 적용할 때 Time.deltaTime 만큼 값을 곱할 필요가 없습니다. FixedUpdate 가 프레임 속도와 관계없이 신뢰할 수있는 타이머에서 호출되기 때문입니다.
  • Update: Update 는 프레임당 한 번 호출됩니다. 프레임 업데이트를 위한 주요 작업 함수입니다.
  • LateUpdate: LateUpdate  Update 가 끝난 후 프레임당 한 번 호출됩니다. Update 에서 수행된 모든 계산은 LateUpdate 가 시작할 때 완료됩니다. LateUpdate 는 일반적으로 다음의 3인칭 카메라에 사용합니다. 캐릭터를 움직이고 Update 로 방향을 바꾸게 하는 경우 LateUpdate 에서 모든 카메라 움직임과 로테이션 계산을 수행할 수 있습니다. 이렇게 하면 카메라가 포지션을 추적하기 전에 캐릭터가 완전히 움직였는지 확인할 수 있습니다.

일반적으로 순서가 명시적으로 문서화되거나 설정 가능한 경우를 제외하고, 다른 게임 오브젝트에 대해 동일한 이벤트 함수가 호출되는 순서를 사용해서는 안 됩니다. (플레이어 루프를 보다 세세하게 제어해야 하는 경우 PlayerLoop API를 사용할 수 있습니다.)

동일한 MonoBehaviour 서브 클래스의 다른 인스턴스에 대해 이벤트 함수가 호출되는 순서를 지정할 수 없습니다. 예를 들어 한 MonoBehaviour의 Update 함수는 다른 게임 오브젝트(해당 부모 또는 자식 게임 오브젝트 포함)의 동일한 MonoBehaviour에 대해 Update 함수 전후에 호출될 수 있습니다.

한 MonoBehaviour 서브 클래스의 이벤트 함수가 다른 서브 클래스의 이벤트 함수 전에 호출되도록 지정할 수 있습니다(Project Settings 창의 Script Execution Order 패널 사용). 예를 들어 두 개의 스크립트(EngineBehaviour, SteeringBehaviour)가 있는 경우 EngineBehaviour가 항상 SteeringBehaviour 전에 업데이트되도록 스크립트 실행 순서를 설정할 수 있습니다.

 

애니메이션 업데이트 루프

Unity가 애니메이션 시스템을 평가할 때 이러한 함수와 프로파일러 마커가 호출됩니다.

  • OnStateMachineEnter: State Machine Update 단계 동안 컨트롤러의 상태 머신이 엔트리 상태를 통과하는 전환을 만들 때 이 콜백이 첫 번째 업데이트 프레임에 대해 호출됩니다. StateMachine 하위 상태에 대한 전환의 경우에는 호출되지 않습니다.

    이 콜백은 Controller 컴포넌트(예: AnimatorController 또는 AnimatorOverrideController 또는 AnimatorControllerPlayable)가 애니메이션 그래프에 있을 때에만 발생합니다.

    참고: 이 콜백을 StateMachineBehaviour 컴포넌트에 추가하면 멀티스레드 상태 머신 평가가 비활성화됩니다.
  • OnStateMachineExit: State Machine Update 단계 동안 컨트롤러의 상태 머신이 종료 상태를 통과하는 전환을 만들 때 이 콜백이 마지막 업데이트 프레임에 대해 호출됩니다. StateMachine 하위 상태에 대한 전환의 경우에는 호출되지 않습니다.

    이 콜백은 Controller 컴포넌트(예: AnimaorController 또는 AnimatorOverrideController 또는 AnimatorControllerPlayable)가 애니메이션 그래프에 있을 때에만 발생합니다.

    참고: 이 콜백을 StateMachineBehaviour 컴포넌트에 추가하면 멀티스레드 상태 머신 평가가 비활성화됩니다.
  • Fire Animation Events: 마지막 업데이트 시간과 최신 업데이트 시간 사이에 샘플링된 모든 클립에서 모든 애니메이션 이벤트를 호출합니다.
  • StateMachineBehaviour (OnStateEnter/OnStateUpdate/OnStateExit): 레이어가 최대 3개의 활성 상태(현재 상태, 중단된 상태, 다음 상태)를 가질 수 있습니다. 이 함수는 OnStateEnter, OnStateUpdate 또는 OnStateExit 콜백을 정의하는 StateMachineBehaviour 컴포넌트가 포함된 각 활성 상태에 대해 호출됩니다.

    제일 먼저 함수가 현재 상태에 대해 호출되고 중단된 상태에 대해 호출된 후 마지막으로 다음 상태에 대해 호출됩니다.

    이 단계는 Controller 컴포넌트(예: AnimatorController 또는 AnimatorOverrideController 또는 AnimatorControllerPlayable)가 애니메이션 그래프에 있을 때에만 발생합니다.
  • OnAnimatorMove: 업데이트 프레임마다 루트 모션을 수정할 수 있도록 각 Animator 컴포넌트에 대해 한 번 호출됩니다.
  • StateMachineBehaviour(OnStateMove): 이 콜백을 정의하는 StateMachineBehaviour가 포함된 각 활성 상태에 대해 호출됩니다.
  • OnAnimatorIK: 애니메이션 IK를 설정합니다. IK pass가 활성화된 각 애니메이터 컨트롤러 레이어에 대해 한 번 호출됩니다.

    휴머노이드 릭을 사용하는 경우에만 이 이벤트가 실행됩니다.
  • StateMachineBehaviour(OnStateIK): IK pass가 활성화되어 있는 레이어에서 이 콜백을 정의하는 StateMachineBehaviour 컴포넌트가 포함된 각 활성 상태에 대해 호출됩니다.
  • WriteProperties: 다른 모든 애니메이션화된 프로퍼티를 메인 스레드에서 씬에 작성합니다.

유용한 프로파일 마커

스크립트 라이프사이클 플로우차트에 표시된 일부 애니메이션 함수는 호출할 수 없는 이벤트 함수입니다. 즉, Unity가 애니메이션을 처리할 때 호출되는 내부 함수입니다.

이 함수에는 프로파일 마커가 있으므로 프로파일러를 사용하여 프레임에서 Unity가 호출하는 시간을 확인할 수 있습니다. Unity가 이러한 함수를 호출하는 시간을 알면 호출한 이벤트 함수가 실행된 시간을 정확하게 파악하는 데 도움이 됩니다.

예를 들어 FireAnimationEvents 콜백에서 Animator.Play를 호출한다고 가정해 보겠습니다. State Machine Update  Process Graph 함수가 실행된 후에 FireAnimationEvents 콜백이 발동했다는 사실을 알면 애니메이션 클립이 즉시 재생되는 것이 아니라 다음 프레임에서 재생된다는 것을 예측할 수 있습니다.

  • State Machine Update: 이 단계에서 모든 상태 머신이 실행 시퀀스대로 평가됩니다. 이 단계는 Controller 컴포넌트(예: AnimatorController 또는 AnimatorOverrideController 또는 AnimatorControllerPlayable)가 애니메이션 그래프에 있을 때에만 발생합니다.

    참고: 상태 머신 평가는 대개 멀티스레드이지만, 특정 콜백(예: OnStateMachineEnter  OnStateMachineExit)을 추가하면 멀티스레딩이 비활성화됩니다. 자세한 내용은 위의 애니메이션 업데이트 루프를 참조하십시오.
  • ProcessGraph: 모든 애니메이션 그래프를 평가합니다. 여기에는 평가할 모든 애니메이션 클립에 대한 샘플링과 루트 모션 계산이 포함됩니다.
  • ProcessAnimation: 애니메이션 그래프의 결과를 블렌딩합니다.
  • WriteTransforms: 모든 애니메이션화된 트랜스폼을 워커 스레드에서 씬에 작성합니다.

    IK pass가 활성화된 여러 개의 레이어가 있는 휴머노이드 릭은 여러 개의 WriteTransforms 패스를 가질 수 있습니다(스크립트 라이프사이클 플로우차트 참조).

 

렌더링

  • OnPreCull: 카메라가 씬을 컬링하기 전에 호출됩니다. 컬링은 어떤 오브젝트를 카메라에 표시할지 결정합니다. OnPreCull은 컬링 발생 직전에 호출됩니다.
  • OnBecameVisible/OnBecameInvisible: 오브젝트가 카메라에 표시되거나/표시되지 않을 때 호출됩니다.
  • OnWillRenderObject: 오브젝트가 표시되면 각 카메라에 한 번 호출됩니다.
  • OnPreRender: 카메라가 씬 렌더링을 시작하기 전에 호출됩니다.
  • OnRenderObject: 모든 일반 씬 렌더링이 처리된 후 호출됩니다. 이 때 커스텀 지오메트리를 그리는 데에 GL 클래스 또는 Graphics.DrawMeshNow를 사용할 수 있습니다.
  • OnPostRender: 카메라가 씬 렌더링을 마친 후 호출됩니다.
  • OnRenderImage: 씬 렌더링이 완료된 후 호출되어 이미지의 포스트 프로세싱이 가능합니다. 포스트 프로세싱 효과를 참고하십시오.
  • OnGUI: GUI 이벤트에 따라 프레임당 여러 번 호출됩니다. 레이아웃 및 리페인트 이벤트는 우선 처리되며 각 입력 이벤트에 대해 레이아웃 및 키보드/마우스 이벤트가 다음으로 처리됩니다.
  • OnDrawGizmos: 시각화 목적으로 씬 뷰에 기즈모를 그릴 때 사용됩니다.

참고: 이러한 콜백은 빌트인 렌더 파이프라인에서만 작동합니다.

 

코루틴

일반적인 코루틴 업데이트는 Update 함수가 반환된 후 실행됩니다. 코루틴은 주어진 YieldInstruction이 완료될 때까지 실행을 중단(양보)할 수 있는 함수입니다. 코루틴의 다른 사용법은 다음과 같습니다.

  • yield 코루틴은 모든 Update 함수가 다음 프레임에 호출된 후 계속됩니다.
  • yield WaitForSeconds 지정한 시간이 지난 후, 모든 Update 함수가 프레임에 호출된 후 계속됩니다.
  • yield WaitForFixedUpdate 모든 FixedUpdate가 모든 스크립트에 호출된 후 계속됩니다. FixedUpdate 전에 코루틴이 양보하면 현재 프레임의 FixedUpdate 이후에 재개합니다.
  • yield WWW WWW 다운로드가 완료된 후 계속됩니다.
  • yield StartCoroutine 코루틴을 연결하고 MyFunc 코루틴이 먼저 완료되기를 기다립니다.

 

오브젝트를 파괴할 때

  • OnDestroy: 오브젝트 존재의 마지막 프레임에 대해 모든 프레임 업데이트를 마친 후 이 함수가 호출됩니다. 오브젝트는 Object.Destroy 또는 씬 종료에 대한 응답으로 파괴될 수 있습니다.

 

종료할 때

다음 함수는 씬의 활성화된 모든 오브젝트에서 호출됩니다.

  • OnApplicationQuit: 이 함수는 애플리케이션 종료 전 모든 게임 오브젝트에서 호출됩니다. 에디터에서 사용자가 플레이 모드를 중지할 때 호출됩니다.
  • OnDisable: 동작이 비활성화되거나 비활성 상태일 때 이 함수가 호출됩니다.

 

Models/Player폴더에서 Player를 하이라키로 끌어다 놓는다. 씬뷰에 끌어다 놓을 경우 Position을(0,0,0)으로 설정한다.

 

유니티 엔진의 개발방식

유니티는 컴포넌트 기반과 멀티스레드 기반의 DOTS  두가지 개발방식을 지원한다.

 

컴포넌트 기반의 개발방식

독립적인 기능 단위로 컴포넌트를 제작한 다음 필요한 기능을 조립하는 방식을 말한다. 블록조립같은 방식이고 컴포넌트의 재사용이 가능하고 높은 생산성이 장점인 개발 방법론이다.

 

 

 

 

+ Recent posts