Search code examples
c#unity-game-enginescriptable-object

how to correctly create a variable that will accept different classes


I have a main code that stores all information about a player:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

[CreateAssetMenu(fileName = "CarData", menuName = "Data/Car/CarData")]
public class CarData : ScriptableObject
{
    [SerializeField] public ScriptableObject carAttachmentData;
    private int playerHealth;
    void Start()
    {
        playerHealth = carBodyData.health;
    }
}

and I need this variable to accept only two classes, namely these:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

[CreateAssetMenu(fileName = "CarAttachment1Data", menuName = "Data/Car/CarAttachmentData")]
public class CarAttachment1Data : ScriptableObject
{
    public int health; //for example
}

and

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

[CreateAssetMenu(fileName = "CarAttachment2Data", menuName = "Data/Car/CarBodyData")]
public class CarAttachment2Data : ScriptableObject
{
    public int health; //for example
}

and the unit gives an error when compiling:

'ScriptableObject' does not contain a definition for 'healthUp' and no accessible extension method 'healthUp' accepting a first argument of type 'ScriptableObject' could be found (are you missing a using directive or an assembly reference?)

(in reality, the healthUp variable exists, this is the real error code)

the problem can be solved by accepting the data CarAttachment1Data or CarAttachment2Data, but I need the variable to take two possible classes at once, since this option is allowed

classes cannot be combined, since in unity these are completely different objects, but they contain the same classes that are needed to get them in the main script

tried public interface but it generates an error

tried asking chatGPT question but it couldn't help


Solution

  • It is not possible to declare a variable of 2 different types in c#. You can move common functionality into a base class:

    using UnityEngine;
    
    public class CarBase : ScriptableObject
    {
        public int Health;
    }
    

    subclasses:

    using UnityEngine;  
    
    [CreateAssetMenu(fileName = "Truck", menuName = "Truck", order = 0)]
    public class Truck : CarBase
    {
        public int LoadCapacity;
    }
    

    and

    using UnityEngine;
    
    [CreateAssetMenu(fileName = "Taxi", menuName = "Taxi", order = 0)]
    public class Taxi : CarBase
    {
        public int PassengersCount;
    }
    

    in Editor you can save 2 different assets for "Taxi" and "Truck" and check type in the calling code:

    using UnityEngine;
    
    public class Garage : MonoBehaviour
    {
        [SerializeField] private CarBase carInfo;
    
        public void Awake()
        {
            Debug.Log(carInfo.Health);
            if (carInfo is Taxi)
            {
                var taxiInfo = (Taxi)carInfo;
                Debug.Log(taxiInfo.PassengersCount);
            }
        }
    }