Files
FutureMen2/Assets/_FutureMen2/Scripts/Actions/TortoiseActions.cs
2026-01-29 17:34:43 +08:00

346 lines
8.8 KiB
C#
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections;
using System.Collections.Generic;
using BehaviorDesigner.Runtime.Tasks;
using DragonLi.Core;
using UnityEngine;
public class TortoiseSprintAttack : Action
{
private TortoiseBoss boss;
private bool isFinished;
[Header("Sprint")]
public float sprintDistance = 3f;
public float sprintSpeed = 3f;
[Header("Angry Trample")]
public float angryDuration = 3f;
public float rotateSpeed = 90f;
public override void OnStart()
{
boss = GetComponent<TortoiseBoss>();
isFinished = false;
boss.ResetSkill1();
StartCoroutine(SkillFlow());
}
public override TaskStatus OnUpdate()
{
return isFinished ? TaskStatus.Success : TaskStatus.Running;
}
IEnumerator SkillFlow()
{
// ===== Phase 1冲刺 =====
yield return SprintThroughPlayer();
// ===== Phase 2愤怒践踏旋转 =====
yield return AngryTrample();
// ===== Phase 3转向玩家 → Idle =====
yield return RotateToPlayer();
boss.Idle();
isFinished = true;
}
#region Phase 1 - Sprint
IEnumerator SprintThroughPlayer()
{
// boss.Roar();
// yield return new WaitForSeconds(0.6f);
boss.BeginAttack();
boss.Run();
GameManager.Ins.PlaySound3D("1.19",transform);
Transform player = GameManager.Ins.player.transform;
Vector3 dir = (player.position - boss.transform.position).normalized;
dir.y = 0;
// 🎯 贯穿目标点
Vector3 targetPos = player.position + dir * sprintDistance;
// A* 移动
boss.aiPath.maxSpeed = sprintSpeed;
boss.aiPath.isStopped = false;
boss.aiPath.destination = targetPos;
// 面向移动方向
boss.transform.rotation = Quaternion.LookRotation(dir);
// 等待到达
while (!boss.aiPath.reachedEndOfPath)
{
if (boss.isDead)
{
StopAllCoroutines();
isFinished = true;
}
yield return null;
}
boss.aiPath.isStopped = true;
boss.EndAttack();
}
#endregion
#region Phase 2 - Angry Trample
IEnumerator AngryTrample()
{
Transform player = GameManager.Ins.player.transform;
// 1⃣ 计算玩家方向(基准方向)
Vector3 dir = player.position - boss.transform.position;
dir.y = 0;
if (dir.sqrMagnitude < 0.01f)
yield break;
Quaternion baseRot = Quaternion.LookRotation(dir);
// 2⃣ 左侧 30°
Quaternion leftRot = baseRot * Quaternion.Euler(0, -15f, 0);
yield return RotateAndTrample(leftRot);
// 3⃣ 右侧 30°
Quaternion rightRot = baseRot * Quaternion.Euler(0, 15f, 0);
yield return RotateAndTrample(rightRot);
}
IEnumerator RotateAndTrample(Quaternion targetRot)
{
// 先转向
while (Quaternion.Angle(boss.transform.rotation, targetRot) > 1f)
{
if (boss.isDead)
{
StopAllCoroutines();
isFinished = true;
}
boss.transform.rotation = Quaternion.RotateTowards(
boss.transform.rotation,
targetRot,
rotateSpeed * Time.deltaTime
);
yield return null;
}
// 播放践踏动画
boss.Trample();
// 在该方向持续践踏
float timer = 0f;
while (timer < angryDuration)
{
timer += Time.deltaTime;
yield return null;
}
}
#endregion
#region Phase 3 - Rotate To Player
IEnumerator RotateToPlayer()
{
Transform player = GameManager.Ins.player.transform;
Vector3 dir = player.position - boss.transform.position;
dir.y = 0;
if (dir.sqrMagnitude < 0.01f)
yield break;
Quaternion targetRot = Quaternion.LookRotation(dir);
while (Quaternion.Angle(boss.transform.rotation, targetRot) > 1f)
{
if (boss.isDead)
{
StopAllCoroutines();
isFinished = true;
}
boss.transform.rotation = Quaternion.RotateTowards(
boss.transform.rotation,
targetRot,
rotateSpeed * Time.deltaTime
);
yield return null;
}
}
#endregion
}
public class TortoiseFireballAttack : Action
{
private TortoiseBoss boss;
private bool isFinished;
[Header("Fireball")]
public float shootInterval = 0.2f;
public float launchHeight = 4f;
public float flightTime = 1.2f;
public override void OnStart()
{
boss = GetComponent<TortoiseBoss>();
isFinished = false;
boss.ResetSkill2();
StartCoroutine(Fire());
}
public override TaskStatus OnUpdate()
{
return isFinished ? TaskStatus.Success : TaskStatus.Running;
}
IEnumerator Fire()
{
boss.Roar();
yield return new WaitForSeconds(0.5f);
foreach (var point in boss.firePoints)
{
SpawnFireBall(point);
yield return new WaitForSeconds(shootInterval);
}
yield return new WaitForSeconds(1f);
isFinished = true;
}
void SpawnFireBall(Transform firePoint)
{
Vector3 playerPos = GameManager.Ins.player.transform.position;
// 在玩家周围随机半径1米落点
Vector2 rand = Random.insideUnitCircle * 1f;
Vector3 targetPos = playerPos + new Vector3(rand.x, 0, rand.y);
GameObject ball = Object.Instantiate(boss.fireBallPre, firePoint.position, Quaternion.identity);
FireBallProjectile proj = ball.GetComponent<FireBallProjectile>();
proj.LaunchToTarget(firePoint.position, targetPos, flightTime);
proj.SetDamage(boss.Data.Atk_2);
}
}
public class TortoiseDrillingAttack : Action
{
private TortoiseBoss boss;
private Transform player;
private bool isFinished;
public float moveDuration = 20f;
public float maxChaseDistance = 12f; // 超过这个距离才开始校正
public float chaseStrength = 0.5f; // 校正强度(越小越自然)
public override void OnStart()
{
boss = GetComponent<TortoiseBoss>();
player = GameManager.Ins.player.transform;
isFinished = false;
boss.ResetSkill2();
boss.ResetSkill1();
StartCoroutine(Drilling());
}
public override TaskStatus OnUpdate()
{
return isFinished ? TaskStatus.Success : TaskStatus.Running;
}
IEnumerator Drilling()
{
// 1⃣ 钻地
yield return StartCoroutine(boss.Drilling());
// 2⃣ 弹球移动
yield return StartCoroutine(DrillBounceMove(moveDuration));
// 3⃣ 钻出
yield return StartCoroutine(boss.EndDrilling());
isFinished = true;
}
public IEnumerator DrillBounceMove(float duration)
{
float timer = 0f;
// ⭐ 第一次方向:直奔玩家
Vector3 moveDir = player.position - transform.position;
moveDir.y = 0;
if (moveDir.sqrMagnitude < 0.01f)
moveDir = transform.forward;
moveDir.Normalize();
boss.skill3Effect.SetActive(true);
boss.skill3Collider.enabled = true;
GameManager.Ins.PlaySound3D("1.25", transform, true);
while (timer < duration)
{
timer += Time.deltaTime;
if (boss.isDead)
yield break;
// 🧲 距离玩家过远时 → 轻微方向校正
Vector3 toPlayer = player.position - transform.position;
toPlayer.y = 0;
float distToPlayer = toPlayer.magnitude;
if (distToPlayer > maxChaseDistance)
{
Vector3 desiredDir = toPlayer.normalized;
// 轻微修正,不是强追踪
moveDir = Vector3.Lerp(
moveDir,
desiredDir,
chaseStrength * Time.deltaTime
);
moveDir.y = 0;
moveDir.Normalize();
}
Vector3 nextPos =
transform.position + moveDir * boss.drillMoveSpeed * Time.deltaTime;
// 🔥 撞墙反弹
if (Physics.Raycast(
transform.position,
moveDir,
out RaycastHit hit,
1.2f,
boss.drillHitMask))
{
moveDir = Vector3.Reflect(moveDir, hit.normal);
moveDir.y = 0;
moveDir.Normalize();
}
else
{
transform.position = nextPos;
}
yield return null;
}
}
}