Unity官方Dots范例工程学习——Entities101-Tornado

  大家好,我是阿赵。继续学习Unity官方的DOTS例子。
  Tornado这个例子是Entites101的最后一个例子,是一个龙卷风特效的例子。

一、 Config

在这里插入图片描述

  打开SubScene看看,里面的Config物体上挂着脚本,记录了这个例子需要用到的各种参数。
  现在看这些参数会感觉莫名其妙,到了下面具体的功能再回头看会清晰一点。

二、 建筑生成部分

  这里用到了2个System,分别是BuildingSpawnSystem和BuildingRenderSystem。
  这里用到的组件是Bar:

public struct Bar : IComponentData
{
    public int pointA;
    public int pointB;
    public float length;
}

  这个组件可以理解成是组成建筑的一根积木,比如:
在这里插入图片描述

  在生成这些建筑的时候,会分成2种,一种是有高度的建筑物,另外一种是散落在地上的建筑材料。它们在生成的时候记录的是点,比如里面有100根积木,每根积木有2个顶点,那么就有200个顶点(这里只是举例,建筑物其实是3个顶点前后连接生成3根积木),在生成的时候会把这些顶点全部存在Config的实体里面,然后Bar的pointA和pointB,记录的就是存在Config里面的顶点坐标列表的index。
  在BuildingSpawnSystem里面,就是要生成这些Bar数据,首先是建筑数据:

for (int i = 0; i < 35; i++)
{
    int height = random.NextInt(4, 12);
    var pos = new float3(random.NextFloat(-45f, 45f), 0f, random.NextFloat(-45f, 45f));
    float spacing = 2f;
    var anchor = byte.MaxValue;
    for (int j = 0; j < height; j++)
    {
        points.Add(new float3(pos.x + spacing, j * spacing, pos.z - spacing));
        connectivity.Add(anchor);

        points.Add(new float3(pos.x - spacing, j * spacing, pos.z - spacing));
        connectivity.Add(anchor);

        points.Add(new float3(pos.x, j * spacing, pos.z + spacing));
        connectivity.Add(anchor);

        anchor = 0;
    }
}

在这里插入图片描述

  这里随机生成了35栋层高随机4到12的建筑物。
然后是地上的细节:

for (int i = 0; i < 600; i++)
            {
                var posA = new float3(random.NextFloat(-55f, 55f), 0f, random.NextFloat(-55f, 55f));
                var posB = posA;

                posA.x += random.NextFloat(-.2f, -.1f);
                posA.y += random.NextFloat(0f, 3f);
                posA.z += random.NextFloat(.1f, .2f);
                points.Add(posA);

                connectivity.Add(0);

                posB.x += random.NextFloat(.2f, .1f);
                posB.y += random.NextFloat(0f, .2f);
                posB.z += random.NextFloat(-.1f, -.2f);
                points.Add(posB);

                if (random.NextFloat() < .1f)
                    connectivity.Add(byte.MaxValue);
                else
                    connectivity.Add(0);
            }

在这里插入图片描述

  两者加在一起,就形成了整个场景建筑的数据了:
在这里插入图片描述

  把这些顶点组成Bar数据,存起来。
  然后在BuildingRenderSystem里面,使用IJobEntity进行多线程批处理,根据Bar数据,把具体的模型显示出来

public partial struct PointRenderJob : IJobEntity
{
    [ReadOnly] public NativeArray<float3> CurrentPoints;

    public void Execute(ref LocalToWorld ltw, in Bar bar, in BarThickness thickness)
    {
        var a = CurrentPoints[bar.pointA];
        var b = CurrentPoints[bar.pointB];

        var d = math.distance(a, b);

        var norm = (a - b) / d;

        var t = (a + b) / 2;
        var r = quaternion.LookRotationSafe(norm, norm.yzx);
        var s = new float3(new float2(thickness.Value), d);

        ltw.Value = float4x4.TRS(t, r, s);
    }
}

三、 风暴生成部分

1、 TornadoSpawnSystem

  这个System的作用是生成1000个粒子模型。并且随机位置:

public void OnUpdate(ref SystemState state)
{
    var config = SystemAPI.GetSingleton<Config>();
    var entities = state.EntityManager.Instantiate(config.ParticlePrefab, 1000, Allocator.Temp);

    var random = Random.CreateFromIndex(1234);

    foreach (var entity in entities)
    {
        var particle = SystemAPI.GetComponentRW<Particle>(entity);
        var transform = SystemAPI.GetComponentRW<LocalTransform>(entity);
        var color = SystemAPI.GetComponentRW<URPMaterialPropertyBaseColor>(entity);

        transform.ValueRW.Position = new float3(random.NextFloat(-50f, 50f), random.NextFloat(0f, 50f),
            random.NextFloat(-50f, 50f));
        transform.ValueRW.Scale = random.NextFloat(.2f, .7f);
        particle.ValueRW.radiusMult = random.NextFloat();
        color.ValueRW.Value = new float4(new float3(random.NextFloat(.3f, .7f)), 1f);
    }

    state.Enabled = false;
}

  如果单纯运行这个System,会看到这样的效果:
在这里插入图片描述

2、 TornadoSystem

  这个System会通过IJobEntity多线程计算粒子被龙卷风吸引的效果。
  先通过BuildingSystem.Position方法算出现在的时间点龙卷风应该所在的坐标,然后通过  BuildingSystem.TornadoSway算出龙卷风吸力摇摆的坐标,模拟物体绕着龙卷风旋转。
  然后通过摇摆的坐标和粒子本身的坐标做一个力的方向,让粒子模拟被龙卷风吸引着旋转的效果:

public void Execute(ref LocalTransform transform, in Particle particle)
{
    var tornadoPos = new float3(Tornado.x + BuildingSystem.TornadoSway(transform.Position.y, ElapsedTime),
        transform.Position.y, Tornado.y);
    var delta = tornadoPos - transform.Position;
    float dist = math.length(delta);
    delta /= dist;
    float inForce = dist - math.saturate(tornadoPos.y / 50f) * 30f * particle.radiusMult + 2f;
    transform.Position += new float3(-delta.z * ParticleSpinRate + delta.x * inForce, ParticleUpwardSpeed,
        delta.x * ParticleSpinRate + delta.z * inForce) * DeltaTime;
    if (transform.Position.y > 50f)
    {
        transform.Position.y = 0f;
    }
}

  结合起来,现在的龙卷风变成这样了,它会吸引粒子,并且在场景里面移动:
在这里插入图片描述

3、 CameraSystem

  做完上面2步之后,龙卷风动起来了,但摄像机并没有跟随着龙卷风移动。所以需要通过CameraSystem对摄像机进行控制。
  同样是通过BuildingSystem.Position得到当前时间点龙卷风所在的坐标,然后找到主摄像机,把坐标同步:

public void OnUpdate(ref SystemState state)
{
    var tornadoPosition = BuildingSystem.Position((float)SystemAPI.Time.ElapsedTime);
    var cam = Camera.main.transform;
    cam.position = new Vector3(tornadoPosition.x, 10f, tornadoPosition.y) - cam.forward * 60f;
}

四、 交互部分

  经过了上面的步骤,我们已经生成了建筑物,也生成了龙卷风效果,但现在龙卷风还不会破坏建筑物。
为了达到龙卷风会破坏建筑物的效果,我们看看最后的BuildingSystem。
  这里的做法有点类似于龙卷风吸引粒子的做法,也是通过Position得到龙卷风坐标,通过TornadoSway得到摇摆坐标,然后把进入范围内的bar的point从原来坐标吸到空中。
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值