314 lines
7.8 KiB
C#
314 lines
7.8 KiB
C#
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 bool isFinished;
|
||
|
||
public float moveDuration = 20f;
|
||
public override void OnStart()
|
||
{
|
||
boss = GetComponent<TortoiseBoss>();
|
||
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 = Random.insideUnitSphere;
|
||
moveDir.y = 0;
|
||
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 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;
|
||
}
|
||
}
|
||
|
||
|
||
} |