using System.Collections; using System.Collections.Generic; using TMPro; using UnityEngine; namespace WildAttack { /// /// 敌人类 /// public class Enemy : MonoBehaviour { #region Members Transform finalPos; private Animator enemyAnim; private float speed; private int score; private int hp; private int monsterId; private int weaponId; /// /// 是否到达目的地 /// private bool arriveTarget; private int atk; private float attackIntervalTime; Transform armorTrans; Transform animTrans; /// /// 装备 /// private Stack ArmorStack; /// /// 装备破碎动画 /// private Stack AnimStack; /// /// 存放路径点信息list /// private List wayList; private int nextWayIndex; private AudioSource audioSource; private int spawnGroupId; private Transform HpBarRoot; #endregion #region Lifecycle private void OnEnable() { finalPos = GameObject.Find("finalPos").transform; HpBarRoot = GameObject.Find("HpBarRoot").transform; enemyAnim = GetComponent(); arriveTarget = false; nextWayIndex = 0; wayList = new List(); audioSource = GetComponent(); } bool isBorn = true; bool isDead = false; Vector3 deadPos; // Update is called once per frame void Update() { CheckAnimState(); if (Vector3.Distance(transform.position, finalPos.position) < 15f) { GetComponent().isKinematic = true; } // Attack // check state if (arriveTarget && !isDead && ProcessManager.GetInstance().CurrLevel > 0) { enemyAnim.SetBool("run1", false); enemyAnim.SetBool("run2", false); // check distance if (attackIntervalTime > 0) { attackIntervalTime -= Time.deltaTime; } else { PlayAttackAnim(); attackIntervalTime = WeaponModule.GetInstance().GetData(weaponId).cd; } } } private void FixedUpdate() { if (isBorn) return; if (isDead) return; if (ProcessManager.GetInstance().CurrLevel <= 0) return; // change run anim if (this.weaponId == 3 && this.hp < 3) { enemyAnim.SetBool("run2", true); } else { enemyAnim.SetBool("run1", true); } // check arrived if (nextWayIndex >= wayList.Count) { arriveTarget = true; return; } // check distance if (Vector2.Distance(new Vector2(transform.position.x, transform.position.z), wayList[nextWayIndex]) < 1.5f) { nextWayIndex++; } else { // 射线检测下个目标点y轴 Vector3 target = new Vector3(wayList[nextWayIndex].x, transform.position.y, wayList[nextWayIndex].y); Ray ray = new Ray(new Vector3(wayList[nextWayIndex].x, transform.position.y + 10, wayList[nextWayIndex].y), -transform.up); RaycastHit hitInfo; if (Physics.Raycast(ray, out hitInfo, 100, 1 << LayerMask.NameToLayer("Plane"))) { if (hitInfo.collider.gameObject.layer == LayerMask.NameToLayer("Plane")) { target = new Vector3(wayList[nextWayIndex].x, hitInfo.point.y, wayList[nextWayIndex].y); } } // 移动 MoveTowards(target); } } bool isJumping = false; GameObject jumpTarget; /// /// trigger 触发切换行进路线 /// /// private void OnTriggerEnter(Collider other) { if (other.gameObject.layer != LayerMask.NameToLayer("WayPoint")) return; // 触发检测是路径点或跳跃点 if (other.gameObject.name.Contains("jumpPoint")) { // get跳跃目的地 string index = other.gameObject.name.Split('_')[1]; if (other.gameObject.name.Split('_')[2] == "1") { if (isJumping) { return; } isJumping = true; jumpTarget = GameObject.Find($"jumpPoint_{index}_2"); enemyAnim.SetTrigger("jump" + Random.Range(1, 3)); } else if (other.gameObject.name.Split('_')[2] == "2") { isJumping = false; } return; } // 切换路径点 int nextGroupID = 0; for (int i = 0; i < EnemyManager.GetInstance().GetWayPoints().Length; i++) { if (Vector3.Distance(other.transform.position, EnemyManager.GetInstance().GetWayPoints()[i].transform.position) < 1f) { nextGroupID = i + 1; break; } } SetNewWayPoint(nextGroupID); } #endregion #region Functions public void Init(int monsterId, int weaponId, int spawnGroupId) { isBorn = true; transform.GetComponentInChildren().enabled = false; transform.GetComponentInChildren().enabled = false; transform.GetComponent().isKinematic = true; isDead = false; this.monsterId = monsterId; hp = this.monsterId; this.weaponId = weaponId; this.spawnGroupId = spawnGroupId; MonsterData monsterData = MonsterModule.GetInstance().GetData(this.monsterId); speed = monsterData.speed; score = monsterData.num; WeaponData weaponData = WeaponModule.GetInstance().GetData(weaponId); atk = weaponData.atk; attackIntervalTime = 0; // spawnGroupId == -1 默认关卡怪 if (spawnGroupId <= 0) { Vector2 pos = GameModule.GetInstance().GetDoubleParams("startMonsterXZ"); transform.localPosition = new Vector3(pos.x, 10, pos.y); // raycast get Y Ray ray = new Ray(new Vector3(transform.position.x, 30, transform.position.z), -transform.up); RaycastHit hitInfo; if (Physics.Raycast(ray, out hitInfo, 100, 1 << LayerMask.NameToLayer("Plane"))) { if (hitInfo.collider.gameObject.layer == LayerMask.NameToLayer("Plane")) { transform.position = new Vector3(transform.position.x, hitInfo.point.y, transform.position.z); } } transform.LookAt(Camera.main.transform); // 动画 enemyAnim.SetBool("flag", true); } else { transform.localPosition = EnemyManager.GetInstance().GetWayPoints()[spawnGroupId - 1].transform.position; } enemyAnim.SetTrigger("born"); // 判断血量 上装备 if (this.hp > 1) { ArmorStack = new Stack(); armorTrans = transform.Find("ArmorTrans"); for (int i = 0; i < this.hp - 1; i++) { GameObject armor = armorTrans.GetChild(i).gameObject; armor.SetActive(true); ArmorStack.Push(armor); } AnimStack = new Stack(); animTrans = transform.Find("AnimTrans"); for (int i = 0; i < this.hp - 1; i++) { GameObject anim = animTrans.GetChild(i).gameObject; anim.transform.GetComponentInChildren().SetBool("dead", false); anim.SetActive(false); //armorTrans.GetChild(i).GetComponent().enabled = true; AnimStack.Push(anim); } } } private float voiceTime = 0; /// /// 判断动画状态 出生死亡 /// private void CheckAnimState() { AnimatorStateInfo animInfo = enemyAnim.GetCurrentAnimatorStateInfo(0); if (animInfo.normalizedTime > 0.9f && animInfo.IsName("Born")) { isBorn = false; transform.GetComponentInChildren().enabled = true; transform.GetComponentInChildren().enabled = true; transform.GetComponent().isKinematic = false; } if (animInfo.IsName("Dead1") || animInfo.IsName("Dead2")) { transform.position = deadPos; if (animInfo.normalizedTime > 0.9f) { ResetEnemy(); gameObject.SetActive(false); return; } return; } else { // 初始怪随机时间播放随机嘲讽音效 if (voiceTime <= 0 && spawnGroupId <= 0) { audioSource.clip = Resources.Load($"Voice/Enemy/joke_{Random.Range(1, 5)}"); if (UserSettings.ins.openEffect) audioSource.Play(); Vector2 voiceSpawn = GameModule.GetInstance().GetDoubleParams("monsterATKVoiceTime"); voiceTime = Random.Range(voiceSpawn.x, voiceSpawn.y); } else { voiceTime -= Time.deltaTime; } } } /// /// 被击 /// public void Hitted(int damage, bool isHead) { if (hp <= 0) { return; } // 掉血 hp -= damage; // 血量判断 if (hp <= 0) { // 是否被箭攻击 if (damage == 1) { audioSource.clip = Resources.Load("Voice/Enemy/Hitted"); if (UserSettings.ins.openEffect) audioSource.Play(); } Dead(); // 气球 运动 CreateBalloon(transform.position, isHead); } else { // 拿矛的敌人血量小于3切换奔跑动画 if (hp < 3 && this.weaponId == 3) { enemyAnim.SetBool("run1", false); enemyAnim.SetBool("run2", true); } // 被击表现 for (int i = 0; i < damage; i++) { if (ArmorStack.Peek()) { GameObject armor = ArmorStack.Pop(); armor.SetActive(false); } } GameObject anim = null; for (int i = 0; i < damage; i++) { if (AnimStack.Peek()) { anim = AnimStack.Pop(); StartCoroutine(DestroyArmor(anim)); } } // 装备受击音效 if (damage == 1) { if (anim != null && UserSettings.ins.openEffect) anim.GetComponent().Play(); } } } /// /// 敌人死亡 /// private void Dead() { if (!isDead) { // 敌人死亡表现 deadPos = transform.position; enemyAnim.SetTrigger("dead" + Random.Range(1, 3)); transform.GetComponentInChildren().enabled = false; transform.GetComponentInChildren().enabled = false; isDead = true; // 初始怪不加分 if (spawnGroupId > 0) { GameMananger.GetInstance().AddScore(score); } } } /// /// 掉装备 /// /// /// IEnumerator DestroyArmor(GameObject armor) { armor.SetActive(true); armor.GetComponentInChildren().SetBool("dead", true); yield return new WaitForSeconds(1); armor.GetComponentInChildren().SetBool("dead", false); armor.SetActive(false); } /// /// replace OnDestroy /// public void ResetEnemy() { if (ArmorStack != null && ArmorStack.Count > 0) { for (int i = 0; i < armorTrans.childCount; i++) { //armorTrans.GetChild(i).GetComponentInChildren().SetBool("dead", false); //armorTrans.GetChild(i).GetComponent().enabled = true; armorTrans.GetChild(i).gameObject.SetActive(false); } ArmorStack.Clear(); } if (AnimStack != null && AnimStack.Count > 0) { for (int i = 0; i < AnimStack.Count; i++) { if (animTrans.GetChild(i).GetComponentInChildren()) { animTrans.GetChild(i).GetComponentInChildren().SetBool("dead", false); } //armorTrans.GetChild(i).GetComponent().enabled = true; animTrans.GetChild(i).gameObject.SetActive(false); } AnimStack.Clear(); } speed = 0; //GetComponent().constraints = RigidbodyConstraints.FreezeRotation; GetComponent().isKinematic = false; EnemyManager.GetInstance().enemyList.Remove(this); ProcessManager.GetInstance().EnemyDead(); } /// /// 敌人死亡生成气球 /// /// /// private void CreateBalloon(Vector3 pos, bool isHead) { // 爆头非爆头 数量不同 int num = isHead ? 3 : 2; for (int i = 0; i < num; i++) { GameObject balloon = BalloonPool.GetInstance().GetRedBalloon(); balloon.transform.position = new Vector3(pos.x - i, pos.y + 2, pos.z - i); balloon.SetActive(true); } } private void PlayAttackAnim() { enemyAnim.SetTrigger($"attack{weaponId}"); } /// /// 攻击逻辑 绑定在animation的Event上 /// public void Attack() { if (!GameMananger.GetInstance().isOver) { audioSource.clip = Resources.Load("Voice/Enemy/Attack"); if (UserSettings.ins.openEffect) audioSource.Play(); GameMananger.GetInstance().SubHp(atk); GameObject flotage = FlotagePool.GetInstance().GetGameObject(); flotage.SetActive(true); flotage.GetComponent().Init(Camera.main.WorldToScreenPoint(HpBarRoot.position + Vector3.up * 5), -atk, GameModule.GetInstance().GetRGB("BloodLossRGB"), StringModule.GetInstance().GetData("hpUnit"), FlotageTypeEnum.Fixed); } } private void MoveTowards(Vector3 target) { if (isJumping && (enemyAnim.GetCurrentAnimatorStateInfo(0).IsName("Jump1") || enemyAnim.GetCurrentAnimatorStateInfo(0).IsName("Jump2")) && enemyAnim.GetCurrentAnimatorStateInfo(0).normalizedTime > 0.2f) { // 冰冻魔法触发后跳跃不到目标点 // fixme: 使用配置中的speed transform.position = Vector3.Lerp(transform.position, jumpTarget.transform.position + Vector3.up * 2, MonsterModule.GetInstance().GetData(monsterId).speed / 2 * Time.deltaTime); return; } transform.LookAt(target); transform.position = Vector3.MoveTowards(transform.position, target, Time.deltaTime * speed); // 防止倾斜 transform.rotation = new Quaternion(0, transform.rotation.y, 0, transform.rotation.w); } /// /// 速度相关 /// /// public void SetSpeed(float multiple) { speed = MonsterModule.GetInstance().GetData(this.monsterId).speed * multiple; if (UserSettings.ins.openEffect) transform.Find("Bip001/Bip001 Pelvis/Bip001 Spine/Bip001 Spine1/body/slow").GetComponentInChildren().Play(); } public void ResetSpeed() { speed = MonsterModule.GetInstance().GetData(this.monsterId).speed; transform.Find("Bip001/Bip001 Pelvis/Bip001 Spine/Bip001 Spine1/body/slow").GetComponentInChildren().Stop(); } /// /// 切换路径点list 重新随机 /// /// public void SetNewWayPoint(int nextGroupID) { arriveTarget = false; nextWayIndex = 0; List wayDataList = WayPointModule.GetInstance().GetDataByGroup(nextGroupID); List weight = new List(); foreach (var item in wayDataList) { weight.Add(item.weight); } wayList = wayDataList[WeightRandomUtils.GetInstance().GetRandomId(weight) - 1].wayPoint; } #endregion } }