Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Unity Actions/events/delegates confusion

Discussion in 'Scripting' started by Colossalchrist97, Jul 15, 2023.

  1. Colossalchrist97

    Colossalchrist97

    Joined:
    Feb 2, 2021
    Posts:
    1
    Hi guy, first time poster here.

    Having some trouble setting up Actions in Unity for a small project I'm working on. Would love to get some guidance as I'm a little confused.

    basic setup is:

    I click a ui button element to move the player character in a certain direction. i.e. forward, back, left, right.
    Code (CSharp):
    1.     void onMoveForwardClicked()
    2.     {
    3.         Actions.OnPlayerMoved(Directions.Forward);
    4.     }
    I have a class I've called Actions that looks like this

    Code (CSharp):
    1.    
    2. public static class Actions
    3. {
    4.     public static Action<Directions> OnPlayerMoved;
    5. }
    6.  
    My player script has a method that takes an enum parameter of directions and uses a switch statement to set the new position for a 2d array I use as my map/arena.

    Code (CSharp):
    1.     public void MovePlayer(Directions direction)
    2.     {
    3.         switch (direction)
    4.         {
    5.             case Directions.Forward:
    6.                     _NewPositionInRing.x -= 1;
    7.                     break;
    8.             case Directions.Backward:
    9.                     _NewPositionInRing.x += 1;
    10.                     break;
    11.             case Directions.Left:
    12.                     _NewPositionInRing.y -= 1;
    13.                     break;
    14.             case Directions.Right:
    15.                     _NewPositionInRing.y += 1;
    16.                     break;
    17.             default:
    18.                 break;
    19.         }
    20.     }

    My map class instantiates the 10x10 2D array and sets an initial position for the player. The map class also has a method to set the players new position and reset the old position to 0 (empty space)

    Code (CSharp):
    1.     public void setNewPlayerPositions(Vector2Int oldPos, Vector2Int newPos, int playerID)
    2.     {
    3.         Debug.Log("oldPos: X:" + oldPos.x + ", Y:" + oldPos.y);
    4.         Debug.Log("newPos: X:" + newPos.x + ", Y:" + newPos.y);
    5.  
    6.         Player1Postions = new Vector2Int(newPos.x, newPos.y);
    7.         mapArray[newPos.x, newPos.y] = playerID;
    8.         mapArray[oldPos.x, oldPos.y] = 0;
    9.     }
    I'm a little confused on how I can hook this ui button up such when clicked it updates the correct values using unity Actions.

    I may be fundamentally misunderstanding how to do this, but I am open to learning so any help is appreciated. Thanks!
     
  2. jurganson

    jurganson

    Joined:
    Jun 14, 2016
    Posts:
    5
    So I am not sure of your overall structure regarding which classes know which and such. But to me, it looks like your Actions class is a hub for things that can happen in your game. If this is the case, you could use EventHandlers instead and then have your respective observer classes be notified when a specific action is invoked, something like this:

    Code (CSharp):
    1. // Actions
    2. public static class Actions
    3. {
    4.     public static EventHandler<Directions> OnPlayerMoved;
    5. }
    6.  
    7. // onMoveForward
    8. void onMoveForwardClicked()
    9. {
    10.     Actions.OnPlayerMoved?.Invoke(this, Directions.Forward);
    11. }
    12.  
    13. // SomeClass
    14. public class SomeClass
    15. {
    16.     public void Start()
    17.     {
    18.         // Subscribing to the OnPlayerMoved event
    19.         Actions.OnPlayerMoved += (sender, direction) => { MovePlayer(direction); }
    20.  
    21.         /*
    22.             Another way to subscribe which is not through a lambda could be to define a method
    23.             with the signature public void MovePlayer(object sender, Directions direction)
    24.             and the subscribe like so:
    25.             Actions.OnPlayerMoved += MovePlayer;
    26.         */
    27.     }
    28.  
    29.     public void MovePlayer(Directions direction)
    30.     {
    31.         switch (direction)
    32.         {
    33.             case Directions.Forward:
    34.                     _NewPositionInRing.x -= 1;
    35.                     break;
    36.             case Directions.Backward:
    37.                     _NewPositionInRing.x += 1;
    38.                     break;
    39.             case Directions.Left:
    40.                     _NewPositionInRing.y -= 1;
    41.                     break;
    42.             case Directions.Right:
    43.                     _NewPositionInRing.y += 1;
    44.                     break;
    45.             default:
    46.                 break;
    47.         }
    48.     }
    49. }
     
  3. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,104
    You just need to have the Player object add its MovePlayer method to the invocation list of the Actions.OnPlayerMoved delegate during it's initialization.

    It's also important to remove the method from the list when the object is destroyed / becomes inactive, to prevent potential memory leaks (the invocation list can keep growing and growing with each instance, and prevent the garbage collector from clearing the destroyed objects from memory).
    Code (CSharp):
    1. void OnEnable() => Actions.OnPlayerMoved += MovePlayer;
    2. void OnDisable() => Actions.OnPlayerMoved -= MovePlayer;
     
    Ryiah likes this.
  4. jurganson

    jurganson

    Joined:
    Jun 14, 2016
    Posts:
    5
    Bump on the unsubscribe, thanks for pointing it out @SisusCo.
     
    SisusCo likes this.