religion/Assets/Scripts/Boss/木马/TrojanHorse.cs
Roman 65237ef698 Squashed commit of the following:
commit 0d7446d2e7a625f033cda6acc496c6cddfe2d75f
Author: SAIPO <grasste0403@hotmail.com>
Date:   Sat Dec 25 22:53:32 2021 +0800

    修改建议及完善特效

    修改建议:
    1.添加了击中的粒子特效,但是还需要迭代
    2.修复马死后灰尘不会消失的bug

    完善特效
    1.制作了死亡时的阴间特效,已经在全场景实装
    2.制作了闪电的辉光特效。
    3.调整了所有场景的全局shader以适配死亡阴间特效

# Conflicts:
#	UserSettings/EditorUserSettings.asset
2021-12-26 21:25:59 +08:00

372 lines
13 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Sirenix.OdinInspector;
using DG.Tweening;
/// <summary>
/// 木马类
/// </summary>
public class TrojanHorse : Enemy, Boomer.I_CanBeBoomedObj
{
// _____ _ _ _
// | __ \ | | | (_)
// | |__) | _| |__ | |_ ___
// | ___/ | | | '_ \| | |/ __|
// | | | |_| | |_) | | | (__
// |_| \__,_|_.__/|_|_|\___|
/// <summary>
/// 攻击之间的间隔时间
/// </summary>
[Header("攻击之间的间隔时间")][FoldoutGroup("木马")]
public float timeBetweenAttacks;
/// <summary>
/// 伊斯兰小怪的预制体
/// </summary>
[Header("伊斯兰小怪的预制体")][FoldoutGroup("预制体")]
public GameObject yiSiLan;
/// <summary>
/// 召唤小怪攻击中,生成小怪之间间隔的最短时间
/// </summary>
[Header("召唤小怪攻击中,生成小怪之间间隔的最短时间")][FoldoutGroup("木马")]
public float yiSiLanMinTime;
// <summary>
/// 召唤小怪攻击中,生成小怪之间间隔的最长时间
/// </summary>
[Header("召唤小怪攻击中,生成小怪之间间隔的最长时间")][FoldoutGroup("木马")]
public float yiSiLanMaxTime;
/// <summary>
/// 炸弹的预制体,用来喷射的那种
/// </summary>
[Header("炸弹的预制体,用来喷射的那种")][FoldoutGroup("预制体")]
public GameObject sprayBoomer;
/// <summary>
/// 喷射炸弹的时间间隔
/// </summary>
[Header("喷射炸弹的时间间隔")][FoldoutGroup("木马")]
public float sprayBoomerTime;
/// <summary>
/// 喷射炸弹的方向
/// </summary>
[Header("喷射炸弹的方向")][FoldoutGroup("木马")]
public Vector2 sprayBoomerDir;
/// <summary>
/// 喷射炸弹的力度倍数
/// </summary>
[Header("喷射炸弹的力度倍数")][FoldoutGroup("木马")]
public float sprayBoomerMultiple;
/// <summary>
/// 召唤炸弹攻击,炸弹从天而降的初速度
/// </summary>
[Header("召唤炸弹攻击,炸弹从天而降的初速度")][FoldoutGroup("木马")]
public Vector2 callBoomStartVelocity;
[Header("召唤炸弹攻击,炸弹从天而降的初速度")] [FoldoutGroup("木马")]
public List<ParticleSystem> trojanHorseParticleSystems;
// _____ _ _
// | __ \ (_) | |
// | |__) | __ ___ ____ _| |_ ___
// | ___/ '__| \ \ / / _` | __/ _ \
// | | | | | |\ V / (_| | || __/
// |_| |_| |_| \_/ \__,_|\__\___|
/// <summary>
/// 返回类型为协程、参数为空的委托类型
/// </summary>
private delegate IEnumerator Action();
/// <summary>
/// 开关,控制此时木马是否在移动
/// </summary>
[SerializeField][Header("此时木马是否在移动")][FoldoutGroup("状态")][ReadOnly]
public bool isMove = false;
/// <summary>
/// 召唤伊斯兰小怪的初始位置
/// </summary>
private Transform callYiSiLanPosition;
/// <summary>
/// 喷射炸弹的起点
/// </summary>
private Transform sprayBoomerPosition;
/// <summary>
/// 召唤炸弹攻击的最左边
/// </summary>
private Transform callBoomerPositonLeft;
/// <summary>
/// 召唤炸弹攻击的最右边
/// </summary>
private Transform callBoomerPositonRight;
/// <summary>
/// 此时是否被打断?主要用来停止喷射攻击
/// </summary>
[Header("此时是否被打断")][SerializeField][FoldoutGroup("状态")][ReadOnly]
private bool wasInterupt = false;
// _____ _ _ ____ _
// / ____| | | | _ \ | |
// | | __ _| | | |_) | __ _ ___| | __
// | | / _` | | | _ < / _` |/ __| |/ /
// | |___| (_| | | | |_) | (_| | (__| <
// \_____\__,_|_|_|____/ \__,_|\___|_|\_\
void Start(){Init();}
void Update(){
//如果开关开着,则移动
if(isMove)
Move();
}
// _ _ _
// | \ | | | |
// | \| | ___ _ __ _ __ ___ __ _| |
// | . ` |/ _ \| '__| '_ ` _ \ / _` | |
// | |\ | (_) | | | | | | | | (_| | |
// |_| \_|\___/|_| |_| |_| |_|\__,_|_|
private void Init(){
//开启粒子
for (int i = 0; i < trojanHorseParticleSystems.Count; i++)
{
trojanHorseParticleSystems[i].Play();
}
//初始化生命值
HPLeft = HP;
//找到必须的组件和物体
callYiSiLanPosition = transform.Find("小怪召唤点");
sprayBoomerPosition = transform.Find("喷射炸弹点");
callBoomerPositonLeft = transform.Find("召唤炸弹攻击最左点");
callBoomerPositonRight = transform.Find("召唤炸弹攻击最右点");
}
/// <summary>
/// 执行一次攻击
/// </summary>
private IEnumerator StartAATK(){
//等待攻击间隔
yield return new WaitForSeconds(timeBetweenAttacks);
//决定行动
Action action = DecideAAction();
//开始行动
StartCoroutine(action());
}
/// <summary>
/// 决定行动的函数
/// </summary>
private Action DecideAAction(){
Action action;
///从0、1、2中随机生成一种
int r = Random.Range(0,3);
if(r == 0)
action = CallYiSiLan;
else if(r == 1)
action = SprayBoomer;
else
action = CallBoomer;
return SprayBoomer;
}
/// <summary>
/// 攻击方式:召唤小怪
/// </summary>
private IEnumerator CallYiSiLan(){
Debug.Log("正在使用:召唤伊斯兰");
//循环若干次(这里先硬编码成3次)
for(int i = 0; i < 3; i++){
//实例化预制体
YiSiLan yi = Instantiate(
yiSiLan,
callYiSiLanPosition.position,
Quaternion.identity
).GetComponent<YiSiLan>();
//等待范围内的随机时间
yield return new WaitForSeconds(
Random.Range(yiSiLanMinTime,yiSiLanMaxTime)
);
}
ATKEnd();
}
/// <summary>
/// 攻击方式:喷射炸弹💣
/// </summary>
/// <returns></returns>
private IEnumerator SprayBoomer(){
//开始喷射动画
GetComponent<Animator>().SetBool("isSpray",true);
yield return new WaitForSeconds(1f);
Debug.Log("正在使用:喷射炸弹");
//循环若干次(这里先硬编码成3次)
for(int i = 0; i < 3; i++){
if(wasInterupt) break;
//实例化预制体
Boomer boomer = Instantiate(
sprayBoomer,
sprayBoomerPosition.position,
Quaternion.identity
).GetComponent<Boomer>();
//初始化喷出的炸弹
//给予初始的速度
yield return new WaitForEndOfFrame();
boomer.m_rigidbody.velocity = sprayBoomerDir * (i + 1) * sprayBoomerMultiple;
boomer.isThisCanBeReturned = true;
boomer.GetComponent<ParticleSystem>().Play();
//给予炸弹扭矩
boomer.m_rigidbody.angularVelocity = 500f;
//等待喷射炸弹时间间隔
yield return new WaitForSeconds(sprayBoomerTime);
}
//结束喷射动画
yield return new WaitForSeconds(2f);
GetComponent<Animator>().SetBool("isSpray",false);
wasInterupt = false;
ATKEnd();
}
/// <summary>
/// 攻击方式:召唤炸弹💣
/// </summary>
/// <returns></returns>
private IEnumerator CallBoomer(){
Debug.Log("正在使用:召唤炸弹");
//循环若干次(这里先硬编码成3次)
for(int i = 0; i < 3; i++){
//实例化预制体
Boomer boomer = Instantiate(
sprayBoomer,
new Vector3(
//x取余范围内随机
Random.Range(callBoomerPositonLeft.position.x,
callBoomerPositonRight.position.x),
//yz随起点
callBoomerPositonLeft.position.y,
callBoomerPositonLeft.position.z
),
Quaternion.identity
).GetComponent<Boomer>();
//初始化喷出的炸弹
//先等待本帧结束,创建炸弹完毕
yield return new WaitForEndOfFrame();
//给予初始的速度
boomer.m_rigidbody.velocity = callBoomStartVelocity;
//修改炸弹的落地爆炸时间
boomer.landBoomTime = 1f;
//等待喷射炸弹时间间隔
yield return new WaitForSeconds(sprayBoomerTime);
}
ATKEnd();
}
/// <summary>
/// 木马不停右移的函数,每帧调用一次,有开关控制
/// </summary>
private void Move(){
//给自身位置加上向右的速度
transform.position += new Vector3(
speed * Time.deltaTime,0,0
);
}
// ______ _
// | ____| | |
// | |____ _____ _ __ | |_
// | __\ \ / / _ \ '_ \| __|
// | |___\ V / __/ | | | |_
// |______\_/ \___|_| |_|\__|
/// <summary>
/// 当玩家进入监视范围(前期调试,后期可能需要安排演出)
/// </summary>
/// <param name="target"></param>
public override void OnFindThePlayer(Transform target){
if(state == State.wander){
//修改状态为发现玩家
state = State.atk;
//开始攻击
StartCoroutine(StartAATK());
//开始屏幕震动
FindObjectOfType<VibrationManager>().HorseShakeScream();
//开始向右移动
isMove = true;
}
}
/// <summary>
/// 攻击结束的时候触发,重新开始新一轮攻击
/// </summary>
public void ATKEnd(){
if(state == State.atk) StartCoroutine(StartAATK());
}
protected override void OnTouchThePlayer(MyPlayer player){
//
Debug.Log("创到玩家了");
//
//当创到玩家,让玩家受伤
//告诉玩家,你被攻击了
player.OnBeHit(ATK,
((transform.position.x -
player.transform.position.x)
> 0) ? 1 : -1);//通过自身位置和玩家位置的比较来返回玩家本次的受击方向
}
public override void OnDead(){
//修改粒子透明度
for (int i = 0; i < trojanHorseParticleSystems.Count; i++)
{
StartCoroutine(SetParticleColor(trojanHorseParticleSystems[i], 0, 1f));
}
//播放死亡动画
GetComponent<Animator>().SetBool("isDead",true);
Debug.Log("啊我死了");
isMove = false;
state = State.dead;
FindObjectOfType<VibrationManager>().inHorseStage = false;
FindObjectOfType<VibrationManager>().StopHorseShakeScream();
FindObjectOfType<Transfer>().GetComponent<BoxCollider2D>().enabled = true;
//上传玩家进度
FindObjectOfType<PlayerInfo>().rate = (int) MyPlayer.Progress.;
FindObjectOfType<PlayerInfo>().UpdatePlayerInfo();
}
public override void OnBeHit(MyPlayer.AtkMethod hitMethod,int hitDir){
//结算生命值
HPLeft -= MyPlayer.atkMethodMagnification[hitMethod];
}
// _____ _ __
// |_ _| | | / _|
// | | _ __ | |_ ___ _ __| |_ __ _ ___ ___
// | | | '_ \| __/ _ \ '__| _/ _` |/ __/ _ \
// _| |_| | | | || __/ | | || (_| | (_| __/
// |_____|_| |_|\__\___|_| |_| \__,_|\___\___|
public void BeBoomed(float atk, int dir, Boomer boomer){
if(boomer.isThisCanBeReturned){
OnBeHit(MyPlayer.AtkMethod.,dir);
wasInterupt = true;
if(CheckDead()) OnDead();
}
}
public Transform ObjTransform(){return transform;}
//修改粒子,使粒子淡出
private IEnumerator SetParticleColor(ParticleSystem particleSystem,float endValue,float speed)
{
Color color = particleSystem.main.startColor.color;
while (particleSystem.main.startColor.color.a>endValue)
{
yield return new WaitForSeconds(0.15f);
color.a -= 0.1f;
//解决warming
#pragma warning disable 0618
particleSystem.startColor = color;
}
}
}