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 float retreatDistance = 8f;
public float retreatSpeed = 6f;
public override void OnStart()
{
boss = GetComponent();
isFinished = false;
// 标记技能正在执行,防止被中断
boss.isSkillExecuting = true;
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;
// 3️⃣ 面向玩家
yield return RotateToPlayer();
// 4️⃣ 吐舌
boss.TongueAttack();
yield return new WaitForSeconds(3f);
float dis = Vector3.Distance(boss.mouthPoint.position, lockPos);
yield return new WaitForSeconds(dis / tongueSpeed);
// 5️⃣ 吐舌结束立即返回待机(解决延迟问题)
boss.Idle();
// 6️⃣ 后撤(并行执行,不阻塞动画切换)
boss.StartCoroutine(RetreatFromPlayer());
// 等待后撤完成
yield return new WaitForSeconds(0.1f);
boss.Idle();
boss.isSkillExecuting = false; // 标记技能执行结束
isFinished = true;
}
IEnumerator RetreatFromPlayer()
{
Transform player = GameManager.Ins.player.transform;
Vector3 dir = (transform.position - player.position);
dir.y = 0;
dir.Normalize();
Vector3 targetPos = transform.position + dir * retreatDistance;
NNInfo nn = AstarPath.active.GetNearest(targetPos);
if (nn.node == null || !nn.node.Walkable)
yield break;
boss.aiPath.isStopped = false;
boss.aiPath.maxSpeed = retreatSpeed;
boss.aiPath.destination = nn.position;
boss.Retreat();
while (!boss.aiPath.reachedEndOfPath)
yield return null;
boss.aiPath.isStopped = 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) > 15f)
{
transform.rotation = Quaternion.RotateTowards(
transform.rotation,
targetRot,
720f * Time.deltaTime
);
yield return null;
}
// 立即对齐到目标方向
transform.rotation = targetRot;
}
}
///
/// 毒液弹攻击
///
public class FrogPoisonAttack : Action
{
private FrogBoss boss;
private bool isFinished;
private float rotateSpeed = 360f;
public override void OnStart()
{
boss = GetComponent();
isFinished = false;
// 标记技能正在执行,防止被中断
boss.isSkillExecuting = true;
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 * 3f;
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();
boss.isSkillExecuting = false; // 标记技能执行结束
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
);
boss.frogBugs.Add(bug);
}
}
public class FrogIdleMove : Action
{
[Header("Move Area (Fan Shape)")]
private float moveRadius = 40f; // 可移动半径
private float moveAngle = 90f; // 扇形角度(玩家正前方)
[Header("Stay")]
public float stayTime = 1.5f; // 到点后停留时间
[Header("Rotate")]
public float rotateSpeed = 360f;
[Header("Distance To Player")]
public float minPlayerDistance = 10f; // 离玩家最近距离
public float maxPlayerDistance = 25f; // 离玩家最远距离
[Header("Patrol")]
public float minMoveStep = 10f; // 每次移动的最小距离(关键)
private FrogBoss boss;
private Transform player;
private Vector3 curTarget;
private float stayTimer;
private bool isStaying;
public override void OnStart()
{
boss = GetComponent();
player = GameManager.Ins.player.transform;
isStaying = false;
stayTimer = 0f;
PickNewTarget();
}
public override TaskStatus OnUpdate()
{
if (player == null)
return TaskStatus.Running;
// 🔥 有技能可放 → 退出待机行为
if (boss.HasAnySkillReady())
{
boss.aiPath.isStopped = true;
boss.Idle();
return TaskStatus.Failure;
}
FaceToPlayer();
HandleMove();
return TaskStatus.Running;
}
#region Core Logic
void FaceToPlayer()
{
Vector3 dir = player.position - transform.position;
dir.y = 0;
if (dir.sqrMagnitude < 0.01f)
return;
Quaternion targetRot = Quaternion.LookRotation(dir);
// 使用Slerp实现更平滑的转向
transform.rotation = Quaternion.Slerp(
transform.rotation,
targetRot,
5f * Time.deltaTime
);
}
void HandleMove()
{
float distToTarget = Vector3.Distance(transform.position, curTarget);
// ===== 已到达目标点 =====
if (distToTarget < 0.4f)
{
boss.aiPath.isStopped = true;
boss.Idle();
isStaying = true;
stayTimer += Time.deltaTime;
if (stayTimer >= stayTime)
{
PickNewTarget();
}
return;
}
// ===== 正在移动 =====
isStaying = false;
stayTimer = 0f;
boss.Run();
boss.aiPath.isStopped = false;
boss.aiPath.destination = curTarget;
}
void PickNewTarget()
{
stayTimer = 0f;
isStaying = false;
Vector3 bossPos = transform.position;
Vector3 playerPos = player.position;
const int MAX_TRY = 25;
for (int i = 0; i < MAX_TRY; i++)
{
float baseAngle = Quaternion.LookRotation(bossPos - playerPos).eulerAngles.y;
float angle = baseAngle + Random.Range(-120f, 120f);
float radius = Random.Range(minPlayerDistance, maxPlayerDistance);
Vector3 offset = Quaternion.Euler(0, angle, 0) * Vector3.forward * radius;
Vector3 candidate = playerPos + offset;
candidate.y = bossPos.y;
// 强制不要靠太近当前位置
if (Vector3.Distance(candidate, bossPos) < minMoveStep)
continue;
NNInfo nn = AstarPath.active.GetNearest(candidate);
if (nn.node != null && nn.node.Walkable)
{
curTarget = nn.position;
boss.aiPath.isStopped = false;
return;
}
}
// fallback:侧移
Vector3 side = Vector3.Cross(Vector3.up, (bossPos - playerPos)).normalized;
curTarget = bossPos + side * minMoveStep;
boss.aiPath.isStopped = false;
}
#endregion
}