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
2
Question by Clintmcc · May 12, 2015 at 07:10 AM · instanceaddcomponentargumentsconstructors

Passing arguments into a constructor via AddComponent

Hi there,

I am currently learning c# and a little stuck. I am trying to call an instance of a class and pass some values into a constructor. I was able to achieve this using the usual method of:

SomeClass myclass = New SomeClass(value1,value2)

However I ran into the problem of not being able to use the keyword New in Unity. After some research it looks like there are 2 solutions to that problem. I can remove Monobehavior(which i don't want to do) or I can use AddComponent. AddComponent is the way I want to go but I am unsure how to pass it my values. My code is below and as you can see from the comments I have tried a few things. Any advice?

 if(hit.collider.tag == "Object"){
         Debug.DrawRay(myRay.origin, myRay.direction * hit.distance, Color.red);
         //InteractObject o = ScriptableObject.CreateInstance("InteractObject") as InteractObject;
     
         //InteractObject instancedClass = gameObject.AddComponent<InteractObject>(true,hit.collider.gameObject.name);
     
         //GameObject obj = hit.collider.gameObject;
         //InteractObject script = obj.AddComponent<InteractObject>();
     
         InteractObject o = new InteractObject(true,hit.collider.gameObject.name);

And the InteractObject class:

 public class InteractObject : MonoBehaviour {
 
     private bool rayHit;
     private string objectName;
 
     public InteractObject (bool rayHit, string objectName)
     {
         this.rayHit = rayHit;
         this.objectName = objectName;
         Debug.Log (objectName);
     }

 

Thanks in advance.

Comment
Add comment · 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 AlwaysSunny · May 11, 2015 at 09:38 PM 2
Share

I'm not certain this is even possible. $$anonymous$$ethinks monobehaviors can't utilize your constructors. A separate Initialize method is the appropriate way to pass arguments to a new script instance.

 $$anonymous$$yScript myInstance = obj.AddComponent<$$anonymous$$yScript>();   // when adding
 $$anonymous$$yScript myInstance = obj.GetComponent<$$anonymous$$yScript>() as $$anonymous$$yScript;  // when getting    
 myInstance.Initialize(arguments);
avatar image fafase · May 13, 2015 at 09:55 AM 0
Share

The comment above should be the way to go.

5 Replies

· Add your reply
  • Sort: 
avatar image
2

Answer by Wuzseen · May 12, 2015 at 07:31 AM

If you want constructor like behavior that returns an instance of a Component (that derives MonoBehavior) on a NEW game object here's what you'll need to do:

 public class Foo : MonoBehavior {    
    public static Foo MakeFooObject() {
       GameObject go = new GameObject("FooInstance");
       Foo ret = go.AddComponent<Foo>();
       // do constructory type stuff here, you can add parameters if you want but you're manipulating the instance of Foo from the line above.
    return ret;
    } 
 }

So the key piece of ingenuity here is making a static method that creates a new gameobject and adds this component to it.

I didn't check the code for compilation so small disclaimer copying that might work.

However this isn't really your question.

AddComponent returns a reference of the component you added. MonoBehaviors cannot have constructors (this is a low level thing). But you can always have SetUp methods on monobehaviors that are like constructors. The static method I suggested is when you want to make a new game object and treat a monobehavior kind of like you would a normal C# object. You could extend this to accept a GameObject parameter and isntead of making a new gameobject, it adds the component to the given gameobject then calls the SetUp method of the component which is basically just a constructor.

Comment
Add comment · Show 4 · 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 Clintmcc · May 12, 2015 at 11:13 AM 0
Share

Thanks for your response Wuz.

It's clear to me that I need to study a little more as your answer confused me somewhat.This did however lead me down a new path of research and I have working code. I am unsure however with the way I've written it is correct or if it will cause me problems down the track. Here is what it looks like now:

 public class InteractObject : $$anonymous$$onoBehaviour {
 
     private bool _rayHit;
     private string _objectName;
 
     public static InteractObject Instance;
 
     void Awake(){
         Instance = this;
     }
 
     public static InteractObject hitting (bool rayHit, string objectName)
     {
         
         Instance._rayHit = rayHit;
         Instance._objectName = objectName;
         Debug.Log (objectName);
         return Instance; 
     }


Passing it values like this:

 if (Physics.Raycast (myRay, out hit, closeRayDistance)) {
 
     if(hit.collider.tag == "Object"){
         
         InteractObject.hitting(true, hit.collider.gameObject.name);
 }
 }

Does this look okay to you? In the mean time I think i need to hit the books.

Edit: A little context. I am creating a script for every already existing gameobjects in my world I want to interact with. Basically I am trying to identify if that gameobject is being hit so I can run whatever specific code I like for that gameobject. Like have the object highlight, display it's name on screen etc. This is maybe my 4th time coding this as the first time I used On$$anonymous$$ouseOver (which was super clunky) and other times I was doing silly things with public static variables all over the place. Just looking for an efficient and "correct" way to achieve this.

avatar image Clintmcc · May 13, 2015 at 09:50 AM 0
Share

I have decided to simplify this to better suit my needs and just reference the class and pass values to a public method. I really appreciate the assistance and taking the time to help out.

Thanks.

avatar image fafase · May 13, 2015 at 10:02 AM 1
Share

I see some problem with this approach, first off there is no parameters which was the point of the constructor from the OP. Second it should not create a new game object as this is then useless if you want to add the component to an existing object.

I think the Init method with parameters is the way better.

avatar image Clintmcc · May 13, 2015 at 10:29 AM 0
Share

You may be correct. I'm pretty much running with the fact that most know more about program$$anonymous$$g than I do. I will however post my new code here out of interest sake. I can still pass parameters through:

$$anonymous$$ethod:

 public void RayHit(bool rayHit, string objectName){
     string thisObject = gameObject.name;
     _rayHit = rayHit;
     _objectName = objectName;

 }

Pass Values:

 if (Physics.Raycast (myRay, out hit, closeRayDistance)) {
 
     if(hit.collider.tag == "Object"){
         Debug.DrawRay(myRay.origin, myRay.direction * hit.distance, Color.red);
         objectBeingHit = hit.collider.gameObject.name;
         InteractObject script = GameObject.Find (objectBeingHit).GetComponent<InteractObject> ();
         script.RayHit(true, hit.collider.gameObject.name);
     }
 }

It seems simple but I am getting the result I need while keeping my variables private.

avatar image
2

Answer by derekmblue4011 · May 13, 2018 at 02:24 AM

I know this is an old question but don't believe Wuzseen's answer addresses the OP's issue directly. If I'm not mistaken OP is looking to instantiate their class the way any programmer would expect their class to but Unity's methods for adding GameObject components does not incorporate class constructors. Something I've done that works, which unfortunately makes no use of the class constructor, is instead of making a class constructor use a void method the same way you would your constructor and call it directly after adding to your GameObject. For example:

 test = this.gameObject.AddComponent(typeof(InteractObject)) as InteractObject;
 test.InteractObjectConstructor(true, "String");

where your class would then contain:

 public class InteractObject : MonoBehaviour
 {
     private bool rayHit;
     private string objectName;
 
     public void InteractObjectConstructor (bool rayHit, string objectName)
     {
         this.rayHit = rayHit;
         this.objectName = objectName;
         Debug.Log (objectName);
     }
 ...
 }

the down side to this method is your class constructor is not called automatically.

Comment
Add comment · Show 1 · 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 horoxix · Nov 23, 2018 at 04:35 AM 0
Share

Are you able to use this method in a factory like class? I think you may have solved my problem =-)

avatar image
-1

Answer by ShawnFeatherly · Feb 27, 2020 at 12:34 AM

If you need the parameter accessible in Awake() or Start() you'll have to pass in the value before AddComponent() is called. One (hacky) way to do this is passing the parameter through a static field of the monobehaviour.

     public static string ConstructorConfig;
     public string Config;
     void Awake()
     {
         if (Config == null)
         {
             Config = ConstructorConfig;
             ConstructorConfig = null;
         }
         Debug.Log("I have some " + Config);
     }

Then set the parameter just before calling AddComponent()

     InteractObject.ConstructorConfig = "parameter goodies";
     gameObject.AddComponent<InteractObject >();
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 roman_sedition · May 26, 2021 at 04:51 AM

Tried it out mainly because I wanted to change some private properties of a monobehaviour I wanted to add as a component, but I didn't want to have any public methods accessible for that monobehaviour.

     public static void AddComponentTo(GameObject go, int _num, string _word)
     {
         VirtualMono mono = go.AddComponent<VirtualMono>();
         mono.Init(_num, _word);
         
     }
 
     private void Init(int _num, string _word)
     {
         num = _num;
         word = _word;
     }


So in terms of this example, I made a public static method AddComponentTo() which by default it is mandatory that the gameobject you want to add the component to is a parameter, all subsequent parameters relate to whatever you want to pass to the constructor method Init(). Overload both for whatever extra constructors you require.

Usage.

 VirtualMono.AddComponentTo(go, 5, "blah!");

Where 'go' is some gameobject reference.

Niche situation since you could just make the Init method public and just call it after you've added it to a gameobject. But I've got my reasons to use it so other people might have some reason to use it to.

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 sisus_co · Dec 28, 2021 at 09:34 PM

Passing arguments into a constructor via AddComponent is not supported out of the box in Unity but it is actually possible to pull it off:

  1. Create an AddComponent extension method for GameObject that accepts arguments. This method will first store the arguments in a static container, then add the component to the GameObject, and finally clear the arguments from the container.

  2. In the default (parameterless) constructor of your component fetch the provided arguments from the container and pass them to another constructor in the same class which accepts the arguments.


 public static class GameObjectExtensions
 {
     public static TComponent AddComponent<TComponent, TFirstArgument, TSecondArgument>
         (this GameObject gameObject, TFirstArgument firstArgument, TSecondArgument secondArgument)
             where T : MonoBehaviour
     {
         Arguments<TFirstArgument, TSecondArgument>.First = firstArgument;
         Arguments<TFirstArgument, TSecondArgument>.Second = secondArgument;
         
         var component = gameObject.AddComponent<TComponent>();
 
         Arguments<TFirstArgument, TSecondArgument>.First = default;
         Arguments<TFirstArgument, TSecondArgument>.Second = default;
 
         return component;
     }
 }
 
 public static class Arguments<TFirstArgument, TSecondArgument>
 {
     public static TFirstArgument First { get; internal set; }
     public static TSecondArgument Second { get; internal set; }
 }
 
 public class InteractObject : MonoBehaviour
 {
     private bool rayHit;
     private string objectName;
 
     public InteractObject(bool rayHit, string objectName)
     {
         this.rayHit = rayHit;
         this.objectName = objectName;
         Debug.Log(objectName);
     }
 
     public InteractObject() : this(Arguments<bool, string>.first, Arguments<bool, string>.second) { }
 }


Usage:


 InteractObject instancedClass = gameObject.AddComponent<InteractObject, bool, string>
                                                        (true, hit.collider.gameObject.name);


One of the coolest things about this pattern is that you can actually assign arguments into read-only fields and properties in the constructor :o

I have an asset called Init(args) that implements a pattern similar to this (but with bells and whistles).

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

9 People are following this question.

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

Related Questions

AddComponent Loop 1 Answer

Add an instance of a script as a component? 1 Answer

How to add new instance of a script to a game object? 2 Answers

Associate objects to a prefab 1 Answer

How can I link a GameObject instance to a script variable in a Prefab using the editor? 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