Use GetComponent to find a script by partial name

How can I use GetComponent to find a script attached to the gameobject by part of script name, since unity doesn’t allow scripts with same name to exist, even in different folder?

You can’t with the current implementation of GetComponent. Could you explain why you want to do this in the first place?

I’m making a space sim. I’m at the part where I want to add multiple ships. Everything is ready except unity for some reason doesn’t allow 2 javascripts with the same name to exist, even if they are each in different folder.

So I thought that I could maybe use a part of the script name and use GetComponent to find it, but nothing works

Every ship has it’s own unique Stats.js file but for unity this seems to be a problem

All I want to do is to make GetComponent load a script by first name. if I have 2 scripts that are named like Stats_Freighter5 and Stats_Destroyer7, I want the GetComponent to just look for “Stats” in the file name

Could you post an example of one of your Stats scripts please?

Stat script is not a problem, the problem is that unity doesn’t allow 2 scripts with same name to exist. The problem is this

var SelectedShip : GameObject;
var SelectedShipStats : Stats;

function Start () {
SelectedShip = gameObject.FindWithTag(“SelectedPlayerShip”);
SelectedShipStats = SelectedShip.GetComponent(“Stats”);
}

This will not load a file that’s called Stats_HeavyFighter or Stats.Heavyfigher or anything. It only allows a file to be called Stats, and I can’t have 1 stat file for 100 ships

It needs to be modular. I know I can just put GetComponent(“Stats_Heavyfighter”) but it will only accept heavy fighter when it docks at a station

The point of me requesting the stats script was so that I could see how you are implementing it. It sounds like you’re implementing a bunch of different stats in a single script. You should be implementing each of them as one singular component. Then simply adding the desired stat components to the ship to prevent writing duplicate code and simplifying the whole thing. If you want to have selectable stats you could just create an array with each type of stat component for the specific ship and iterate over the array to add/get the components during selection. Let me know if you want me to expand on this.

However, with your current implementation you would need to use an interface like IStats. You could then use GetComponent(IStats) to get the interface as long as all your Stats classes implement the interface. This is assuming the javascript implementation of GetComponent supports interfaces like it does in C#.

Putting stats of 100 ships in a single file is something that I honestly don’t want to do. But here is the stats file. Many other scripts access it such as station docking manager, npc manager, ship info viewer etc

//Stats file for BlankShip

var hp : float;                                                        //Hull Points
var shield : float;                                                    //Shield Capacity
var speed : float;                                                     //Max Speed
var cargocap : float ;                                                 //Cargo Capacity

var maxhp : float;                                                    //Max Hull Points, used for upgrades
var maxshield : float;                                                //Max Shield Points, used for upgrades
var maxspeed : float;                                                //Max Speed, used for upgrades
//var turretamount = "";                                            //Unused right meow

var ShipName = "No Ship Selected";                                            //Ship Name, can be anything, Max 20 Characters.
var ShipClass = "";                                    //Ship Class, can be custom but quests look only for specific ones such as Fighter, Scout, Frigate etc.
var ShipDesc = "";                                                    //Shop Description, Max 550 Characters.
var ShipValue : int;                                                //Ship Value, Max 7 Characters.
var ShipPic : Texture2D;                                            //Ship Picture, Size must be 500x300 px

var weapons = "";    //Weapon name, used only for ship info viewer, can be anything.
var WepDmgHp : float;                                                //Damage that the weapon does to ship and station hull
var WepDmgSh : float;                                                //Damage that the weapon does to ship and station shields

//var shieldrecharge : int;
//var gencap : int;         //Generator Capacity
//var accel : int;        // Acceleration

function Start () {
        ShipDesc = "";
        hp = 0;
        maxhp = 0;
        shield = 0;
        maxshield = 0;
        speed = 0;
        maxspeed = 0;
        cargocap = 0;
        ShipValue = 0;
        WepDmgHp = 0;
        WepDmgSh = 0;
        ShipPic = Resources.Load("Pictures/ShipPics/blank") as Texture2D;
}

As I thought… I assume you are also writing separate classes for each ship type? If you don’t mind a C# example I would be more than glad to write one up real fast. Also, do your managers have a reference to the ship objects themselves?

Ship Class is just a string that mission manager reads and based on that it allows you to take a mission or not. All managers use tags to find ships, and sure, I’d like to see your example, I’m very frustrated by this limitation :confused:

It really sounds like you should have only one stats script, and set the values differently in the inspector.

Alternatively, you could have several if they have fields that differ, and use inheritance to share the fields that are equal. Then you could use GetComponent with the base class.

Single stat file to handle 100+ ships? There are also ships with special functions that are also stored in stat file, and if I want to modify 1 ship later I just need to open it’s respective stat file

It sounds like you’re struggling with the concept that adding a “Stats” component to different gameobjects makes them different “instances” so you have a single “template” (the script source) but each time you attach it to something you are making an “instance” of it…

It also sounds like you might benefit from a look at things like ScriptableObjects, there are a few tutorials on them in the “learn > Live training sessions”

A class is a representation of a concept - in your case “the stats of a spaceship”. If two classes differ only in what values the fields are set to at Start, there’s no good reason to have different scripts.

The big downside with what you’re doing now is that you can’t use the stats in other scripts. If you write a method like this:

//example
function PrintDesc(BlankShip ship) {
    print(ship.ShipDesc);
}

You can only give it BlankShips. It can’t print the stats of say a Cruiser or Battleship. Unless, of course, you turn off #pragma strict, in which case your code will be slow as hell, and horribly hard to maintain.

How are you creating these ships? From prefabs? From script? Some other way? That’ll help me give you advice on how to solve this problem.

Hmm no. Ship Stat file is a single script, which is unique to every ship.

When ship docks at a station, the station offers upgrades and other services based on the ship’s Stats.js file. It does so by first finding the ship that docked by tag since only selected ships can dock so it looks for “SelectedPlayerShip”. when it finds it, then it looks for Stats.js file.

This would all work but unity doesn’t allow scripts with same name… which makes absolutely zero sense to me since the files are not in the same folder either.

I cannot have 1 file handle 100 ships, it’s very impractical and hard to edit. What if I want to add special function to a single ship that a station needs to read? Now I need to write dozen more scripts because the Stats file has to be generic without any extras

All ships are prefabs, Stats file is important

Ship in itself is a 3D model. Every ship has about 7 scripts like MoveToMarker, CargoBayHandler, ItemCollector, ShipSelfDefense etc etc. All of them use the Stats.js file to get data and it works as long as there is just 1 file called Stats.js

Normally, if you need two scripts of the same name to work, at least with c#, you’d use different namespaces. I’m not sure if java has namespaces?

However, scripts are more of a blueprint. It’s not 1 script for all ships to share, since each ship maintains it’s own “instance” of the script. Now, if you’re wanting to create a unique script for each ship, this is easy to solve.

A couple things you can consider. One might be to use interfaces. This way you can find the script by the interface. The interface can declare a base level of stats. So your interface may say declare “hp, armor, etc”. Then your script “battleship, fighter” might use the interface and declare their own variables.

The other option is you have your stats script with basic stats including a variable called shipType. This would tell you what type of ship it is. So if it’s battleship, you can use an if statement to know you need to load the script called “battleship” with a getcomponent.

There are other ways, but I think the confusion is why you’re needing more than one stat script, assuming all ships have the same stats. (just different values)

Then you should just have a single Stats script, remove the Start method, and set it’s values in the prefab.

Is there nothing else I can do? Add ID to the script and make unity load it by ID? Anything but this, I’ve had so much problems with this way of editing that I’d rather want to avoid it. I’ve had unity reset whole script when I added or changed function, therefore I could lose all ship data, and the data is very complex… it includes ship lore and information

No. Unity has no way of knowing what script you want if they are named the same. You create one script, and set the values in the inspector for each prefab. Or, you store the data in a json/xml file that you can pull from that has base stats for the ship. (or from a saved file if the player can save their game, which I’m assuming they can)

Ok here is my example… It’s actually quite large but should give you the basic idea of how to implement it. You can easily modify it to work 100% with the inspector as well. I prefer a programmatic approach though.

public class ShipAttribute : MonoBehaviour
{
    public float Value = 0.0f;
    public float Max = 0.0f;

    public virtual string Name { get { return GetType().Name; } }
}

public class Hull : ShipAttribute
{
    //implement hull stuff here
}

public class Shield : ShipAttribute
{
    //implement shielding stuff here
}

public class Thruster : ShipAttribute
{
    //implement thruster stuff here
}

public abstract class ShipWeapon : MonoBehaviour
{
   public abstract string Name { get; }
   public abstract float MinHullDamage { get; }
   public abstract float MaxHullDamage { get; }
   public abstract float MinShieldDamage { get; }
   public abstract float MaxShieldDamage { get; }
   public abstract float FireRate { get; }
   public abstract Texture2D Pic { get; }

   public float GetRandomHullDamage()
   {
     return Random.Range(MinHullDamage, MaxHullDamage);
   }

   public float GetRandomShieldDamage()
   {
     return Random.Range(MinShieldDamage, MaxShieldDamage);
   }

   //implement other shared weapon stuff here
}

public class Cannon : ShipWeapon
{
   public override string Name { get { return "Cannon"; } }
   public override float MinHullDamage { get { return 10; } }
   public override float MaxHullDamage { get { return 20; } }
   public override float MinShieldDamage { get { return 1; } }
   public override float MaxShieldDamage { get { return 3; } }
   public override float FireRate { get { return 20.0f; } }
   public override Texture2D Pic { get { return Resources.Load("CannonPic") as Texture2D; } }
}

public abstract class Ship : MonoBehaviour
{
    public abstract string Name { get; }
    public abstract string Class { get; }
    public abstract string Desc { get; }
    public abstract int Value { get; }
    public abstract Texture2D Pic { get; }

    //implement other shared ship behaviour here
}

public class Fighter : Ship
{
    private Hull m_Hull = null;
    private Shield m_Shield = null;
    private Thruster m_Thruster = null;
    private ShipWeapon m_LeftWeapon = null;
    private ShipWeapon m_RightWeapon = null;

    public override string Name { get { return "Fighter"; } }
    public override string Class { get { return "SomeFighterShipClass"; } }
    public override string Desc { get { return "FighterDescription"; } }
    public override int Value { get { return 1000; } }
    public override Texture2D Pic { get { return Resources.Load("FighterPic") as Texture2D; } }

    void Awake()
    {
        //set up default values
        m_Hull = gameObject.AddComponent<Hull>();
        m_Hull.Value = m_Hull.Max = 100.0f;

        m_Shield = gameObject.AddComponent<Shield>();
        m_Shield.Value = m_Shield.Max = 100.0f;

        m_Thruster = gameObject.AddComponent<Thruster>();
        m_Thruster.Value = m_Thruster.Max = 25.0f;

        m_LeftWeapon = gameObject.AddComponent<Cannon>();
        m_RightWeapon = gameObject.AddComponent<Cannon>();
    }
}

public class Freighter : Ship
{
    private Hull m_Hull = null;
    private Shield m_Shield = null;
    private Thruster m_Thruster = null;

    public override string Name { get { return "Freighter"; } }
    public override string Class { get { return "SomeFreighterShipClass"; } }
    public override string Desc { get { return "FreighterDescription"; } }
    public override int Value { get { return 100000; } }
    public override Texture2D Pic { get { return Resources.Load("FreighterPic") as Texture2D; } }

    void Awake()
    {
        //set up default values
        m_Hull = gameObject.AddComponent<Hull>();
        m_Hull.Value = m_Hull.Max = 350.0f;

        m_Shield = gameObject.AddComponent<Shield>();
        m_Shield.Value = m_Shield.Max = 450.0f;

        m_Thruster = gameObject.AddComponent<Thruster>();
        m_Thruster.Value = m_Thruster.Max = 45.0f;
    }
}

public class ShipSelecterThingy : MonoBehaviour
{
   private Ship m_SelectedShip = null;
   private ShipAttribute[] m_Attributes = null;
   private ShipWeapon[] m_Weapons = null;

   void Start()
   {
     GameObject shipObject = GameObject.FindWithTag("SelectedPlayerShip");
     m_SelectedShip = shipObject.GetComponent<Ship>();//get the ship
     Fighter fighter = m_SelectedShip as Fighter;
     if (fighter != null)
     {
       Debug.Log("Ship is a fighter.");
     }
     Freighter freighter = m_SelectedShip as Freighter;
     if (freighter != null)
     {
       Debug.Log("Ship is a freighter.");
     }
     m_Attributes = shipObject.GetComponents<ShipAttribute>();//returns all the attributes on the ship
     m_Weapons = shipObject.GetComponents<ShipWeapon>();//returns all the weapons on the ship

     Hull selectedShipHull = shipObject.GetComponent<Hull>();//get just the hull
     Shield selectedShipShield = shipObject.GetComponent<Shield>();//get just the shield
     Thruster selectedShipThruster = shipObject.GetComponent<Thruster>();//get just the thruster
   }
}