https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/delegates/
Delegate (대리자)
- microsoft의 docs를 보면
delegate는 특정 매개 변수 목록 및 반환 형식이 있는 메서드에 대한 참조를 나타내는 형식이다.
delegate는 메서드를 다른 메서드에 인수로 전달하는 데 사용된다.
요런 내용으로 설명하고 있다.
코드로 예를 들면
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour
{
// delegate는 함수 자체를 인자로 넘길 수 있는 하나의 형식(위는 반환을 string)이라고 생각
private delegate string stringDelegate();
// 이렇게 매개변수도 받을 수 있음
private delegate string stringDelegate2(string wow);
/// <summary>
/// 선언한 stringDelegate Delegate를 매개변수로 받아오고
/// </summary>
void DelegateTest(stringDelegate stringDG)
{
// string 형식으로 반환 하니까 받아서 log찍어서 확인
string test = stringDG();
Debug.Log(test);
}
string DebugTest()
{
Debug.Log("1");
// return도 때릴 수 있음
return "Hello World!!!";
}
string DebugTest2()
{
Debug.Log("2");
return "Hello World~~~";
}
private void Start()
{
DelegateTest(DebugTest);
// delegate를 선언하고
stringDelegate ex = new stringDelegate(DebugTest);
// 이렇게 한 메서드가 아니라 여러 메서드를 연결 할 수 있음
ex += DebugTest2;
DelegateTest(ex);
}
}
요렇게 간단히 테스트해보면
이런 결과를 얻을 수 있음
ex로 선언한 delegate의 경우 DebugTest, DebugTest2를 연결했기 때문에 순차적으로 실행됨
그러나 로그를 보면
1 -> Hello World!!! -> 2 -> Hello World~~~가 아니라
1 -> 2 -> Hello World~~~가 떴는데
이는 실행 순서가 DebugTest -> DebugTest2 -> DelegateTest() 순 이기 때문에 DelegateTest()에서는 DebugTest2의 반환 값인 Hello World~~~를 받았기 때문
--- 다음으로 ---
https://docs.microsoft.com/ko-kr/dotnet/api/system.action-1?view=net-6.0
https://docs.unity3d.com/2022.1/Documentation/ScriptReference/Events.UnityAction.html
Action의 경우는 microsoft와 unity의 docs를 다 보는 게 좋을 듯 (뭐 어차피 내용은 같음)
내용을 보면
- 매개 변수가 하나이고 값을 반환하지 않는 메서드를 캡슐화합니다.
- + System의 네임스페이스를 가짐 => using System;
- Unity Actions를 사용하면 여러 함수를 동적으로 호출할 수 있습니다.
- Unity Actions에는 인수가 없으므로 호출하는 함수에도 인수가 없어야 합니다.
요런 식으로 있음
[ * microsoft의 docs내용 중 위에 진하게 한 부분은 잘 이해가 안 가긴 하는데 음 ..
정확하지는 않지만 매개변수도 없고 return type도 없는 게 맞는 걸로 알고 있음.. ]
코드로 예를 보면
using System;
using UnityEngine;
public class UpdateManager
{
[Tooltip("Managers - Update에 돌릴 메서드 등록 위함")]
public Action _update = null;
[Tooltip("Managers - Update에 돌릴 메서드 등록(BgScroll)")]
public Action _updateBgScroll = null;
/// <summary>
/// Managers - Update()
/// </summary>
public void OnUpdate()
{
if (_update != null)
_update.Invoke();
if (_updateBgScroll != null)
_updateBgScroll.Invoke();
}
public void Clear()
{
_update = null;
_updateBgScroll = null;
}
}
개인 프로젝트에서 사용 중인 코드인데
(OnUpdate의 경우 Managers.cs의 Update()에서 돌고 있을 거임)
뭐 사실 Action을 하나로 두고 사용해도 되지만 가독성도 그렇고 기능을 확실히 분리해두는 게 좋다 생각하여 위딴 식으로 작성함
+
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BgScroll : MonoBehaviour
{
[Header("--- 미리 가지고 있어야 할 data ---")]
[SerializeField, Tooltip("MeshRenderer")]
MeshRenderer _mesh = null;
[Header("--- 세팅 ---")]
[SerializeField, Tooltip("배경 스크롤 스피드")]
float _speed = 0;
[Header("--- 참고용 ---")]
[SerializeField, Tooltip("현재 배경의 Offset")]
float _offset = 0;
/// <summary>
/// BgManager.cs에서 돌릴 BG를 Init
/// Scroll - UpdateM - action 등록
/// </summary>
public void Init()
{
Managers.UpdateM._updateBgScroll -= Scroll;
Managers.UpdateM._updateBgScroll += Scroll;
}
/// <summary>
/// 비활성화 시 action 해제
/// </summary>
private void OnDisable()
{
if (Managers.Instance != null)
Managers.UpdateM._updateBgScroll -= Scroll;
}
/// <summary>
/// 배경 scroll
/// </summary>
void Scroll()
{
_offset += _speed * Time.deltaTime;
_mesh.material.mainTextureOffset = new Vector2(_offset, 0);
}
}
이런 식으로 (배경 스크롤 코드임)
Init()시에 Action에 등록 후 Scroll() 메서드를 열심히 굴려줌 (매개변수도 없고 return type도 없고)
* 참고로 delegate든 action이든 등록할 때 += 로 등록을 하는데 항상 -=를 한 뒤에 +=를 하는 습관을 들이는 게 좋음 +=를 했는데 이미 +=를 한 상태라면 두 번씩 호출될 수 있기 때문
'Unity > Tips' 카테고리의 다른 글
Unity 애니메이션은 코드 없이 CrossFade (3) | 2022.02.13 |
---|---|
Unity 확장 메서드 사용 (0) | 2022.01.19 |
Unity 메모리 관리 간단한 [ UnloadUnusedAssets(), Singleton 사용 시 ] (0) | 2021.12.16 |
OnApplicationFocus, OnApplicationPause (0) | 2021.12.15 |
Unity PackageCache 등의 package 오류 (특히 Unity버전 변경 시) (0) | 2021.12.07 |