docs.unity3d.com
Search Results for

    Show / Hide Table of Contents

    Simulate groups of bodies in separate physics worlds

    It is possible to simulate groups of bodies totally separately from each other, in separate physics worlds. Each body in each world is represented by a separate Entity and each Entity must have all components that are needed for physics simulation in its world. PhysicsWorldIndex.Value denotes the index of physics world that the Entity belongs to (0 is the default value and represents the main world). Note that Entities for different physics worlds will be stored in separate ECS chunks, due to different values of the shared component. To enable custom simulation of bodies in non-default worlds, you need to:

    1. Assign the respective bodies to different worlds.
    2. Create a system group that derives from CustomPhysicsSystemGroup.
    3. Make an empty constructor that calls the constructor from CustomPhysicsSystemGroup and provides it with world index values and a flag that indicates whether to share static bodies between worlds.
    4. Optionally override Pre/PostGroupUpdateCallback() or AddExistingSystemsToUpdate.

    Assign bodies to different worlds

    By default, bodies are assigned to the main physics world (world index 0). To assign a body to a different world, add a PhysicsWorldIndexAuthoring component to the GameObject you want to modify alongside its Rigidbody component. Then, set its World Index property to the desired value.

    CustomPhysicsSystemGroup

    When you override CustomPhysicsSystemGroup with your own group, you can freely specify the update order of that group via [UpdateBefore/After/InGroup] attributes. In the background, that group enables all physics systems to run in multiple groups - the main one, which processes world index 0 entities, and a custom one, which processes the specified world index entities. In the background, it creates PhysicsSystemGroup as part of your new group. In addition to enabling only base systems to run in that group, all user systems defined in PhysicsInitializeGroup, PhysicsSimulationGroup, BeforePhysicsSystemGroup and AfterPhysicsSystemGroup run in the new group, as well. PhysicsWorldSingleton and SimulationSingleton retrieval will return the singletons of the currently ran group. Example:

        [UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
        public partial class UserPhysicsGroup : CustomPhysicsSystemGroup
        {
            public UserPhysicsGroup() : base(1, true) {} // This physics group simulates entities with world index 1 and shares static entities with the main world.
        }
    
        [UpdateInGroup(typeof(PhysicsInitializeGroup))] // As the system updates inside [PhysicsSinitializeGroup], it will automatically be ran inside UserPhysicsGroup as well
        public partial class CheckWorldIndexSystem : SystemBase
        {
            protected override void OnUpdate()
            {
                var physicsWorldSingleton = GetSingleton<PhysicsWorldSingleton>();
                if (physicsWorldSingleton.PhysicsWorldIndex.Value == 0)
                {
                    // ...
                    // When ran as part of main physics group, this code path will be hit.
                }
                else
                {
                    // ...
                    // When ran as part of UserPhysicsGroup, this code path will be hit.
                }
            }
        }
    

    AddExistingSystemsToUpdate()

    • If your system is not in one of the mentioned groups above that automatically run in multiple groups, you need to add it on your own by overriding AddExistingSystemsToUpdate().

    BeforePhysicsSystemGroup and AfterPhysicsSystemGroup

    • If you have systems that have [UpdateBefore(typeof(PhysicsSystemGroup))] or [UpdateAfter(typeof(PhysicsSystemGroup))] and need them in the group that operates on non-default index entities, calling AddExistingSystemsToUpdate() won't work.
    • In those cases, replace those attributes with these: [UpdateInGroup(typeof(BeforePhysicsSystemGroup))] and [UpdateInGroup(typeof(AfterPhysicsSystemGroup))].
    • The systems should be ran properly in multiple groups when that is done.
    • These groups provide no behavior difference between [UpdateBefore(typeof(PhysicsSystemGroup))] or [UpdateAfter(typeof(PhysicsSystemGroup))] and aren't necessary if you don't use the multiple worlds feature.

    PreGroupUpdateCallback() and PostGroupUpdateCallback()

    These callbacks are called by CustomPhysicsGroup before/after the nested physics systems update. Sometimes, it is not enough for the systems just to be ran in two different groups in order to work properly. This mainly refers to state, for example, if your system has a NativeArray, it might need to be saved and switched by another array in a different group before it is ran. PreGroupUpdateCallback() is the place to switch state. Similarly, when the custom group finishes updating, you need to restore the main group state (in this example, an array). PostGroupUpdateCallback() is the place to do that. Internally, physics operates this way - in PreGroupUpdateCallback() - PhysicsWorldData is saved and replaced by another storage, and a proper PhysicsWorldSingleton is set up. Same applies for Simulation and SimulationSingleton. Finally, in PostGroupUpdateCallback() the main world data and singletons are restored.

    If overriding these methods, it is necessary to call base.Pre/PostGroupUpdateCallback(), so the physics properly switches state.

    Limitations

    The main physics world and all other physics worlds use the same PhysicsStep singleton.

    Next steps

    Now that you know how to create bodies, it would be a good time to learn about Collision queries and filtering. At that stage you should be all set for at least intermediate use of Unity Physics and can progress onto the more advanced topics such as understanding the Physics pipeline and modifying simulation as it is running (directly or via slotting in systems between physics pipeline stages) and getting a deeper understanding of how the code works.

    In This Article
    Back to top
    Copyright © 2026 Unity Technologies — Trademarks and terms of use
    • Legal
    • Privacy Policy
    • Cookie Policy
    • Do Not Sell or Share My Personal Information
    • Your Privacy Choices (Cookie Settings)