2
\$\begingroup\$

See the answer by me, this problem is pretty much my own mistakes of miss understandings.

So, here is my problem.

I have parent class called CameraBehaviour derived from MonoBehaviour

public class CameraBehaviour : MonoBehaviour
{
    public MinMax CameraViewRange;

    private Single CalculateViewRange() { ... }
}

and have two class ActionCamera2D and ActionCamera3D derived from CameraBehaviour

public class ActionCamera2D : CameraBehaviour
{
    [MinMaxRange (2f, 5f)]
    public new MinMax CameraViewRange = new MinMax(2f, 5f);
}

public class ActionCamera3D : CameraBehaviour
{
    [MinMaxRange(20f, 50f)]
    public new MinMax CameraViewRange = new MinMax(20f, 50f);
}

as you can see, both the script has CameraViewRange with new keyword and has different MinMaxRange attribute attached on each script, so the limit is will be vary between this script but still using the same CalculateViewRange calculation as the parent script.

But it turns out to be not possible, in Unity at least, raising an error:

The same field name is serialized multiple times in the class or its parent class.
This is not supported: Base(MonoBehaviour) CameraViewRange
  • MinMaxRange is a custom written attribute for property drawer.
  • MinMax is a custom struct that store min and max value.

      • So, how can I overcome / deal with this problem ?
      • No, you can't, it's the C# design pattern to prevent that.
      • Is my code pattern here is wrong ?
      • Yes.
      • Or is this the C# and Unity limitations ?
      • It's just the C# and Unity Inspector design pattern.

thanks

\$\endgroup\$
9
  • \$\begingroup\$ Maybe implement CameraBehaviour::CameraViewRange as virtual and override it on both ActionCamera2D and ActionCamera3D? \$\endgroup\$ – OnoSendai Feb 22 '18 at 6:46
  • \$\begingroup\$ @OnoSendai unfortunately no, C# can't set field as a virtual, AFAIK only functions can be virtual, with that being said, I was thinking to remove the CameraViewRange from CameraBehaviour and mark the CalculateViewRange() as virtual and override it from the child class, It's possible, but the problem is ( well maybe it's not a problem ), both the ActionCamera2D and ActionCamera3D use the same calculation, and having two same calculation on different class seems out of OOP context. \$\endgroup\$ – deanrihpee Feb 22 '18 at 6:56
  • 1
    \$\begingroup\$ You're right, my comment was incomplete. Can you set CameraViewRange as an auto-implemented virtual property (public virtual MinMax CameraViewRange {get; set;}) \$\endgroup\$ – OnoSendai Feb 22 '18 at 7:18
  • \$\begingroup\$ You tried to make CameraViewRange a property and rename its corresponding variable between the parent and the sub (and make them private serializable through [SerializeField])? \$\endgroup\$ – Nikaas Feb 22 '18 at 7:32
  • \$\begingroup\$ @OnoSendai it's possible, but my property drawer have some problem with property so can't set the value on Unity inspector \$\endgroup\$ – deanrihpee Feb 22 '18 at 7:48
1
\$\begingroup\$

Well after hours of debugging and searching other solutions, I think it's not possible to do that, I've encountered using [NonSerializedAttribute] and [SerializeFieldAttribute] but the behaviour is changed as it seems to be different instance with same name.

so the solution ?

    • Remove the field from parent class.
    • Convert the CalculateViewRange() into virtual.

code :

public class CameraBehaviour : MonoBehaviour
{
    protected virtual Single CalculateViewRange() { }
}

public class ActionCamera2D : CameraBehaviour
{
    [MinMaxRange (2f, 5f)]
    public MinMax CameraViewRange = new MinMax(2f, 5f);

    protected override Single CalculateViewRange() { CameraRangeCalculation }
}

public class ActionCamera3D : CameraBehaviour
{
    [MinMaxRange (20f, 50f)]
    public MinMax CameraViewRange = new MinMax(20f, 50f);

    protected override Single CalculateViewRange() { CameraRangeCalculation }
}
    • Remove the field from child class.
    • Basically, just give up about the limiting range feature, it seems not possible.

code :

public class CameraBehaviour : MonoBehaviour
{
    public MinMax CameraViewRange;
    private Single CalculateViewRange() { }
}

public class ActionCamera2D : CameraBehaviour
{
    ...
    // 2D Specific Functions
    ...
}

public class ActionCamera3D : CameraBehaviour
{
    ...
    // 3D Specific Functions
    ...
}
  1. Bonus If you need this not paricularly for Unity / Unity Inspector / Unity Editor, you can use Property with the same name and then explicitly declare the get; set; to update the parent's field value.

code :

public class ParentClass
{
    public Single FooBar;

    private Single MultiplyFooBarBy2()
    {
        return this.FooBar * 2;
    }
}

public class ChildClass : ParentClass
{
    public Single FooBar
    {
        get => base.FooBar;
        set => base.FooBar = value;
    }
}

// OR which is possibly compatible with Unity Inspector [using attributes]

public abstract class ParentClass
{
    protected abstract Single FooBar { get; set; }

    private Single MultiplyFooBarBy2()
    {
        return this.FooBar * 2;
    }
}

public class ChildClass : ParentClass
{
    //[Range (0f, 1f)] // Untested, but should do
    public Single FieldOfFooBar;

    protected override Single FooBar
    {
        get => this.FieldOfFooBar;
        set => this.FieldOfFooBar = value;
    }
}

EDIT :

Well I should've realized that it's not possible at the very begining.
You can't override fields. And expecting the parent will get the child's value.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.