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
0
Question by Tomer-Barkan · Oct 15, 2013 at 06:44 AM · instantiateprefabmonobehaviour

Duplicating a prefab

I'm trying to create a Spawner, that will spawn enemies around it's location. Now, I'm trying to make this a generic Spawner, so it receives a Spawnable which is an abstract subclass of MonoBehaviour, as parameter in it's constructor, and is supposed to create objects from that Spawnable template.

Now, each Spawnable has a method that Instantiates a copy of self. This copy is not simple instantiation, becuase depending on the specific implementation of Spawnable, it copies some of its parameters to the newly instantiated object.

 public abstract class Spawnable : MonoBehaviour {
     public abstract void Spawn(Vector3 position);
 }

 public class Enemy : Spawnable {
     public float health;

     public override void Spawn(Vector3 position) {
         GameObject spawnedObject = (GameObject)Instantiate(this.gameObject, position, Quaternion.identity);
         spawnedObject.GetComponent<Enemy>().health = this.health;
     }
 }

Now, say I have one prefab for Enemy, but then I want to create different Spawner objects, each spawning enemies with different health. So I need several Enemy prefabs, each one with different health, and pass them on as parameters to the Spawners.

Which brings us to my question: How do I duplicate the Enemy prefab so I can have several instances with different health values? Or maybe any other ideas? It's important to me to keep these generic and not limited to specific NPC implementations.

Comment
Add comment · Show 8
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 Benproductions1 · Oct 15, 2013 at 07:18 AM 0
Share

Why not just have a list of different healths your enemy can have (probably on the enemy class) and then select one either randomly or as another argument to the Spawn function.

I do have a question though. If you want a generic prefab spawner, why is your prefab instantiating itself?

avatar image Tomer-Barkan · Oct 15, 2013 at 07:45 AM 0
Share

Like I said, I'm trying to keep it generic. Health is just an example, in reality the variables are much more complicated and each NPC type has different variables. I don't want them randomized altogether, for instance in the beginner area the spawner will have a prefab with low health, but farther away one with higher health.

That's also why the prefab is instantiating itself - only it knows which variables need to be copied to the new instance.

avatar image Benproductions1 · Oct 15, 2013 at 08:17 AM 0
Share

I believe that you can achieve the same thing you desire using a much "nicer" method. As far as I understand it, your "Enemy" (just an example) script is used for two things right now. It's used as the spawner (for that type), as well as a gameplay object. A much nicer method would be to have the spawner be the thing that spawns the objects (ins$$anonymous$$d of the objects themselves) and ins$$anonymous$$d of you calling something like a "Spawn" function on the prefab, you can simply write that code right in the Start function of that object. Or if you want more information passed you can simply call some setVars function from the spawner and have the same effect.

This would be much easier to understand and much much nicer to maintain. The less duplicate code the better. So why duplicate Instantiate the same way in every subclass of Spawnable when you can write it once somewhere else?

However, other than the way you instantiate, my suggestion of using lists etc, for those values is still my answer to your question :)

avatar image Tomer-Barkan · Oct 15, 2013 at 10:01 AM 0
Share

Ok, let's take a look at a more complicated scenario. Say we have two types of NPC - Enemy and Passerby.

Enemy has health, money and weapon, where weapon is another class by itself.

Passerby has health and appearance which is also a class by itself.

Now, I thought of a single Spawner class that can spawn either Enemys or Passerbys, depending on the prefab I give it. So if I gave it a prefab of Enemy with gun as weapon, it would spawn enemies with guns, but if I gave it a prefab of Enemy with knife as weapon, it would spawn knife wielding enemies. The same way I could have two Spawners spawn different types of Passerbys.

Now, if I went with your suggestion, I would need two different Spawner classes, and each spawner class would have to duplicate all the variables of the spawned object. So an EnemySpawner would also have health, weapon, and money, so it can set these variables when it spawns the enemy.

Now consider at least 20 classes of NPCs that can be spawned. I'd also need 20 spawner classes. And every time I change the NPC's variables (say adding a secondary weapon), I'd need to add the same variable to the spawner class.

Do you still think your suggestion is a more elegant solution? If you do, I'd love to hear what you think makes it more elegant. I'm open to other ideas as long as I can be convinced they are better :)

BTW, you can think of the Spawn() method of the spawnable object as a copy constructor in C++, or a clone() method in java, which are general practice in those languages although they don't exist in C#.

avatar image Benproductions1 · Oct 16, 2013 at 12:36 AM 1
Share

I think you missinterpreted my comment. I specifically stated, that ins$$anonymous$$d of calling something like "Spawn" to set the variabless, just do them in something like Start or even your own function.
For instance:

 public class Spawner : $$anonymous$$onoBehaviour {
     public void Spawn(Spawnable prefab) {
         Spawnable object = (Spawnable)Instantiate(prefab);
         object.Set(prefab);
     }
 }
 
 public class Enemy : Spawnable {
     public override void Set(Enemy prefab) {
         this.health = prefab.health;
     }
 }

As you can see, my solution is more elegant and produces a lot less repeated code.

The problem is, that $$anonymous$$onoBehaviour objects aren't normal objects. They are tightly tied to the Unity Runtime system, so a bitwise copy just doesn't work.

Also, C# does have cloning features (even though it really is a bad idea to directly clone something). Look at the IClonable interface for instance ;)

Show more comments

1 Reply

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

Answer by Benproductions1 · Oct 17, 2013 at 08:45 AM

Hello,

Ok, now that we are clear about what you want to achieve I can give you a proper answer:

 //This is what I would do
 
 //You have your class everything derives from
 public abstract class Spawnable : MonoBehaviour {
     //This will generate a set of data contained in one object
     public abstract Stats GetData();
     
     //This will apply a set of data to the current object
     public abstract void SetData(Stats stats);
 }
 
 //Then you have your spawner class
 public class Spawner : MonoBehaviour {
     public Spawnable prefab;
     private Stats stats;
     
     //At the start we want to get stats which all our prefabs will use
     public void Start() {
         stats = prefab.GetData();
     }
     
     public void Spawn() {
         Spawnable obj = (Spawnable)Instantiate(prefab, transform.position, transform.rotation);
         //when we spawn a prefab, we want to apply the spawners stats to it
         obj.SetData(stats);
     }
 }

Stats can really be anything. A string, a number etc. That is up to you how you plan on formatting that ;)
This method will give you the functionality you need, along with the genericness you strive for.

Hope this helps,
Benproductions1

Comment
Add comment · Show 6 · 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 Tomer-Barkan · Oct 17, 2013 at 08:59 AM 0
Share

It does help, but unfortunately doesn't solve my original question. Since I still have to supply the spawner with a spawnable prefab, I need several instances of the same prefab (each with different stats)...

I guess it would work if I manually set the "stats" variable of the spawner ins$$anonymous$$d of getting it from the prefab in the start().

Still, for other users sake that see this question - is there a way to duplicate a prefab that you know of?

avatar image Benproductions1 · Oct 17, 2013 at 09:25 AM 0
Share

No, prefabs are just references. You can't duplicate a prefab. With my solution you don't need different instances of a prefab, that's the whole point

avatar image Tomer-Barkan · Oct 17, 2013 at 09:45 AM 0
Share

True, but I need to create a Stats class per NPC type (since stats are not just floats and they differ between NPC types). That' still a bit of a hassle.

Thanks anyway, I'll try searching for an alternative a bit more and update the thread soon.

avatar image Benproductions1 · Oct 17, 2013 at 09:21 PM 1
Share

It's really not very hard (or a lot of code) to make a Stats class per NPC type. $$anonymous$$uch less code than copy-pasting an instantiate method everywhere. As an alternative you could have the "Stats" stored in a static list of the "NPC" and have each spawner access that list by index (id). Of course that means you don't need a Stats class for each prefab however it wouldn't be very nice either :)

avatar image Tomer-Barkan · Oct 18, 2013 at 11:19 AM 0
Share

I ended up basing my solution on your answer, using an internal class within the spawnable prefab, that had all the data needed when spawning. When creating a spawner, I passed it that internal class. Whenever the spawner needed to spawn something, it instantiated the spawnable prefab, and also set the internal data class, cloning the one it had in it.

This is not entirely elegant solution, since each NPC type had a different internal data class, so I used a common parent class that the spawner could hold, but then each specific NPC class would have to force cast it to it's specific data type.

Also, found another possible solution, which also has it's problems: I could duplicate the prefab by Instantiating it, and then disabling the instantiated object. The drawback is that you then have to enable it again after instantiating again, and perhaps other problems that I can't think of...

Thanks for your help.

Show more comments

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

15 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

Related Questions

Associate objects to a prefab 1 Answer

Updating a variable on a script in an instanced object 1 Answer

Why is transform.position of a prefab that's been instantiated different than a gameobject created on the scene, when they are in the exact same position? 1 Answer

Instantiate object 1 Answer

Prefab instantiated wrong scale on mobile 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