Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 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
4
Question by bradford · Oct 26, 2013 at 06:07 PM · prefabmonobehavior

Class Constructor on Instantiated objects

I'm encountering a recurring design problem in my Unity coding, and I'd like to see if others have found a satisfactory solution. To understand the problem, let's start by comparing the traditional c# class constructor with 'Object.Instantiate':

  • C# class constructors can accept generic input parameters which can be customized by the developer.

  • Object.Instantiate, on the other hand, allows only a fixed set of input parameters. These parameters are used to define the transform for the instantiated object, we can't customize beyond that.

So, we can't pass data of our choosing to the object created by Object.Instantiate in the same way that we could pass to a class constructor. Which leads to the question, how do you pass such data?

I've been using a few patterns to pass this data. My current solution is to Object.Instantiate the object, then pass in needed data after Instantiation:

 // instantiate our prefab
 GameObject instantiatedObject = Object.Instantiate(prefabResource, Vector3.zero, Quaternion.identity) as GameObject;
 
 // get the MonoBehavior that's attached to this object 
 SomeMonoBehavior mono = instantiatedObject.GetComponent(typeof(SomeMonoBehavior)) as SomeMonoBehavior;
 
 mono.field1 = new foobar();
 mono.field2 = new foobaz();
 ...

this works, but It doesn't feel elegant, and I end up creating a lot of 'boilerplate' code to handle what would typically be handled by a class constructor.

I'm not blocked on this, but I feel like there's a better solution for this that I'm missing. Thanks!

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

4 Replies

· Add your reply
  • Sort: 
avatar image
18

Answer by Azrapse · Oct 26, 2013 at 06:43 PM

Make all your prebabs have a script with a method Initialize.

Design that method as you please, accepting as many parameters as you wish, and that runs the initializing logic you wish.

Instatiante your game objects like this:

 SpecialEnemy enemy = Object.Instantiate(enemyPrefab, Vector3.zero, Quaternion.identity).GetComponent<SpecialEnemy>();
 
 enemy.Initialize("Darth Vader", 9000, "lightsaber", true);

It would be even better if, instead of instantiating the object directly, you create instead some Factory where you specify a type, and then the Factory creates the gameobject and returns to you the particular component object you want.

Something like

 SpecialEnemy enemy1 = ObjectFactory.CreateSith("Darth Vader", 9000, "lightsaber", true);
 SpecialEnemy enemy2 = ObjectFactory.CreateStormTrooper("Stormtrooper", 30, "blaster", false);
 SpaceShip ship1 = ObjectFactory.CreateXWing("X-Wing", 350, "quad lasers", false);

The object factory could be something like this

 public class ObjectFactory : MonoBehaviour 
 {
     protected static ObjectFactory instance; // Needed

     public GameObject sithPrefab;
     public GameObject stormtrooperPrefab;
     public GameObject xwingPrefab;

     void Start()
     {
         instance = this;
     }

     public static SpecialEnemy CreateSith(string name, int health, string weapon, bool forceUser)
     {
         var enemy = Object.Instantiate(instance.sithPrefab, Vector3.zero, Quaternion.identity).GetComponent<SpecialEnemy>();
         enemy.Initialize(name, health, weapon, forceUser);
         return enemy;
     }

     [...]  // Do the same for the other kinds of prefabs.
 
 }


Attach it to some empty gameobject, and fill up the different prefab slots by dragging them in the inspector.

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 karlhulme · Oct 26, 2013 at 07:02 PM 0
Share

This is a great approach. $$anonymous$$ight help to know that in order to implement this your ObjectFactory will need access to the prefab, in Azrapse's example, sithPrefab. I can think of 3 options...

  1. pass it into the CreateSith call (requires all dependent objects to have a reference to the prefab)

  2. load it directly from resources (means Unity can't track the prefab usage)

  3. make your ObjectFactory a $$anonymous$$onoBehaviour so that you can register the prefab on it using the inspector. (this requires a bit of a fiddle so that the CreateSith call remains static)

avatar image Azrapse · Oct 26, 2013 at 07:09 PM 0
Share

I have updated the code for the Factory in my answer following your suggestions, @karlhulme.

avatar image benjigga · Aug 13, 2017 at 08:04 PM 0
Share

I had to set instance = this in Awake() ins$$anonymous$$d of Start().

avatar image
2

Answer by olejuer · Dec 10, 2015 at 05:20 PM

Another solution is to create a class MonoBehaviourBase that extends MonoBehaviour and have all Scripts extend that one. That way you can define custom Insantiate-methods for each of your prefabs that require one. I got the idea from this handy article http://devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

 using UnityEngine;
 
 public class MonoBehaviourBase : MonoBehaviour
 {
     public static Object InstantiatePrefabA(GameObject original, ParamType param,
         Vector3 position = default(Vector3), Quaternion rotation = default(Quaternion))
     {
         GameObject result = (GameObject) Instantiate(original, position, rotation);
         SomeComponent someComponent = result.GetComponent<SomeComponent>();
         // handle someComponent = null
         someComponent.Foo(param);
         return result;
     }
 }
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 tpainton · Jun 14, 2015 at 03:03 PM

Really a more elegant solution needs to be provided in the platform. we are creating objects. Anytime an object is created, there needs to be a constructor. A great option would be a parameter in the Instantiate method that called for a Delegate constructor.

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 Bonfire-Boy · Dec 10, 2015 at 06:04 PM 2
Share

Couldn't disagree more.

Note that this isn't actually about initialising the object, it's about initialising its components. It could have any number of components, and any number of them (including, quite often, none of them) might require some sort of additional initialisation. To me it seems perfectly reasonable to put all this in the hands of the person who created the prefab. That's the person that knows what the components are and whether they need further initialisation.

A system for all this in the engine would have to be quite complicated in order to be of any real use, and it would still involve me having to write my Initialisation functions and then decide which components needed initialising and how. I can't see how it's going to end up being any simpler than my calling the initialisation function(s) explicitly straight after instantiating, and it'd certainly be less transparent.

I'd much rather the Unity devs spent their time on more useful things

avatar image
1

Answer by hexagonius · Mar 15, 2017 at 02:07 PM

I'd like to throw another solution in the ring (based off of @Azrapse solution):

 public class Test : MonoBehaviour{
   public Test Init(<parameters>){
     ...;
     return this;
   }
 }
 
 public class Instantiator : MonoBehaviour {
   void Start(){
     var newTest = Instantiate<Test>(prefab).Init(<param>);
   }
 }
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

24 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

Related Questions

Cannot alter MonoBehaviour state variables 2 Answers

C# Instantiate Prefab from Class That Does not Inherit from MonoBehavior 2 Answers

Saving customized transform in game 1 Answer

Rotating specific prefab - instantiated with Random.Range 2 Answers

Why Transform and not Prefab? 2 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