Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 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 /
avatar image
5
Question by furic · Aug 29, 2013 at 03:14 AM · gameobjectvariablestartaddcomponentawake

AddComponent passing variable before Start/Awake

How can we AddComponent() to a gameObject and passing variable to it, but the component can read the variable in Start() / Awake()? It seems Start / Awake already ran in AddComponent line... I just want it check once so it seems not optimised having it checked in Update()

 MyClass mc = AddComponent("MyClass") as MyClass; 
 mc.myVar = 1;

In MyClass.cs:

 public class MyClass : MonoBehaviour
 {
   public int myVar = 0;
   void Start ()
   {
     if (myVar == 1)
     {
       // Do something
     }
   }
 }

p.s. I tried Add component in one line with parameters, but it seems do nothing to Start() / Awake();

Comment
Add comment · Show 6
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 perchik · Aug 29, 2013 at 03:46 AM 0
Share

Can I ask what you're trying to accomplish? Generally if you need the script to start with the component on it, you need to assign it in the editor.

If you are trying to make sure that some gameobject actually has a component, then look at RequireComponent

I think you'll also end up in some kind of weird infinite loop when you try to add a component [to a GameObject] that already has that script on it.

avatar image furic · Aug 29, 2013 at 06:09 AM 0
Share

thx for ur reply.

basically im trying to dynamically read a list of inventory items and add it's corresponding skill (eg. HPRegen, CallTank extending Skill class) class to a button, and pass some variable into it (eg. damage, cooldown etc)....

that's why I want the skill is set up in Starts(), of course I can put a bool in update to make the initialise run only once... but just curious about a better way

avatar image bubzy · Aug 29, 2013 at 07:16 AM 0
Share

I think you can call start() at any time,

avatar image furic · Aug 29, 2013 at 07:27 AM 1
Share

damn... you are right... just call Start() after passing the variable, or simply make a manual function like Initialze().... how easy....

avatar image Deepscorn · Nov 17, 2015 at 11:06 AM 1
Share

$$anonymous$$essing things with lifecycle may have ugly circumstances in future. So, I wouldn't even try to do such thing. Why don't create another component with data (call it $$anonymous$$yData or something), add it and then add component $$anonymous$$yClass, which will rely on it (via GetComponent())? Code organization becomes simple when you first think of what you are trying to accomplish and what Unity means you have

Show more comments

5 Replies

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

Answer by Dani Phye · Nov 21, 2014 at 11:22 PM

This answer is a little late, but I was using NonGamingCoder's solution and I ran into a problem when I needed a component to create another component in Awake, but that third object initialization required the values I initialized in the second object during awake. So basically I needed something "before awake." I found a sorta hacky solution that seems to work pretty well though - and it is a general enough pattern it can be adapted to lots of different things once you get the hang of it.

Imagine we start with a GameManager object, and on GameManager's Awake we want to make a Player, which then makes a FishingPole - yet we want the player and the fishing pole to both have a reference to the GameManager at the beginning of their awakes. Then the code would be:

 public class GameManager : MonoBehaviour
 {
     public Player player;
     public Awake()
     {
         GameObject playerObject = new GameObject();
         player = Player.AddPlayerComponent(playerObject, this);
         player.gameObject.name = "Player";
     }
 }

 public class Player : MonoBehaviour
 {
     public GameManager gameManager;
     public FishingPole fishingPole;

     public static Player AddPlayerComponent(GameObject objectAddingPlayerTo, GameManager gameManager)
     {
         objectAddingPlayerTo.SetActive(false);

         Player player = objectAddingPlayerTo.AddComponent<Player>() as Player;

         // Variable initialization goes here - 
         // All of this will be called before Player's awake because
         // the object holding the Player component is currently not active.
         player.gameManager = gameManager;

         objectAddingPlayerTo.SetActive(true);

         return player;
     }

     public Awake()
     {
         GameObject fishingPoleObject = new GameObject();

         // We can use the gameManager variable here because it will already be initialized
         // since akwake isn't called until sometime after we called
         // objectPlayerAddingTo.SetActive(true);
         fishingPole = FishingPole.AddFishingPoleComponenet(fishingPoleObject, this, gameManager);
         fishingPole.gameObject.name = "Fishing Pole";
     }
 }

 public class FishingPole: MonoBehaviour
 {
     Player player;
     GameManager gameManager;

     public static FishingPole AddFishingPoleComponent(GameObject objectAddingFishingPoleTo, Player player, GameManager gameManager)
     {
         objectAddingFishingPoleTo.SetActive(false);

         FishingPole fishingPole = objectAddingFishingPoleTo.AddComponent<FishingPole>() as FishingPole;
         fishingPole.player = player;
         fishingPole.gameManager = gameManager;

         objectAddingFishingPoleTo.SetActive(true);

         return fishingPole;
     }
     public Awake()
     {
         // This will begin with player and gameManager already pointing to the other objects
     }
 }




Comment
Add comment · Show 7 · 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 adrenak · Apr 16, 2016 at 11:48 AM 0
Share

This is excellent! Considering that many developers have a practice of extending $$anonymous$$onoBehaviour into a class of their own, this can be added as an extended feature and made to look less hack-ish ;)

avatar image matovski · May 17, 2016 at 10:27 PM 0
Share

Amazing answer. Tackles perfectly the problem in a way that can be used in other contexts. Solved one of my problems with some adapting and changing :)

avatar image Bunny83 · May 18, 2016 at 01:00 AM 0
Share

I would suggest an extension method like this:

 public static class GameObjectExtension
 {
     public static T AddComponentWithInit<T>(this GameObject obj, System.Action<T> onInit) where T : Component
     {
         bool oldState = obj.activeSelf;
         obj.SetActive(false);
         T comp = obj.AddComponent<T>();
         if (onInit != null)
             onInit(comp);
         obj.SetActive(oldState);
     }
 }

With this extension method somewhere in your project you can do this:

 GameObject someObject;
 
 someObject.AddComponentWithInit<FishingPole >(f=>{f.player = player; f.game$$anonymous$$anager = game$$anonymous$$anager});

This allows you to specify a custom callback which is executed before Awake. Inside that callback you get the reference to the newly added component. It also doesn't force the gameobject to be active at the end but restores the state it had when the method was called. So if the GameObject was already deactivated it stays deactivated.

Another approach would be to use a temp class with IDisposable to allow a neat disable block in case you want to add multiple components:

 public class GameObjectDeactivateSection : IDisposable
 {
     GameObject go;
     bool oldState;
     public GameObjectDeactivateSection(GameObject aGo)
     {
         go = aGo;
         oldState = go.activeSelf;
         go.SetActive(false);
     }
     public void Dispose()
     {
         go.SetActive(oldState);
     }
 }
 
 public static class GameObjectExtension
 {
     public static IDisposable Deactivate(this GameObject obj)
     {
         return new GameObjectDeactivateSection(obj);
     }
 }


With those two classes you can simply do:

 GameObject someObject;
 
 using(someObject.Deactivate())
 {
     FishingPole pole = someObject.AddComponent<FishingPole>();
     pole.player = player;
     pole.game$$anonymous$$anager = game$$anonymous$$anager;
 }

The gameobject will be deactivated inside the using section. As soon as the section is left the old state of the gameobject will be restored.

avatar image BAIZOR Bunny83 · Jan 22, 2017 at 12:14 AM 0
Share

Great classes, easy to use. I just want to update it little bit. Add this to GameObjectExtension:

         public static T AddComponent<T>(this GameObject gameObject, Action<T> action) where T : Component
         {
             using (gameObject.Deactivate())
             {
                 T component = gameObject.AddComponent<T>();
                 if (action != null) action(component);
                 return component;
             }
         }

avatar image BAIZOR Bunny83 · Jan 22, 2017 at 12:19 AM 0
Share

And now, you can do just this:

 gameObject.AddComponent<AudioSource>(x => x.pitch = 0.1f);
avatar image andyborrell · Jan 17, 2018 at 11:17 AM 0
Share

A problem with disabling and enabling a GameObject is that it kills any Coroutines that were running on the object.

avatar image menderbug andyborrell · Jun 19, 2018 at 11:03 AM 0
Share

It also invokes OnDisable and OnEnable on all components in the game object's hierarchy, which might have side effects.

avatar image
10

Answer by petrucio · Oct 26, 2017 at 06:39 AM

Credit to Dani Phye for the starting solution, but it's a giant wall of code that can be stripped down to the part the concerns people looking for the answer:

 this.gameObject.SetActive(false);
 
 var mc = this.AddComponent<MyClass>; 
 mc.myVar = 1;
 
 // Awake of MyClass will only get called when the object is re-enabled below. Voila!
 this.gameObject.SetActive(true);

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 musickgm · Feb 12, 2018 at 04:56 PM 0
Share

Yes! Anyone still looking here, give this solution a try!

avatar image menderbug · Jun 19, 2018 at 10:59 AM 1
Share

The caveat with this approach is that this will call OnDisable and OnEnable on every component in gameObject's hierarchy, and it will also kill all coroutines running on those components.

avatar image jj_unity328 · Jul 26, 2018 at 01:45 PM 0
Share

hacky but ok! Hopefully your Behaviours don't call anything you don't want upon being enabled/disabled.

avatar image
1

Answer by NonGamingCoder · Aug 29, 2013 at 08:25 AM

Dude,

I've been hitting this kind of thing recently. It's not the nicest solution, as in it's quite ugly, but here it goes:

  1. Create objects during Awake()

  2. Initialize during Start()

Eg.

 public class MyClass : MonoBehaviour
 {
     public int myVar = 0;

     public void Awake()
     {
        // We want to see what order things are getting called...
        Debug.Log(string.Format("{1}@{0} Awake", name, GetType().Name));
     }
 
     public void Start()
     {
         Debug.Log(string.Format("{1}@{0} Start", name, GetType().Name));

         if (myVar == 1)
         {
             // Do something
         }
     }
 }

 public class MyClassHost : MonoBehaviour
 {
     private MyClass _mc;
 
     public void Awake()
     {
        Debug.Log(string.Format("{1}@{0} Awake", name, GetType().Name));
        _mc = AddComponent<MyClass>();
     }
 
     public void Start()
     {
        Debug.Log(string.Format("{1}@{0} Start", name, GetType().Name));

         // By the time we get to here, MyClass.Awake will have been called.
         _mc.myVar = 1;
     }
 }

Like I said, it's not the nicest solution, you would normally want to do this all in one go, and if it wasn't unity, you'd do this in the constructor.

Also, Unity is going to call Start(), so don't do it yourself. Utilise Unity's lifecycle and let Unity do it's magic. Run this code as-is, and watch the console. You'll see Start() gets called, but maybe not in the order you were expecting.

Disclaimer: No warranty is provided.

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
1

Answer by DawidNorasDev · Jun 19, 2018 at 11:35 AM

Why do you only let script initialization happen in Start / Awake ? Make public method Init(), and call it after you have set everything you wanted. Or even call it with those parameters

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
0

Answer by K0m1x · Nov 15, 2021 at 09:51 AM

Turns out the way you do it is simple... Set the object to inactive before you addcomponent, and the awake function will only play when you set it to active again.

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

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

32 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

Related Questions

How to reference GameObject in Awake or Start 2 Answers

If a script is attached to more than one gameObject, will Start() & Awake() run more than once? 2 Answers

How would I be able to subtract from a variable when it hits something? (OnCollisionEnter) 1 Answer

Photon Instantiate a prefab and add script on it. 1 Answer

Problems with the triggers(not recognized) 1 Answer


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