• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
  • Help Room /
avatar image
Question by stalyan77 · Aug 21, 2015 at 07:05 PM · managerbooleansdelegatesevent-handlingstatic-variables

How to best organize bool variables and code modularity in general?

Hi there!

I'm making my first "serious" attempt to make a game in Unity. Along the way, i'm learning how to improve my basic C# programming skills, getting to know the particular ways in which Unity behaves, etc.

I've managed to create a isKinematic movement for my player, also my own physics collision system for static colliders (checking what's below and above the player, to the sides, etc) and moving platforms (i can stay on the platform and move and even jump quite well).

It has taken my a lot of time to do this, about 4 weeks since I started working on my free time after work and weekends, but i'm happy to have kept progressing little by little by solving unforeseen challenges (for me they are =)).

So now comes the question: My player script starts getting longer and longer. There i have the movement and collision system, and it's there were i check if the raycasts have hit any other object by asking their tag (i'm not using onTrigger functions as I prefer to go for preventive physics) and how the player should act.

As you may imagine, or maybe it's my lack of expertise in programming, i have LOTS of bools for any given situation. Some examples:

  • if player is not grounded and hits something when start jumping.

  • the same for when the player is going down on his jump.

  • check if I hit a static collider with the head and if it's so do not jump the maxJumpHeigh but only a portion.

  • if it's not grounded and i hitted a moving platform while the platform is going up.

  • the same for when is going down.

  • etc, etc, etc.

When i have a bug or wrong behaviour with movement or collisions, i need to go through all these bools, and each small change it's painful as there are many bool combinations i must take into account.

  • So, is there a way to keep the bools organized, kind of a bool manager in a separate script?

  • Do you also use so many bools in your code, or i'm I doing something wrong? Is this the price one must have to pay to have a solid movement and collision system and be able to handle the most complex gameplay combinations?

  • If I create so many scripts to make things more modular, won't it be too painful and too verbose to refer to so many bools (and variables in general) in the shape of thisClassScript.thisMethod.thisVariable?

I've never used any game manager and to be honest I don't know where and how to start using it. I keep reading about the topic and also the dangers of using global static variables, (there should be only a few in the total code to follow encapsulation or proper OOP methodology they say)... i've never used delegates or virtual functions either yet (maybe I'm having the need but I haven't realize it yet!)... i'm wondering if things are getting more complicated because I actually yet don't understand fully how OOP works and all the possible solutions C# offers.

Any advice for the bools organization, links you think can clear out my existencial doubts (some of those are too complex for beginners) will be more than welcome. =)

Comment
cjdev
rhenevers

People who like this

2 Show 2
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Owen-Reynolds · Aug 22, 2015 at 03:29 PM 0
Share

I've moved this to the new Help Room section of UA.

Main UA is best for single, non-opinion Q's about Unity-specific features (see the FAQ.) The Forum is more for discussion/opinion Qs (which this really is.) But the Help Room area is only a day old, so we're not sure how people will use it.

avatar image rhenevers · May 30, 2020 at 07:05 PM 0
Share

I know this thread is pretty old, but this was exactly what I needed to read. I have the same problems with a gang of bools sitting around and everyone's answer was super informative and helpful. State Machines, Event Systems, Delegates, and decoupling.

It's amazing these concepts aren't discuss more in Unity tutorials. Instead everyone asks and teaches how to make complicated stuff before focusing on these core fundamental skills.

Thanks again everyone! <3 <3 @stalyan77 @cjdev @VesuvianPrime @FortisVenaliter

4 Replies

· Add your reply
  • Sort: 
avatar image
Best Answer

Answer by cjdev · Aug 21, 2015 at 08:11 PM

You're definitely on the right track with your follow up research. You've found that bools are good for local logic but get unwieldy when used for the interaction of more than a few objects. Static game manager classes are typically discouraged but can actually be perfectly viable in smaller games. If you are just making a small prototype to test your programming knowledge and to develop your skills you might actually want to start there, if only to learn more about static classes and how they work. Ultimately though, for a larger project you want something that allows your various objects to communicate in a decoupled fashion. In other words, in a way that allows you to change or delete the objects without disrupting the state of all the other objects in your game.

A common way of doing this is an event manager. Unity has a very good tutorial on the basics here. The principle of the system is that you have an intermediate static class that stores events, essentially collections of functions that are run when the event is called. In this way any number of objects can register functions for an event that a specific object (or objects) then calls, making it as though that object were calling all those functions itself. The power of the system is that if you should change the object to no longer call the event, say to have another object call it, or to remove one of the functions being called, only one object needs to be edited. This 'decoupling' prevents the huge amount of clutter that the bool and static class system present and offers a level of flexibility that is very helpful in the development process.

There is another advantage of more advanced event handler examples which is that they can take parameters for the functions in the event from the object that is calling the event. This can be very useful for passing information between scripts without having those scripts needing to know about each other. You can find many different event managers online but here is a basic example of one that takes 0-2 parameters:

 using UnityEngine;
 using System;
 using System.Collections;
 using System.Collections.Generic;
 
 public static class EventManager {
 
     public enum EVNT { MyEvent1, MyEvent2, MyEvent3 };
     private static Dictionary<EVNT, Delegate> eventTable = new Dictionary<EVNT, Delegate>();
 
 
     public static void AddHandler(EVNT evnt, Action action)
     {
         if (!eventTable.ContainsKey(evnt)) eventTable[evnt] = action;
         else eventTable[evnt] = (Action)eventTable[evnt] + action;
     }
 
     public static void AddHandler<T>(EVNT evnt, Action<T> action)
     {
         if (!eventTable.ContainsKey(evnt)) eventTable[evnt] = action;
         else eventTable[evnt] = (Action<T>)eventTable[evnt] + action;
     }
 
     public static void AddHandler<T, U>(EVNT evnt, Action<T, U> action)
     {
         if (!eventTable.ContainsKey(evnt)) eventTable[evnt] = action;
         else eventTable[evnt] = (Action<T, U>)eventTable[evnt] + action;
     }
 
     public static void Broadcast(EVNT evnt)
     {
         Delegate d;
         if (eventTable.TryGetValue(evnt, out d))
         {
             Action action = d as Action;
             if (action != null) action();
         }
     }
 
     public static void Broadcast<T>(EVNT evnt, T param)
     {
         Delegate d;
         if (eventTable.TryGetValue(evnt, out d))
         {
             Action<T> action = d as Action<T>;
             if (action != null) action(param);
         }
     }
 
     public static void Broadcast<T, U>(EVNT evnt, T param, U param2)
     {
         Delegate d;
         if (eventTable.TryGetValue(evnt, out d))
         {
             Action<T, U> action = d as Action<T, U>;
             if (action != null) action(param, param2);
         }
     }
 }

It is very straightforward to use. Create an event in the EVNT enum then use EventManager.AddHandler(EventManager.EVNT.MyEvent, MyFunction); to register a function named MyFunction to be run when MyEvent is called. Finally use EventManager.Broadcast(EventManager.EVNT.MyEvent); to call the event. If you have a function with an int parameter it would be EventManager.AddHandler<int>(EventManager.EVNT.MyEvent, MyFunction); and EventManager.Broadcast<int>(EventManager.EVNT.MyEvent, 42);

I know that can look a bit intimidating for someone new to C# but it's not too bad when it's broken down. The events are defined in the enum EVNT { MyEvent1, MyEvent2, MyEvent3 }; which is basically just a universal label all the objects can use. The event table static Dictionary<EVNT, Delegate> eventTable is what stores the delegates (a variable that holds a function or functions) that get run when the event is called. The AddHandler function AddHandler<T>(EVNT evnt, Action<T> action) takes any type (represented by T here) and has parameters of an EVNT enum and an Action (a type of delegate) with a parameter of type T. This function just sets the delegate as that EVNT's eventTable delegate or adds to it. Finally in Broadcast<T>(EVNT evnt, T param) the EVNT is looked for in the eventTable and if it's there the delegate is run with the parameter T.

Comment
Positive7
stalyan77
rhenevers

People who like this

3 Show 0 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image

Answer by VesuvianPrime · Aug 21, 2015 at 08:01 PM

Hey @stalyan77

What you're talking about is a very common problem, and a popular solution is to employ a state machine:

http://gameprogrammingpatterns.com/state.html

A state machine will use polymorphism to avoid crazy conditional statements, and help you compartmentalize your logic.

Comment
Positive7
stalyan77
rhenevers

People who like this

3 Show 0 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image

Answer by FortisVenaliter · Aug 21, 2015 at 08:24 PM

I think what you need to learn next are enums. Enums are basically named int values and they are fantastic for state behaviours.

So you can do something like this:

 public enum States
 {
     InAir,
     JustLanded,
     JustJumped,
     OnGround,
 }

 public States CurrentState;

 public void Start()
 {
     CurrentState = States.OnGround;
 }

And then just change the value to the appropriate one.

Also, there are a few in there that seem superfluous. Ask yourself this: When I define a bool, will I use it in more than one function? If not, it likely does not need to be a class variable, and can just be defined in the function. You can also inline them if they're only calculated and used once per frame. For example, instead of doing this:

 private bool value;

 void function()
 {
     value = /*calculation*/;
     if(value)
     {
         ...
     }
 }

You can do this:

 if(/*calculation*/)
 {
      ...
 }

Comment
stalyan77
rhenevers

People who like this

2 Show 0 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image

Answer by stalyan77 · Aug 22, 2015 at 03:11 AM

To do justice to your kind answers I've first tried to assimilate, at least up to my partial current knowlege and understanding, all the amazing knowledge you shared here before attempting a reply.

What you're talking about is a very common problem, and a popular solution is to employ a state machine:

http://gameprogrammingpatterns.com/state.html

I knew this site but hadn't happened to read about FSMs, and as I was reading the examples of the Heroine, I felt much identified with it as it's my current struggle. Even there were some things I didn't catch fully as the examples are in C++, i grasped most of it. I was specially attracted by the last part about Concurrent, Hierachical State Machines and Pushdown Automata and I will investigate more about this topics.. Many thanks for sharing @VesubianPrime.

Ultimately though, for a larger project you want something that allows your various objects to communicate in a decoupled fashion. In other words, in a way that allows you to change or delete the objects without disrupting the state of all the other objects in your game. A common way of doing this is an event manager. Unity has a very good tutorial on the basics here.

I had once seen this video but didn't fully grasped it. I also have been stumbling a lot about this "decoupling" thing when reading articles and to be honest i didn't know what exactly was about. Now after reading about FSM and trying to understand better what the video says, I have things clearer (I guess =))

About the video, one of the interesting things is the remark and straightforward advice about using events over delegates if you have more classes that "do something".

I also think that now the term "decoupling" is much clearer to me. So by "subscribing" and "unsubscribing" functions to events, you separate the functions themselves from the "call to action" to say so, correct me if i'm wrong. I like this concept and how it can relate to what is said in the FSMs link about encapsulating all the functionality in the same class instead of setting variables in other classes... (that's what i need to achieve in my code now).

When I first read about the advanced event handle template you shared -without watching the video about events- I could barely understand anything... So I watched the video first, and one thing that called my attention was that the event delegate and event itself must be void and accept no parameters... don't know if this is a limitation of events or just the video example, i'll investigate. I went back to the code you posted and read it three times carefully, also your explanations, and I think i've grasped it a little bit better now. **Correct me if I'm wrong, this advanced event handler has the advantage over regular events in that:

  • it accepts parameters and types.

  • there's no need to unsubscribe so you reduce the danger of memory leaks and the worryness of having to explicitly unsuscribe under circunstances that you may not know until further in the development process.**

thanks @cjdev this sheds a bunch of light to my learning path ahead.

About enums, i guess you are right @FortisVenaliter, much of the problem is that i throw bools into the cookpot to solve problems along the way, then i find edge cases and I need to dismiss some bools and throw in others... so i'll take a look back into my code and see if there are bools that cannot be more encapsulated.

  1. I'll first think about enums and if it fits the needs of my game.

  2. I want to definitely try to go from theory to practice with FSMs and Events or event handlers. I'll keep investigating and when I feel more confident i'll give it a serious try.

I'm grateful guys, you've put me on the right track, I needed this feedback to keep going. =)

Comment
cjdev
rhenevers

People who like this

2 Show 5 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image cjdev · Aug 22, 2015 at 04:07 AM 1
Share

It seems like you've definitely got a handle on things and I'm sure you'll have this down in no time with the way you're approaching it. You're spot on about the events, and also what the example I gave you does indeed allow you to pass parameters into your events, something that the video doesn't. In addition, while you don't necessarily have to unsubscribe the events there are sometimes cases where you might want to do so, for example when you want an object to perform an action a finite number of times. I didn't include the code because it was already a wall of text but if you add this after the broadcasts...

    public static void RemoveHandler(EVNT evnt, Action action)
     {
         if(eventTable[evnt] != null)
             eventTable[evnt] = (Action)eventTable[evnt] - action;
         if (eventTable[evnt] == null)
             eventTable.Remove(evnt);
     }
 
     public static void RemoveHandler<T>(EVNT evnt, Action<T> action)
     {
         if (eventTable[evnt] != null)
             eventTable[evnt] = (Action<T>)eventTable[evnt] - action;
         if (eventTable[evnt] == null)
             eventTable.Remove(evnt);
     }
 
     public static void RemoveHandler<T, U>(EVNT evnt, Action<T, U> action)
     {
         if (eventTable[evnt] != null)
             eventTable[evnt] = (Action<T, U>)eventTable[evnt] - action;
         if (eventTable[evnt] == null)
             eventTable.Remove(evnt);
     }

Then you will be able to unsubscribe from events as well. Keep in mind that memory leaks are generally not a concern here as the events are essentially just a collection of delegates in a dictionary, each one like a string of methods chained together that gets called whenever you broadcast the event.

avatar image stalyan77 cjdev · Sep 19, 2015 at 09:33 PM 1
Share

Hi again @cjdev,

I know it's almost been a month since you answered my question, but as i deem the topic so important i'll take the chance to ask you further if you mind, i don't want to implement anything in my code unless i fully understand its inner workings.

These weeks i've been on a pilgrimage trying to grasp concepts i had heard of about but never stop to look at... FSMs, Funcs, Actions, Generics, boxing-unboxing...

I think now i'm in a better position to understand the basic Event Manager you put as example. I've made some tests and it works fine! but i just have some doubts about it...

 private static Dictionary<EVNT, Delegate> eventTable = new Dictionary<EVNT, Delegate>();

I was wondering: Why the dictionary Tvalue type is declared as Delegate when the type that is added in AddHandler is Action? why not declare it directly as Action? (is it because in the Broadcast method you use the "if (eventTable.TryGetValue(evnt, out d))" and isn't possible to use the out keyword with Actions?

When you do:

 public static void AddHandler<T>(EVNT evnt, Action<T> action)
     {
         if (!eventTable.ContainsKey(evnt)) eventTable[evnt] = action;
         else eventTable[evnt] = (Action<T>)eventTable[evnt] + action;
     }

I do not know what happens internally here when using the '+' operator... does the Tvalue holds 2 actions for that TKey in the Dictionary, creating kind of a List? Or is it actually that the action originally stored now holds a reference to the added action, so it's 2 actions in 1?

Why the cast (Action) in front? If i have lots of events, could this constant boxing incurr in any performance hit?

  public static void Broadcast(EVNT evnt)
     {
         Delegate d;
         if (eventTable.TryGetValue(evnt, out d))
         {
             Action action = d as Action;
             if (action != null) action();
         }
     }

When broadcasting events and passing parameters to the associated actions, are those values always passed by value? i mean, if I pass and object as parameter, does this create an exact copy of it or is it passed by reference? if it's a copy, again, could this incurr in any performance hit?

I apologize if some of my questions do not make much sense, i'm still assimilating these new concepts.

avatar image cjdev stalyan77 · Sep 20, 2015 at 03:13 AM 1
Share

The reason the Tvalue type is declared as a delegate is because Dictionaries, and collections in general in .Net, don't support generic types. This means you have to cast it to the type that can contain all the different variations of actions and then back again. Addressing the performance cost of the boxing, it probably would have an effect if you had a lot of events firing every frame. Generally events are meant for single, discrete, important moments during runtime when some logic needs to change functionality. Still, if you want to run them for something like user input you could get around the boxing performance hit by creating separate functions with the explicit types and a separate dictionary to store the actions.

Using the + operator on the Action works because all delegates are what's called multicast delegates in .Net. Basically it just means that delegates are actually not just storage for a single function but for one or more functions and when you use + or - on them you are just adding or subtracting some function from the collection that gets called when the delegate is called.

When broadcasting events you call them with the enum (which is just a labeled int) and whatever parameters you choose. These get passed by value which can be a bit confusing because that can mean either the number (like int, float, double), characters (char, string), or boolean values or it can mean the reference to an object. The key here about the objects is that the value is the reference itself which gets passed, not a copy of the object. The reference is like a pointer to the original object and any changes you make to it will affect the object because you are changing what the reference refers to: the original object. However, if you assign another object or value to the reference then the reference no longer points to the original object but to that new thing, meaning that the original object does not get modified by the assignment. If you do want the original object to get modified you can use ref in front of the parameter to ensure that all changes made to the parameter carry over to the original object or variable.

Hope this helps, have fun with the C#!

Show more comments
avatar image stalyan77 · Aug 22, 2015 at 08:46 AM 2
Share

Got it @cjdev. Now it's time to study in-depth all what you exposed here and devise how i can best implement these features in my code and what will suit me best, let see if i can manage to get all those rebellious bools, states and transitions a bit under control. Thanks again!

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

5 People are following this question.

avatar image avatar image avatar image avatar image avatar image

Related Questions

What are special YAML GameManagers for? 1 Answer

Unity package manage error 0 Answers

Hi guys, does anyone know what i need on unity 2018 in order to interact with hololens ? 0 Answers

How do I create a static bool? 1 Answer

How do I reset a trigger after moving an object out of it? 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges