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

Using delegates/events to do camera transitions

Discussion in 'Scripting' started by shakenbake444, Sep 10, 2022.

  1. shakenbake444

    shakenbake444

    Joined:
    Jul 23, 2019
    Posts:
    21
    I'm trying to learn events in order to make my code cleaner and I'm playing with delegates and events to move my camera when a player collides with a certain portion of the level. Here is some code that works. But what I notice is that you can only invoke one method from an event? I feel like this shouldn't be the case. Anyway, the intent is that based on info about the collision the publisher should call either MoveCameraUp or MoveCameraRight. But this approach requires that both functions will be called. Is it possible to call only the one i want based on some collision conditions?

    Code (CSharp):
    1. public class CameraTransitionObjScript : MonoBehaviour // attached to block
    2. {
    3.     public delegate void MoveCamera();
    4.    
    5.     public static event MoveCamera moveCamera;
    6.  
    7.     private void OnTriggerEnter2D(Collider2D col)
    8.     {
    9.         moveCamera?.Invoke();
    10.     }
    11. }
    and here is the camera. What i'm trying to also do is make only the camera control it's own movement, not have other objects control it's movements (only because I heard that's bad because it creates dependencies)

    Code (CSharp):
    1. public class MoveTransition : MonoBehaviour // attached to main camera
    2. {
    3.     void OnEnable()
    4.     {
    5.         CameraTransitionObjScript.moveCamera += MoveCameraRight;
    6.         CameraTransitionObjScript.moveCamera += MoveCameraUp;
    7.     }
    8.  
    9.     private void MoveCameraRight()
    10.     {
    11.         var currentPosition = transform.position;
    12.         transform.position += new Vector3(84f, 0f, 0f);
    13.     }
    14.  
    15.     private void MoveCameraUp()
    16.     {
    17.         var currentPosition = transform.position;
    18.         transform.position += new Vector3(0f, 45f, 0f);
    19.     }
    20. }
     
  2. uwdlg

    uwdlg

    Joined:
    Jan 16, 2017
    Posts:
    129
    You could either add a parameter to the MoveCamera delegate, then have a single MoveCamera method with the same parameter subscribe to the event in the MoveTransition class that calls one or the other movement method based on the parameter value.
    Or figure out which movement should be triggered right in the OnTriggerEnter2D callback and call one of two separate events, one for up and one for right, that each have their own listeners in MoveTransition.
    I would opt for the second option, I assume it makes more sense for the trigger object to decide which movement should be triggered and directly express that by raising a matching event. The other way seems overkill for such a simple case and would make more sense if more data was influencing the decision and/or more than the two reactions were possible.
     
    shakenbake444 likes this.
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,762
    There is nothing like a "transition" going on above... lines 12 and 18 instantly snap the camera around by a large amount.

    Camera stuff is pretty tricky... you may wish to consider using Cinemachine from the Unity Package Manager.

    There's even a dedicated forum: https://forum.unity.com/forums/cinemachine.136/

    You have many separate happening here... DO NOT combine them in your brain:

    - a trigger type of collision has happened
    - based on something (what?) you must decide to:
    --> do nothing
    --> move the camera up
    --> move the camera right
    - you have the barest beginning of a camera controller script
    --> it can be told to go right
    --> it can be told to go up
    - that script needs to be told to do these things.

    It's obvious that one delegate won't suffice, unless you make a delegate that takes an argument saying "go left" or "go right". I would NOT take that approach because then you are going to make the decision of what to do in two places!!!

    All the confusion above really is unnecessary at the scale of game you're working at. NOBODY needs events... period. In certain circumstances they provide an excellent abstraction of some type of data transfer. They don't automatically do this, and I would argue that the above situation might just as well be handled by some other mechanism.

    Specifically I would make a CameraTransitionMarker and put it only on triggers that cause transitions. This script would have everything necessary for the camera controller to do its thing, such as "look left, look right"

    Then the on trigger method would look for one of those and if it saw one, it could call a delegate and pass the CameraTransitionMarker in to the camera controller.

    The beauty of this is that ONLY triggers that need to move the camera will do.

    There is nothing for the trigger to care about.

    Stepping it up another level, by using interfaces you could make any trigger in your game do something special, and none of the intervening code would care.

    Using Interfaces in Unity3D:

    https://forum.unity.com/threads/how...rereceiver-error-message.920801/#post-6028457

    https://forum.unity.com/threads/manager-classes.965609/#post-6286820

    Check Youtube for other tutorials about interfaces and working in Unity3D. It's a pretty powerful combination.
     
    shakenbake444 likes this.
  4. shakenbake444

    shakenbake444

    Joined:
    Jul 23, 2019
    Posts:
    21
    Thanks for the response. I'm new to unity and frankly interfaces completely elude me. I need to make a class that has an unimplemented function. Then I have to implement it in the class taking action anyway. I can do this much simpler by just creating a reference to it and calling their functions.