How would I add extra info for different parts?

Ok so first let me explain what I have, and then I will explain what I want to do.

So I have this script:
It allows me to create parts, and then set its variables, like name, mass etc

public Part[] partInfo; // I store the info of each part in this array, and then acces it by:  partInfo[id of the part I wanna get info about]

[System.Serializable]
public struct Part {
    public string partName;
    public float mass; //mass of the part
    public bool top, bottom, sides; //where other parts can be attached
    public Sprite texture; //the sprite-texture of the part
}

Ok so this are the stats that each part has.

Now what I would like to do is add some extra variables to some Parts.

So for example I would have a “Fuel tank” part, and I would need a “Fuel” variable for it, but I would not like to have it on all the other parts.

Is there any way to do this? maybe with some kind of inheritance of struct / class or something?

Yeah you could accomplish that with inheritance. The design is up to you, but one way to do it would be to have a “Part” class that has all the common properties to all parts. Then create a class “FuelTank”, which inherits from Part, and also has a “fuel” variable and things specific to FuelTanks.

1 Like

Hm ok so there is just 1 problem with that, and its that then I cant have the nice array of “Part” references.

Is there any workaround that?

So right now this is what I have done so far:

public Part[] partInfo; // I store the info of each part in this array, and then acces it by:  partInfo[id of the part I wanna get info about]

//[System.Serializable]
public class PartBasic { //the basic info of a part
    public string partName;
    public float mass; //mass of the part
    public bool top, bottom, sides; //where other parts can be attached
    public Sprite texture; //the sprite-texture of the part
}

public class Tank : PartBasic {  // I can't store this is the partInfo array :/
    public float fuel;
}

Anything that inherits from Part is also a Part. So your array can contain all Parts and FuelTanks. You will just need to cast them to Parts to put them in the list, and cast them to FuelTanks when you need the specific FuelTank values and functions. There is no data loss when casting from FuelTank to Part.

1 Like

Hm ok ill try :stuck_out_tongue:
Thanks you very much for the help!

Here’s an example for reference:

public class Part {
    public string partName;
    public float mass; //mass of the part
    public bool top, bottom, sides; //where other parts can be attached
    public Sprite texture; //the sprite-texture of the part

    public Part(string partName, float mass, bool top, bool bottom, bool sides, Sprite texture) {
        this.partName = partName;
        this.mass = mass;
        this.top = top;
        this.bottom = bottom;
        this.sides = sides;
        this.texture = texture;
    }
}

public class FuelTank : Part {
    public float fuel;

    public FuelTank(string partName, float mass, bool top, bool bottom, bool sides, Sprite texture, float fuel)
        : base(partName, mass, top, bottom, sides, texture) { // send parameters to base class constructor

        this.fuel = fuel;
    }
}

public class PartManager : MonoBehaviour {
    Part[] parts;

    private void Start() {
        parts = new Part[10];

        parts[0] = new Part("part1", 0, true, true, true, null);

        // this automatically casts from FuelTank to Part by assignment to a base class variable
        parts[1] = new FuelTank("fuelTank", 10, false, false, true, null, 100);

        Part part = parts[0];
        print(part.partName);

        // Part cannot automatically be converted to FuelTank, so a cast must be done

        // method using 'as'
        FuelTank fueltank = parts[1] as FuelTank;

        // if the cast was successful
        if(fueltank != null) {
            print(fueltank.partName);
            print(fueltank.fuel);
        } else {
            print(parts[1].partName + " is not a FuelTank");
        }

        // method using 'is'
        if(parts[1] is FuelTank) {
            // since you now know it's a FuelTank, you can use this cast with confidence
            FuelTank fueltank2 = (FuelTank)parts[1];
            print(fueltank2.partName);
            print(fueltank2.fuel);
        }
    }
}
1 Like

Holy s*hit, thank you very much! hahahaha, this makes everything so clear

You’re welcome. I just edited it to include both ‘as’ and ‘is’ methods of casting and checking.

If you need to cast, generally ‘as’ is the better choice because it directly returns the casted object. ‘is’ is nice if you don’t have to cast, and just want to know what it is because it returns a boolean.

1 Like

What you can do is have your Part class inherit from ScriptableObject. (This will negate the previous examples for code-created instances at runtime, and instead you create the instances at edit-time in the Unity editor, I’ll explain.)

Scriptable Objects are scripts that can be instantiated as Assets in your project files, and then customized per-asset. So you can create a FuelTank instance in your project files, and add it to the list of Parts.

You would make one class Part like this:

using UnityEngine;

[CreateAssetMenu(fileName = "NewPart", menuName = "PartTypes/Part", order = 1)]
public class Part : ScriptableObject {
    public string name;
    public float mass; //mass of the part
    public bool top, bottom, sides; //where other parts can be attached
    public Sprite texture; //the sprite-texture of the part
}

and then one FuelTank like this:

using UnityEngine;

[CreateAssetMenu(fileName = "NewFuelTank", menuName = "PartTypes/FuelTank", order = 2)]
public class FuelTank : Part {
    public float fuel;
}

Once you make and save those new C# files, you will be able to use the asset menu and go to Assets → Create → PartTypes → Part

That will create a new instance of your scriptable object in your project files. You can customize it there, and add that to your Part list just like a prefab or anything else. Just drag and drop it into the list as an object reference.

You can do the same thing for FuelTank: Assets → Create → PartTypes → FuelTank.

Customize the new instance, and add it to the Parts list. Repeat for all your parts.

So now you have a bunch of Part assets that you customize per-asset, instead of a huge list in the inspector, and you can create and customize the data for any type of Part, and add them all to the same list.

3 Likes

It gives me this error: 2849323--208157--upload_2016-11-11_18-51-31.png

Edit: Nvm my fault, I forgot to add the “ScriptableObject”.

Also this asset creating thing is amazing :smile:

1 Like

Double check that your Part class indeed inherits from ScriptableObject as in my example code.

public class Part : ScriptableObject {

I’m having another problem again with files not exporting, but I posted it in another thread: https://forum.unity3d.com/threads/problem-with-script-made-asset-not-exporting.440821/