274 lines
6.6 KiB
C#
274 lines
6.6 KiB
C#
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<FrogBugEnemy> frogBugs = new List<FrogBugEnemy>();
|
|
|
|
|
|
public GameObject[] bossCrystals;
|
|
|
|
private float rotateSpeed = 180f; // 越大转得越快(插值系数)
|
|
|
|
public List<FrogBugEnemy> GetAliveTentacles()
|
|
{
|
|
List<FrogBugEnemy> 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 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
|
|
}
|