Not Understanding what is going on with physics

Hello everyone. I am new to Unity DOTS, so my question may be a little silly, but I am really frustrated at the moment

I have some simple scene: just 2 cubes as platforms and a character (who is just a cylinder in fact). All of them are with Box Colliders. Character also has a Rigidbody Component and a very simple MovementComponent (stores float speed and float3 target). Lastly there is one ISystem - MovementSystem. It moves Character to the given target with a given speed. Also Unity Physics package was added to the project of course. Nothing extraordinary, as I said before

public struct MovementComponent : IComponentData
{
    public float speed;
    public float3 target;
}

public class MovementAuthoring : MonoBehaviour
{
    public float speed;
    public float3 target;
    public class Baker : Baker<MovementAuthoring>
    {
        public override void Bake(MovementAuthoring authoring)
        {
            AddComponent(this.GetEntity(TransformUsageFlags.Dynamic), new MovementComponent { speed = authoring.speed, target = authoring.target });
        }
    }
}
public partial struct MovementSystem : ISystem
{
    public void OnCreate(ref SystemState state)
    {
        state.RequireForUpdate<MovementComponent>();
    }

    public void OnUpdate(ref SystemState state)
    {
        var moveJob = new MovementJob { time = SystemAPI.Time.DeltaTime };
        moveJob.Schedule();
    }
}

public partial struct MovementJob : IJobEntity
{
    public float time;
    public void Execute(ref LocalTransform transform, in MovementComponent movementComponent)
    {
        float3 dir = math.normalize(movementComponent.target - transform.Position);
        transform.Position += dir * time * movementComponent.speed;
    }
}

So I have 2 questions, which can be described with this video:

So the questions are:

  1. Why my cylinder jumped? I didn’t press any button, didn’t do anything at that moment at all. Also that has happened not one time. I am not sure if I can stably recreate that thing, but at least I know that it happened 3 or 4 times.
  2. Why my cylinder can rotate because of the gravity and how can I fix that? As can be seen on the video, I checked the boxes in the Rigidbody Component to freeze rotation, but it does not work at all. Before this, cylinder also was just falling down on the side when it was starting to climb up. For some reason now it doesn’t happen, I don’t know why :frowning: Maybe it is a little random, and I am just a little unlucky.

And also there is an additional question, which is not connected with the video before:
I tried to RayCast from the LocalTransform.Position of that cylinder to the “new float3 (0, -100, 0)”. I was expecting to see that it detected the cube under it, but it doesn’t. So it is also a frustrating situation for me

Hi!

Few things I can point out to help you :

Before testing ecs behaviour, by pressing play, it is better to close the tested subscene. You should be able to modify the target position of the MovementComponent from the entities hierarchy (Window->Entities->hierarchy). Changing the authoring component value during play mode is specifically not a good practice. The idea behind the authoring component is that you bake data in a runtime format, and as baking does not happen at runtime (in your built application), it make little sense to change the authoring component and trigger baking during playmode (i even did not know that it could be done). So if you want your playmode simulation to behave as close as the game once built, close your subscene and check the entity hierarchy.

But the origin of your problems does not lie in closing or not the subscene, it comes from the fact that you are changing the transform of a physic entity. As in classic rigidbodies physics from gameobjects, changing the transform of a physic object directly will lead to undefined behaviours, as the transform system will “fight” with the physics system to move your entity.

So in order to move your physics objects, either they are dynamic and you move them with forces (there is an extension in the physic package that allow you to take a physic body and apply forces to them), or they are kinematic, as in the case of a character controller, and it then become a lot harder as you have to manage a lot more (for instance a kinematic character controller is pretty tough to make). Fortunately, unity (or more specifically Phil st Amand) made one for you : the package com.unity.charactercontroller.

Regarding why you character jumped, i believe it is because the transform system tried to push it under the floor (z-target was set to -8), and once its collider was overlapping with the floor collider, the collision response made it fly. The fact it was sent flying that high comes from the stateless nature of the physics package, which, in the contrary of havok, make all collision response more, hum…, Let say more “violent” (but that is an other subject, i digress)

Anyway, let me know if I you need more help to setup what you are trying to do.

Firstly, thank you very much for such a detailed answer. It really helped me to understand some DOTS things better. Also wanted to add that I am preparing to make something similar to RTS game, so this “character” would be an ordinary unit, not a detailed main character under player’s direct control. Maybe that information will be helpful, because yeah - I have some more questions to ask…

  1. As I understand for my “character” I should use dynamic, not kinematic physics model, right? (In fact I don’t understand where it could be useful to choose kinematic instead of dynamic) Also for moving I should change PhysicsVelocity.Linear (or maybe even PhysicsVelocity.Linear.xz) value, right?
    If I am right in these questions (which I am not sure at all), then it doesn’t work, as I thought or I just messed up in some other thing. Here is the new Job for that kind of moving:
public partial struct MovementJobVelocity : IJobEntity
{
    public float time;
    public void Execute(ref LocalTransform transform, in MovementComponent movementComponent, ref PhysicsVelocity velocity)
    {
        float3 dir = math.normalize(movementComponent.target - transform.Position);
        velocity.Linear.xz = dir.xz * time * movementComponent.speed;
    }
}

And there is a video, showing the result

So as you can see on the video, cylinder don’t move until I make the speed value very high. Moreover, when it is starting to move it just fall on its side. And the problem here is that I still have “Freeze Rotation” checks on X and Z coordinates. In other words I still don’t understand why my cylinder rotates, when I have “frozen” its rotation; and I don’t understand how to make moving smoother (as I don’t understand why it needs such a big value to start mooving. Maybe drag is a main source of problems here? If so, how can I solve these problems?) Maybe problems here are because of wrong understanding of velocity.Linear property (main source of information on that was that page of documentation - Attracting bodies to an entity | Unity Physics | 1.0.16)

  1. Am I right, that when I close Subscene for editing, I should use Entities Hierarchy, if I want to check or correct some data in entities` components?
  2. What is DebugDisplay.DrawComponent? It can be seen in the hierarchy in the video. It is outside of the subscene, so I suppose it is some MonoBehavior. Also if I delete it and start play, it reappears, which frustrates me a little. Of course it is quite obvious from the name, that it is some debug thing; but still I am frustrated a little, as I do not know anything else about that uninvited resident of my scene…

I need to ask you something before answering your questions. What is the physics used for in your game? Is it to avoid unit collision? Or is it for some projectile-unit collision? Or is it for something else? Just need a bit more info to better understand your use case of physics.

Yeah, I suppose it won`t be anything more than just to avoid unit collision. Well, also using physics may be a solution for units not to go through the terrain, as it will be not just a plane (there will be some mountains, or lowlands, or something like that).
It is not so complex task, and it was a thought in my mind before, that using a Physics just for that can be a little too much. So I tried to use Raycasts to solve the problem with terrain just by giving the y coordinate of units the value of CastRay result. But as you saw in my first message, I have faced with some problems there, so I tried to use Physics for that, which led me here :slight_smile:

Just noticed the end of your first message, I did not make the connection with RTS like game when first reading it. I’m not an expert in RTS games, but for the little I know, I believe the raycast solution is the one you should go with. Let’s try to solve your raycast problem. What collision filter are you setting in your raycast?

public partial struct MovementJob : IJobEntity
{
    public float time;
    public CollisionWorld collisionWorld;
    public void Execute(ref LocalTransform transform, in MovementComponent movementComponent)
    {
        RaycastInput rayDown = new RaycastInput
        {
            Start = transform.Position,
            End = new float3(0, -100, 0),
            Filter = new CollisionFilter
            {
                BelongsTo = ~0u
            }
        };
        if (collisionWorld.CastRay(rayDown, out Unity.Physics.RaycastHit closestHit))
        {
            transform.Position.y = closestHit.Position.y + 1;
        }
        else
        {
            Debug.Log("ERROR: Terrain under unit is not found");
        }
        float3 tempDir = movementComponent.target - transform.Position;
        tempDir.y = 0;
        float3 dir = math.normalize(tempDir);
        transform.Position += dir * time * movementComponent.speed;


    }
}

I tried to use that code and two more variants, when the Filter part is uncommented:

  1. With the value ~0u
  2. With the value 128u
    Plane under the cylinder has 6th layer, so last variant`s value is because of it (2^7 = 128. As I understand that is the int value for the 6th layer, if we are counting layers from 0).
    And also as I understand not valued Filter or Filter = ~0u means that all layers will be included in calculations.

Also, I should answer your 3 questions, for the first one, linear Velocity does not need you to multiply by deltaTime, which means (as fixedDeltaTime is often inferior to 0.02) that you had to set your speed value around 50 to get a movement of equivalent to one meter per second. Regarding rotating while frozen, I’m not actually sure, as I don’t use the classics gameObject rigidbodies to bake my physics object. I’ll try to investigate on this.

About your second question, yes, you are right, when you close subscenes for editing and press play mode, modifing component values in the entities hierarchy is the good way to go to test and debug.

About your third, don’t mind it, it seems to always be there with physics, and it does not harm your project. I suppose you should just leave it and forget about it.

About raycast, modify your code to do this (replace 3 with any layer your terrain is into):

var raycastInput = new RaycastInput()
{
    Start = transform.Position,
    End = transform.Position + math.mul(transform.Rotation, new float3(0f,-data.RayLenght,0f)),
    Filter = new CollisionFilter()
    {
        BelongsTo = ~0u,
        CollidesWith = 1u << 3, 
        GroupIndex = 0
    }
};

Wait, I just remembered that you use the classic gameobject rigidbody and collider component for baking. Just to test, import the custom authoring monobehaviours, from the sample of the physics package (check the package manager). Then create a PhysicsMaterialTemplate for the terrain (Right Click in folders, Create->UnityPhysics->PhysicsMaterialTemplate), and assign 3 (or what you want, as long as you keep it consistent in raycast code) to the belongsTo layers, leave collide with everything. Add the physicsShape component instead of the mesh collider of your terrain, and put the terrain physicsMaterialTemplate in it. It should work after that.

Well, yeah it works now! =)
But can you please explain some things:

  1. What math.mul (quaternion, float3) is for? I have only found info (Method mul | Mathematics | 1.2.6) about different variants of mul (floatsome number, floatsome number), which makes a scalar product or just a matrix multiplication. But what means the resulting float3 of variant with quaternion?
  2. What is about ~0u in CollisionFilter properties? What does this syntax mean?
  3. Why does this solution does not work with the classic GameObject Rigidbody and Collider Component?
  1. I took the code from my tank controller, that needs the raycast to check if the tank is grounded to be rotated when the tank’s x rotation changed while climbing a slope. It is not necessary in your case, as your unit probably won’t rotate on the x-axis. You can replace it by End = transform.Position + new float3(0f,-rayLength,0f);

  2. It is bit-mask syntax, 0u is every bit to 0, so belongs to (edit : and not collides with) nothing, and ~ invert this mask, settings all layers bit value to 1, so belongsTo everything.

  3. I’m used to the custom authoring components and only use them, so I might be wrong, but I believe the physicsMaterialTemplate feature can not be used easily with classic colliders components (maybe with baking systems it is possible). The unity team has not implemented this feature into the physics classic components, but they want to. See : Official - Upcoming authoring changes for Unity Physics and Havok Physics for Unity - Unity Forum

1 Like

Well, in fact in my future project there will be some kind of vehicles (as well as tanks, I suppose), so I also need this feature to rotate units on x and z axes, depending on the terrain under them =) Because of that, if it is not hard for you, can you please explain that mul overload for me? I have some mathematical knoledge (finished first course of mathematical university), so I think (or at least hope :)) I should understand it

And about that authoring and classic Physics components. As I understood from your speech, all of these means that “Terrain Tools” package for Unity will not work properly with DOTS, right? Just because it has classic Terrain Collider, I suppose. If so, can you give an advice for me, what are my options about creating landscape, which will be not just a big plane (there will be mountaines, lowlands and something like that)?

Well, I’ll be honest with you, I don’t remember my algebra courses enough (and I don’t remember doing quaternions back then) to make a fully mathematical detailed explanation of the formula under, but here’s something I can give you. The implementation of unity mul for this specific overload is this, and just after it in math code comes the same method with a different name: rotate.

/// <summary>Returns the result of transforming a vector by a quaternion.</summary>
/// <param name="q">The quaternion transformation.</param>
/// <param name="v">The vector to transform.</param>
/// <returns>The transformation of vector v by quaternion q.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float3 mul(quaternion q, float3 v)
{
    float3 t = 2 * cross(q.value.xyz, v);
    return v + q.value.w * t + cross(q.value.xyz, t);
}

/// <summary>Returns the result of rotating a vector by a unit quaternion.</summary>
/// <param name="q">The quaternion rotation.</param>
/// <param name="v">The vector to rotate.</param>
/// <returns>The rotation of vector v by quaternion q.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float3 rotate(quaternion q, float3 v)
{
    float3 t = 2 * cross(q.value.xyz, v);
    return v + q.value.w * t + cross(q.value.xyz, t);
}

This name is more transparent of what this method does : it rotates a vector by a quaternion. Which is exactly what I needed. And all utility methods of the math class are commented explaining exactly what they are doing. So If you ever face this kind of problems, doing vehicle and tank controller, the math class should have a commented method to help you out, without rewriting complex quaternion formulas.

About Terrain package, you are right, it can’t be used directly in dots. There is a Unity.Physics.TerrainCollider struct, but it does not have any authoring components. Last time I looked, you could do terrain baking with custom code, but you have to say goodbye to tree colliders (from what I remember). Here is the thread : Using Unity Terrain with DOTS workflow - Unity Forum .

I must also say that the dots team is working on an ecs terrain package. It seems to be one of the active topics behind the doors with the animation package.

Ok, I think I understood everything as much as I can at the moment.
Thank you so much for your enormous help! If not you, I am not sure if I could cope with all that stuff.

2 Likes