using System; using System.Collections; using System.Collections.Generic; using DG.Tweening; using DragonLi.Core; using UnityEngine; using Random = UnityEngine.Random; public class FrogBoss : Enemy { [Header("Base")] public GameObject clipQuadObj; public Animator bossAnim; [Header("Skill Prefabs")] public Transform mouthPoint; public GameObject poisonBallPrefab; public GameObject eggPrefab; public Transform eggFirePoint; public EnemyBoneHit mouthBoneHit; public List frogBugs = new List(); public GameObject[] bossCrystals; private float rotateSpeed = 180f; // 越大转得越快(插值系数) public List GetAliveTentacles() { List list = new(); foreach (var t in frogBugs) if (t != null && !t.isDead) list.Add(t); return list; } private void Start() { clipQuadObj.transform.localPosition = new Vector3(0, -5f, 0); mouthBoneHit.SetDamage(Data.Atk_1P); bloodSlider.gameObject.SetActive(false); foreach (var item in bossCrystals) { item.SetActive(false); } transform.LookAt(GameManager.Ins.player.transform.position.ReflectVectorXOZ()); } public override void Update() { base.Update(); if (enemyState != EnemyState.Show && enemyState != EnemyState.Dead) { skill1Timer += Time.deltaTime; skill2Timer += Time.deltaTime; Transform player = GameManager.Ins.player.transform; if (!player) return; Vector3 dir = player.position - transform.position; dir.y = 0; if (dir.sqrMagnitude < 0.0001f) return; Quaternion targetRot = Quaternion.LookRotation(dir); transform.transform.rotation = Quaternion.RotateTowards( transform.transform.rotation, targetRot, rotateSpeed * Time.deltaTime ); } } #region Show public override void Show() { base.Show(); clipQuadObj.transform.DOLocalMoveY(10, 5).OnComplete(() => { isShowEnd = true; Roar(); }); } public override void EndShow() { base.EndShow(); bloodSlider.gameObject.SetActive(true); foreach (var item in bossCrystals) { item.SetActive(true); } } #endregion #region Skill Reset public bool HasAnySkillReady() { return skill1Timer >= skill1Cooldown || skill2Timer >= skill2Cooldown || IsUserSkill3(); } public bool IsUserSkill3() { float hpPercent =health / maxHealth; int index = Mathf.FloorToInt(hpPercent / 0.2f); if (index < spikeTriggerIndex) { spikeTriggerIndex = index; return true; } return false; } public void ResetSkill1() => skill1Timer = 0; public void ResetSkill2() => skill2Timer = 0; #endregion #region Animation Wrappers public void Roar() { bossAnim.SetInteger("State", 0); GameManager.Ins.PlaySound3D("1.2", transform); } public void Run() { bossAnim.SetInteger("State", 2); GameManager.Ins.PlaySound3D("1.19", transform); } /// /// 后撤 /// public void Retreat() { bossAnim.SetInteger("State", 6); GameManager.Ins.PlaySound3D("1.19", transform); } public void Idle() { bossAnim.SetInteger("State", 1); if(isDead) return; GameManager.Ins.PlaySound3D("1.20", transform, true); } public override void Hit() { if(enemyState!= EnemyState.Idle) return; base.Hit(); int hitIndex = Random.Range(0, 100); string hitStr=hitIndex>=50 ?"isHit1":"isHit2"; bossAnim.SetTrigger(hitStr); } public void TongueAttack() { bossAnim.SetInteger("State", 3); GameManager.Ins.PlaySound3D("1.31", transform, true); } public void Spit() { bossAnim.SetInteger("State", 4); GameManager.Ins.PlaySound3D("1.20", transform, true); } public void EggAttack() { bossAnim.SetInteger("State", 5); } [NonSerialized] public float tongueRange = 10f; public float moveSpeed = 3.5f; public bool IsPlayerInTongueRange() { return Vector3.Distance( transform.position, GameManager.Ins.player.transform.position ) <= tongueRange; } public IEnumerator MoveToTongueRange() { Run(); while (!IsPlayerInTongueRange()) { Vector3 playerPos = GameManager.Ins.player.transform.position; Vector3 dir = (playerPos - transform.position).normalized; // 只在 XZ 平面移动 transform.position += new Vector3( dir.x, 0, dir.z ) * moveSpeed * Time.deltaTime; // 面向玩家 transform.forward = Vector3.Lerp( transform.forward, new Vector3(dir.x, 0, dir.z), Time.deltaTime * 8f ); yield return null; } Idle(); } #endregion public override void ChangeHp(float value, object info, Transform _sender) { if(enemyState== EnemyState.Show) return; base.ChangeHp(value, info, _sender); } #region Die public override void Dead() { if (isDead) { return; } GameManager.Ins.curLevel++; isDead = true; health = 0; if (bloodSlider != null) bloodSlider.gameObject.SetActive(false); if(ColliderComponent!=null) ColliderComponent.enabled = false; if(behaviourTree != null) behaviourTree.enabled = false; GameManager.Ins.PlaySound3D("1.46",transform,true); foreach (var item in bossCrystals) { if(item==null) continue; item.SetActive(false); } foreach (var item in GetAliveTentacles()) { item.Dead(); } StartCoroutine(DeathDissolve()); } IEnumerator DeathDissolve() { clipQuadObj.SetActive(true); bloodSlider.gameObject.SetActive(false); clipQuadObj.transform.localPosition = new Vector3(0, 5f, 0); bossAnim.SetBool("isDie",true); yield return new WaitForSeconds(3f); clipQuadObj.transform.DOLocalMoveY(-5f, 5); yield return new WaitForSeconds(8f); GameManager.Ins.CreateBoss(transform.position.ReflectVectorXOZ()); Destroy(gameObject); } #endregion }