Skip to content

门泊吴船亦已谋

Unity Physics 学习笔记 第三章 刚体的运动状态

本文介绍获取与修改刚体速度的方法
并实现控制立方体每隔一段时间朝随机方向运动,具有匀速运动与施加冲量两种方式

添加组件控制方向

我们新建一个用于控制运动方向的组件

MoveDirection.cs

[Serializable]
public struct MoveDirection : IComponentData {
    public Unity.Mathematics.Random random;
    public float timeToChangeDirection;
    public float2 direction;
}

解释:这里把 random 放进去是为了保证随机数生成的均匀性

然后写一个 Authoring 用来把这个组件添加到 Entity 上

RandomMoveCubeAuthoring.cs

public class RandomMoveCubeAuthoring : MonoBehaviour, IConvertGameObjectToEntity {
    public void Convert (Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) {
        var moveRandomCmpt = new MoveDirection {
            random = new Unity.Mathematics.Random ((uint) System.DateTime.Now.Ticks),
            timeToChangeDirection = new Unity.Mathematics.Random ((uint) System.DateTime.Now.Ticks).NextFloat (),
            direction = Unity.Mathematics.float2.zero
        };
        dstManager.AddComponentData (entity, moveRandomCmpt);
    }
}

配置 Entity

新建一个立方体 GameObject,移除 Box Collider,添加 Convert To Entity、Physics Shape、Physics Body 以及我们写的 RandomMoveCubeAuthoring 脚本
在 Physics Body 中把重力系数设为 0,线性阻尼设为 0.5。其他的用默认值就行

这样这个 GameObject 在启动后会被自动转化为 Entity 并具有物理相关的组件以及 MoveDirection 组件

控制运动状态

显然,写一个 System 生成随机方向,然后修改这个立方体的速度就行了

下面有匀速运动和添加冲量两个版本,区别在于匀速运动每一帧都把速度修改为指定值,而添加冲量只需要在方向改变的那一帧修改速度

这个是匀速版本的

public class RandomMoveSystem : JobComponentSystem {
    [BurstCompile]
    struct RandomMoveJob : IJobForEach<MoveDirection, PhysicsVelocity> {
        public float deltaTime;
        public void Execute (ref MoveDirection moveDirection, ref PhysicsVelocity velocity) {
            var dir = moveDirection;
            dir.timeToChangeDirection -= deltaTime;
            if (dir.timeToChangeDirection < 0) {
                dir.timeToChangeDirection += 1;
                dir.direction = 0.5f * math.normalize (dir.random.NextFloat2 () - new float2 (0.5f, 0.5f));
            }
            moveDirection = dir;
            var v = velocity.Linear;
            v = new float3 (dir.direction, 0);
            velocity = new PhysicsVelocity { Linear = v };
        }
    }
    protected override JobHandle OnUpdate (JobHandle inputDeps) {
        return new RandomMoveJob { deltaTime = Time.DeltaTime }.Schedule (this, inputDeps);
    }
}

这个是冲量版本的,发现立方体会受到线性阻尼的影响,如果不明显可以把线性阻尼再改大一点

public class RandomMoveSystem : JobComponentSystem {
    [BurstCompile]
    struct RandomMoveJob : IJobForEach<MoveDirection, PhysicsVelocity> {
        public float deltaTime;
        public void Execute (ref MoveDirection moveDirection, ref PhysicsVelocity velocity) {
            var dir = moveDirection;
            dir.timeToChangeDirection -= deltaTime;
            if (dir.timeToChangeDirection < 0) {
                dir.timeToChangeDirection += 1;
                dir.direction = 0.5f * math.normalize (dir.random.NextFloat2 () - new float2 (0.5f, 0.5f));
                var v = velocity.Linear;
                v += new float3 (dir.direction, 0);
                velocity = new PhysicsVelocity { Linear = v };
            }
            moveDirection = dir;
        }
    }
    protected override JobHandle OnUpdate (JobHandle inputDeps) {
        return new RandomMoveJob { deltaTime = Time.DeltaTime }.Schedule (this, inputDeps);
    }
}