Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Get all scripts in resources folder

Discussion in 'Scripting' started by Filtiarn_, Apr 17, 2015.

  1. Filtiarn_

    Filtiarn_

    Joined:
    Jan 24, 2013
    Posts:
    173
    Hi I need to get all scripts in my resources folder.

    I have done.
    Code (CSharp):
    1. var scripts = Resources.LoadAll<UnityEditor.MonoScript>("");
    .It works in editor and on desktop but when I try to build a Windows Store project it does not work.
    Error says "type of namespace of unity editor could not be found", is there away to include this namespace in a build?

    The reason I need to do this because I have items database. Each Item has an string called effect which is a string of a script name. I keep a list of Effect type scripts and use there functions when appropriate. An example would be when the player uses an item it gets this script and through "reflection" it invokes a method called "OnUse". Each item needs to have its own logic but each item shares similar variables such as Id,Description,Mesh and Icon. Each item is stored in a xml file and is created when the application launches.

    I'm using Unity5.0 for its new features but AddComponent("String") no longer works. If this did I could have added this component, called the function, and then removed it.

    I'm basically using C# trying to use C# as a scripting language instead of LUA,RUBY, or something else since it would just be more complicated, and may not be as powerful as just directly using C#.


    Thanks in advanced.
     
  2. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    UnityEditor doesn't get included in builds at all so I'm surprised that even works in Standalone.

    You're probably better off namespacing those classes into their own namespace and using reflection to get new instances of them.
     
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,513
    Use reflection to get the types:

    Here we find a script type by its name:
    Code (csharp):
    1.  
    2.         public static System.Type FindType(string typeName, bool useFullName = false, bool ignoreCase = false)
    3.         {
    4.             if (string.IsNullOrEmpty(typeName)) return null;
    5.  
    6.             StringComparison e = (ignoreCase) ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
    7.             if (useFullName)
    8.             {
    9.                 foreach (var assemb in System.AppDomain.CurrentDomain.GetAssemblies())
    10.                 {
    11.                     foreach (var t in assemb.GetTypes())
    12.                     {
    13.                         if (string.Equals(t.FullName, typeName, e)) return t;
    14.                     }
    15.                 }
    16.             }
    17.             else
    18.             {
    19.                 foreach (var assemb in System.AppDomain.CurrentDomain.GetAssemblies())
    20.                 {
    21.                     foreach (var t in assemb.GetTypes())
    22.                     {
    23.                         if (string.Equals(t.FullName, typeName, e)) return t;
    24.                     }
    25.                 }
    26.             }
    27.             return null;
    28.         }
    29.  
    Here's one where we can find many types based on some type they inherit from or implement:
    Code (csharp):
    1.  
    2.         public static IEnumerable<Type> GetTypesAssignableFrom(System.Type rootType)
    3.         {
    4.             foreach (var assemb in System.AppDomain.CurrentDomain.GetAssemblies())
    5.             {
    6.                 foreach (var tp in assemb.GetTypes())
    7.                 {
    8.                     if (rootType.IsAssignableFrom(tp)) yield return tp;
    9.                 }
    10.             }
    11.         }
    12.  
    from:
    https://github.com/lordofduct/space.../blob/master/SpacepuppyBase/Utils/TypeUtil.cs

    Furthermore it sounds to me like you want interfaces here. You're talking about multiple items that have their own "logic" (this in programming terms is called 'implementation'), but share the same named variables and functions (this in programming terms is called the 'interface' of an object).

    Interface, the structure, is used to define interfaces of objects, that you can then implement from class to class independently.

    Code (csharp):
    1.  
    2. public interface IItem
    3. {
    4.     string Id { get; set; }
    5.     string Description { get; set; }
    6.     Mesh Mesh { get; set; }
    7.     Texture2D Icon { get; set; }
    8.  
    9.     void OnUse();
    10. }
    11.  
    Then you can implement it like this:

    Code (csharp):
    1.  
    2. public class Bottle : MonoBehaviour, IItem
    3. {
    4.     [SerializeField()]
    5.     private string _id;
    6.     [SerializeField()]
    7.     private string _desc;
    8.     [SerializeField()]
    9.     private Mesh _mesh;
    10.     [SerializeField()]
    11.     private Texture2D _icon;
    12.  
    13.  
    14.     #region IItem Interface
    15.     public string Id
    16.     {
    17.         get
    18.         {
    19.             return _id;
    20.         }
    21.         set
    22.         {
    23.             _id = value;
    24.         }
    25.     }
    26.  
    27.     public string Description
    28.     {
    29.         get
    30.         {
    31.             return _desc;
    32.         }
    33.         set
    34.         {
    35.             _desc = value;
    36.         }
    37.     }
    38.  
    39.     public Mesh Mesh
    40.     {
    41.         get
    42.         {
    43.             return _mesh;
    44.         }
    45.         set
    46.         {
    47.             _mesh = value;
    48.         }
    49.     }
    50.  
    51.     public Texture2D Icon
    52.     {
    53.         get
    54.         {
    55.             return _icon;
    56.         }
    57.         set
    58.         {
    59.             _icon = value;
    60.         }
    61.     }
    62.  
    63.     public void OnUse()
    64.     {
    65.         //do some stuff
    66.     }
    67.  
    68.     #endregion
    69.  
    70. }
    71.  
    Now all your items can be treated as IItem instead, accessed the same, BUT they can have their own implementations (logic) each.

    Code (csharp):
    1.  
    2. var item = this.gameObject.GetComponent<IItem>(); //this is now supported in Unity5
    3. item.OnUse();
    4.  
     
    Filtiarn_ likes this.
  4. Filtiarn_

    Filtiarn_

    Joined:
    Jan 24, 2013
    Posts:
    173
    Thanks for the fast replies. I got what I wanted working!!!

    So like I said each item is created from XML, Instead of creating different items using code.
    Example of an item of 3 similar weapons in XML. You will notice that that there very similar. They vary in stats and only some use effects.

    Code (CSharp):
    1. Weapon id="weapon_IronSword" name="Iron Sword" description="The most common sword and weakest sword but can be bought for a cheap price and is really durable." uses="50" worth="500" icon="TexturePracticeSword" texture="TexturePracticeSword" mesh="PracticeSword" rank="0" mt="6" hit="95" crt="0" minRng="1" maxRng="1" wt="2" wEx="0" attackTypeClose="0" attackTypeRanged="0" effect ="WindEffect" />
    2.  
    3.  
    4. Weapon id="weapon_IronSword2" name="Iron Sword" description="The most common sword and weakest sword but can be bought for a cheap price and is really durable." uses="50" worth="500" icon="TexturePracticeSword" texture="TexturePracticeSword" mesh="PracticeSword" rank="0" mt="8" hit="100" crt="10" minRng="1" maxRng="1" wt="2" wEx="0" attackTypeClose="0" attackTypeRanged="0" effect ="WindEffect" />
    5.  
    6. Weapon id="weapon_IronSword3" name="Iron Sword" description="The most common sword and weakest sword but can be bought for a cheap price and is really durable." uses="50" worth="500" icon="TexturePracticeSword" texture="TexturePracticeSword" mesh="PracticeSword" rank="0" mt="8" hit="100" crt="10" minRng="1" maxRng="1" wt="2" wEx="0" attackTypeClose="0" attackTypeRanged="0" effect ="NULL" />
    7.  
    8.  
    Weapon Objects are then created using this XML data.

    I then load all of effect scripts in my project and put them in a list.
    Code (CSharp):
    1. foreach (var assemb in System.AppDomain.CurrentDomain.GetAssemblies()) {
    2.             foreach (var tp in assemb.GetTypes())
    3.                 if (tp.BaseType == typeof(Effect))
    4.                 effects.Add(tp.Name,tp);
    5.  
    6.         }
    Weapon Class
    Code (CSharp):
    1. [System.Serializable]
    2. public class Weapon : Item
    3. {
    4.     public int rank = 0;
    5.     public int mt = 0;
    6.     public int hit = 0;
    7.     public int crt = 0;
    8.     public int minRng = 0;
    9.     public int maxRng = 0;
    10.     public int wt = 0;
    11.     public int wEx = 0;
    12.     public enum WeaponAttackType { PHYSICAL, MAGICAL };
    13.     public WeaponAttackType weaponAttackTypeClose;
    14.     public WeaponAttackType weaponAttackTypeRanged;
    15.  
    16.     public Weapon(string id)
    17.     {
    18.         this.id = id;
    19.         itemType = ItemType.WEAPON;
    20.         weaponAttackTypeClose = WeaponAttackType.PHYSICAL;
    21.         weaponAttackTypeRanged = WeaponAttackType.PHYSICAL;
    22.     }
    23.  
    24.     public static Weapon CreateCopy(Weapon toCopy)
    25.     {
    26.         Weapon copy = new Weapon(toCopy.id);
    27.         copy.name = toCopy.name;
    28.         copy.description = toCopy.description;
    29.         copy.uses = toCopy.uses;
    30.         copy.uses = toCopy.uses;
    31.         copy.currentUses = toCopy.currentUses;
    32.         copy.worth = toCopy.worth;
    33.         copy.icon = toCopy.icon;
    34.         copy.mesh = toCopy.mesh;
    35.         copy.texture = toCopy.texture;
    36.         copy.effect = toCopy.effect;
    37.         copy.itemType = toCopy.itemType;
    38.      
    39.         copy.rank = toCopy.rank;
    40.         copy.mt = toCopy.mt;
    41.         copy.hit = toCopy.hit;
    42.         copy.crt = toCopy.crt;
    43.         copy.minRng = toCopy.minRng;
    44.         copy.maxRng = toCopy.maxRng;
    45.         copy.wt = toCopy.wt;
    46.         copy.wEx = toCopy.wEx;
    47.         copy.weaponAttackTypeClose = toCopy.weaponAttackTypeClose;
    48.         copy.weaponAttackTypeRanged = toCopy.weaponAttackTypeRanged;
    49.      
    50.         return copy;
    51.     }
    52. }
    53.  
    when a weapon hits something it then calls the OnHit function(Which extends the logic of weapon) of what ever effect it is using. These effects also have different abstract functions that can be used on different cases such as drinking an item.

    Code (CSharp):
    1. MethodInfo memberInfo = effects["WindEffect"].GetMethod("OnHit");
    2.                 memberInfo.Invoke(Activator.CreateInstance(ffects["WindEffect"]),RefrenceOfUnitEntityThatOwnsThisItem});
    This might be weird but what if I want two weapons that are the same but one is just stronger(All other stats are the same). I just did not want to create a class for each weapon(That's why I did not use interfaces). Not all weapons use effects, only a few so them all having the same variables would make no sense in having there own classes .
     
  5. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,513
    You're not only using reflection (slow), but creating a new WindEffect object each time you call to do the wind effect?

    First and foremost, if your 'Effect' class either declared an abstract/virtual 'OnHit' method, or implemented some IEffect interface, the 'OnHit' would be defined there. Then you could do something like this:

    Code (csharp):
    1.  
    2. var effect = Activator.CreateInstance(effects["WindEffect"]) as Effect;
    3. effect.OnHit(ReferenceOfUnityEntityThatOwnsThisItem);
    4.  
    Furthermore, you could instead of filling the dictionary with the 'type', fill it with instances of the effects:

    Code (csharp):
    1.  
    2. Dictionary<string, Effect> effects = new Dictionary<string, Effect>();
    3. foreach (var assemb in System.AppDomain.CurrentDomain.GetAssemblies())
    4. {
    5.     var effectType = typeof(Effect);
    6.     foreach (var tp in assemb.GetTypes())
    7.         if (effectType.isAssignableFrom(tp))
    8.             effects.Add(tp.Name, System.Activator.CreateInstance(tp));
    9.  
    10. }
    11.  
    12.  
    13.  
    14. //elsewhere
    15. effects["WindEffect"].OnHit(ReferenceOfUnityEntityThatOwnsThisItem);
    16.  
    But even then, I could think of an even better method of doing this all.

    And that would be that you just make 'Effect' inherit from MonoBehaviour, have this abstract 'OnHit' function defined on it, and then wherever you have a Weapon that gets added effects you just attach the Effect component to the same GameObject the Weapon is attached to. Then to know what effects the weapon has you just say:

    Code (csharp):
    1.  
    2. var effects = theWeapon.GetComponents<Effect>();
    3. foreach(var effect in effects) effect.OnHit();
    4.  
    1) you can have more than 1 effect on the weapon.
    2) you don't need to pass in the 'RefrenceOfUnitEntityThatOwnsThisItem', because it's attached to the entity that owns it.


    When you create the weapons from xml, you have the string name of the effects on the weapon. You use the reflection to get the actual type for the effect, and you add it to the gameobject along with the weapon.

    I'll write up a simple implementation so you can see. brb.
     
    Filtiarn_ likes this.
  6. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,513
    And here you can see what I mean.

    Code (csharp):
    1.  
    2. //example xml for a weapon
    3. <weapon id="windsword" name="Wind Sword" strength="4">
    4.     <effects>
    5.         <effect type="WindEffect" />
    6.     </effects>
    7. </weapon>
    8.  
    9. public interface IEffect
    10. {
    11.     void OnHit();
    12. }
    13.  
    14. public abstract class Effect : MonoBehaviour, IEffect
    15. {
    16.     private Weapon _weapon;
    17.  
    18.     protected virtual void Awake()
    19.     {
    20.         _weapon = this.GetComponent<Weapon>();
    21.     }
    22.  
    23.     public Weapon Weapon { get { return _weapon; } }
    24.  
    25.     public abstract void OnHit();
    26.  
    27.     void IEffect.OnHit()
    28.     {
    29.         this.OnHit();
    30.     }
    31. }
    32.  
    33. public class WindEffect : Effect
    34. {
    35.     public override void OnHit()
    36.     {
    37.         //do whatever a windeffect does
    38.     }
    39. }
    40.  
    41. public class Weapon : MonoBehaviour
    42. {
    43.  
    44.     public string Id;
    45.     public float Strength;
    46.  
    47.     /// <summary>
    48.     /// Create a weapon from xml config node
    49.     /// </summary>
    50.     /// <param name="target">The gameobject to attach the weapon to</param>
    51.     /// <returns></returns>
    52.     public static Weapon CreateWeapon(GameObject target, XElement xel)
    53.     {
    54.         var weapon = target.AddComponent<Weapon>();
    55.         weapon.Id = xel.Attribute("id").Value;
    56.         weapon.Strength = float.Parse(xel.Attribute("strength").Value);
    57.  
    58.         foreach(XElement xeffect in xel.Element("effects").Elements("effect"))
    59.         {
    60.             var stp = xeffect.Attribute("type").Value;
    61.             var tp = TypeUtil.FindType(stp, typeof(IEffect), false, true); //using that FindType function I linked in previous post
    62.             if(tp != null)
    63.             {
    64.                 weapon.gameObject.AddComponent(tp);
    65.             }
    66.         }
    67.  
    68.         return weapon;
    69.     }
    70.  
    71. }
    72.  
     
    Last edited: Apr 18, 2015
    Filtiarn_ likes this.
  7. Filtiarn_

    Filtiarn_

    Joined:
    Jan 24, 2013
    Posts:
    173
    Thanks a lot lordofduct, you have been very helpful. Thanks for the feedback.