using System.Collections; using System.Collections.Generic; using BehaviorDesigner.Runtime.Tasks; using DragonLi.Behaviour; using UnityEngine; using Action = BehaviorDesigner.Runtime.Tasks.Action; using System.Collections; using BehaviorDesigner.Runtime.Tasks; using DG.Tweening; using Pathfinding; using UnityEngine; /// /// 吐舌攻击 /// public class FrogBleepAttack : Action { private FrogBoss boss; private bool isFinished; public float tongueSpeed = 25f; public float damage = 30f; private float rotateSpeed = 360f; // 每秒旋转角度 public override void OnStart() { boss = GetComponent(); isFinished = false; boss.ResetSkill1(); boss.StartCoroutine(SkillRoutine()); } public override TaskStatus OnUpdate() { return isFinished ? TaskStatus.Success : TaskStatus.Running; } IEnumerator SkillRoutine() { // 1️⃣ 不在攻击范围 → 先移动 if (!boss.IsPlayerInTongueRange()) { yield return boss.StartCoroutine( boss.MoveToTongueRange() ); } // 2️⃣ 锁定玩家位置(关键) Vector3 lockPos = GameManager.Ins.player.transform.position; // 面向玩家 yield return RotateToPlayer(); // 3️⃣ 吐舌头 boss.TongueAttack(); yield return new WaitForSeconds(0.4f); float dis = Vector3.Distance(boss.mouthPoint.position, lockPos); float time = dis / tongueSpeed; yield return new WaitForSeconds(time); boss.Idle(); isFinished = true; } IEnumerator RotateToPlayer() { Transform player = GameManager.Ins.player.transform; Vector3 dir = player.position - transform.position; dir.y = 0; if (dir.sqrMagnitude < 0.01f) yield break; Quaternion targetRot = Quaternion.LookRotation(dir); while (Quaternion.Angle(transform.rotation, targetRot) > 1f) { transform.rotation = Quaternion.RotateTowards( transform.rotation, targetRot, rotateSpeed * Time.deltaTime ); yield return null; } } } /// /// 毒液弹攻击 /// public class FrogPoisonAttack : Action { private FrogBoss boss; private bool isFinished; private float rotateSpeed = 360f; // 每秒旋转角度 public override void OnStart() { boss = GetComponent(); isFinished = false; boss.ResetSkill2(); boss.StartCoroutine(Attack()); } public override TaskStatus OnUpdate() { return isFinished ? TaskStatus.Success : TaskStatus.Running; } IEnumerator Attack() { yield return RotateToPlayer(); boss.Spit(); yield return new WaitForSeconds(0.5f); for (int i = 0; i < 3; i++) { Vector2 rand = Random.insideUnitCircle * 1.2f; Vector3 target = GameManager.Ins.player.transform.position + new Vector3(rand.x, 0, rand.y); GameObject ball = Object.Instantiate( boss.poisonBallPrefab, boss.mouthPoint.position, Quaternion.identity ); ball.GetComponent().Launch( boss.mouthPoint.position, target, boss.Data.Atk_2dot, boss.Data.Atk_2Time ); yield return new WaitForSeconds(0.5f); } boss.Idle(); isFinished = true; } IEnumerator RotateToPlayer() { Transform player = GameManager.Ins.player.transform; Vector3 dir = player.position - transform.position; dir.y = 0; if (dir.sqrMagnitude < 0.01f) yield break; Quaternion targetRot = Quaternion.LookRotation(dir); while (Quaternion.Angle(transform.rotation, targetRot) > 1f) { transform.rotation = Quaternion.RotateTowards( transform.rotation, targetRot, rotateSpeed * Time.deltaTime ); yield return null; } } } /// /// 吐卵 召唤小虫怪 /// public class FrogEggAttack : Action { private FrogBoss boss; private bool isFinished; [Header("Egg Config")] public int eggCount = 12; public float shootInterval = 0.15f; public float fanAngle = 60f; public float launchHeight = 3f; public float flightTime = 1.1f; public override void OnStart() { boss = GetComponent(); isFinished = false; boss.StartCoroutine(Attack()); } public override TaskStatus OnUpdate() { return isFinished ? TaskStatus.Success : TaskStatus.Running; } IEnumerator Attack() { boss.EggAttack(); yield return new WaitForSeconds(0.5f); boss.aiPath.isStopped = true; Transform firePoint = boss.eggFirePoint; // 嘴巴 float step = fanAngle / (eggCount - 1); float startAngle = -fanAngle * 0.5f; int eggBugCount = boss.GetAliveTentacles().Count; int insCount; if (eggBugCount >= 12) { boss.Idle(); isFinished = true; yield break; } insCount=12-eggBugCount; for (int i = 0; i < insCount; i++) { float angle = startAngle + step * i; // 🔥 轻微左右转头 boss.transform .DORotate( boss.transform.eulerAngles + new Vector3(0, angle * 0.15f, 0), 0.1f ); SpawnEgg(firePoint, angle); yield return new WaitForSeconds(shootInterval); } yield return new WaitForSeconds(0.5f); // 吐完跑向左右 Vector3 side = Random.value > 0.5f ? -boss.transform.right : boss.transform.right; boss.transform.DOMove(boss.transform.position + side * 5f, 1.5f); boss.Idle(); isFinished = true; } void SpawnEgg(Transform firePoint, float angle) { GameObject egg = Object.Instantiate( boss.eggPrefab, firePoint.position, Quaternion.identity ); FrogBugEnemy bug = egg.GetComponent(); bug.SetAtk(boss.Data.Atk_2,boss.Data.Hp_CS2); // 扇形方向 Vector3 dir = Quaternion.Euler(0, angle, 0) * boss.transform.forward; // 落点 Vector3 targetPos = firePoint.position + dir * Random.Range(3.5f, 5.5f); bug.LaunchEgg( firePoint.position, targetPos, launchHeight, flightTime, boss.Data.Atk_3, boss.Data.Hp_CS2 ); } } public class FrogIdleMove : Action { public float moveRadius = 4f; // 扇形半径 public float moveAngle = 90f; // 扇形角度 public float stayTime = 3f; // 到点后停留时间 public float rotateSpeed = 360f; private FrogBoss boss; private Transform player; private float stayTimer; private Vector3 curTarget; [Header("Distance To Player")] public float minPlayerDistance = 10f; // 最近不能小于 public float maxPlayerDistance = 20f; // 最远不能超过 public override void OnStart() { boss = GetComponent(); player = GameManager.Ins.player.transform; PickNewTarget(); } public override TaskStatus OnUpdate() { if (player == null) return TaskStatus.Running; if (boss.HasAnySkillReady()) { boss.aiPath.isStopped = true; boss.Idle(); return TaskStatus.Failure; } FaceToPlayer(); Move(); return TaskStatus.Running; // 永远不结束 } #region Core void FaceToPlayer() { Vector3 dir = player.position - transform.position; dir.y = 0; if (dir.sqrMagnitude < 0.01f) return; Quaternion targetRot = Quaternion.LookRotation(dir); transform.rotation = Quaternion.RotateTowards( transform.rotation, targetRot, rotateSpeed * Time.deltaTime ); } void Move() { if (Vector3.Distance(transform.position, curTarget) < 0.3f) { stayTimer += Time.deltaTime; boss.Idle(); if (stayTimer >= stayTime) PickNewTarget(); return; } boss.Run(); boss.aiPath.isStopped = false; boss.aiPath.destination = curTarget; } void PickNewTarget() { stayTimer = 0f; Vector3 bossPos = transform.position; Vector3 toPlayer = player.position - bossPos; toPlayer.y = 0; // 玩家正前方扇形 Vector3 forward = toPlayer.normalized; const int MAX_TRY = 10; for (int i = 0; i < MAX_TRY; i++) { float angle = Random.Range(-moveAngle * 0.5f, moveAngle * 0.5f); Vector3 dir = Quaternion.Euler(0, angle, 0) * forward; float dist = Random.Range(moveRadius * 0.4f, moveRadius); Vector3 candidate = bossPos + dir * dist; // 👉 与玩家距离校验 float playerDist = Vector3.Distance(candidate, player.position); if (playerDist < minPlayerDistance || playerDist > maxPlayerDistance) continue; // A* 校正 NNInfo nn = AstarPath.active.GetNearest(candidate); if (nn.node != null && nn.node.Walkable) { curTarget = nn.position; return; } } // 🔥 兜底:保持原地 curTarget = bossPos; } #endregion }