using System.Collections.Generic; using BehaviorDesigner.Runtime; using BehaviorDesigner.Runtime.Tasks; using DragonLi.Core; using DragonLi.Frame; using Unity.VisualScripting; using UnityEngine; using UnityEngine.AI; public class CheckEnemyState : Conditional { public SharedInt curEnemyState; public override TaskStatus OnUpdate() { if (transform.GetComponent().enemyState == (EnemyState)curEnemyState.Value) { return TaskStatus.Success; } return TaskStatus.Failure; } } public class SetEnemyState : Action { public SharedInt curEnemyState; public override TaskStatus OnUpdate() { var enemy= transform.GetComponent(); if (enemy != null) { enemy.enemyState = (EnemyState)curEnemyState.Value; return TaskStatus.Success; } return base.OnUpdate(); } } public class MoveToPlayerNearby3 : Action { public SharedGameObject self; public SharedFloat minRange = new SharedFloat { Value = 3f }; public SharedFloat maxRange = new SharedFloat { Value = 10f }; public SharedFloat avoidRadius = new SharedFloat { Value = 2f }; public SharedLayerMask enemyLayer; public int maxAttempts = 15; private NavMeshAgent agent; private Vector3 targetPosition; public override void OnStart() { base.OnStart(); agent = GetComponent(); // 随机优先级,降低 agent 之间争路 agent.avoidancePriority = Random.Range(0, 100); agent.obstacleAvoidanceType = ObstacleAvoidanceType.HighQualityObstacleAvoidance; agent.autoBraking = false; Transform player = GameManager.Ins.player.transform; targetPosition = FindValidPosition(player); if (agent.isActiveAndEnabled) agent.SetDestination(targetPosition); } public override TaskStatus OnUpdate() { if (!agent.pathPending && agent.remainingDistance <= agent.stoppingDistance) return TaskStatus.Success; return TaskStatus.Running; } private Vector3 FindValidPosition(Transform player) { // 从 Manager 或其他地方拿到所有敌人的引用列表 List allEnemies = GameManager.Ins.curEnemyList; Vector3 bestPos = Vector3.zero; float bestScore = -1f; for (int i = 0; i < maxAttempts; i++) { // 1. 随机取点 Vector3 dir = Random.insideUnitSphere; dir.y = 0; dir.Normalize(); float dist = Random.Range(minRange.Value, maxRange.Value); Vector3 raw = player.position + dir * dist; // 2. NavMesh 采样 if (!NavMesh.SamplePosition(raw, out NavMeshHit hit, 2f, NavMesh.AllAreas)) continue; var cand = hit.position; // 3. 与玩家最小距离硬性筛掉 if (Vector3.Distance(cand, player.position) < minRange.Value) continue; // 4. 计算到其它每个敌人的最小距离 float minDistToOthers = float.MaxValue; foreach (var go in allEnemies) { if (go == null || go == self.Value) continue; float d = Vector3.Distance(cand, go.transform.position); minDistToOthers = Mathf.Min(minDistToOthers, d); if (minDistToOthers < avoidRadius.Value) break; // 太近了,提前跳出 } // 5. 如果通过了 avoidRadius,就直接返回 if (minDistToOthers >= avoidRadius.Value) return cand; // 6. 否则记录最佳分数点 if (minDistToOthers > bestScore) { bestScore = minDistToOthers; bestPos = cand; } } // 如果所有尝试都没严格过,也选“最远离群”的那个 if (bestScore > 0f) return bestPos; // 兜底:玩家前方一个安全距离 Vector3 fb = player.position + player.forward * minRange.Value; if (NavMesh.SamplePosition(fb, out NavMeshHit fh, 2f, NavMesh.AllAreas)) return fh.position; // 最后随机返回一个点 return player.position + Random.insideUnitSphere * (minRange.Value + 0.5f); } // 调试画出可行区域 void OnDrawGizmosSelected() { if (self == null || self.Value != gameObject) return; Gizmos.color = Color.cyan; Gizmos.DrawWireSphere(targetPosition, 0.2f); } } /// /// 检测boss是否到阶段血量 /// public class CheckEnemyHp : Conditional { public SharedFloat hpIndex; public override TaskStatus OnUpdate() { var curHpIndex = transform.GetComponent().health/transform.GetComponent().maxHealth; if (curHpIndex <= hpIndex.Value) { return TaskStatus.Success; } return TaskStatus.Failure; } } public class UserSkill : Action { public Enemy EnemyObj; public SharedFloat hpIndex; public override void OnStart() { base.OnStart(); EnemyObj = transform.GetComponent(); } public override TaskStatus OnUpdate() { if (EnemyObj == null) return TaskStatus.Failure; var curHpIndex = EnemyObj.health/EnemyObj.maxHealth; if (curHpIndex <= hpIndex.Value) { EnemyObj.userSillIng = false; } var isUserIng = EnemyObj.userSillIng; if (isUserIng) return TaskStatus.Running; return TaskStatus.Success; } } public class BossIsUserSkill : Conditional { public override TaskStatus OnUpdate() { Enemy curEnemy = GetComponent(); if(curEnemy.userSillIng) return TaskStatus.Success; return TaskStatus.Failure; } } public class BossIsAttackState : Conditional { public override TaskStatus OnUpdate() { Enemy curEnemy = GetComponent(); if(curEnemy.isAttack) return TaskStatus.Success; return TaskStatus.Failure; } } public class BossIsQteAttack : Conditional { public SharedBool isQteAttack; public override TaskStatus OnUpdate() { if(isQteAttack.Value) return TaskStatus.Success; return TaskStatus.Failure; } } public class WaitAllPetDie : Action { public override TaskStatus OnUpdate() { if (GameManager.Ins.IsAllBossPetDie()) { Enemy curEnemy = GetComponent(); if (curEnemy) { curEnemy.isShield = false; curEnemy.shieldObj.SetActive(false); } return TaskStatus.Success; } return TaskStatus.Running; } } public class IsBossGunDie : Conditional { public SharedString GunIdStr; private List gunIdList; public override void OnStart() { base.OnStart(); gunIdList=new List(); string[] str=GunIdStr.Value.Split(','); foreach (var item in str) { gunIdList.Add(int.Parse(item)); } } public override TaskStatus OnUpdate() { Enemy curEnemy = GetComponent(); foreach (var id in gunIdList) { if (curEnemy.components[id] != null && !curEnemy.components[id].isDead) { return TaskStatus.Failure; } } return TaskStatus.Success; } } public class BossQteAttack : Action { private Enemy _curEnemy; public float QteTime; public SharedBool IsQteAttacked; public SharedBool IsStopQteAttacked; private float _currentQteTime; public override void OnStart() { base.OnStart(); //QteTime = 5; _curEnemy = GetComponent(); if (_curEnemy) { IsQteAttacked.Value = false; _curEnemy.StartQteAttack(); } } public override TaskStatus OnUpdate() { _currentQteTime += Time.deltaTime; if (_curEnemy.components[^1] != null && _curEnemy.components[^1].isDead) { IsStopQteAttacked.Value =true; _curEnemy.StopQteAttack(); return TaskStatus.Success; } if (_currentQteTime >= QteTime) { IsStopQteAttacked.Value =false; _curEnemy.ThreeAttackMode(); return TaskStatus.Success; } return TaskStatus.Running; } } public class CooldownTick : Action { public SharedFloat cooldownTimer; public SharedBool skillReady; public SharedFloat hp; public override TaskStatus OnUpdate() { Enemy curEnemy = GetComponent(); var curHpIndex = curEnemy.health/curEnemy.maxHealth; if (curHpIndex <= hp.Value) { skillReady.Value = false; cooldownTimer.Value = 15; return TaskStatus.Success; } if (cooldownTimer.Value > 0f) { cooldownTimer.Value -= Time.deltaTime; if (cooldownTimer.Value <= 0f) { cooldownTimer.Value = 0f; skillReady.Value = true; return TaskStatus.Success; } } return TaskStatus.Running; } } public class ReleaseSkill : Action { public SharedFloat cooldownTimer; public SharedBool skillReady; public float skillCooldown = 15f; public override void OnStart() { base.OnStart(); // 进入冷却 cooldownTimer.Value = skillCooldown; skillReady.Value = false; } } public class NormalAttack : Action { public override void OnStart() { // 你的普攻逻辑 Debug.Log("执行普攻"); Enemy curEnemy = GetComponent(); curEnemy.Attack(); } } public class IsSkillReady : Conditional { public SharedBool skillReady; public override TaskStatus OnUpdate() { return skillReady.Value ? TaskStatus.Success : TaskStatus.Failure; } } public class ConditionalStopQte : Conditional { public SharedBool IsStopQteAttack; public override TaskStatus OnUpdate() { if(!IsStopQteAttack.Value) return TaskStatus.Success; return TaskStatus.Failure; } }