311 lines
8.4 KiB
C#
311 lines
8.4 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using DG.Tweening;
|
||
using DragonLi.Core;
|
||
using UnityEngine;
|
||
|
||
public class Tentacle : Enemy
|
||
{
|
||
public float upIndex;
|
||
private float downIndex=-7;
|
||
|
||
public GameObject model;
|
||
public GameObject atkEx;
|
||
|
||
public Animator animator;
|
||
|
||
public EnemyBoneHit[] skill1BoneHits;
|
||
public EnemyBoneHit[] skill1ExBoneHits;
|
||
public EnemyBoneHit[] skill2BoneHits;
|
||
|
||
private Vector3 _startPos;
|
||
private bool isAttacking;
|
||
private Quaternion _originRot;
|
||
private float rotateSpeed = 180f; // 每秒旋转角度
|
||
private void Start()
|
||
{
|
||
_startPos = transform.position;
|
||
atkEx.SetActive(false);
|
||
foreach (var item in skill1BoneHits)
|
||
{
|
||
item.gameObject.SetActive(false);
|
||
}
|
||
foreach (var item in skill2BoneHits)
|
||
{
|
||
item.gameObject.SetActive(false);
|
||
}
|
||
foreach (var item in skill1ExBoneHits)
|
||
{
|
||
item.gameObject.SetActive(false);
|
||
}
|
||
bloodSlider.gameObject.SetActive(false);
|
||
skill1ExBoneHits[0].transform.localScale=new Vector3(skill1ExBoneHits[0].transform.localScale.x, 10, skill1ExBoneHits[0].transform.localScale.z);
|
||
skill1ExBoneHits[0].transform.localPosition=new Vector3(skill1ExBoneHits[0].transform.localPosition.x,0, 10);
|
||
}
|
||
|
||
public override void SetData(EnemyData data)
|
||
{
|
||
base.SetData(data);
|
||
enemyState = EnemyState.Show;
|
||
health = Data.Hp_CS1;
|
||
maxHealth = Data.Hp_CS1;
|
||
bloodSlider.SetName("巨妖触手");
|
||
isDead = false;
|
||
isShowEnd = false;
|
||
}
|
||
|
||
public override void EndShow()
|
||
{
|
||
enemyState = EnemyState.Idle;
|
||
bloodSlider.gameObject.SetActive(true);
|
||
}
|
||
|
||
void PlayIdle()
|
||
{
|
||
if(isDead)
|
||
return;
|
||
animator.SetInteger("state",0);
|
||
enemyState = EnemyState.Idle;
|
||
GameManager.Ins.PlaySound3D("1.18",transform);
|
||
}
|
||
|
||
public IEnumerator Attack(bool isFurious)
|
||
{
|
||
if (isAttacking||isDead)
|
||
yield break;
|
||
isAttacking = true;
|
||
|
||
// ⭐ 记录初始朝向
|
||
_originRot = transform.rotation;
|
||
GameManager.Ins.PlaySound3D("1.8",transform);
|
||
// 0️⃣ 攻击前转向玩家
|
||
yield return RotateToPlayer();
|
||
|
||
// 1️⃣ 前摇
|
||
yield return new WaitForSeconds(0.8f);
|
||
|
||
// 2️⃣ 播放攻击动画
|
||
|
||
animator.SetInteger("state",1);
|
||
BeginAttack();
|
||
enemyState = EnemyState.NormalAttack;
|
||
yield return new WaitForSeconds(1.72f);
|
||
GameManager.Ins.PlaySound3D("1.9",transform,true);
|
||
// 4️⃣ 攻击判定 / 特效
|
||
DoAttackHit(isFurious);
|
||
// 5️⃣ 等动画播完
|
||
yield return new WaitForSeconds(3.2f);
|
||
|
||
// ⭐ 攻击结束后转回
|
||
//yield return RotateBack();
|
||
|
||
// 6️⃣ 切回 Idle
|
||
PlayIdle();
|
||
EndAttack();
|
||
|
||
isAttacking = false;
|
||
}
|
||
|
||
int GetCurrentFrame(int layer = 0)
|
||
{
|
||
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(layer);
|
||
AnimatorClipInfo[] clipInfos = animator.GetCurrentAnimatorClipInfo(layer);
|
||
|
||
if (clipInfos.Length == 0)
|
||
return 0;
|
||
|
||
AnimationClip clip = clipInfos[0].clip;
|
||
|
||
float normalizedTime = stateInfo.normalizedTime % 1f; // 防止循环动画溢出
|
||
float currentTime = normalizedTime * clip.length;
|
||
int currentFrame = Mathf.FloorToInt(currentTime * clip.frameRate);
|
||
|
||
return currentFrame;
|
||
}
|
||
|
||
float GetCurrentClipLength(int layer = 0)
|
||
{
|
||
AnimatorClipInfo[] clipInfos = animator.GetCurrentAnimatorClipInfo(layer);
|
||
|
||
if (clipInfos.Length == 0)
|
||
return 0f;
|
||
|
||
return clipInfos[0].clip.length;
|
||
}
|
||
|
||
IEnumerator RotateToPlayer()
|
||
{
|
||
Transform player = GameManager.Ins.player.transform;
|
||
|
||
Vector3 dir = player.position - transform.position;
|
||
dir.y = 0;
|
||
|
||
if (dir.sqrMagnitude < 0.01f)
|
||
yield break;
|
||
|
||
Quaternion targetRot = Quaternion.LookRotation(dir);
|
||
|
||
while (Quaternion.Angle(transform.rotation, targetRot) > 1f)
|
||
{
|
||
transform.rotation = Quaternion.RotateTowards(
|
||
transform.rotation,
|
||
targetRot,
|
||
rotateSpeed * Time.deltaTime
|
||
);
|
||
yield return null;
|
||
}
|
||
}
|
||
|
||
IEnumerator RotateBack()
|
||
{
|
||
while (Quaternion.Angle(transform.rotation, _originRot) > 1f)
|
||
{
|
||
transform.rotation = Quaternion.RotateTowards(
|
||
transform.rotation,
|
||
_originRot,
|
||
rotateSpeed * Time.deltaTime
|
||
);
|
||
yield return null;
|
||
}
|
||
}
|
||
|
||
public override void EndAttack()
|
||
{
|
||
base.EndAttack();
|
||
foreach (var item in skill1BoneHits)
|
||
{
|
||
item.gameObject.SetActive(false);
|
||
}
|
||
foreach (var item in skill1ExBoneHits)
|
||
{
|
||
item.gameObject.SetActive(true);
|
||
}
|
||
}
|
||
|
||
void DoAttackHit(bool isFurious)
|
||
{
|
||
// 开启攻击特效
|
||
atkEx.SetActive(true);
|
||
enemyState = EnemyState.SpikeAttack;
|
||
foreach (var item in skill1BoneHits)
|
||
{
|
||
item.gameObject.SetActive(true);
|
||
item.SetDamage(isFurious? Data.Atk_1B: Data.Atk_1P);
|
||
}
|
||
foreach (var item in skill1ExBoneHits)
|
||
{
|
||
item.gameObject.SetActive(true);
|
||
item.SetDamage(isFurious? Data.Atk_1B: Data.Atk_1P);
|
||
}
|
||
// 一小段时间后关闭特效
|
||
StartCoroutine(HideAtkEx());
|
||
}
|
||
|
||
IEnumerator HideAtkEx()
|
||
{
|
||
yield return new WaitForSeconds(1f);
|
||
|
||
atkEx.SetActive(false);
|
||
}
|
||
public void Hide()
|
||
{
|
||
GameManager.Ins.PlaySound3D("1.15",transform,true);
|
||
bloodSlider.gameObject.SetActive(false);
|
||
model.transform.DOMoveY(downIndex, 1f).OnComplete(() =>
|
||
{
|
||
model.SetActive(false);
|
||
});
|
||
}
|
||
|
||
public override void Hit()
|
||
{
|
||
if(enemyState!= EnemyState.Idle)
|
||
return;
|
||
animator.SetTrigger("hit");
|
||
}
|
||
|
||
public void Spike(Vector3 pos)
|
||
{
|
||
model.SetActive(true);
|
||
model.transform.position = new Vector3(pos.x, downIndex, pos.z);
|
||
animator.SetInteger("state",2);
|
||
BeginAttack();
|
||
foreach (var item in skill2BoneHits)
|
||
{
|
||
item.SetDamage(Data.Atk_3);
|
||
}
|
||
model.transform.DOMoveY(upIndex,1).SetEase(Ease.OutBounce).OnComplete(() =>
|
||
{
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
if(isDead)
|
||
return;
|
||
EndAttack();
|
||
model.transform.DOMoveY(downIndex,1).SetEase(Ease.OutBounce).OnComplete(() =>
|
||
{
|
||
transform.position=new Vector3(_startPos.x,downIndex,_startPos.z);
|
||
model.transform.localPosition=Vector3.zero;
|
||
PlayIdle();
|
||
transform.DOMoveY(upIndex,1).SetEase(Ease.OutBounce);
|
||
});
|
||
}, 3f);
|
||
});
|
||
}
|
||
|
||
public void RefreshToBoss()
|
||
{
|
||
if(isDead)
|
||
return;
|
||
_startPos=transform.position;
|
||
|
||
model.SetActive(true);
|
||
model.transform.DOLocalMoveY(upIndex, 1).OnComplete(() =>
|
||
{
|
||
bloodSlider.gameObject.SetActive(true);
|
||
});
|
||
}
|
||
|
||
public override void ChangeHp(float value, object info, Transform _sender)
|
||
{
|
||
if(enemyState== EnemyState.Show)
|
||
return;
|
||
base.ChangeHp(value, info, _sender);
|
||
if(isDead)
|
||
return;
|
||
GameManager.Ins.PlaySound3D("1.10",transform);
|
||
}
|
||
|
||
public override void Dead()
|
||
{
|
||
base.Dead();
|
||
health = 0;
|
||
animator.SetBool("isDie",true);
|
||
GameManager.Ins.PlaySound3D("1.11",transform,true);
|
||
transform.parent = null;
|
||
StopAllCoroutines();
|
||
}
|
||
|
||
public override void Update()
|
||
{
|
||
base.Update();
|
||
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.rotation = Quaternion.RotateTowards(
|
||
transform.rotation,
|
||
targetRot,
|
||
rotateSpeed * Time.deltaTime
|
||
);
|
||
}
|
||
}
|
||
|