431 lines
13 KiB
C#
431 lines
13 KiB
C#
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using BehaviorDesigner.Runtime;
|
||
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.TeleTrust;
|
||
using DG.Tweening;
|
||
using DragonLi.Core;
|
||
using DragonLi.Frame;
|
||
using UnityEngine;
|
||
|
||
public class Boss : Enemy
|
||
{
|
||
public GameObject player;
|
||
public GameObject[] twoAttackObjs;
|
||
public GameObject oneAttackObj;
|
||
|
||
public GameObject bigXl;//大招蓄力特效
|
||
public GameObject mzObj;//瞄准特效
|
||
public GameObject damagableObj;//受伤特效
|
||
public GameObject qteTargetPre;
|
||
|
||
public Transform[] enemyPos;
|
||
|
||
private bool _startAttack;
|
||
private bool _isAttacking;
|
||
private bool _isShow;
|
||
|
||
public int attackMode;
|
||
|
||
public override void Init()
|
||
{
|
||
base.Init();
|
||
bigXl.SetActive(false);
|
||
mzObj.SetActive(false);
|
||
_isShow = true;
|
||
damagableObj.SetActive(false);
|
||
player = GameManager.Ins.player;
|
||
foreach (var item in components)
|
||
{
|
||
item.Stop();
|
||
}
|
||
components[^1].boxCollider.enabled = false;
|
||
bloodSlider.gameObject.SetActive(false);
|
||
enemyState = EnemyState.Show;
|
||
attackMode = 0;
|
||
}
|
||
|
||
public override void StopAttack()
|
||
{
|
||
base.StopAttack();
|
||
attackMode = 0;
|
||
components[0].Stop();
|
||
StopAllCoroutines();
|
||
_isAttacking = false;
|
||
userSillIng = false;
|
||
}
|
||
|
||
public override void ChangeHp(float value, object info, Transform _sender)
|
||
{
|
||
base.ChangeHp(value, info, _sender);
|
||
}
|
||
|
||
public void FirstShow(Vector3 enemyDoorPos)
|
||
{
|
||
enemyState = EnemyState.FirstShow;
|
||
isShield = true;
|
||
GameInit.Ins.PlayAudio("1.2",transform,true, () =>
|
||
{
|
||
StartCoroutine(FirstShowTor( enemyDoorPos));
|
||
});
|
||
|
||
}
|
||
|
||
IEnumerator FirstShowTor(Vector3 enemyDoorPos)
|
||
{
|
||
var go= GameManager.Ins.CreateEnemyDoor(enemyDoorPos, Vector3.zero,Vector3.one*3 );
|
||
go.GetComponent<EnemyDoor>().desTime = 10;
|
||
go.GetComponent<EnemyDoor>().InitData();
|
||
yield return new WaitForSeconds(2f);
|
||
transform.DORotate(new Vector3(0, 180, 0), 2f).OnComplete(() =>
|
||
{
|
||
AnimatorComponent.SetFloat("speedf",1);
|
||
if (GameInit.Ins.gamePlace == GamePlace.Yangzhou_Hanjiang_Tansuozhongxin)
|
||
{
|
||
transform.DOMoveZ(-5, -10).OnComplete(() =>
|
||
{
|
||
Destroy(gameObject);
|
||
});
|
||
}
|
||
else
|
||
{
|
||
transform.DOMoveZ(-5, 4).OnComplete(() =>
|
||
{
|
||
Destroy(gameObject);
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
public override void Show()
|
||
{
|
||
base.Show();
|
||
isAttack = false;
|
||
isShield = true;
|
||
_isShow = true;
|
||
AnimatorComponent.SetFloat("speedf",1);
|
||
GameInit.Ins.PlayAudio("1.16",GameInit.Ins.self.transform,true);
|
||
float endValue = 10;
|
||
|
||
if (GameInit.Ins.gamePlace == GamePlace.HangZhouLongHuTianJie)
|
||
endValue = 20.5f;
|
||
if (GameInit.Ins.gamePlace == GamePlace.Yangzhou_Hanjiang_Tansuozhongxin)
|
||
endValue = -4.5f;
|
||
if (GameInit.Ins.gamePlace == GamePlace.Guangzhou_Panyv_Zhanting)
|
||
endValue = 3f;
|
||
if (GameInit.Ins.gamePlace == GamePlace.Anhui_Wuhu_Guanwei)
|
||
endValue = 4.5f;
|
||
if (GameInit.Ins.gamePlace == GamePlace.ShanDong_Langfang_QingzhouTaihuacheng)
|
||
endValue = 18f;
|
||
if(GameInit.Ins.gamePlace == GamePlace.Shandong_Jining_Wai)
|
||
{
|
||
transform.DOMove(new Vector3(22.5f,transform.position.y,-0.5f), 4).OnComplete(() =>
|
||
{
|
||
Both();
|
||
});
|
||
}
|
||
else
|
||
{
|
||
transform.DOMoveZ(endValue, 4).OnComplete(() =>
|
||
{
|
||
Both();
|
||
});
|
||
}
|
||
|
||
}
|
||
|
||
public void Both()
|
||
{
|
||
AnimatorComponent.SetFloat("speedf",0);
|
||
AnimatorComponent.SetBool("isBoth",true);
|
||
GameInit.Ins.PlayAudio("1.14",transform,true);
|
||
_isShow = false;
|
||
MonoSingleton<CoroutineTaskManager>.Instance.WaitSecondTodo(() =>
|
||
{
|
||
AnimatorComponent.SetBool("isBoth",false);
|
||
isAttack = true;
|
||
bloodSlider.gameObject.SetActive(true);
|
||
isShield = false;
|
||
},6f);
|
||
}
|
||
|
||
public override void Attack()
|
||
{
|
||
base.Attack();
|
||
if (!_isAttacking)
|
||
{
|
||
_isAttacking = true;
|
||
attackMode=Random.Range(1,4);
|
||
}
|
||
}
|
||
|
||
public override void OneAttackMode()
|
||
{
|
||
base.OneAttackMode();
|
||
PerformThrowShield();
|
||
}
|
||
|
||
[Header("盾牌投掷")]
|
||
[Tooltip("盾牌预制体")]
|
||
public GameObject shieldPrefab;
|
||
|
||
[Header("盾牌参数")]
|
||
public float shieldSpeed = 30f;
|
||
public float groundY = 0.5f;
|
||
public float stayTime = 2f;
|
||
private float hitRadius = 1f;
|
||
private float damageAmount = 3000f;
|
||
|
||
//// <summary>
|
||
/// 外部调用:让 Boss 执行投掷盾牌技能
|
||
/// </summary>
|
||
public void PerformThrowShield()
|
||
{
|
||
attackMode = 4;
|
||
AnimatorComponent.SetBool("isCastEnd",true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 盾牌飞回 Boss 手时自动调用,结束投掷动画
|
||
/// </summary>
|
||
private void OnShieldReturned()
|
||
{
|
||
AnimatorComponent.SetBool("isCastEnd",false);
|
||
components[1].GetComponent<MeshRenderer>().enabled = true;
|
||
attackMode = 0;
|
||
userSillIng = false;
|
||
}
|
||
|
||
public override void Show2()
|
||
{
|
||
base.Show2();
|
||
StopAllCoroutines();
|
||
}
|
||
|
||
//释放剑雨
|
||
public override void TwoAttackMode()
|
||
{
|
||
//base.TwoAttackMode();
|
||
userSillIng = true;
|
||
attackMode = 5;
|
||
AnimatorComponent.SetBool("isCastEnd",true);
|
||
}
|
||
|
||
public override void StartQteAttack()
|
||
{
|
||
attackMode = 6;
|
||
AnimatorComponent.SetBool("isCastEnd",false);
|
||
MonoSingleton<CoroutineTaskManager>.Instance.WaitSecondTodo(() =>
|
||
{
|
||
bigXl.SetActive(true);
|
||
mzObj.SetActive(true);
|
||
},2f);
|
||
}
|
||
|
||
public override void BossQteAttack()
|
||
{
|
||
base.BossQteAttack();
|
||
AnimatorComponent.SetBool("isCastEnd",true);
|
||
attackMode = 0;
|
||
bigXl.SetActive(false);
|
||
mzObj.SetActive(false);
|
||
}
|
||
|
||
public void QteAttack()
|
||
{
|
||
damagableObj.SetActive(true);
|
||
qteTargetPre.transform.position = player.transform.position;
|
||
player.GetComponent<IDamagable>().ApplyDamage(GameInit.Ins.self.maxHp/2,null,transform);
|
||
shieldObj.SetActive(false);
|
||
isShield = false;
|
||
}
|
||
|
||
public override void StopQteAttack()
|
||
{
|
||
base.StopQteAttack();
|
||
bigXl.SetActive(false);
|
||
mzObj.SetActive(false);
|
||
components[^1].StopQteAttack();
|
||
shieldObj.SetActive(false);
|
||
isShield = false;
|
||
attackMode = 0;
|
||
}
|
||
|
||
public override void Update()
|
||
{
|
||
base.Update();
|
||
AnimatorComponent.SetInteger("attackMode",attackMode);
|
||
if(_isShow) return;
|
||
// 平滑朝向玩家
|
||
Vector3 targetDir = GameManager.Ins.player.transform.position - transform.position;
|
||
targetDir.y = 0f;
|
||
|
||
if (targetDir != Vector3.zero)
|
||
{
|
||
Quaternion targetRotation = Quaternion.LookRotation(targetDir);
|
||
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 2f);
|
||
}
|
||
|
||
curEnemyTime-=Time.deltaTime;
|
||
if (curEnemyTime <=0 )
|
||
{
|
||
if(GameManager.Ins.GetCurEnemyListCount()<=8)
|
||
ShowEnemy();
|
||
curEnemyTime = enemyTime;
|
||
}
|
||
}
|
||
|
||
private float enemyTime=45f;
|
||
private float curEnemyTime;
|
||
public void ShowEnemy()
|
||
{
|
||
List<int> enemyList = new List<int>(){1, 4, 6};
|
||
|
||
for (int i = 0; i < enemyPos.Length; i++)
|
||
{
|
||
Vector3 curEnemyPos = new Vector3(enemyPos[i].position.x, 0, enemyPos[i].position.z);
|
||
GameManager.Ins.CreateCallEnemyEffect(curEnemyPos);
|
||
}
|
||
MonoSingleton<CoroutineTaskManager>.Instance.WaitSecondTodo(() =>
|
||
{
|
||
for (int i = 0; i < enemyPos.Length; i++)
|
||
{
|
||
int index = Random.Range(0, 3);
|
||
Vector3 curEnemyPos = new Vector3(enemyPos[i].position.x, 0, enemyPos[i].position.z);
|
||
GameManager.Ins.CreateEnemy(enemyList[index], curEnemyPos, Vector3.zero, false);
|
||
}
|
||
}, 2f);
|
||
}
|
||
|
||
public override void Dead()
|
||
{
|
||
base.Dead();
|
||
GameManager.Ins.WinEndGame();
|
||
GameInit.Ins.PlayAudio("1.15",GameInit.Ins.self.transform,true);
|
||
}
|
||
public void Play1Attack()
|
||
{
|
||
components[0].CmdFire2(player.transform.position);
|
||
GameInit.Ins.PlayAudio("2.32砸击",transform,false);
|
||
}
|
||
public void Play2Attack()
|
||
{
|
||
components[1].GetComponent<MeshRenderer>().enabled = false;
|
||
// 2. 实例化盾牌并初始化
|
||
GameObject shieldGO = Instantiate(shieldPrefab, components[1].transform.position, Quaternion.identity);
|
||
ShieldProjectile sp = shieldGO.GetComponent<ShieldProjectile>();
|
||
if (sp != null)
|
||
{
|
||
sp.Initialize(
|
||
player.transform,
|
||
components[1].transform,
|
||
shieldSpeed,
|
||
groundY,
|
||
stayTime,
|
||
hitRadius,
|
||
damageAmount);
|
||
|
||
// 3. 订阅盾牌返回完成事件
|
||
sp.OnReturnComplete += OnShieldReturned;
|
||
}
|
||
else
|
||
{
|
||
Debug.LogError("BossController: 盾牌预制体上缺少 ShieldProjectile 脚本");
|
||
}
|
||
}
|
||
|
||
|
||
[Header("剑雨攻击配置")]
|
||
[Tooltip("可飞行的剑预制体")]
|
||
public GameObject swordProjectilePrefab;
|
||
[Tooltip("剑飞行速度")]
|
||
public float swordFlySpeed = 15f;
|
||
[Tooltip("剑落地后停留时间")]
|
||
public float swordStayTime = 2f;
|
||
[Tooltip("剑击中玩家半径")]
|
||
public float swordHitRadius = 1f;
|
||
[Tooltip("剑造成的伤害")]
|
||
private float swordDamage = 500f;
|
||
[Tooltip("剑起飞时的高度偏移")]
|
||
public float swordHeightOffset = 5f;
|
||
/// <summary>
|
||
/// 对外调用:触发一次剑雨攻击
|
||
/// </summary>
|
||
public void SwordRainAttack()
|
||
{
|
||
isShield = true;
|
||
if (shieldObj)
|
||
shieldObj.SetActive(true);
|
||
StartCoroutine(FlySword());
|
||
}
|
||
|
||
IEnumerator FlySword()
|
||
{
|
||
int index = 0;
|
||
// 2. 每个挂点都取一个“剑模型”数据,实例化为可飞行的 SwordProjectile
|
||
foreach (var item in twoAttackObjs)
|
||
{
|
||
var anchor= item.GetComponent<Transform>();
|
||
// 2.1 如果挂点下有“子物体”是剑模型,先隐藏它
|
||
anchor.GetComponent<MeshRenderer>().enabled = false;
|
||
Transform showPos = anchor;
|
||
if (anchor.childCount > 0)
|
||
{
|
||
showPos= anchor.GetChild(0);
|
||
}
|
||
// 2.2 实例化一个 SwordProjectile 并初始化
|
||
Vector3 spawnPos = anchor.position + Vector3.up * swordHeightOffset;
|
||
GameObject swordGO = Instantiate(swordProjectilePrefab, spawnPos, Quaternion.identity);
|
||
SwordProjectile sp = swordGO.GetComponent<SwordProjectile>();
|
||
if (sp != null)
|
||
{
|
||
sp.Initialize(
|
||
player.transform,
|
||
showPos,
|
||
swordFlySpeed,
|
||
groundY,
|
||
swordStayTime,
|
||
swordHitRadius,
|
||
swordDamage);
|
||
sp.OnReturnComplete += () => OnSingleSwordReturned(anchor);
|
||
index++;
|
||
if(index%2==0)
|
||
yield return new WaitForSeconds(1.5f);
|
||
}
|
||
else
|
||
{
|
||
Debug.LogError("SwordRainAttack: 未在 swordProjectilePrefab 上找到 SwordProjectile 脚本");
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 某把剑返回到 backPoint(挂点)时调用
|
||
/// 我们在所有剑都返回完毕时,再结束投掷动画
|
||
/// </summary>
|
||
private int swordsReturnedCount = 0;
|
||
private void OnSingleSwordReturned(Transform anchor)
|
||
{
|
||
// 显示挂回到背部的“原始剑模型”:
|
||
anchor.GetComponent<MeshRenderer>().enabled = true;
|
||
|
||
swordsReturnedCount++;
|
||
// 如果所有挂点的剑都已经返回,则动画结束
|
||
if (swordsReturnedCount >= twoAttackObjs.Length)
|
||
{
|
||
OnAllSwordsReturned();
|
||
}
|
||
}
|
||
|
||
private void OnAllSwordsReturned()
|
||
{
|
||
// 重置计数
|
||
swordsReturnedCount = 0;
|
||
AnimatorComponent.SetBool("isCastEnd",false);
|
||
attackMode = 0;
|
||
userSillIng = false;
|
||
isShield = false;
|
||
if (shieldObj)
|
||
shieldObj.SetActive(false);
|
||
}
|
||
}
|