728x90

스크립트를 하나 만들어서

그곳에 초당 프레임을 찍어주는 코드를 작성한 후 

오브젝트에 붙여서 프레임을 확인해보도록 한다.

using UnityEngine;
using System.Collections;
 
public class FPSDisplay : MonoBehaviour
{
	float deltaTime = 0.0f;
 
	void Update()
	{
		deltaTime += (Time.unscaledDeltaTime - deltaTime) * 0.1f;
	}
 
	void OnGUI()
	{
		int w = Screen.width, h = Screen.height;
 
		GUIStyle style = new GUIStyle();
 
		Rect rect = new Rect(0, 0, w, h * 2 / 100);
		style.alignment = TextAnchor.UpperLeft;
		style.fontSize = h * 2 / 100;
		style.normal.textColor = new Color (0.0f, 0.0f, 0.5f, 1.0f);
		float msec = deltaTime * 1000.0f;
		float fps = 1.0f / deltaTime;
		string text = string.Format("{0:0.0} ms ({1:0.} fps)", msec, fps);
		GUI.Label(rect, text, style);
	}
}

특히 스마트폰 환경의 개발과 PC환경에서의 프레임은 확연히 다르기 떄문에

해당 환경에서 내가 원하는 프레임이 나오는지 확인하는 것도 중요한 부분이다.

더 확장해서는 원하는 타이밍 뭐 개발용 앱, 배포용 앱 등 상태 값을 하나 둬서 상태 값에 따라 화면에 프레임 표시가 뜨게한다거나 안뜨게 한다거나 할수도 있을 것이다.

요즘에 나오는 스마트폰이나, 태블릿 등등은 워낙 성능이나, 기능면에서 좋게 나와서 확실히 예전보다는 더 높은 프레임을 바라볼수 있는 환경이 되었으나,

그만큼 개발에 들어가는 퀄리티도 계속해서 높아지고 있는 만큼 해당 환경에서 프레임을 체크하는것은 필수 이다.

728x90
Posted by 정망스
,
728x90

애니메이션 이벤트(Animation event)

이 기능은 애니메이션의 실행 도중, 원하는 시점에 원하는 함수를 호출할 수 있게 해준다. 

이 애니메이션 이벤트를 사용하는 방법은 2가지가 있는데 FBX 모델과 함께 임포트된 애니메이션에서 사용하는 방법과 애니메이션 클립(Animation clip)에서 사용하는 방법이다.

방법 1 : FBX 모델과 함께 임포트된 애니메이션에서 애니메이션 이벤트 사용하기

프로젝트 창(Project view)에서 임포트한 FBX파일을 선택하면 Inspector 창에 그 FBX파일의 정보들이 보일 것이다. 그 중에서 상단의 Animations라는 탭을 선택하면 그 FBX에 포함된 애니메이션의 정보를 볼 수 있다. 우리가 필요로 하는 애니메이션 이벤트 기능은 그 중에서 Events라는 곳 안에서 사용할 수 있다. 그 항목을 열면 다음과 같은 내용을 볼 수 있다 : 

노란색으로 표시된 버튼을 누르면 다음과 같이 애니메이션이 재생되는 도중에 실행될 이벤트가 새로 생성된다 :

위의 이미지에서 파란색으로 표시된 것을 드래그하면 이 이벤트가 실행될 시점을 조절할 수 있으며 그 아래의 입력 필드의 내용들은 다음과 같다 

 필드 이름 내용 
Function 이벤트 시점에 실행될 함수의 이름 
Float 함수에 float형 매개변수가 있을 때 들어갈 값
Int 함수에 int형 매개변수가 있을 때 들어갈 값
String 함수에 string형 매개변수가 있을 때 들어갈 값
Object 실행할 함수가 들어있는 스크립트

 

using UnityEngine;

public class AttackComponent : MonoBehaviour
{
    public void AttackDamage()
    {
        // 적에게 데미지를 주는 처리
        Debug.Log("데미지 60!");
    }
}

공격 애니메이션에서 적에게 무기가 맞는 시점이 위의 Events 이미지에서 0:050라고 가정하자. 다음과 같이 이전에 생성한 이벤트를 0:050 지점으로 옮기고 Object에 생성한 AttackComponent 스크립트를 넣어주고 Function에는 AttackDamage 함수 이름을 입력해주면 된다.

다음과 같은 과정을 끝내고 나면 애니메이션이 실행되고 0:050 지점을 지날 때마다 유니티 에디터에서 "데미지 60!"이라는 로그가 출력될 것이다.

방법 2 : 애니메이션 클립에서 애니메이션 이벤트 사용하기

애니메이션 클립은 3D 모델 없이 애니메이션에 대한 정보만을 가지고 있는 것을 이야기한다. 물론 임포트한 FBX 모델 파일에서 애니메이션만 꺼내와서 사용하는 것도 가능하다. 이러한 애니메이션 클립에서 애니메이션 이벤트를 사용하는 방법은 이전에 소개한 FBX 모델에 포함된 애니메이션에서 사용하는 방법과 상당히 비슷하다.

프로젝트 창에서 애니메이션클립을 선택하고 애니메이션 탭을 열면 다음과 같은 화면을 볼 수 있다.(만약 애니메이션 탭이 보이지 않는다면 상단의 Windows 메뉴에서 Animation을 찾아서 열거나 Ctrl+6 단축키를 이용해서 열 수 있다)

애니메이션 탭에서도 FBX 파일 애니메이션의 이벤트에서 봤던 것과 같은 모양의 버튼을 볼 수 있는데 이것을 통해서 이벤트를 생성할 수 있고 드래그를 통해서 이벤트의 시점을 이동시킬 수도 있다.

그리고 이 이벤트를 선택하면 Inspector 창에서 다음과 같은 내용을 볼 수 있다 : 

이 이후에는 방법 1에서 진행한 것과 같이 진행하면 원하는 결과를 얻을 수 있게 된다.

728x90

'Unity' 카테고리의 다른 글

유니티 - 캐시 서버 (Cache Server)  (0) 2021.07.23
유니티 - 프레임 표시하기  (0) 2021.07.23
유니티 - 라이트맵 (LightMap)  (0) 2019.08.12
유니티 - 충돌 (Trigger, Collider)  (0) 2019.08.07
유니티 - 에디터 확장 기능  (0) 2019.08.05
Posted by 정망스
,
728x90

우선 라이트맵이 무엇인지 대해 설명을 해보도록 하자.

Lightmap
라이트맵

라이트맵은 3D CG에서 빛의 방향과 세기에 따라 생성되는 빛을 받는 오브젝트의 그림자, 반사면, 면의 밝기 차이 등의 라이팅 정보를 사전에 저장하는 텍스쳐를 뜻한다. 

플레이어가 바라보는 시야 및 씬의 환경 배치, 광원의 수와 조도 등에 따라서 화면에 출력되는 빛은 시시각각 다르게 보여지게 되며 이를 시각적으로 처리하는 연산에는 빛의 입자 정보를 일일히 따져보아야 하는 상당한 부하가 수반된다. 

게임같은 경우, 빛을 계산하는 것이 컨텐츠의 전부가 아니기 때문에 라이팅에서 컴퓨팅 비용을 많이 사용하게 되면 게임플레이 코드 처리나 물리 연산 등에서 활용할 수 있는 자원이 줄어든다. 때문에 최대한 효율적으로 빛을 처리하고 다른 부분에서의 퍼포먼스도 보장하기 위하여 고안된 방법이 바로 라이트 정보를 미리 오브젝트의 텍스쳐에 '라이트맵'이라는 별도의 채널로 저장하여 마치 빛을 받고있는 듯 보이게 하는 라이트맵 방식이다. 이를 흔히 업계에서는 '라이트맵을 굽는다' 고 표현한다.

즉 요약 하면 실시간으로 빛에 의한 변화를 계산하기에는 엄청난 연산과 비용을 요구하기 때문에 이를 미리 계산하여 정보를 가지고 있는 하나의 텍스쳐를 이용해서 빛이 존재하는것처럼 효과를 준다는 정도로 이해하면 될 듯 하다.

유니티와 관련된 라이트맵 정보는 

https://docs.unity3d.com/kr/current/Manual/Lightmapping.html

 

라이트매핑: 시작하기 - Unity 매뉴얼

이 페이지에서는 Unity의 라이트매핑에 대해 소개합니다. 라이트매핑은 씬의 표면 밝기를 미리 계산하고 계산 결과를 나중에 사용하기 위해 차트 또는 “라이트맵”에 저장하는 프로세스입니다.

docs.unity3d.com

링크로 참고해서 과정을 진행해보거나 보면 될듯 하다.

728x90
Posted by 정망스
,
728x90

- 충돌처리를 위한 조건

우선 충돌이 일어나기 위해서는 두 GameObject가 모두 Collider를 가지고 있어야 하며 둘 중 하나는 Rigidbody를 가지고 있어야 한다.

두 GameObject중 하나만 움직인다면 움직이는 GameObject가 Rigidbody를 가지고 있어야 한다.

 

위 그림은 Collider가 잘 보이게 하기 위해 GameObject보다 크기를 약간 키워 보았다. 위에서 보이는 초록색 부분이 Collider로 실제로 충돌을 감지하는 영역이다.

Unity에서 제공하는 Object들에는 기본적으로 Collider가 들어가 있으며 Box Collider, Sphere Collider, Capsule Collider 등이 있다. 만약 다른 Model을 불러와 작업한다면 Model에 알맞게 Collider를 설정해 주어야 올바른 충돌처리를 할 수 있다.

 

- Trigger

Trigger는 GameObject간의 물리적 연산을 하지 않고 충돌을 감지할 수 있다. 즉, 두 GameObject가 접촉했을때 서로 튕겨 나가지않고 그냥 통과하게 된다.

Trigger를 쓰기 위해서는 해당 Collider의 Is Trigger 항목을 체크해야 한다.

다음으로 스크립트에서 함수로 충돌 이벤트를 처리할 수 있다.

void OnTriggerEnter(Collider col) { }

void OnTriggerStay(Collider col) { }

void OnTriggerExit(Collider col) { }

다음과 같이 Enter, Stay, Exit 3가지 버전의 OnTrigger 함수를 만들 수 있다.

3가지 함수는 다음과 같은 특징을 나타낸다.

Enter - 충돌이 시작되는 순간 호출

Stay - 충돌이 되고있을 때 매 프레임마다 호출

Exit - 충돌이 끝날 때 호출

함수의 파라메터로 Collider 객체가 들어오며 col을 이용해 충돌한 GameObject에 대한 처리를 할 수 있다. 

 

- Collision

Collision은 Trigger와 다르게 물리적인 연산을 하며 충돌을 감지한다.

주의할 것은 Rigidbody의 Kinematic 속성이 꺼져 있어야 충돌이 발생할 수 있다.

void OnCollisionEnter(Collision col) { }

void OnCollisionStay(Collision col) { }

void OnCollisionExit(Collision col) { }

Trigger와 동일하게 3가지 함수를 만들 수 있으며 특징 또한 동일하다.

함수의 파라메터로 Collision 객체가 들어오며 col을 이용해 충돌한 GameObject에 대한 처리를 할 수 있다.

 

- Tag

충돌을 처리할 때 어떤 Object와 충돌을 했는 지도 중요하기 때문에 이에 대한 처리도 해주어야 한다. 이때 가장 많이 사용하는 것이 Tag 속성이다.

Tag 속성은 위와 같이 Inspector창에서 해당 GameObject의 Tag를 지정해 줄 수 있으며 Add Tag에서 새로운 Tag를 만들 수도 있다.

void OnTriggerEnter(Collider col) {

    if (col.tag == "Enemy")

    {

        // event.

    }

}

그럼 Enemy 라는 태그를 가진 GameObject랑만 충돌처리를 하고 싶다면 위와같이 if문으로 처리할 수 있다.

또한 다중 if문으로 여러 GameObject들에 다른 이벤트를 처리 할 수도 있다. 

728x90
Posted by 정망스
,
728x90

2장 표준에서 사용할 수 있는 에디터 확장기능

이미 유니티 상에서 준비되어 있는 Attribute를 사용하면 편하고 자유롭게
커스터마이즈 할수 있음.

2.1 인스펙터의 외관을 변경
(1) Range

좌측은 기본상태, 우측이 Range를 사용해 변경한 상태.

using UnityEngine;
using System.Collections;

public class NewBehaviourScript : MonoBehaviour
{
    [Range(1, 10)]
    public int num1;

    [Range(1, 10)]
    public float num2;

    [Range(1, 10)]
    public long num3;

    [Range(1, 10)]
    public double num4;
}


(2) Multiline / TextArea
기본적으로 1줄짜리 TextField인데, 여러줄의 TextArea로 변경할 수 있음.
Multiline도 TextArea랑 별 차이 없는데, Multiline은 폭에 맞춰 자동적으로 줄바꿈되지 않고,
스크롤 바를 표시하지 않음. 특별한 이유가 없으면 TextArea를 사용하는걸 추천.

using UnityEngine;
using System.Collections;

public class NewBehaviourScript : MonoBehaviour
{
    [Multiline(5)]
    public string multiline;

    [TextArea(3, 5)]
    public string textArea;
}

2.2 인스펙터에서 다루는 기능을 추가
(1) ContextMenuItem
인스펙터에 표시되어 있는 변수에 콘텍스트 메뉴를 추가함. 다른 변수들도 일제히 수치를 변경하지 않으면 안되거나, 순서가 필요한 요소를 자동화하는 용도로 사용하면 될듯. 
컴포넌트 단위로 수치를 리셋시키는 Reset 기능은 있지만 각 변수에 대한 리셋 기능은 없으므로 이걸로 추가하면 됨.

using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    [ContextMenuItem ("Random", "RandomNumber")]
    [ContextMenuItem ("Reset", "ResetNumber")]
    public int number;

    void RandomNumber ()
    {
        number = Random.Range (0, 100);
    }

    void ResetNumber ()
    {
        number = 0;
    }
}


(2) ColorUsage
색의 변경을 위한 컬러 픽커를 사용함. 알파값 사용/미사용, HDR 용 등으로 설정.

using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    public Color color1;

    [ColorUsage (false)]
    public Color color2;

    [ColorUsage (true, true, 0, 8, 0.125f, 3)]
    public Color color3;
}

2.3 인스펙터의 외관을 정리
프로퍼티에 직접작용하지는 않지만, 외관 정리용으로 사용하는게 있음.
(1) Header

using UnityEngine;
using System;

public class NewBehaviourScript : MonoBehaviour
{
    [Header("Player Settings")]
    public Player player;

    [Serializable]
    public class Player
    {
        public string name;

        [Range(1,100)]
        public int hp;
    }

    [Header("Game Settings")]
    public Color background;
}

(2) Space : 말그대로 공백. 줄 띄워씀.

using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    [Space(16)]
    public string str1;

    [Space(48)]
    public string str2;
}

(3) Tooltip
프로퍼티에 대한 설명을 인스펙터 상에서 확인하게 만들고 싶을때 사용.

using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    [Tooltip("これはツールチップです")]
    public long tooltip;
}


(4) HideInInspector : 본래 public인 변수는 인스턴스에 표시되지만, 이거 쓰면 표시 안됨.

using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    public string str1;

    [HideInInspector]
    public string str2;
}


2.4 인스펙터를 좀 편리하게 하자
(1) RequireComponent
[특정 컴포넌트가 최소 1개는 Attach되어 있어야 한다]고 하는 제약을 거는 속성입니다.
Animator와 관련된 스크립트를 작성할때, Animator 컴포넌트가 붙어있어야 한다고 제약을 건다든가.
RequireComponent가 사용된 스크립트를 Attach하면 자동으로 RequireComponent로 지정한 컴포넌트도 Attach됨. 이미 Attach되어 있으면 아무것도 안함. 그리고 지정된 컴포넌트를 삭제하려고 하면 못한다고 표시뜸.

using UnityEngine;

[RequireComponent(typeof(Animator))]
public class NewBehaviourScript : MonoBehaviour
{
    Animator animator;

    void Awake ()
    {
        animator = GetComponent<Animator> ();
    }
}

(2) DisallowMultipleComponent
하나의 게임 오브젝트에 같은 컴포넌트를 여러개 Attach하는것을 금지하는 속성.
2개 이상 같은 컴포넌트 넣고 게임 실행하면 못한다고 표시뜸.
이 속성이 설정된 클래스를 상속한 클래스에도 이 속성이 적용됨.

using UnityEngine;

public class NewBehaviourScript : Base
{
}
using UnityEngine;

[DisallowMultipleComponent]
public class Base : MonoBehaviour
{
}

(3) FormerlySerializedAs
변수명을 변경했을때에 새로운 변수명에 데이터를 이동시키기 위한 속성.
인스펙터에 표시되듯이, Serialized된 데이터는 변수명을 경로로써 보존함. 이런 상태에서 변수명을 바꾸면 변수의 데이터는 초기화됨. 그래서 이런 문제를 회피하기 위한 속성.
(역주 : using UnityEngine.Serialization; 추가해야함)

using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    [SerializeField]
    [FormerlySerializedAs("hoge")]
    string fuga;
}

변수명의 변경과 FormerlySerializedAs 속성의 추가, oldName의 지정은 동시에 이루어져야함.
스크립트의 컴파일에 의해 필요없는 데이터는 파괴되어버림. 변수명 변경하고 한번 컴파일, 그러고 나서 속성 추가하고 oldName 지정해봐야 데이터는 이미 날아가고 없다는거.

(4) AddComponentMenu
Component 메뉴에 메뉴항목을 추가합니다.
스크립트는 모두 Component/Scripts 메뉴의 안에 정리되어 있음. 범용적인 스크립트 컴포넌트 군을 작성할 때, 하나의 카테고리에 정리하고 싶을때 사용. 그럴때 AddComponentMenu를 사용한 스크립트는 다른 장소에 메뉴가 작성되므로 Component/Scripts 메뉴 안에서 소거됩니다.

using UnityEngine;

[AddComponentMenu("MyUI/Tween Color")]
public class TweenColor : MonoBehaviour
{
}

 

2.5 게임 개발을 편하게 하자
(1) ExecuteInEditMode
게임 실행중이 아니어도 MonoBehaviour를 상속한 컴포넌트의 주요 함수가 호출되는 효과.
호출되는 타이밍은 게임 오브젝트가 갱신되는 때. 씬 Asset을 더블클릭해서, 씬을 로드할 때에는 Awake와 Start 함수가, 인스펙터 등에서 컴포넌트의 변수 등을 변경하면 Update가 호출됨. 
또한, OnGUI 에서 설치된 GUI가 에디터의 GUI 렌더링 사이클을 돌면서 표시되는식.

using UnityEngine;

[ExecuteInEditMode]
public class NewBehaviourScript : MonoBehaviour
{
    [Range(0,10)]
    public int number;

    void Awake ()
    {
        Debug.Log ("Awake");
    }

    void Start ()
    {
        Debug.Log ("Start");
    }

    void Update ()
    {
        Debug.Log ("Update");
    }
}


(2) ContextMenu
컴포넌트의 컨텍스트 메뉴에서 함수를 실행함.
ContextMenuItem과 이름과 기능이 비슷하지만, 추가하는 컨텍스트 메뉴의 장소가 다름.

using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    [Range (0, 10)]
    public int number;

    [ContextMenu ("RandomNumber")]
    void RandomNumber ()
    {
        number = Random.Range (0, 100);
    }

    [ContextMenu ("ResetNumber")]
    void ResetNumber ()
    {
        number = 0;
    }
}

(3) SelectionBase
씬 뷰에서 오브젝트를 선택했을때 [선택된 게임 오브젝트를 지정]하거나 [게임 오브젝트의 선택 순서를 결정]할 때 사용합니다. 보통, 씬 뷰에서 오브젝트를 선택한 때에는 루트 게임 오브젝트가 선택됨.

원래 Cube를 클릭하면 Cube만 선택되는데, 자식 오브젝트에 SelectionBase를 붙이면, Cube를 클릭했을때 자식 오브젝트부터 먼저 선택되는 효과.

using UnityEngine;

[SelectionBase]
public class NewBehaviourScript : MonoBehaviour
{
}

https://blog.naver.com/PostView.nhn?blogId=hammerimpact&logNo=220770056749&parentCategoryNo=&categoryNo=&viewDate=&isShowPopularPosts=false&from=postView

728x90

'Unity' 카테고리의 다른 글

유니티 - 라이트맵 (LightMap)  (0) 2019.08.12
유니티 - 충돌 (Trigger, Collider)  (0) 2019.08.07
유니티 - Editor Folder  (0) 2019.08.04
유니티 - PropertyDrawer  (0) 2019.08.03
유니티 - ScriptableObject  (0) 2019.08.02
Posted by 정망스
,


맨 위로
홈으로 ▲위로 ▼아래로 ♥댓글쓰기 새로고침