/// --------------------------------------------- /// Behavior Designer /// Copyright (c) Opsive. All Rights Reserved. /// https://www.opsive.com /// --------------------------------------------- namespace Opsive.BehaviorDesigner.Samples { using Opsive.BehaviorDesigner.Runtime.Components; using Opsive.BehaviorDesigner.Runtime.Tasks; using Unity.Entities; using UnityEngine; using System; [Tooltip("Damages any entity that has the HealthComponent.")] [Shared.Utility.Category("Behavior Designer Samples/DOTS")] public class Damage : ECSActionTask { [Tooltip("The amount of damage to apply.")] [SerializeField] float m_DamageAmount; /// /// Resets the task to its default values. /// public override void Reset() { m_DamageAmount = 1; } /// /// Returns a new TBufferElement for use by the system. /// /// A new TBufferElement for use by the system. public override DamageComponent GetBufferElement() { return new DamageComponent() { Index = RuntimeIndex, DamageAmount = m_DamageAmount, }; } } /// /// The DOTS data structure for the Damage struct. /// public struct DamageComponent : IBufferElementData { [Tooltip("The index of the node.")] public ushort Index; [Tooltip("The amount of damage to apply.")] public float DamageAmount; } /// /// A DOTS flag indicating when a Fire node is active. /// public struct DamageFlag : IComponentData, IEnableableComponent { } /// /// Runs the Damage logic. /// [DisableAutoCreation] public partial class DamageTaskSystem : SystemBase { public Action OnDamage; /// /// Updates the logic. /// protected override void OnUpdate() { var ecb = new EntityCommandBuffer(WorldUpdateAllocator); foreach (var (branchComponents, taskComponents, damageComponents) in SystemAPI.Query, DynamicBuffer, DynamicBuffer>().WithAll()) { for (int i = 0; i < damageComponents.Length; ++i) { var damageComponent = damageComponents[i]; var taskComponent = taskComponents[damageComponent.Index]; var branchComponent = branchComponents[taskComponent.BranchIndex]; if (!branchComponent.CanExecute) { continue; } if (taskComponent.Status != TaskStatus.Queued) { continue; } // Apply the damage. foreach (var (healthComponent, entity) in SystemAPI.Query>().WithEntityAccess()) { healthComponent.ValueRW.Value -= damageComponent.DamageAmount; if (healthComponent.ValueRO.Value <= 0) { ecb.AddComponent(entity); } OnDamage?.Invoke(healthComponent.ValueRO.Value); } // The task will always return immediately. taskComponent.Status = TaskStatus.Success; var taskComponentBuffer = taskComponents; taskComponentBuffer[damageComponent.Index] = taskComponent; } } ecb.Playback(EntityManager); ecb.Dispose(); } } }