스파르타 게임개발종합반(Unity)/TIL - 본캠프 매일 공부 기록

2024.05.27 TIL - InputSytem, InvokeEvent, Phase, 데미지 Flash효과 - Coroutine, 낮과 밤 표현 - Directional Light, Gradient, AnimationCurve, AutoCollider(콜라이더 크기), Font Asset(폰트 굽기), Static 옵션

테크러너 2024. 5. 27.

InputSytem -  InvokeEvent

`InvokeEvent`는 버튼 이벤트처럼 콜백 메서드를 등록해서 사용한다.

 

    private Vector2 curMovementInput;

    public void OnMove(InputAction.CallbackContext context)
    {
        if (context.phase == InputActionPhase.Performed)
        {
            curMovementInput = context.ReadValue<Vector2>();
        }
        else if (context.phase == InputActionPhase.Canceled)
        {
            curMovementInput = Vector2.zero;
        }
    }

`InputSystem`에 등록해둔 키값의 정보가 `context`에 저장되고, `ReadValue`로 불러올 수 있다.

또한 `phase`로 키값이 눌러졌을 때, 뗐을 때 등등의 상태에 따라 어떤 작업을 수행할지 정할 수 있다.

Phase 설명
Disabled 동작이 비활성화되어 입력을 받을 수 없다.
Waiting 동작이 활성화되어 입력을 기다리고 있다.
Started 입력 시스템이 동작과 상호 작용을 시작하는 입력을 받았다.(키가 눌러졌다.)
Performed 동작과의 상호 작용이 완료되었다. (키가 눌러지고 있다.)
Canceled 동작과의 상호 작용이 취소되었다. (키를 뗐다.)

공식 문서▼

https://docs.unity3d.com/Packages/com.unity.inputsystem@1.5/manual/Actions.html#action-callbacks

 

 

데미지 입는 Flash 애니메이션 - Coroutine(코루틴)

    public void Flash()
    {
        if (coroutine != null)
        {
            StopCoroutine(coroutine);
        }

        image.enabled = true;
        image.color = new Color(1f, 100f / 255f, 100f / 255f);
        coroutine = StartCoroutine(FadeAway());
    }

    private IEnumerator FadeAway()
    {
        float startAlpha = 0.3f;
        float a = startAlpha;

        while (a > 0)
        {
            a -= (startAlpha / flashSpeed) * Time.deltaTime;
            image.color = new Color(1f, 100f / 255f, 100f / 255f, a);
            yield return null;
        }

        image.enabled = false;
    }

데미지를 입었을 때 화면이 빨간 Falsh효과를 내도록하는 코드이다.

여기서 `(startAlpha / flashSpeed)`는 시간당 알파 값의 변화량을 나타낸다. 그리고 프레임 레이트에 관계없이 일정한 속도로 알파 값이 변경되도록 하기 위해 `Time.deltaTime`을 곱해준다.

코루틴은 `yield return` 이 있어야 하는데, `null`을 리턴해주면 코루틴이 다음 프레임까지 일시 중지되도록 한다.

즉, `yield return null;`은 "하나의 프레임을 대기한다"는 의미이다.

 

 

낮과 밤 구현 - Directional Light, Gradient, AnimationCurve

유니티에서 `Directional Light`로 Sun을 표현한다.

그래서 `Rotation`의 `x`값을 0~360도로 바꾸면 낮과 밤이 바뀌는듯한 현상을 볼 수 있다.

Lighting의 Environment창을 보면 Lighting의 Intensity Multiplier, Reflections의 Intensity Multiplier가 있다.

`Intensity Multiplier`는 빛의 강도인데, 낮에는 빛의 강도가 쎄고 밤에는 빛의 강도가 약하게 하기 위해 코드로 조절해야한다.

 

우선 낮일 때와 밤일 때의 `Directional Light`를 각각 둔다.

Sun은 노란색, Moon은 푸르스름한 색으로 설정한다.

 

    [Header("Sun")]
    public Light sun;
    public Gradient sunColor;
    public AnimationCurve sunIntensity;

    [Header("Moon")]
    public Light sun;
    public Gradient sunColor;
    public AnimationCurve sunIntensity;

    [Header("Other Lighting")]
    public AnimationCurve lightingIntensityMultiplier;
    public AnimationCurve reflectionIntensityMultiplier;

 

`Gradient`는 그라데이션이라 생각하면 된다. 색이 점점 변하는 것을 표현해준다.

`AnimationCurve`는 Sun과 Moon의 조명을 서서히 늘려주기 위해 사용된다.

 

    void Update()
    {
        time = (time + timeRate * Time.deltaTime) % 1.0f;
    }

시간이 점점 지나가는걸 계산하는건데, `1.0f`를 나머지 연산하는 이유연산 결과를 0과 1사이로 유지시켜주기 위함이다.

`Directional Light`가 0~360도로 회전하는데, 이 값을 `0f~1.0f`로 매핑시켰다. 그래서 시간도 0과 1사이로 유지시켜준다.

 

lightSource.transform.eulerAngles = (time - (lightSource == sun ? 0.25f : 0.75f)) * noon * 4f;

하루가 `0f~ 1.0f`로 변화하는데 정오는 `0.5f`이다.

그런데 360도에서 0.5f는 180도이기 때문에 Sun일 때는 `time(0.5f) - 0.25f`를 해줘야 90도가 나온다.

그리고 `noon`이라는 90도를 곱해준다.

그런데 90도에다가 0.25를 곱하면 90이 안나온다. 그래서 `4f`까지 곱해주는 것이다. (90*4 = 360, 360*0.25 = 90)

 

 

콜라이더 크기 설정

박스 콜라이더의 크기를 설정할 때 3D공간에서는 크기를 딱 맞추기가 어렵다.

그래서 나는 이때까지 빨간점부분에 보이는 정육각형의 면을 한 번 클릭하여 2D 화면처럼 만든 후 콜라이더 크기를 조절했다.

 

그런데 튜터님 한 분이 코드로 콜라이더 크기를 딱 맞추게 하는 방법을 알려주셨다!!..

public class AutoCollider : MonoBehaviour
{
#if UNITY_EDITOR
    private void OnValidate()
    {
        Renderer mr = GetComponentInChildren<MeshRenderer>();
        if (mr == null) mr = GetComponentInChildren<SkinnedMeshRenderer>();
        var box = GetComponentInChildren<BoxCollider>();
        box.center = mr.bounds.center - transform.position;
        box.size = mr.bounds.size;
        UnityEditor.EditorApplication.delayCall += () =>
        {
            DestroyImmediate(this);
        };
    }
#endif
}

위의 스크립트를 작성해서

 

오브젝트에 해당 스크립트를 부착해주면 위의 사진처럼 오브젝트 크기에 딱! 맞는 콜라이더 크기가 설정된다.

 

코드를 한 번 분석해보겠다.

#if UNITY_EDITOR
#endif

우선 위의 코드는 전처리 지시문이다.

둘 사이에 있는 코드는 특정 조건에서만 컴파일되도록 제어된다.

`#if UNITY_EDITOR`라는 조건이 있는데, 이 조건은 코드가 Unity 에디터 환경에서 실행될 때만 포함되도록 하는 조건문이다. 즉, 빌드된 게임에는 포함되지 않고, 개발 중에 에디터상에만 사용되는 코드이다.

 

        Renderer mr = GetComponentInChildren<MeshRenderer>();
        if (mr == null) mr = GetComponentInChildren<SkinnedMeshRenderer>();

우선 해당 오브젝트의 `MeshRenderer`를 불러온다.

 

        var box = GetComponentInChildren<BoxCollider>();
        box.center = mr.bounds.center - transform.position;
        box.size = mr.bounds.size;

`BoxCollider` 컴포넌트를 불러온 후 오브젝트의 ` MeshRenderer`경계의 중심과 사이즈를 박스 콜라이더에 매핑한다.

`MeshRenderer`의 `bounds`는 월드 좌표계에서의 경계상자를 나타낸다.

`BoxCollider`의 `center`는 로컬 좌표계에서의 중심을 나타낸다.

그래서 로컬 좌표계로 변환하기 위해 `mr.bounds.center - transform.position`을 빼주는 것이다.

 

        UnityEditor.EditorApplication.delayCall += () =>
        {
            DestroyImmediate(this);
        };

Unity 에디터 내에서 특정 작업이 완료된 후 스크립트가 실행되도록 예약하는 코드이다.

`delayCall` 델리게이트를 사용하여 다음 프레임이 시작될 때 `DestroyImmediate(this)`를 호출하여 해당 객체를 즉시 파괴하도록 예약한다.

그래서 첨부한 gif를 보면 AutoCollider 스크립트를 부착했는데 바로 사라지는 것을 볼 수 있다.

 

 

폰트 굽는법(Font Asset 만드는 법)

Source Font File : Font 파일 넣기

Sampling Point Size : Auto Sizing

Padding : 5

Packing Method : Fast

Atlas Resolution : 4096 4096

Character Set : Custom Range

Character Sequence :

`32-126` : 알파벳 범위

`44032-55203` : 한글 범위(받침 글자 포함)

`12593-12643` : 한글인데 'ㅁ ㅏ'처럼 띄워쓰기된 글자들의 범위

`8200-9900` : 특수문자 범위

Render Mode : SDFAA

 

 

Static 옵션

오브젝트에 Static옵션이 켜져있는 것을 볼 수 있다.

이는 오브젝트가 움직이지 않고 고정된 상태에서 렌더링 되는 경우에 유용하다.

예를 들면 그냥 돌같이 배경적인 요소들 말이다.

 

반응형

댓글