美文网首页
DOT Training Sample —— Jump The

DOT Training Sample —— Jump The

作者: 珏_Gray | 来源:发表于2019-11-18 16:13 被阅读0次

    https://github.com/Unity-Technologies/DOTS-training-samples


    Original

    代码清单:

    • Box.cs
    • CameraControl.cs
    • Cannonball.cs
    • CannonballPrefab.cs
    • Game.cs
    • Options.cs
    • OptionsToggle.cs
    • Parabola.cs
    • Player.cs
    • SliderProp.cs
    • Tank.cs
    • TerrainArea.cs
    1. Box.cs

    构成场地的各个立方体。

    namespace JumpTheGun {
    
        public class Box : MonoBehaviour {
    
                    //立方体位置的间隔,默认为1,当立方体长度也为1时,正好无缝
            public const float SPACING = 1; 
    
                    // 竖直方向的偏移,没什么用
            public const float Y_OFFSET = 0;
    
                    // 最低高度
            public const float HEIGHT_MIN = .5f;
    
                    //最低高度的颜色
            public static Color MIN_HEIGHT_COLOR = Color.green;
    
                    //最高高度的颜色
            public static Color MAX_HEIGHT_COLOR = new Color(99 /255f, 47 /255f, 0 /255f);
    
                    //当前box处于第几行、第几列
            public int col { get; private set; }
            public int row { get; private set; }
    
                    //高度访问器,修改高度时,调用UpdateTransform
            public float height {
                get {
                    return _height;
                }
                set {
                    _height = value;
                    UpdateTransform();
                }
            }
                  //  顶部的高度(local space)
            public float top {
                get {
                    return transform.localPosition.y + height / 2;
                }
            }
                //   颜色访问器
            public Color color {
                get {
                    return meshRenderer.material.color;
                }
                set {
                    meshRenderer.material.color = value;
                }
            }
               // 设置box的行、列、高度,并调用UpdateTransform
            public void SetBox(int col, int row, float height){
                this.col = col;
                this.row = row;
                this.height = height;
                UpdateTransform();
            }
             
    //检测box是否与参数传入的正方体碰撞
            public bool HitsCube(Vector3 center, float width) {
                            //box的bounds
                Bounds boxBounds = new Bounds(transform.localPosition, new Vector3(SPACING, height, SPACING));
                            //正方体的bounds
                Bounds cubeBounds = new Bounds(center, new Vector3(width, width, width));
    
                return boxBounds.Intersects(cubeBounds);
            }
    
    //更新transform组件,且根据高度改变颜色
     // 访问Game.instance.maxTerrainHeight获得最高高度
            public void UpdateTransform(){
    
                Vector3 pos = new Vector3(col * SPACING, height / 2 + Y_OFFSET, row * SPACING);
                Vector3 scale = new Vector3(1, height, 1);
    
                transform.localPosition = pos;
                transform.localScale = scale;
    
                // 改变颜色,根据高度线性插值
                if (Mathf.Approximately(Game.instance.maxTerrainHeight, HEIGHT_MIN)) {
                    color = MIN_HEIGHT_COLOR;
                } else {
                    color = Color.Lerp(MIN_HEIGHT_COLOR, MAX_HEIGHT_COLOR, (height - HEIGHT_MIN) / (Game.instance.maxTerrainHeight - HEIGHT_MIN));
                }
    
            }
                  //box被炮弹打中后,降低一定高度
            public void TakeDamage(){
                height = Mathf.Max(HEIGHT_MIN, height - Game.instance.boxHeightDamage);
            }
    
            // Use this for initialization
            void Awake() {
                meshRenderer = GetComponent<MeshRenderer>();
            }   
                 // 高度
            private float _height = 1;
              // Mesh renderer引用,用来修改颜色
            private MeshRenderer meshRenderer;
    
        }
    
    }
    
    2. Cannonball.cs && CannonballPrefab.cs
    • CannonballPrefab.cs: 单例,引用加农炮prefab资源,之后可用CannonballPrefab.instance.cannonballPrefab访问
    • Cannonball.cs 静态成员和方法实现对象池。发射方法,根据抛物线更新自身位置,检测碰撞。依赖TerrainArea类、Game类
    3. Parabola.cs

    抛物线类。只有两个静态方法。

    其余省略,面向对象大家都比较熟悉就不赘述了。本来想画下类之间的依赖关系图。但其实就是一团乱麻。当然,你可以想方设法让代码看起来“漂亮”些,但其实复杂度的本源是问题本身。你对问题的数据分析和建模,以及采用的算法才是你该着重思考的部分。传统的面向对象经常使我们没法跳出框架,尝试用不同的角度去分析问题,更不用说,它经常使我们陷入一些无意义的框架陷阱。


    Ported

    代码清单:

    • BlockTransformSystem.cs
    • CannonballSystem.cs
    • ComponentTypes.cs
    • FollowPlayer.cs
    • NewGameProxy.cs
    • NewGameSystem.cs
    • Options.cs
    • Parabola.cs
    • PlayerBouceSystem.cs
    • PlayerPositionCacheSystem.cs
    • TankAimSystem.cs
    • TankFireSystem.cs
    • TerrainSystem.cs

    主要是找ECS和非ECS之间的状态(数据)传递的方法。虽然传统的OOP有很多弊端,但并不是一无是处。同样的,ECS也不是解决所有问题的银色子弹。我们要灵活地应用它们来解决问题。

    Method 1: Cache State in System (ECS -> Monobehavior)

    我们可以将数据保存一份在system中,之后我们可以在Monobehavior中使用World.Avtive.GetOrCreateSystem得到system实例就能访问数据了。ECS有明确要求Component不能有方法,但System里是可以有成员变量的(并不是鼓励,我们需要仔细考虑)。关于System间的依赖关系,我们尽可能通过系统的执行顺序,和读写ComponentData来减少。

    Method 2: Save reference in System (Monobehavior <-> ECS)

    其实跟方法1本质相同,当我们允许在System保存变量后,就可以使用GameObject.Find方法在ComponentSystem中获得Monobehavior的实例引用。

    Method 3 : Singleton or Global Variable

    单例和全局变量很显然也可以轻易的获得引用。但我们要警惕,全局的mutable变量很有可能带来灾难。

    Method 4: Singleton Component/Entity ?

    ECS的很大优势在于其内存布局,大大加快我们遍历数据的速度。但这有个前提,需要许多同类型的对象,“Where there is one,there is many”。可在游戏中,我们同样有许多“manager”,它们只需要一个实例。对于这种情况,应该与普通的Component区别对待。Unity还在完善和优化这种少量Entity的情况。

    代码详情:

    1. ComponentType.cs

    所有Component Data类型。

    namespace JumpTheGun {
        // Use a 2D position for block entities, mainly to avoid the default
        // EndFrameTransformSystem (in favor of BlockTransformSystem).
        struct BlockPositionXZ : IComponentData
        {
            public float2 Value;
        }
        struct BlockHeight : IComponentData
        {
            public float Value;
        }
        // Index of a block in the terrain cache array.
        struct BlockIndex : IComponentData
        {
            public int Value;
        }
    
    //抛物线轨迹
        struct ArcState : IComponentData
        {
            public float3 Parabola; // a, b, c parameters
            public float StartTime;
            public float Duration;
            public float3 StartPos;
            public float3 EndPos;
        }
    //坦克开火cd
        struct TankFireCountdown : IComponentData
        {
            public float SecondsUntilFire;
        };
    
        // Marks blocks whose LocalToWorld matrix need to be updated after
        // their height changes.`
        struct UpdateBlockTransformTag : IComponentData {}
        // Tags to differentiate tank base & tank cannon entities.
        // TODO(@cort): use IJobChunk to filter based on MeshInstanceRenderer value instead?
        struct TankBaseTag : IComponentData {}
        struct TankCannonTag : IComponentData {}
    }
    
    2. BlockTransformSystem.cs

    Block指构成地形的立方块。这个系统的作用是更新blocks的transform,即LocalToWorld Matrix。

    Jobs List:
    1)BlockTransformJob 。
    Query:

    权限 ComponentType
    Read BlockPositionXZ
    Read BlockHeight
    Read UpdateBlockTransformTag
    ReadWrite LocalToWorld
    因为我们需要在Job中删除UpdateBlockTransformTag组件,所以必须使用EntityCommandBuffer。这里我们使用BeginSimulationEntityCommandBufferSystem提供command buffer。
    namespace JumpTheGun
    {
        // For blocks marked with UpdateBlockTransformTag, use their position
        // and height to compute a new LocalToWorld matrix.
        [UpdateAfter(typeof(TerrainSystem))]
        [UpdateBefore(typeof(TransformSystemGroup))]
        public class BlockTransformSystem : JobComponentSystem
        {
            //[BurstCompile] // Can't currently add/remove components in Burst jobs
            struct BlockTransformJob : IJobForEachWithEntity<BlockPositionXZ, BlockHeight, UpdateBlockTransformTag, LocalToWorld>
            {
                public EntityCommandBuffer.Concurrent CommandBuffer;
    
                public void Execute(Entity entity, int index, [ReadOnly] ref BlockPositionXZ position,
                    [ReadOnly] ref BlockHeight height, [ReadOnly] ref UpdateBlockTransformTag _, ref LocalToWorld localToWorld)
                {
                    float3 fullPos = new float3(position.Value.x, 0.0f, position.Value.y);
                    float3 fullScale = new float3(1.0f, height.Value, 1.0f);
                    // TODO(cort): Use WriteGroups here instead
                    localToWorld = new LocalToWorld
                    {
                        Value = math.mul(float4x4.Translate(fullPos), float4x4.Scale(fullScale))
                    };
                    CommandBuffer.RemoveComponent<UpdateBlockTransformTag>(index, entity);
                }
            }
    
            private BeginSimulationEntityCommandBufferSystem _barrier;
            protected override void OnCreateManager()
            {
                _barrier = World.GetOrCreateSystem<BeginSimulationEntityCommandBufferSystem>();
            }
    
            protected override JobHandle OnUpdate(JobHandle inputDeps)
            {
                var handle = new BlockTransformJob
                {
                    CommandBuffer = _barrier.CreateCommandBuffer().ToConcurrent(),
                }.Schedule(this, inputDeps);
                _barrier.AddJobHandleForProducer(handle);
                return handle;
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:DOT Training Sample —— Jump The

          本文链接:https://www.haomeiwen.com/subject/kkpvictx.html