Search code examples
c#unity-game-engine

How can I read static properties from instanced classes?


I know this question has been asked with other flavours, but I don't find mine... sorry if duplicated.

I have a function that internally uses the Time class and its properties, as deltaTime, for example.

In order to debug my function, I wouldn't like to use the Time class as is, but a derived one, a TimeDebug : Time class, and override the deltaTime property, turning it into something predictable, i.e.:

public class TimeDebug : Time
{
    public static new float deltaTime { get { return 0.2f; } }
}

My function would consume the class as a polymorphic parameter:

void DoSomething(TimeDebug timer)
{
...
...
}

My function could receive a Time or a TimeDebug parameter, depending on "Release mode" or "Debug mode":

DoSomething(new TimerDebug())   // debug mode

DoSomething(new Timer())   // release mode

Now comes the question: The compiler won't let me compile a read access to static member deltaTime, because I do it from an instance of a class. For example, I can't do:

void DoSomething(TimeDebug timer)
{
Debug.Log(timer.deltaTime);   // won't compile!!
}

How can I pass the class parameter so I can read the deltaTime property, no matter if class parameter is Time or TimeDebug?


Solution

  • I feel as though this is an XY problem. You don't actually care about "getting a static property through an instance", you're trying to fix the deltaTime to a certain value in Unity (conditionally).

    Which can be done by just setting Time.captureDeltaTime to 0.2f:

    If this property has a non-zero value then Time.time increases at an interval of captureDeltaTime (scaled by Time.timeScale) regardless of real time and the duration of a frame. This is useful if you want to capture a movie where you need a constant frame rate and want to leave enough time between frames to save screen images.

    Obviously, because you're locking the deltaTime without locking the framerate, the game will run WAY too fast for most computers. (1 second realtime at 200fps would be 0.2 (deltaTime) * 200 (frames) = 40 seconds game-time)

    As to why it's called "captureDeltaTime"; it's meant mainly for "capturing" a video of gameplay, as fast as possible, with no regards for how it looks in realtime. Kind of how like video editors will scrub through a video way faster than realtime when rendering.


    Addressing the "Y" part of the XY problem: you can't override a static property, since static properties cannot be virtual.

    Best you can do is make a new class that has a non-static virtual float deltaTime property of its own, and make two child classes that inherit from it, one that returns Time.deltaTime, and one that returns 0.2f; then pass in those classes:

    public class Timer {
      public virtual float deltaTime => Time.deltaTime;
    }
    
    public class DebugTimer : Timer {
      public override float deltaTime => 0.2f;
    }
    

    Then you can just pass in a Timer instance:

    void DoSomething(Timer timer)
    {
        Debug.Log(timer.deltaTime);
    }