Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Feedback Please Support Time Hierarchy

Discussion in 'Scripting' started by yu_yang, Jul 28, 2021.

  1. yu_yang

    yu_yang

    Joined:
    May 3, 2015
    Posts:
    60
    Unity now supports two time modes: scaled & unscaled. I have an idea of Time Hierarchy, let me explain how it woks.

    Code (CSharp):
    1. Root (local time scale = 1)
    2. |__ Game (local time scale = 0.2)
    3. |   |__ Player
    4. |   |__ Normal Enemy
    5. |   |__ Slow Down Enemy (local time scale = 0.6, time scale = 0.12)
    6. |__ UI
    This is a Time Hierarchy. A project has a Time Hierarchy, it contains a root node at first, developers can add child nodes later. Every node has a local time scale setting, the final time scale of a node is product of all local time scales of all parent nodes. Now we can pause game by setting local time scale of "Game" node to zero.

    A game object has a time node option, it can select one node from Time Hierarchy, or use "Inherit" - it means using time node from parent game object. If a component needs "Update", it has a time node option too, default value is "Inherit" - it means using time node from the attached game object. Now, we can update all the components of a character in a same time setting automatically, whether it is physics, animation, particle system or even audio.

    This design is used to replace current scaled & unscaled time settings. This makes it easier for developers to implement time-related designs, such as game pause, bullet time, slow down skill, and other cool things, you can even make a game like Braid.
     
    april_4_short likes this.
  2. MartinMa_

    MartinMa_

    Joined:
    Jan 3, 2021
    Posts:
    455
    I dont get why it is better then just *float
     
    Bunny83 likes this.
  3. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,741
    You could implement this on your own. Something like this:
    Code (csharp):
    1. public class LocalTimeScale : MonoBehaviour {
    2.    public float timeScale = 1f;
    3.  
    4.    public static float GetTimeScaleMultiplier(Transform transform) {
    5.       float timeScale = 1f;
    6.       Transform thisTransform = transform;
    7.       while (thisTransform != null) {
    8.          var lts = thisTransform.GetComponent<LocalTimeScale>();
    9.          if (lts != null) timeScale *= lts.timeScale;
    10.          thisTransform = thisTransform.parent;
    11.       }
    12.       return timeScale;
    13.    }
    14.  
    15.    public static float GetDeltaTime(Transform transform) {
    16.       return GetTimeScaleMultiplier(transform) * Time.deltaTime;
    17.    }
    18. }
    19.  
    20. //anywhere else
    21. transform.Translate(Vector3.forward * LocalTimeScale.GetDeltaTime(transform));
    22.  
    I guess you'd have to do some extra work for stuff like Animators to work correctly but not too much, since you can play with animator.speed and such.
     
    Bunny83 likes this.
  4. yu_yang

    yu_yang

    Joined:
    May 3, 2015
    Posts:
    60
    Except the physics engine, most components expose some APIs to handle time scaling, but in a real game project, handling these things is very cumbersome. For example, some particle effects in our game need to be played at unscaled time. When the game is paused (Time.timeScale=0), other particle effects will be paused normally, but these particle effects will not be paused. We have to collect these particle effects through scripts and traverse them when the game is paused or resumed. This is just a particle system, other modules also need to do the same processing.
     
  5. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,507
  6. yu_yang

    yu_yang

    Joined:
    May 3, 2015
    Posts:
    60
    Thank you, Physics2D.Simulate is indeed used in our project, but it is global, not for each rigidbody. I hope that each rigidbody can be set to independent time scaling so that we don't have to do a lot of complicated processing.
    (Our current solution is that if we want to increase the time scale of a rigidbody, we convert it to increase its movement velocity. Before that, we have to record an unscaled velocity and adjust the acceleration applied to it, then scale the unscaled velocity and set it to rigidbody. If collision happen, we have to fix the recorded unscaled velocity. In short, this is complicated :)
    In addition, Time Hierarchy is used to solve different problems, not only related to the physics engine.
     
    Last edited: Jul 28, 2021
  7. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    I wanted something sort of like this a long while back and I created my "SPTime" and "ITimeSupplier" for it:

    SPTime
    https://github.com/lordofduct/space...lob/master/SpacepuppyUnityFramework/SPTime.cs

    ITimeSupplier:
    https://github.com/lordofduct/space...ter/SpacepuppyUnityFramework/ITimeSupplier.cs

    CustomTimeSupplier (used to create custom times):
    https://github.com/lordofduct/space...pacepuppyUnityFramework/CustomTimeSupplier.cs

    For starters it gave object identity to which time mode you wanted so that way you can consume an object representing which time you wanted to tick by.

    But also you could add custom time suppliers that had specific scales (like what you described above).

    Like my summary says:
     
    april_4_short likes this.
  8. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,507
    How would per body simulation work? That makes no sense to me or at least I'm not sure how interaction between two colliders using two different time-scales would work or why it would be required.

    If these bodies/colliders don't interact then you can place them in separate local physics scenes and simulate them independently.
     
    StarManta likes this.
  9. yu_yang

    yu_yang

    Joined:
    May 3, 2015
    Posts:
    60
    Such requirements are indeed difficult to understand for general games, they are related to science fiction or magic stories. Imagine an object (or character) whose time is accelerated. In its own view, its states are normal (states refer to velocity and angular velocity), but they are accelerated for others.
    What happens to the collision of rigidbodies scaled at different times? Here we need to distinguish between self-states and absolute states. When a collision occurs, calculate their absolute states after the collision according to the absolute states before the collision, and then calculate their self-states according to the time scale values of themselves.
    If Unity supports modifying the time scaling of rigidbody, I'm sure there will be many developers using it to make interesting games in the future.
     
    Last edited: Jul 28, 2021
  10. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,507
    Sorry but none of that makes any sense to me because it's shrouded in your own terminology. You can apply velocity changes with a scaled time so that affects acceleration however when that object hits another object (with another time-scale) it hits it with a higher velocity which affects it differently. Collisions are not directional, they are mutual. At this point, it's NOT a time-scaled thing, it's a velocity-scaled thing. It's this I'm confused about and why you'd want such interactions.

    If by states you mean it has to have some state according to all the different objects which all might be at potentially different time-scales then it just gets complex. It's also something that would need to rewire the core of the 2D and 3D physics systems and I've yet to hear an advantage which would outweight the disadvantage of everyone paying for this even if they're not using it.

    I think you'd need to break this down into two bodies at completely different time-scales and detail how they'd change position, how contacts should be created between them and how collision responses should be scaled.

    I'm hoping something useful comes out of the discussion for sure but right now I see a solution looking for a problem.
     
  11. koirat

    koirat

    Joined:
    Jul 7, 2012
    Posts:
    2,008
    Can you write equation for this.
    Frankly speaking as was mentioned above I also got problem understanding how time scale would work, I can image slowing or speeding up rigid body depending on time scale, but collision of objects with different time scale is quite difficult to imagine.
    Something like identical bodies collide but one bounce faster than other ?
     
  12. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,741
    And every scifi or magic universe will have its own rules for what happens when two objects in different physics time scales interact with each other.

    You cast "freeze time" on an enemy, then go punch them. Do they fall over like a statue from the velocity of your punch, or do they not move at all because their time is frozen? Your game may want the first, but my game might want the second.

    There is no correct answer because "two objects with different time scales interacting" isn't something that's possible in the real world. Asking a general-purpose game engine to support this is frankly an absurd request.

    Write your own.
     
    lordofduct likes this.
  13. yu_yang

    yu_yang

    Joined:
    May 3, 2015
    Posts:
    60
    Let me explain some concepts with examples.
    In the original physics engine, imagine two identical balls, A and B, moving in a straight line and about to collide. The speed of A is 1, and the speed of B is -1. After the collision, both are stationary.
    Now, add time scaling to rigidbodies. The default time scaling of all rigidbodies is 1. We change the time scale of A to 2, then self-speed is still 1, but the absolute speed becomes 2.
    The collision only cares about absolute speeds. Before the collision, the absolute speed of A was 2, and the absolute speed of B was -1. After the collision, the absolute speeds of both became 0.5. Since A's time scale is 2, self-speed is now 0.25.
    Why introduce the concept of self-speed and absolute speed? This is to facilitate modification of time scaling. Now, if the time scale of A is changed from 2 to 1, self-speed will remain unchanged at 0.25, and the absolute speed will change from 0.5 to 0.25. In addition, when applying force (acceleration) to an object, it can be applied to self space, no matter how the time scaling changes, there is no need to change the magnitude of the applied force (acceleration).

    This is actually an interesting language problem. The core of the problem lies in explaining the word "freeze", and has nothing to do with the timeScale I discussed. You can understand that I am discussing the second situation. The first situation can be directly implemented in the current game engine, it is just a visual effect, and there is no requirement for the physics engine.
    In the second situation, this is actually a "divide by 0" problem. After the collision, the absolute speed is divided by 0 to get self-speed. What should it be? I can't answer this question, but what is certain is that the absolute speed after it is still 0.
    The self-speed calculation rule after the collision discussed above is a default rule. I suggest allowing developers to customize it, including the case where the timeScale is 0.

    To add time scaling to the rigidbody, you only need to add a little bit of code to the physics engine, and it will not affect existing projects. The main content is as follows:
    the rigidbody adds selfVelocity and selfAngularVelocity, the existing velocity and angularVelocity are absolute velocity and absolute angular velocity;
    timeScale is added to the rigidbody, the default is 1;
    Keep velocity and angularVelocity equal to selfVelocity and selfAngularVelocity multiplied by timeScale, when modifying timeScale, selfVelocity and selfAngularVelocity remain unchanged;
    After the collision, let selfVelocity and selfAngularVelocity equal to velocity and angularVelocity divided by timeScale (allowing developers to customize it);
    Provide APIs such as AddForceSelf.

    If you don't want to influence general developers, you can make it an optional package.
     
  14. yu_yang

    yu_yang

    Joined:
    May 3, 2015
    Posts:
    60
    In addition, regardless of whether the rigidbody allows time scaling or not, be sure to consider adding Time Hierarchy to unity.
     
  15. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,741
    Yet you expect the physics engine developer to? Because they'd have to. I still think you haven't thought through the implications of having differently-timescaled rigidbodies interacting with each other.

    Let's try a simpler scenario scenario, a time-warped pool game. You set the timeScale of the 8-ball to zero, and then hit it with the cue ball at speed 1, then set its timescale to 1. What happens to it? Does it remain still? The only way for that to make sense would be that it fully removes itself from physics calculations. Does it receive a speed of 1 from the cue ball's collision? That might seem like the instinctively right answer, but it's nonsense tbh, because from the point of view of the 8-ball, it was hit with the cue ball at infinite velocity, so that's the velocity it should shoot off at when it's unfrozen. But now we don't have conservation of momentum because we put 1 m/s into the system and got infinity m/s out of it. So that's also nonsense.

    (And if you think you've got that problem solved, repeat the question with the timescale of the 8-ball being 0.00001 instead of 0. Or 10,000. It makes even less sense than the zero-scale situation.)

    Which is the key word here. Having differently-time-scaled rigidbodies interacting with each other is inherently nonsense. It's something that literally can't exist in realistic physics. Again, if you want to pick a way to interpret the nonsense for your game's reality, have at it! Write your own physics engine to handle those interactions! We're not stopping you! But you're not doing that, you're asking the developer to write nonsense into a reality-based physics engine. Hard pass.

    You can make it an optional package
     
  16. koirat

    koirat

    Joined:
    Jul 7, 2012
    Posts:
    2,008
    Well anyway it is not going to happen. I don't think physx supports rigidbody scoped time scale and unity team is not going to modify physx source.
     
  17. yu_yang

    yu_yang

    Joined:
    May 3, 2015
    Posts:
    60
    I think I have explained my idea, no matter how to calculate the velocity after collision, to support time scaling, it must contain a concept of self-speed, just like Transform must contain localPosition.

    This problem is only encountered when the rigidbody's timeScale is set to 0. Not every project that requires rigidbodies to support timeScale needs to consider this situation. Unity can provide several options by default, such as: keep unchanged, keep at 0, infinity, consistent with velocity...Developers set it according to their own project needs. It is best, as I said, to allow developers to customize this calculation formula.

    We have implemented this in our project, but it has some restrictions, such as calculation of the selfVelocity of the rigidbody after collision is very expensive (a MonoBehaviour and collision handling events must be added), this It can only be achieved by modifying the engine code.