Files
FutureMen2/Assets/_FutureMen2/Scripts/Enemy/FrogBoss/FrogBugEnemy.cs

272 lines
5.6 KiB
C#

using System;
using System.Collections;
using DG.Tweening;
using Pathfinding;
using UnityEngine;
public class FrogBugEnemy : Enemy
{
public GameObject model;
public GameObject egg;
[Header("Egg")]
public float eggShakeTime = 2f;
public float eggShakeStrength = 0.15f;
public GameObject eggBreakFx;
[Header("AI")]
[NonSerialized]
public float attackRange = 1.7f;
public float attackCooldown = 1.5f;
[Header("Jump Back")]
public float jumpBackDistance = 1.5f;
public float jumpBackTime = 0.35f;
[Header("Animation")]
public Animator anim;
private Transform player;
private bool isAttacking;
private float attackTimer;
private float atk;
#region Unity
protected void Start()
{
player = GameManager.Ins.player.transform;
model.SetActive(false);
bloodSlider.gameObject.SetActive(false);
}
public override void Show()
{
base.Show();
//蛋到达落点后 抖动两下 之后播放蛋破碎动画 播放后model打开 蛋消失 怪物切换成EnemyState.NormalAttack
}
public void SetAtk(float curAtk,float maxHp)
{
atk = curAtk;
maxHealth = maxHp;
health = maxHp;
Debug.Log("小怪生命之:"+maxHp);
}
public override void Update()
{
base.Update();
if (enemyState != EnemyState.NormalAttack || player == null)
return;
attackTimer += Time.deltaTime;
HandleMoveAndAttack();
}
#endregion
#region Core Logic
public void LaunchEgg(
Vector3 start,
Vector3 target,
float height,
float time,
float curAtk,
float hp
)
{
atk = curAtk;
maxHealth = hp;
transform.position = start;
model.SetActive(false);
egg.SetActive(true);
StartCoroutine(EggFlyRoutine(start, target, height, time));
}
IEnumerator EggFlyRoutine(
Vector3 start,
Vector3 target,
float height,
float time
)
{
float timer = 0f;
while (timer < time)
{
timer += Time.deltaTime;
float t = timer / time;
Vector3 pos = Vector3.Lerp(start, target, t);
pos.y += Mathf.Sin(t * Mathf.PI) * height;
transform.position = pos;
yield return null;
}
transform.position = target;
StartCoroutine(EggHatch());
}
IEnumerator EggHatch()
{
enemyState = EnemyState.Show;
// 抖动
egg.transform.DOShakePosition(
eggShakeTime,
eggShakeStrength,
vibrato: 10
);
yield return new WaitForSeconds(eggShakeTime);
if (egg.GetComponent<Animator>())
{
egg.GetComponent<Animator>().SetBool("isDie",true);
}
model.SetActive(true);
yield return new WaitForSeconds(2);
egg.SetActive(false);
enemyState = EnemyState.NormalAttack;
}
void HandleMoveAndAttack()
{
float dist = Vector3.Distance(transform.position, player.position);
if (dist <= attackRange)
{
TryAttack();
}
else
{
ChasePlayer();
}
}
void ChasePlayer()
{
if (isAttacking)
return;
ResumeAI();
aiPath.destination = player.position;
anim.SetInteger("State", 1); // Run
}
void TryAttack()
{
if (isAttacking)
return;
if (attackTimer < attackCooldown)
return;
StartCoroutine(AttackRoutine());
}
#endregion
#region Attack
IEnumerator AttackRoutine()
{
isAttacking = true;
attackTimer = 0f;
StopAI();
// 朝向玩家
Vector3 dir = player.position - transform.position;
dir.y = 0;
if (dir.sqrMagnitude > 0.01f)
transform.rotation = Quaternion.LookRotation(dir);
anim.SetInteger("State", 2); // Attack
yield return new WaitForSeconds(0.4f);
DoDamageCheck();
yield return new WaitForSeconds(0.3f);
yield return JumpBack();
anim.SetInteger("State", 1); // Run
ResumeAI();
isAttacking = false;
}
void DoDamageCheck()
{
float dist = Vector3.Distance(transform.position, player.position);
if (dist <= attackRange + 0.3f)
{
player.GetComponent<EnemyIDamagable>()
?.ApplyDamage(atk, null, transform);
}
}
#endregion
#region Jump Back
IEnumerator JumpBack()
{
StopAI();
Vector3 backDir = -transform.forward;
Vector3 targetPos = transform.position + backDir * jumpBackDistance;
if (Physics.Raycast(transform.position, backDir, out RaycastHit hit, jumpBackDistance))
{
targetPos = hit.point + hit.normal * 0.2f;
}
anim.SetInteger("State", 1); // Run
transform.DOJump(
targetPos,
0.6f,
1,
jumpBackTime
);
yield return new WaitForSeconds(jumpBackTime);
}
#endregion
#region AI Control (A* )
void StopAI()
{
aiPath.isStopped = true;
aiPath.destination = transform.position;
}
void ResumeAI()
{
aiPath.isStopped = false;
}
#endregion
#region Death
public override void Dead()
{
base.Dead();
StopAllCoroutines();
StopAI();
anim.SetBool("IsDie",true);
}
#endregion
}