- Home /
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.
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);
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.
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.
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.
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.
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.
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.
Are you able to use this method in a factory like class? I think you may have solved my problem =-)
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 >();
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.
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:
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.
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).
Your answer
![](https://koobas.hobune.stream/wayback/20220613195333im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
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
Is it costly to get a singleton instance each frame ? 1 Answer