[TIL] C# - 델리게이트 , Action , Func

MINO·2024년 5월 13일
0
post-thumbnail

2024-05-13


Controller 와 Animation 을 관리하는 스크립트에 Action 이 자주 쓰여 정리해보았다.

델리게이트 (delegate)

메서드를 참조하고 호출할 수 있는 형식 (일종의 함수 포인터)
(인스턴스가 아닌 형식임에 유의하자.)

  • 메서드 참조 : 메서드를 매개변수로 전달하거나 다른 메서드의 반환 값으로 사용 가능
  • 메서드 호출 : 델리게이트 인스턴스를 통해 참조된 메서드를 호출 가능
delegate int Calculate(int x,int y);

static int Add(int x,int y)
{
	return x + y;
}

class Program
{
	static void Main()
    {
    	Calculate calc = Add; // 메서드 등록
        
        int result = calc(3,5); // 델리게이트 사용
        Console.WriteLine("결과 : " + result); // 
    }
}

활용 방안

  • 이벤트 핸들링 : 이벤트가 발생했을 때, 호출되는 메서드를 델리게이트로 정의하여 이벤트 핸들러로 등록

  • 콜백 함수 : 콜백(피호출자가 호출자를 다시 호출)함수를 정의하여 비동기 작업의 결과를 처리


public delegate void EnemyAttackHandler(float damage); // 델리게이트 선언

public class Enemy // 적 클래스
{
    public event EnemyAttackHandler OnAttack; // 공격 이벤트

    public void Attack(float damage) // 적의 공격 메서드
    {
        OnAttack?.Invoke(damage); // 이벤트 호출 (null 참조가 아닌 경우에만 멤버에 접근하거나 메서드를 호출)
    }
}


public class Player // 플레이어 클래스
{
    public void HandleDamage(float damage) // 플레이어가 받은 데미지 처리 메서드
    {
        
        Console.WriteLine("플레이어가 {0}의 데미지를 입었습니다.", damage); // 플레이어의 체력 감소 처리 로직
    }
}


static void Main() // 게임 실행
{
    Enemy enemy = new Enemy(); // 적 객체 생성
   
    Player player = new Player(); // 플레이어 객체 생성

    enemy.OnAttack += player.HandleDamage; // 플레이어의 데미지 처리 메서드를 적의 공격 이벤트에 추가

    enemy.Attack(10.0f); // 적의 공격
}

  • 멀티 캐스트 : 여러 개의 메서드를 담을 수 있음 (+= : 담기, -= : 제거)
delegate void MyDelegate(string message); // 델리게이트 선언

static void Method1(string message) // 메서드 1
{
    Console.WriteLine("Method1: " + message);
}

static void Method2(string message) // 메서드 2
{
    Console.WriteLine("Method2: " + message);
}

class Program
{
    static void Main()
    {
        MyDelegate myDelegate = Method1; // 델리게이트 인스턴스 생성 및 메서드 등록
        myDelegate += Method2; // 멀티 캐스트

        myDelegate("Hello!"); // 델리게이트 호출
    }
}

Method1 : Hello!
Method2 : Hello!

로 출력됨


Func

값을 반환하는 메서드를 나타내는 델리게이트.
제네릭 형식 매개변수의 마지막은 반환 타입을 나타낸다.

Ex : Func<int, string> => int 를 입력 받아 string 을 반환하는 메서드


예시


int Add(int x, int y) // 두 개의 int 매개변수를 입력 받아 int 를 반환하는 메서드
{
    return x + y;
}


Func<int, int, int> addFunc = Add; // Func를 이용한 메서드 호출
int result = addFunc(3, 5);
Console.WriteLine("결과: " + result);

Action

값을 반환하지 않는 메서드를 나타내는 델리게이트.
매개변수를 받아들이지만, 반환 타입은 없다.

Ex : Action<int,int> => int 매개변수 2개를 입력 받고, 아무런 값을 반환하지 않는 메서드


예시

void PrintMessage(string message) // string 매개변수를 입력 받아 아무런 값을 반환하지 않는 메서드
{
    Console.WriteLine(message);
}

Action<string> printAction = PrintMessage; // Action을 이용한 메서드 호출
printAction("Hello, World!");

프로젝트에 사용되는 Action 코드

캐릭터의 움직임을 키보드 W/A/S/D 로 입력받아 움직이는 Input System 을 사용하였다.

키보드 입력을 받을 때는 Vector2 를 매개변수로 입력받는 Action OnMovEvent.
마우스 위치의 이동으로 Vector2 를 매개변수로 입력받는 Action OnLookEvent

를 통해 코드를 작성하였지만, 그 동작 과정이 궁금해서 TIL 주제로 작성하게 되었다.

  1. Controlloer.cs
public class Controller : MonoBehaviour
{
    public event Action<Vector2> OnMoveEvent; // Vector2 를 매개변수로 받는 Action
    public event Action<Vector2> OnLookEvent;


    public void CallMoveEvent(Vector2 direction) // 이벤트 호출
    {
        OnMoveEvent?.Invoke(direction);
    }

    public void CallLookEvent(Vector2 direction) // 이벤트 호출
    {
        OnLookEvent?.Invoke(direction);
    }
}

  1. Movement.cs
public class Movement : MonoBehaviour
{
    private Controller movementController;
    private Rigidbody2D movementRigidbody;

    public float speed = 5f;
    private Vector2 movementDirection = Vector2.zero;

    private void Awake()
    {
        movementController = GetComponent<Controller>();
        movementRigidbody = GetComponent<Rigidbody2D>();
    }

    private void Start()
    {
        movementController.OnMoveEvent += Move; // Move 메서드를 OnMoveEvent 에 추가
    }

    private void FixedUpdate()
    {
        ApplyMovement(movementDirection);
    }

    private void Move(Vector2 direction)
    {
        movementDirection = direction;
    }

    private void ApplyMovement(Vector2 direction)
    {
        direction = direction * speed;

        movementRigidbody.velocity = direction;
    }
}

TIL 마무리

수준별 꾸준 실습이 시작되었는데, Action 과 Input System 을 원하는 대로 구현할 수 있어야만
실습을 진행할 수 있어 시작하기가 매우 어려웠다.

TIL 을 통해 Action 과 Input System 의 동작 과정에 대해 다시 생각해보는 시간을 가질 수 있었고, 더 연습해가며 내 지식으로 만들어가야겠다

profile
안녕하세요 게임 개발하는 MINO 입니다.

0개의 댓글