• 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 /
This post has been wikified, any user with enough reputation can edit it.
avatar image
0
Question by Nanity · Jul 24, 2012 at 10:29 PM · classinstancetype

How to convert System.Type into an instance or access the class variables

First question ever! And as always there might be a very easy solution/trick I don't know about...

The details:

  • One weapon script A that handles releasing the projectiles

  • One weapon script B that handles the current avaible weapons

  • Numerous control scripts C1-C8 that regulate the behaviour of the projectiles (1 per weapon)

The issue:

  • In script A I'm in need of accessing the static variables before I instantiate the projectile (like rate of fire)

  • Script B delivers the currently used weapon prefab and its script TYPE C1-C8 (System.Type)

  • I don't know what script will be delived by the script B, so I have to keep script A independent

"missile" is the prefab and has a "MissileControl" script as component.

"gun" is another prefab and has a "GunControl" script as component.

// depending on weaponID script B returns either "GunControl" or "MissileControl" System.Type var projectileType : System.Type = ScriptB.getType(WeaponID); // same does script B for the prefab resource path var weaponPath : String = ScriptB.getPath(WeaponID);

// First attemp to get the rate of fire var instance : Transform = Instantiate(Resources.Load(weaponPath, Transform));

var rof : float = instance.GetComponent(projectileType).rof; // Error: rof is not a member of UnityEngine.Component // but rof is member of ALL C scripts, I promise. Therefore I have to convert this projectileType in a real component name (e.g. GunControl) to be accepted

// Second attemp, trying to create a script instance var instanceScript : projectileType = new projectileType(); // well, I know this had to fail. But I tried at least...

// Third attemp, rof = projectileType.rof; // both GunControl.rof and MissileControl.rof are static, so this shouldn't be a problem

The third solution would be my alltime favourite, but I don't know to create/access a class by it's type... simple problem it seems :(

I bet the solution can be found here, but I have no idea how to take advantage of it: http://msdn.microsoft.com/library/42892f65

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 Mizuho · Jul 25, 2012 at 09:33 AM 0
Share

You could easily get away with a switch statement.

avatar image Bovine · Jul 25, 2012 at 09:45 AM 0
Share

He could, but it's not terribly scalable I$$anonymous$$HO, you can end up with multiple places you need a switch statement: everywhere you need to deal with a weapon (or its projectile).

By leveraging an OOP design, you can more easily create types that have common functionality but with specific implementations. Your base class type becomes you means of switching.

If I consider having a switch statement for my object clicking scenario that we have in our game (see below), then I would have functionality for many different kinds of object in one place. It would be very messy.

The above problem is one that has been solved with polymorphism for some time name.

I can also re-use the constructs from project to project.

avatar image Mizuho · Jul 25, 2012 at 09:57 AM 0
Share

Unfortunately, the usage of Invoke() is not something I would rank highly in my book of things to use given its high processing requirement. If you have any speed concerns, I would definitely give that a miss. I just felt like placing that out there, but there is definitely an easier way.

avatar image Nanity · Jul 25, 2012 at 12:11 PM 0
Share

The mentioned switch statement is already part of script B to turn my weapon enum into my weapon System.Type

Would be a nasty thing to call that block evertime I need a single variable :O

avatar image Bovine · Jul 25, 2012 at 12:14 PM 0
Share

if each script will have the same variable types you can use Polymorphism as I've described, if not, you will need the switch statement on the type anyway to know what methods and properties you can call.

If you do this without polymorphism, you're going to struggle - creating an arbitrary type is one thing, being able to use it is a whole new ballgame.

Show more comments

3 Replies

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

Answer by Bovine · Jul 25, 2012 at 08:36 AM

I haven't tested it, but you might do this like so I imagine:

 Type type = scriptB.GetType();
 ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes);
 dynamic new_weapon = constructor.Invoke(null);

However, I don't think dynamic will be supported in the current .Net version for Unity and I suspect you'll need it given that you don't know the type of the script, then you cannot reliably call methods on it.

What I think you will need is to have a base class for weapons support, i.e.:

 public class MyWeaponBase : MonoBehaviour
 {
     void FireWeapon(GameObject someContext);
 }

And then you would be able to do:

 Type type = scriptB.GetType();
 ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes);
 MonoBehaviour new_weapon = constructor.Invoke(null);
 new_weapon.FireWeapon(this.gameObject);

However, what I suggest you might want to do is have weapon types in a similar hierarchy and when you spawn a weapon, you do so from a list of weapon types available, creating an instance of a prefab with a weapon script on it that supports MonoBehaviour.

Then you should be able to do:

 MyWeaponBase weapon = MyPrefab.GetComponent<MyWeaponBase>();
 weapon.FireWeapon(this.gameObject);

I use this model for items in the world we can click and hence we have the following code:

 void RayHit(POINTER_INFO ptrInfo)
 {  // we only care about change!
    if(ptrInfo.evt == POINTER_INFO.INPUT_EVENT.NO_CHANGE) return;
 
    if(ptrInfo.evt == POINTER_INFO.INPUT_EVENT.TAP)
    {
       GameObject object_hit = ptrInfo.hitInfo.collider.gameObject;
       Assert.IsNotNull(object_hit);
       BVInteractiveObject interactive = object_hit.GetComponent<BVInteractiveObject>();
       if(interactive != null && interactive.ClickDistance >= ptrInfo.hitInfo.distance) interactive.Clicked();
    }
 }

We use EZGUI hence the hook onto its ray casting.

Hope that helps.

Comment
Add comment · Show 8 · 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 Mizuho · Jul 25, 2012 at 10:00 AM 0
Share

This looks a little hard to understand even though I notice that it actually looks like what I was thinking of (besides the switch statement).

You're basically creating a class, $$anonymous$$yWeaponBase, that all weapons will inherit from, then you put an abstract method into them (`FireWeapon()`) and use that to decide between the types? Or am I reading this wrong?

avatar image Bovine · Jul 25, 2012 at 10:09 AM 0
Share

Yes, so ins$$anonymous$$d of a switch statement anywhere you need to DoThing() with a weapon, you would:

$$anonymous$$yWeaponBase weapon = GetComponent<$$anonymous$$yWeaponBase>();
weapon.DoThing();
weapon.DoSomeOtherThing();
int damage = weapon.CalculateDamage();

And then the implementation for that weapon type lives within the script for that weapon and not scattered around your codebase.

avatar image Bunny83 · Jul 25, 2012 at 10:16 AM 0
Share

This doesn't even help with static variables. They don't belong to the instance, they belong to the class itself. You would have to use reflection to get the value of a static variable from a System.Type reference.

However i wouldn't recommend reflection for such a cases. A base class is the way to go and avoid static variables, they are the evil part of OOP ;)

avatar image Bovine · Jul 25, 2012 at 10:18 AM 0
Share

True, sorry, implicit suggestion - I wouldn't recommend static variables for this sort of thing :o)

avatar image Nanity · Jul 25, 2012 at 10:23 AM 0
Share

You suggest the same "base" script for all weapons to have fix reference for all of them. Good approach if all objects should behave the same (in your example it is the object interactive state).

But sooner or later I have to deter$$anonymous$$ate which stats to load, where they are stored and how the weapon should behave. So it can't be avoided to preload the specific weapon details.

Your contructor solution is very much in the direction I was looking to. I wish there'd be the following function: Type.getValue(Type) that returns the type and not the type holding variable. Or does this work with Type.getType()? Will test this afternoon and report then!

Show more comments
avatar image
2

Answer by Jaimi · Jul 25, 2012 at 12:33 PM

Normally, You use Activator.CreateInstance:

System.Activator.CreateInstance(type);

http://msdn.microsoft.com/en-us/library/system.activator.createinstance.aspx

Comment
Add comment · Show 12 · 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 Bovine · Jul 25, 2012 at 12:35 PM 0
Share

Useful shorthand for constructing something.

avatar image Nanity · Jul 25, 2012 at 01:11 PM 0
Share

Already tried that earlier D:


var instance = System.Activator.CreateInstance(projectileType);
var rof : float = instance.RateOfFire;

-> Error: 'RateOfFire' is not a member of 'Object'.

avatar image Bovine · Jul 25, 2012 at 01:15 PM 0
Share

That's because you don't know the type you would need dynamic, which won't be supported

avatar image Bovine · Jul 25, 2012 at 01:16 PM 2
Share

And if your weapons are all different, you need to $$anonymous$$NOW that RateOfFire is a member of your type... switch statement or polymorphism am afraid

avatar image whydoidoit · Jul 25, 2012 at 05:58 PM 1
Share

I guess interfaces are new into Unity Script - obviously work find in C# - so there might have been a problem with implementing properties I guess - you should definitely log it as a bug if it is reproduceable though.

Reflection is SLOW, GetValue causes a JIT on iOS that kills it (though there are workarounds). If your game design requires reflection like this then there's a red flag up about something being wrong.

It strikes me that you want external scripts to know things like rate of fire etc - the object oriented way is to hide that detail in the object and just call CanFire or even just Fire and let it work itself out. The moment you start pulling that stuff out elsewhere you are breaking encapsulation and you will find that everything is fighting against you.

Show more comments
avatar image
0
Wiki

Answer by Nanity · Jul 26, 2012 at 09:39 AM

Yeha, polymorphism works like a charm!

Here's the important code! Thanks to all and maybe it will save some others much trouble:

// player component class weaponHandler { function createWeapon() { var weapon : Transfrom = Instantiate(Resources.Load(prefabPath, Transform)); var script : WeaponControl = weapon.GetComponent(WeaponControl); script.setOwner = transform.root; } }

// the basic script, not attached to any weapon class WeaponControl extends MonoBehaviour { var owner : Transform; var RateOfFire : float;

 function Start () {
     setStats();
 }

 function setStats() {}

}

// one missile script, attached to the missile prefab class MissileControl extends WeaponControl { function setStats() { RateOfFire = 0.5; }

 function Fire() {
     var missileShot : Transform = Instantiate(Resources.Load("MissileShot", Transform));
     var mSS : MissileShotScript = weapon.GetComponent(MissileShotScript);
     mSS.setOwner = owner;
 }

}

// the missileShot script, attached to the missileShot prefab class MissileShotControl extends MonoBehaviour { var owner : Transform; private var speed : float; private var _body : Rigidbody;

 function Start() {
     _body = GetComponent(Rigidbody);
     _body.velocity = transform.forward * speed * Time.deltaTime;
 }

}

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.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

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

Creating a data type instance difference question 1 Answer

Scriptable object gets deleted with a class that holds it? 1 Answer

Set Dirty on class instance? 0 Answers

Need assistance with SubType in custom class (UnityScript or C#) 2 Answers

calling a class named by a string -1 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