I would like to know how I can reinitialize a variable with a different type. More specifically, I’m declaring a variable with a scriptable object type in a monobehaviour class, and I want to declare a new variable with a derived scriptable object type under a derived monobehaviour class. To clear any confusion, here is an example:
public class CarController : MonoBehaviour
{
public CarData carData {get; set;} //CarData is a scriptable object class.
}
public class PlayerCarController : CarController
{
public new PlayerCarData carData {get; set;} //PlayerCarData is also a scriptable object class, which derives from CarData.
}
I tried the above code, however, it doesn’t really work like I would want. I’m getting errors like:
“NullReferenceException: Object reference not set to an instance of an object
CarController.FixedUpdate () (at Assets/Scripts/CarController.cs)”
“The same field name is serialized multiple times in the class or its parent class. This is not supported: Base(PlayerCarController) k__BackingField”
Is there a way to do what I’m trying to accomplish? And what’s the most efficient way to go about it?
Is there a way to retain the same carData variable but changing it’s type to PlayerCarData? Specifically, initializing it when declaring the class property?
You can do it with a seperate property that returns the carData properly casted like this:
public class PlayerCarController : CarController
{
public PlayerCarData PlayerCarData
{
get { return carData as PlayerCarData; }
set { carData = value; }
}
}
Note that C# convention for properties has them written in PascalCase (CarData), not CamelCase (carData). This can quickly lead to confusion because fields are commonly also in CamelCase.
Why are you subclassing anyway? I have a hunch you do so because it’s the OOP thing to do, but it’s rarely a good approach. The classic conundrum being: Enemy => SwordEnemy, Enemy => ShieldEnemy, ??? => SwordWithShieldEnemy
Typically aggregation or a more data-driven approach are preferable. For example if your CarController is either AI or Player controlled, it could have an InputController (class or interface) field and both AI and player input implement InputController and CarController gets assigned an instance of either of these, thus becoming either AI controlled or player controlled.
To really do this you’d have to use generics. Something like:
public class CarController<T> where T : CarData {
public T CarData { get; set; }
}
public class PlayerCarController : CarController<PlayerCarData> {
}
public class TestCode {
static void Example() {
// Not functional but just to show you the compiler is happy:
PlayerCarController pcc = new();
PlayerCarData carData = pcc.CarData;
}
}
I went ahead and tried what you suggested but I’m still getting the same errors, maybe there’s something else wrong in the code?
Only reason I am deriving from a base CarController class is because, as you assumed, I also have an “EnemyAIController” deriving from it. In which both the PlayerCarController and the EnemyAIController have many similar methods, for example, both have a similar moving method which is called in the FixedUpdate. I was also planning on organizing my code more and as you mentioned, I might incorporate a new class for input and so forth.
And for the name of the property, I originally had fields instead of properties, I was just dabbling around and didn’t really pay mind to the name convention.
I’m a novice in C#, and I did venture in a bit with generics, but they do scare me lol. I will try and use this suggestion, I’ll update you when I have.