1
\$\begingroup\$

I just started using events, and got stuck a little. I have a problem with the following code:

class InputHandler
{
      public delegate void Shooting();
      public static  event Shooting OnShoot;

      void Update()
      {
            if( fireButtonPressed)
                OnShoot();
      }
    // Rest of the class.
}

class Weapon
{
     void Shoot()
     {
         //Do the shooting.
     }

    void OnEnable()
   {
         InputHandler.OnShoot += shooting;
   }

   void OnDisable()
   {
         InputHandler.OnShoot -= shooting;         
   }
}

class UI
{
     void UpdateBulletsCount(int bulletsLeft, int magSize)
     {
         //Update the UI.
     }

    void OnEnable()
   {
         InputHandler.OnShoot += UpdateBulletsCount; //  clearly can't do that. 
   }

   void OnDisable()
   {
         InputHandler.OnShoot -= UpdateBulletsCount;
   }
}

My UI class has a method to update the bullet count when you fire, reload or change the weapon. As you can clearly see, it takes in different parameters. This allows me to change the UpdateBulletsCount() to accept no parameters, and find the weapons info through GetComponent or Find, in order to update UI.

However, then the UI class will depend on the Weapon class, which breaks the separation of classes and components that I am trying to achieve. Is there any way to use events without breaking class and component separation?

\$\endgroup\$
  • \$\begingroup\$ @Gnemlock That's fair enough. I voted to close because I wasn't sure how I'd reparse it into an actually clear question. \$\endgroup\$ – doppelgreener Jun 20 '17 at 10:25
  • \$\begingroup\$ @Gnemlock Thanks, I'll take mental note of your advice and that template. :) \$\endgroup\$ – doppelgreener Jun 20 '17 at 10:46
2
\$\begingroup\$

I think the problem here is your input handler class doesn't know anything about your weapon class. Therefore you can't actually transfer information from the weapon class to the UI class. If you want to make this event driven, what you really need to is create an event that signals the UI to update when the weapon properties change. Something like...

class

 InputHandler
{
    void Start()
    {
        // connecting current weapon to current UI to create the pipeline
        activeWeapon.WeaponPropertiesChangedHandler += activeUI.UpdateWeaponPropertiesDisplay;
        activeWeapon.WeaponPropertiesChangedHandler += classA.UpdateWeaponPropertiesForClassA;
        activeWeapon.WeaponPropertiesChangedHandler += classB.UpdateWeaponPropertiesForClassB;
    }

    void Update()
    {
        if (fireButtonPressed)
            OnShoot();
    }
}

class Weapon
{
    public delegate void WeaponPropertiesChanged(int bulletsLeft, int magSize);
    public event WeaponPropertiesChanged WeaponPropertiesChangedHandler;

    void Shoot()
    {
        //Do the shooting.

        // Call this anytime weapon properties change (i.e. ammo, mag size, dam)
        OnWeaponPropertiesChanged();
    }

    public void OnWeaponPropertiesChanged()
    {
        // good practice to check events are assigned so won't blow up if not
        if (WeaponPropertiesChangedHandler != null)
        {
            // Call the property changed handler which is actually calling...
            WeaponPropertiesChangedHandler(bulletsLeft, magSize);
        }
    }
}

class UI
{
    // .... this function in the UI class and... 
    void UpdateWeaponPropertiesDisplay(int bulletsLeft, int magSize)
    {
        //Update the UI.
    }
}

class SomeClassA
{
    // .... this function in class A and... 
    void UpdateWeaponPropertiesForClassA(int bulletsLeft, int magSize)
    {
        // Update class A with weapon properties
    }
}

class SomeClassB
{
    // .... this function in class B
    void UpdateWeaponPropertiesForClassB(int bulletsLeft, int magSize)
    {
        // Update class B with weapon properties
    }
}

This will now give you a pipeline from weapon to UI. So now if your weapon properties change, you just need to call the OnWeaponPropertiesChanged event and pass whatever arguments you need to update the UI.

You will also have to take care with registering your events somewhere else. For example, if you change weapons, you will need to re-register the UI events and unregister the old weapons events. Since I don't know where you store this data, I made a dummy "activeWeapon" and "activeUI" variable that you will need to adjust.

Hope this helps.

Side Note: Right now there are 2 arguments being passed, if this start becomes large and cumbersome, it is a good practice to create an WeaponPropertiesChangedEventArgs Class to pass instead of the two ints.

\$\endgroup\$
  • \$\begingroup\$ Thanks for your answer, but this is the exact same situation I am trying to avoid. I was thinking it would be really nice and clean if I had all my events in one class (InputHandler.cs) and everyother interested class can register and only one event should handle all the logically related functions. For Example: OnShoot should have subscribers from the Weapon and UI class. This is totally my own thing I feel a little uncomfortable having a event which fires just one method. \$\endgroup\$ – Daniyal Azram May 18 '17 at 21:32
  • \$\begingroup\$ So if you want everything piping through the input handler, then you probably don't need events at all because the input handler would have access to both your activeUI and activeWeapon variable. Given this, you can just have your input handler get your weapon variables and pass them into the active UI. \$\endgroup\$ – Greg Petersen May 18 '17 at 21:38
  • \$\begingroup\$ Also, if you want to keep things tidy, you can borrow an idea from WPF and just make a PropertyChangedNotifier class that weapon inherits from. Then you just connect that up to the UI as listed above and voila. Then anytime you have a data structure that should communicate with the UI just have it inherit from that and connect the event. \$\endgroup\$ – Greg Petersen May 18 '17 at 21:41
  • \$\begingroup\$ Really thanks for the tip, I don't really know WPF and haven't used or searched PropertyChangedNotifier I will definitely look into it. \$\endgroup\$ – Daniyal Azram May 18 '17 at 21:43
  • \$\begingroup\$ I was looking into the events so I don't have to care about the references of all the classes which get effected by the shooting this way InputHandler doesn't have to care if there is any UI class or Weapon class and same goes for the UI and Weapon they don't have to care about each other, everything will be independent. I can reuse my classes in other projects with little or no modifications. \$\endgroup\$ – Daniyal Azram May 18 '17 at 21:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.