【DOTS】基于DOTS的BUFF系统实现 (完全版)

在上一篇文章中写的buff很初期,很多细节都没有考虑到,在之后的几天我把他们完善了一下

现在的buff系统支持:
1、能够通用的给Entity添加、移除buff
2、异步的方式实现生命周期
3、支持外部配置Buff初始属性,例如配置不同等级的效果影响等
4、支持通过owner与target的其他属性影响到增加的buff属性
例如:owner有个宝物,效果是给target附加毒时多加x层。
5、提供封装的拓展方法,可简单快速的使用添加、移除等方法

基础结构:
在这里插入图片描述

废话不多说,直接贴代码:
BuffData + BuffTableData: 这个很简单,就是定义了一下Buff的基础结构,其中包含了时间、生命周期标记。配置数据中提供了一些需要外部配置的属性。

using System;
using Unity.Collections;
using Unity.Entities; 

namespace Core.Battle.Buff
{ 
    /// <summary>
    /// 说明:
    /// 由于DOTS的特性,数据就保证绝对的数据
    /// 生命周期的实现,改变为异步实现:当发生改变时,对BuffData的Flag做修改,System会一直迭代遍历BuffData的Flag,当发现
    /// 改动后,会执行对应逻辑,然后再修改回去。
    /// </summary> 
    public struct BuffData : IBufferElementData  
    {
        /// <summary>  
        /// buff的类型  
        /// </summary> 
        public BuffType BuffType;
        
        /// <summary>
        /// 名称
        /// </summary>
        public FixedString64Bytes Name;
        
        /// <summary>
        /// 描述
        /// </summary>
        public FixedString64Bytes Info;

        /// <summary>
        /// 来源Entity ID
        /// </summary>
        public Entity Owner;

        /// <summary>
        /// 目标
        /// </summary>
        public Entity Target;

        /// <summary>
        /// buff等级
        /// </summary>
        public int BuffLevel;
        
        /// <summary>
        ///  buff的层数
        /// </summary>
        public int BuffCount;
  
        /// <summary>
        /// buff的最大层数
        /// </summary>
        public int BuffMaxCount;
        
        /// <summary>
        ///  移除时是否移除所有层
        /// </summary>
        public bool RemoveAllCountOnRemove;

        /// <summary>
        ///  能否叠加
        /// </summary>
        public bool IsSuperposition;
        
        /// <summary>
        /// buff值
        /// </summary>
        public int BuffValue;

        /// <summary>
        /// buff生命周期标记
        /// </summary>
        public BuffFlag BuffFlag;
 
        /// <summary>
        /// buff的时间
        /// </summary>
        public BuffTime BuffTime;

        /// <summary>
        /// 为none就是默认的
        /// </summary> 
        public bool IsDefault()
        {
            return BuffType == BuffType.None;
        }
  
        /// <summary>
        /// 移除 --> 设置成默认即可
        /// </summary>
        public void SetDefault()
        {
            BuffType = BuffType.None;
        }
          
        
        public BuffData(BuffType buffType, Entity owner, Entity target,int buffCount, int buffLevel,double startTime,double duration,BuffTableData tableData)
        {
            BuffType = buffType;
            Owner = owner;
            Target = target;
            BuffCount = buffCount;
            BuffLevel = buffLevel;
            
            BuffMaxCount = tableData.BuffMaxCount;
            BuffValue = tableData.BuffValue;     
            RemoveAllCountOnRemove = tableData.RemoveAllCountOnRemove;
            IsSuperposition = tableData.IsSuperposition;
            Name = tableData.Name;
            Info = tableData.Info;
            
            BuffTime = new BuffTime
            {
                StartTime = startTime,
                EndTime = startTime + duration + tableData.Duration,
                Duration = tableData.Duration + duration,
                CurDuration = tableData.Duration + duration,
                TriggerTime = tableData.TriggerTime,
                TriggerTimer = 0
            };
            
            BuffFlag = new BuffFlag
            {
                IsNewAdd = true
            };
        }
        
        public void Add(BuffData otherBuff)
        {
            if (IsSuperposition)
            {
                BuffCount += otherBuff.BuffCount;
            }
            else
            {
                BuffCount =  otherBuff.BuffCount;
            }

            Owner = otherBuff.Owner;
            BuffLevel = otherBuff.BuffLevel;
            BuffMaxCount = otherBuff.BuffMaxCount;
            BuffValue = otherBuff.BuffValue; 
            
            BuffFlag.IsAdded = otherBuff.BuffCount;

            BuffTime.Duration = otherBuff.BuffTime.Duration; 
            BuffTime.EndTime = BuffTime.StartTime + BuffTime.Duration;
            BuffTime.TriggerTime = otherBuff.BuffTime.TriggerTime;
            BuffTime.CurDuration = BuffTime.Duration; 
        }
        
        /// <summary>
        /// 移除:标记移除,在执行完isRemove标记后,需要手动调用SetDefault
        /// </summary>
        public void Remove()
        {
            BuffFlag.IsRemove = true;
            BuffFlag.IsAdded = 0;
            BuffFlag.IsNewAdd = false;
            BuffFlag.IsReduce = 0;
            BuffFlag.IsTrigger = false;
        }
        
    }
 
    public struct BuffTime
    {
        /// <summary>
        ///  buff添加时的时间
        /// </summary>
        public double StartTime;

        /// <summary>
        ///  上次buff改变的时间
        ///  可能是添加层数也可能是减少层数
        /// </summary>
        public double RefreshTime;
          
        /// <summary>
        /// -1:常驻不触发
        /// buff触发时间
        /// 例如伤害跳动时间之类的
        /// </summary>
        public double TriggerTime; 
        public double TriggerTimer;

        /// <summary>
        ///  预计buff结束的时间
        /// </summary>
        public double EndTime;
        
        /// <summary>
        /// buff的持续时间
        /// </summary>
        public double Duration;
        public double CurDuration;

        /// <summary>
        /// 设置持续时间
        /// </summary> 
        public void SetDuration(double newDuration)
        {
            Duration = newDuration;
            CurDuration = newDuration;
        }
        
        public override string ToString()
        {
            return $"BuffTime [StartTime: {StartTime}, RefreshTime: {RefreshTime}, TriggerTime: {TriggerTime}, EndTime: {EndTime}, Duration: {Duration}]";
        }
    }
 
    public struct BuffFlag
    { 
        /// <summary>
        /// 添加     从无到有才触发
        /// </summary>
        public bool IsNewAdd; 
        /// <summary>
        /// 新增一层  已经有了,又增加了才触发(不会同时与IsNewAdd一起触发)
        /// 可能会增加很多层,这里就改成int了,如果增加了,就不为0
        /// </summary>
        public int IsAdded; 
        /// <summary>
        /// 可能会减少很多层,这里就改成int了,如果减少了,就不为0  
        /// </summary>
        public int IsReduce;    //已处理
        /// <summary>
        /// 是否触发            已处理
        /// </summary>
        public bool IsTrigger; 
        /// <summary>
        /// 是否需要移除了       已处理
        /// </summary>
        public bool IsRemove;
 
        public override string ToString()
        {
            return $"BuffFlag [IsNewAdd: {IsNewAdd}, IsAdded: {IsAdded}, IsReduce: {IsReduce}, IsTrigger: {IsTrigger}, IsRemove: {IsRemove}]";
        }
    }


    /// <summary>
    /// Buff数据表数据
    /// </summary>
    [Serializable]
    public struct BuffTableData : IBufferElementData
    {
        public FixedString64Bytes Name;
        public FixedString64Bytes Info;
        public BuffType BuffType;
        public int Level;
        public int BuffMaxCount;
        public int BuffValue;
        public bool RemoveAllCountOnRemove;
        public bool IsSuperposition;
        public double Duration;
        public double TriggerTime;

        public BuffTableData(int buffMaxCount, int buffValue,int level, bool removeAllCountOnRemove, bool isSuperposition, double duration, double triggerTime, BuffType buffType)
        {
            Name = "";
            Info = "";
            BuffType = buffType;
            BuffMaxCount = buffMaxCount;
            BuffValue = buffValue;
            Level = level;
            RemoveAllCountOnRemove = removeAllCountOnRemove;
            IsSuperposition = isSuperposition;
            Duration = duration;
            TriggerTime = triggerTime;
        }
    } 
}

外部BuffTableData的构建:可以写个拓展工具,用来编辑脚本资源,例如:
在这里插入图片描述

BuffType:定义了一下buff类型

namespace Core.Battle.Buff
{
    public enum BuffType
    {
        None,           // 无
        Damage,         // 直伤
        AddDamageValue, // 直伤伤害增加
    }
}

BuffTimeSystem:这个system里对buffData做处理,负责时间和标记的整理

using Unity.Burst;
using Unity.Entities;

namespace Core.Battle.Buff
{
    /// <summary>
    /// 只负责对时间做处理         古希腊掌管时间的神
    /// </summary>
    [BurstCompile]
    public partial struct BuffTimeSystem : ISystem
    {
        [BurstCompile]
        public void OnCreate(ref SystemState state)
        { 
        }

        [BurstCompile]
        public void OnUpdate(ref SystemState state)
        {
            // 先处理时间
            new UpdateTimeJob()
            {
                elapsedTime = SystemAPI.Time.ElapsedTime,
                deltaTime = SystemAPI.Time.DeltaTime, 
            }.ScheduleParallel(); 
        }
        
        #region 古希腊掌管时间的神
        
        [BurstCompile]
        public partial struct UpdateTimeJob : IJobEntity
        {
            public double elapsedTime;
            public double deltaTime; 
            
            [BurstCompile]
            void Execute(DynamicBuffer<BuffData> buffDataBuffer)
            { 
                for (int i = 0; i < buffDataBuffer.Length; i++)
                {
                    var buffData = buffDataBuffer[i];

                    //为None,说明会在下一帧被移除,这里不用管它   isRemove = true 说明被移除了,也不继续触发,并且应该取消其其他的所有状态来着
                    if (buffData.IsDefault() || buffData.BuffFlag.IsRemove)
                    {
                        continue;
                    }

                    var bt = buffData.BuffTime;
                    var bf = buffData.BuffFlag;

                    //如果没有间隔时间,则不触发
                    if (buffData.BuffTime.TriggerTime > 0)
                    {
                        if (buffData.BuffTime.TriggerTimer > 0)
                        {
                            bt.TriggerTimer -= deltaTime;
                        }
                        else
                        {
                            bf.IsTrigger = true;
                            bt.TriggerTimer = bt.TriggerTime;
                        }
                    }

                    // 持续时间为负数表示无限时间
                    if (bt.Duration > 0f)
                    {
                        bt.CurDuration -= deltaTime;
                        if (bt.CurDuration <= 0)
                        {
                            bf.IsRemove = buffData.RemoveAllCountOnRemove;
                            if (!buffData.RemoveAllCountOnRemove) //减少一层
                            {
                                buffData.BuffCount--;
                                bf.IsReduce = 1;
                                if (buffData.BuffCount <= 0)
                                {
                                    bf.IsRemove = true;
                                }
                            }
                        }
                    }

                    buffData.BuffTime = bt;
                    buffData.BuffFlag = bf;
                    buffDataBuffer[i] = buffData;
                } 
            } 
        } 
        #endregion  
        
    }
}

BuffRemoveSystem:负责移除空buff

using Unity.Burst;
using Unity.Entities;

namespace Core.Battle.Buff
{ 
    /// <summary>
    /// 只移除buff         古希腊死神    (移除其实也可以按照添加那么处理。)
    /// </summary> 
    [BurstCompile]
    [UpdateAfter(typeof(BuffChangeSystem))]
    public partial struct BuffRemoveSystem : ISystem
    { 
        [BurstCompile]
        public void OnCreate(ref SystemState state)
        { 
        }

        [BurstCompile]
        public void OnUpdate(ref SystemState state)
        { 
            new RemoveBuffJob()
            {
            }.ScheduleParallel(); 
        }
        
         #region 古希腊死神 
        [BurstCompile]
        public partial struct RemoveBuffJob : IJobEntity
        {  
            [BurstCompile]
            void Execute(DynamicBuffer<BuffData> buffDataBuffer)
            {
                for (int i = 0; i < buffDataBuffer.Length; i++)
                {
                    if (buffDataBuffer[i].IsDefault())
                    {
                        buffDataBuffer.RemoveAt(i);
                        i--;
                    }
                }
            }
        } 
        #endregion   
    }
}

BuffChangeSystem: 这个比较重要,他处理了几件事:
1、管理了外部新增、移除的buff,所有的变动请求都会由他来处理。
2、它持有BuffTableData列表,用于通过配置来构建buffData。
3、同时他还负责处理buff之间相互影响的效果(例如它有一个宝物(可以看做buff),让中毒效果增加…)

using Core.Config;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities; 

namespace Core.Battle.Buff
{
    public enum ChangeBuffState
    {
        Add,
        /// <summary>
        /// 减少x层
        /// </summary>
        Reduce,
        Remove,
    }
     
    /// <summary>
    /// 备注: 这里的AddBuffData,只是用来添加一个buff的,所以只会有runtime属性,例如类型、来源、时间、层数等
    /// Buff剩余的属性,应该由构建的时候从表里读取。
    /// </summary>
    public struct ChangeBuffData : IBufferElementData
    {
        /// <summary>
        /// 更改的类型
        /// </summary>
        public ChangeBuffState ChangeBuffState; 
        
        /// <summary>  
        /// buff的类型  
        /// </summary> 
        public BuffType BuffType;

        /// <summary>
        /// 来源Entity ID
        /// </summary>
        public Entity Owner;
        
        /// <summary>
        /// 来源Entity ID
        /// </summary>
        public Entity Target;
        
        /// <summary>
        ///  buff添加时的时间
        /// </summary>
        public double StartTime;  

        /// <summary>
        /// 持续时间  //TODO: 这种额外的东西,例如获得了某些宝物,增加伤害、持续时间等,都不该放在这里,而是有一个计算的system处理  这里临时处理了
        /// </summary>
        public double Duration;

        /// <summary>
        /// 层数  增加/删除的层数
        /// </summary>
        public int Count;

        /// <summary>
        /// buff level
        /// </summary>
        public int BuffLevel;
 
        public ChangeBuffData(ChangeBuffState changeBuffState, BuffType buffType, Entity owner, Entity target, double startTime, double duration, int count = 1, int buffLevel = 1)
        {
            ChangeBuffState = changeBuffState;
            BuffType = buffType;
            Owner = owner;
            Target = target;
            StartTime = startTime;
            Duration = duration;
            Count = count;
            BuffLevel = buffLevel;
        }
    }
    
    public struct BuffTableConfig : IComponentData
    {
        public NativeList<BuffTableData> _buffTables;
    }
    
     
    [BurstCompile]
    public partial struct BuffChangeSystem : ISystem
    { 
        [BurstCompile]
        public void OnCreate(ref SystemState state)
        {
            state.RequireForUpdate<GameConfigFlag>();
            
            state.EntityManager.AddComponentData(state.SystemHandle, new BuffTableConfig()
            {
                _buffTables = new NativeList<BuffTableData>(Allocator.Persistent), 
            }); 
        }   

        [BurstCompile]
        public void OnUpdate(ref SystemState state)
        {    
            BuffTableConfig buffTableConfig =
                state.EntityManager.GetComponentData<BuffTableConfig>(state.SystemHandle);
            
            //初始化使用的Data数据
            if (buffTableConfig._buffTables.Length == 0)
            {
                var configEntity = SystemAPI.GetSingletonEntity<GameConfigFlag>();
                
                DynamicBuffer<BuffTableData> buffTableData = state.EntityManager.GetBuffer<BuffTableData>(configEntity);  
                
                foreach (var t in buffTableData)
                {
                    buffTableConfig._buffTables.Add(t);
                }  
                state.EntityManager.SetComponentData(state.SystemHandle, buffTableConfig);
            } 
            
            foreach (var (buffDataBuffer,changeBuffData,entity) in SystemAPI.Query<DynamicBuffer<BuffData>,DynamicBuffer<ChangeBuffData>>().WithEntityAccess())
            {
                var buffDataBufferCopy = buffDataBuffer;
                
                //遍历addBuffDataBuffer,判断条件并构建添加到buffDataBuffer中。 
                for (int i = 0; i < changeBuffData.Length; i++)
                { 
                    switch (changeBuffData[i].ChangeBuffState)
                    {
                        case ChangeBuffState.Add:
                        {
                            var buff = BuffFactory.Get(buffTableConfig._buffTables,changeBuffData[i].BuffType,changeBuffData[i].Owner,
                                changeBuffData[i].Target,changeBuffData[i].StartTime,
                                changeBuffData[i].Duration,changeBuffData[i].Count,changeBuffData[i].BuffLevel);
                            if (buff.BuffType == BuffType.None)
                            {
                                continue;
                            } 
                            // 添加时处理额外效果
                            buff = AddBuffDataHandle(ref state, buff,changeBuffData[i].Owner,changeBuffData[i].Target);
                            
                            bool inList = false; 
                            for (int j = 0; j < buffDataBufferCopy.Length; j++)  
                            {
                                if (buffDataBufferCopy[j].BuffType == buff.BuffType)
                                { 
                                    inList = true; 
                                    var buffData = buffDataBufferCopy[j]; 
                                    //处理entity
                                    buffData.Add(buff);
                                    buffDataBufferCopy[j] = buffData;
                                    break;
                                }
                            }
                            if (!inList)
                            {
                                buffDataBufferCopy.Add(buff);
                            } 
                            break; 
                        }
                        case ChangeBuffState.Remove:
                        {
                            for (int j = 0; j < buffDataBufferCopy.Length; j++)  
                            {
                                if (buffDataBufferCopy[j].BuffType == changeBuffData[i].BuffType)
                                {
                                    var buff = buffDataBufferCopy[j];
                                    //设置为default后,在BuffRemoveSystem中会进行移除
                                    buff.SetDefault();
                                    buffDataBufferCopy[j] = buff;
                                    break;
                                }
                            } 
                            break;
                        }
                        case ChangeBuffState.Reduce:
                        { 
                            for (int j = 0; j < buffDataBufferCopy.Length; j++)  
                            {
                                if (buffDataBufferCopy[j].BuffType == changeBuffData[i].BuffType)
                                {
                                    var buff = buffDataBufferCopy[j];
                                    buff.BuffCount -= changeBuffData[i].Count;
                                    if (buff.BuffCount <= 0)  //层数小于0 则移除
                                    {
                                        buff.SetDefault();
                                    }
                                    buffDataBufferCopy[j] = buff; 
                                    break;
                                }
                            } 
                            break;
                        }
                    }
                } 
                //加完之后,把他清空
                changeBuffData.Clear();
            }
        }


        /// <summary>
        /// 添加buff额外处理,判断敌我身上buff之类的
        /// </summary> 
        private BuffData AddBuffDataHandle(ref SystemState state, BuffData buff, Entity owner, Entity target)
        {
            var addBuff = buff; 
            
            switch (addBuff.BuffType)
            {
                case BuffType.None: 
                    break; 
                case BuffType.Damage:
                    addBuff = DamageBuffHandle(ref state, buff, owner, target);
                    break;
            }
            
            return addBuff;
        }

        private BuffData DamageBuffHandle(ref SystemState state, BuffData buff, Entity owner, Entity target)
        {
            var ownerBuffs = SystemAPI.GetBuffer<BuffData>(owner);

            for (int i = 0; i < ownerBuffs.Length; i++)
            {
                if (ownerBuffs[i].BuffType == BuffType.AddDamageValue)
                {
                    buff.BuffValue += ownerBuffs[i].BuffValue;
                }
            }
            
            return buff;
        } 
        
    }
}

BuffTemplateSystem:用来复制的脚本,可以理解为buff的实际效果,但由于无法继承,则每次新建可以从他身上复制。。

using Core.Battle.Role.Enemy;
using Unity.Burst;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;

namespace Core.Battle.Buff
{
    /// <summary>
    /// 这是一个用来被复制的脚本。
    /// </summary>
    [BurstCompile]
    [UpdateAfter(typeof(BuffTimeSystem))]
    public partial struct BuffTemplateSystem : ISystem
    {
        private EntityCommandBuffer ecb;

        public void OnCreate(ref SystemState state)
        {
            state.RequireForUpdate<BeginSimulationEntityCommandBufferSystem.Singleton>();
        }

        [BurstCompile]
        public void OnUpdate(ref SystemState state)
        {
            ecb = SystemAPI.GetSingleton<BeginSimulationEntityCommandBufferSystem.Singleton>()
                .CreateCommandBuffer(state.EntityManager.WorldUnmanaged); 
            foreach (var (buffData,changeBuff, owner) in SystemAPI.Query<DynamicBuffer<BuffData>,DynamicBuffer<ChangeBuffData>>().WithEntityAccess())
            {
                var buffDataBuffer = buffData;
                for (int i = 0; i < buffDataBuffer.Length; i++)
                { 
                    if (Filter(buffDataBuffer[i].BuffType))
                    { 
                        if (!state.EntityManager.Exists(owner))
                        {
                            continue;
                        }

                        #region 生命周期 
                        var tmpDataBuffer = buffDataBuffer[i];
                        var bf = buffDataBuffer[i].BuffFlag; 
                        // 新加的
                        if (buffDataBuffer[i].BuffFlag.IsNewAdd)
                        {
                            bf.IsNewAdd = false;
                        }
                        // 新加x层
                        if (buffDataBuffer[i].BuffFlag.IsAdded > 0)
                        {
                            bf.IsAdded = 0;
                        }
                        // 减少x层
                        if (buffDataBuffer[i].BuffFlag.IsReduce > 0)
                        {   
                            bf.IsReduce = 0;
                        }   
                        // 每次触发
                        if (buffDataBuffer[i].BuffFlag.IsTrigger)
                        { 
                            bf.IsTrigger = false;    //手动修改触发类型 
                        }  
                        // 移除事件
                        if (buffDataBuffer[i].BuffFlag.IsRemove)
                        {
                            //触发移除事件...
                            
                            //设置默认移除
                            buffDataBuffer[i].SetDefault();
                        } 
                        //赋值回去 
                        tmpDataBuffer.BuffFlag = bf;
                        buffDataBuffer[i] = tmpDataBuffer;
                        #endregion
                    }
                }
            }
        } 
        
        /// <summary>
        /// 是否对该类型做处理
        /// </summary> 
        private bool Filter(BuffType bType)
        {
            return false;
            return bType == BuffType.None;
        }

        public void OnDestroy(ref SystemState state)
        {
 
        }
        
        /// <summary>
        /// 也是个用来复制的模板
        /// </summary>
        [BurstCompile]
        public partial struct JobEntityTemplate : IJobEntity
        {
            public float3 ownerPosition; 
            public EntityCommandBuffer.ParallelWriter ecb;
            
            [BurstCompile]
            void Execute(Entity e,in LocalTransform roleTrans,in EnemyFlag enemyFlag,[EntityIndexInQuery]int index)
            {
                if (math.distance(ownerPosition,roleTrans.Position) <= 5f)
                {
                    // 说明碰到了,消灭它。
                }
            }
        } 
    }
}

BuffHelper:提供封装方法,能够快速的实现增删改查。

using Unity.Burst;
using Unity.Entities;

namespace Core.Battle.Buff
{
    public static class BuffHelper
    {
        /// <summary>
        /// 添加个buff
        /// </summary>
        [BurstCompile]
        public static void AddBuff_Battle(ref this SystemState state,
            Entity target, BuffType bt, Entity owner, double startTime, double duration,int buffCount = 1,int buffLevel = 1)
        {
            var changeInfo = state.EntityManager.GetBuffer<ChangeBuffData>(target); 
            changeInfo.Add(new ChangeBuffData()
            {
                ChangeBuffState = ChangeBuffState.Add,
                BuffType = bt,
                Owner = owner,
                StartTime = startTime,
                Duration = duration,
                Count = buffCount,
                BuffLevel = buffLevel
            }); 
        }
 
        /// <summary>
        /// 直接移除个buff
        /// </summary>
        [BurstCompile]
        public static void RemoveBuff_Battle(ref this SystemState state, Entity target, BuffType bt)
        {
            var changeInfo = state.EntityManager.GetBuffer<ChangeBuffData>(target); 
            changeInfo.Add(new ChangeBuffData()
            {
                ChangeBuffState = ChangeBuffState.Remove,
                BuffType = bt
            }); 
        }
        
        /// <summary>
        /// 移除某个buff多少层
        /// </summary>
        [BurstCompile]
        public static void RemoveBuffCount_Battle(ref this SystemState state, Entity target, BuffType bt, int count)
        {
            var changeInfo = state.EntityManager.GetBuffer<ChangeBuffData>(target); 
            changeInfo.Add(new ChangeBuffData()
            {
                ChangeBuffState = ChangeBuffState.Reduce,
                BuffType = bt,
                Count = count
            }); 
        }


        [BurstCompile]
        public static bool ContainsBuff_Battle(ref this SystemState state, Entity target, BuffType bt)
        {
            var buffData = state.EntityManager.GetBuffer<BuffData>(target);
            for (int i = 0; i < buffData.Length; i++)
            {
                if (buffData[i].BuffType == bt)
                {
                    return true;
                }
            } 
            return false; 
        }
        
        
        /// <summary>
        /// 为none就是没有
        /// </summary> 
        [BurstCompile]
        public static BuffData GetBuff_Battle(ref this SystemState state, Entity target, BuffType bt)
        {
            var buffData = state.EntityManager.GetBuffer<BuffData>(target);
            for (int i = 0; i < buffData.Length; i++)
            {
                if (buffData[i].BuffType == bt)
                {
                    return buffData[i];
                }
            } 
            return new BuffData(){BuffType = BuffType.None}; 
        }
        
    }
}

代码基本就是这样了,最后可以这样很方便的使用这一套buff系统:

using Core.Battle.Buff;
using Unity.Entities;

namespace Core.Battle.Role.Player
{
    //用于初始化player
    public partial struct PlayerInitSystem : ISystem
    {
        public void OnCreate(ref SystemState state)
        {
            state.RequireForUpdate<PlayerFlag>();
        }

        public void OnUpdate(ref SystemState state)
        {
            //暂时只初始化一次  之后有重开等再说
            state.Enabled = false;
            
            foreach (var (playerFlag, e) in SystemAPI
                         .Query<RefRO<PlayerFlag>>().WithEntityAccess())
            {
                // 给player加个buff
                state.AddBuff_Battle(e,BuffType.NormalAtk,e,SystemAPI.Time.ElapsedTime,10000,1,2);    //加了个lv2的普通攻击
                state.AddBuff_Battle(e,BuffType.AddDamageValue,e,SystemAPI.Time.ElapsedTime,-1);      //加了个lv1的伤害增幅
            }
        }
    }
}

最后我定义了一个5攻击的直伤BUFF,外加一个额外附加5伤害的BUFF,成功对范围内敌人造成10点伤害
在这里插入图片描述

  • 13
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Dots(Data-Oriented Technology Stack)是Unity引擎的一种数据导向技术栈,它可以让游戏的数据更加高效地处理和组织。KDTree是一种经典的数据结构,可以用于高效地处理多维空间数据的查询。本篇文章将介绍如何使用C#实现基于Dots的KDTree。 首先,我们需要定义一个点的数据结构。假设我们要处理二维空间中的点,我们可以定义一个名为“Point”的结构体: ``` public struct Point { public float x; public float y; public Point(float x, float y) { this.x = x; this.y = y; } } ``` 接下来,我们需要定义一个节点的数据结构。每个节点包含一个点、一个左子树和一个右子树。如果该节点没有子树,则对应的子树为空: ``` public struct Node { public Point point; public Node left; public Node right; } ``` 我们使用递归方法构建KDTree。具体来说,对于一个给定的点集合,我们首先找到X坐标的中位数,并将其作为根节点。然后,我们将点集合分成两个子集,一个包含所有X坐标小于中位数的点,另一个包含所有X坐标大于中位数的点。接着,我们递归地在每个子集中构建左子树和右子树,直到子集为空。在构建子树时,我们使用Y坐标的中位数来确定左右子树的分裂方式。 下面是构建KDTree的代码: ``` public static Node BuildKdTree(Point[] points, int depth = 0) { if (points == null || points.Length == 0) { return default(Node); } int axis = depth % 2; int medianIndex = points.Length / 2; Array.Sort(points, (a, b) => a.x.CompareTo(b.x)); Node node = new Node(); node.point = points[medianIndex]; node.left = BuildKdTree(points.Take(medianIndex).ToArray(), depth + 1); node.right = BuildKdTree(points.Skip(medianIndex + 1).ToArray(), depth + 1); return node; } ``` 我们可以使用以下代码测试构建KDTree的效果: ``` Point[] points = new Point[] { new Point(2, 3), new Point(5, 4), new Point(9, 6), new Point(4, 7), new Point(8, 1), new Point(7, 2) }; Node root = BuildKdTree(points); ``` 现在,我们已经成功地构建了一个KDTree。接下来,我们需要实现一个查询方法来查找最近邻点。查询方法的思想是从根节点开始向下遍历,直到叶子节点。在遍历的过程中,我们计算当前节点和目标点之间的距离,并将其与当前最近邻点的距离进行比较。如果当前节点更接近目标点,则更新最近邻点。接着,我们根据当前节点和目标点的关系,递归地遍历左子树或右子树。当我们到达叶子节点时,我们将该叶子节点作为当前最近邻点,并将其距离与当前最近邻点的距离进行比较。最终,我们找到了最近邻点。 以下是查询方法的代码: ``` public static Point FindNearestPoint(Node node, Point target) { if (node.left == default(Node) && node.right == default(Node)) { return node.point; } Point best = node.point; if (node.left != default(Node) && target.x < node.point.x) { Point leftBest = FindNearestPoint(node.left, target); if (Distance(leftBest, target) < Distance(best, target)) { best = leftBest; } } if (node.right != default(Node) && target.x > node.point.x) { Point rightBest = FindNearestPoint(node.right, target); if (Distance(rightBest, target) < Distance(best, target)) { best = rightBest; } } return best; } private static float Distance(Point a, Point b) { return Mathf.Sqrt(Mathf.Pow(a.x - b.x, 2) + Mathf.Pow(a.y - b.y, 2)); } ``` 我们可以使用以下代码测试查询方法的效果: ``` Point target = new Point(3, 5); Point nearest = FindNearestPoint(root, target); Debug.Log(nearest.x + ", " + nearest.y); // 输出 "2, 3" ``` 这就是基于Dots的KDTree的实现方法。它可以被用于高效地处理多维空间数据的查询,并且可以很容易地扩展到更高维度的情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值