Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • 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
1
Question by jamesflowerdew · Mar 01, 2016 at 12:01 PM · c#updateoptimisation

An update that behaves like a singleton in a monobehavior

I'm constantly coming up with scenarios where I need to collect complex data once per frame which many instances then go on to use.

I tend to:

1) use update to grab this data with a boolean to determine whether it has already been done, which is then reset on the lateupdate - this costs the extra function call, which may not have huge impact on the actual performance, but does make things messy.

or

2) have a class that I know will have only instance, such as the main character class do it for them, this creates interdependancy which is a pain if you want to grab assets from one game to another, or indeed follow the code six months later.

Is there a way of setting a function within an instantiatable monobehavior which knows that it is done once, and once alone per frame? like this.....

 public class SomethingReallyProlificLikeBeesGrassOrParticles:MonoBehavior{
   static void UpdateOnce(){
     //do something really hairy that you'd be mad to do any more than once per frame if any instance is there
     }
     
     void Update(){
     //do the simple stuff as many times as I have instantiated this class (think in terms of thousands)
     }
 
 }

Comment
Add comment
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

2 Replies

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by Bunny83 · Mar 01, 2016 at 01:46 PM

It's not possible without an extra class. All callbacks from Unity are directed to an instance. Unity doesn't call static methods of classes. So if your "Grass" class should manage itself you would have to pick one of them to do the management stuff as well. While this is possible, it's a horrible approach. A manager should always be seperate from the things it manages.

If Unity would have implemented something like EditorApplication.update for the runtime it would be possible without an extra class. In the editor you could do:

 public class Grass : ScriptableObject
 {
     static List<Grass> m_List = new List<Grass>();
     static bool m_Initialized = false;
     static void Initialize()
     {
         if (!m_Initialized)
         {
             EditorApplication.update += OnUpdate;
             m_Initialized = true;
         }
     }
     static OnUpdate()
     {
         // do something
     }
     // other instance stuff here
     void OnEnable()
     {
         Initialize();
         m_List.Add(this); // add itself to the list.
     }
 }

Unity doesn't have a static update delegate to which you can subscribe at runtime. However you could use a seperate helper class like my CoroutineHelper to achieve the same thing. Instead of the m_Initialited boolean you could simply store the "Run" instance to know it's already running:

 public class Grass : ScriptableObject
 {
     static List<Grass> m_List = new List<Grass>();
     static Run m_UpdateJob = null;
     static void Initialize()
     {
         if (m_UpdateJob == null)
             m_UpdateJob = Run.EachFrame(OnUpdate);
     }
     // [ ... ]
 }


This will ensure that OnUpdate is called once every frame as soon as the first "Grass" instance has been created. This does also work at runtime. The CoroutineHelper class is a selfmanaged singleton. It automatically creates an instance if one is needed. All coroutines which are started by the static methods the Run class provides will run on that singleton instance.

Unity is completely event driven. You don't have control of the programs main loop. That's part of the engines core. So you can't have your code execute somehow every frame without having an instance which receives an event from the engine.

Another approach for a selfmanaging class would be this:

 public class Grass : MonoBehaviour
 {
     int m_LastFrame = -1;
     void Update()
     {
         if (Time.frameCount > m_LastFrame)
         {
             m_LastFrame = Time.frameCount;
             // do something that should only happens once per frame here
         }
         // other update things should be done here.
         // this part is executed for every instance of "Grass".
     }
 }

While this is possible, it adds a bit overhead to each Grass instance. If your class actually doesn't need an Update itself it's just wasted performance to have an Update method in every instance.

With this approach the first Grass instance which get his Update called will do the "extra work". Once it's done it updates the int variable so all other instances will ignore that part until the next frame.

Comment
Add comment · 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
2

Answer by phil_me_up · Mar 01, 2016 at 12:24 PM

I'd probably have a manager class (call it GrassManager for example), which has a list of all the actual blades of grass.

On each update within GrassManager, do what you need to do and then call an update routine on each blade of grass by iterating through your list of active grass blades. Make sure you create your own update routine (public void UpdateGrass()) within the GrassBlade class as you'll have more control over when it is called, as well as it being faster than using the Unity Update() method, which relies on Reflection.

When actually processing the UpdateGrass function, you can either pass in the parameters you need or just reference the GrassManager. There are a couple of ways to do this. You could either setup the GrassManager as a singleton or for each blade of grass you can store a reference to the GrassManager either as your setting up, or pass it during the update function.

The Singleton method is probably the one I would use, and the basis would be something like the below (note this is just written of the top of my head, expect syntax errors etc!)

 class GrassManager : Monobehaviour
 {
 private static GrassManager instance = null;
 private List<GrassBlade> GrassBlades;
 
 public static GrassManager GetInstance()
 {
 return instance;
 }
 
 void Awake()
 {
 if(instance == null)
 {
 instance = this;
 DontDestroyOnLoad(this.gameObject);
 }
 }
 }

Elsewhere within your game, you can now access the GrassManager with GrassManager.GetInstance()

Comment
Add comment · Show 3 · 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 jamesflowerdew · Mar 01, 2016 at 12:52 PM 0
Share

$$anonymous$$any thanks, but that's what I do already. I'm hoping someone knows how get the grass script (although I'm not actually thinking grass here) to manage itself on a once per frame basis, without needing a babysitting class. I'd thought Invoke() at the start, but am not sure whether you could detect that this has happened, and thus know to do it only once. Another thought was patching your calcs onto another function, (Perhaps naughtily an internal one) with UnityEngine.That'sthefunctionIwasLookingFor+=mycheekyBahaviour();, but I'm too new to patching functions like this right now ;).

avatar image phil_me_up jamesflowerdew · Mar 01, 2016 at 01:43 PM 1
Share

Hmmm, I'm a little confused by what you're trying to do..

Update will occur once per frame. Calling that in a manager class will allow you yo update the grass manager once per frame. Calling an update on each blade from this update will then update each blade of grass, once per frame. All the common data can be calculated before calling update on each blade of grass, and then each blade of grass can access this data through the singleton pattern.

If you are dealing with loads of objects then you really want to keep things as simple as possible. Having delegates, actions, listeners etc are perfectly appropriate in some cases, but overkill in others. Obviously I don't completely know what your trying to achieve, but having the manager class as I described above is probably the best solution in most cases. Each blade can access the manager class without needing to pass around references / copy data etc making it more efficient than passing parameters in functions or storing copies / references in each blade.

This situation isn't really babysitting. In fact it's almost less like babysitting than just having them all as separate game objects. By having a manager you have a greater understanding of the objects in your game, greater control over the update / initialisation routines etc and less reliance upon Reflection, which is slow.

Sorry if that's no help!

avatar image jamesflowerdew phil_me_up · Mar 02, 2016 at 12:55 AM 0
Share

Hi phil, wanted to explain ,I upvoted your answer but didn't choose it because whilst it works and I know it works, it's not what I was looking for.

A single call to any class (not instance) per frame would be so handy, and negate the need for manager classes in many cases. Ironically, According to @Bunny83 the answer is not really so I'll likely remain doing things as described. 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.

Follow this Question

Answers Answers and Comments

110 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Need help with Async 0 Answers

why OnTriggerEnter is not work if with void Update 2 Answers

FixedUpdate and Update not working in script 0 Answers

How do you execute code every X angles reliably? 2 Answers

My Unity.exe deleted (Unity 2019.3.11),My Unity.exe was deleted (Unity 2019.3.11) 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