using Spine.Unity; using Spine; using System.Collections; using System.Collections.Generic; using UnityEngine; public class Demonic : MoveCharacter { [Header("友方单位属性")] public PlayerController player; //召唤师 public int playerID; public int id; public float costMp = 10; public float totalSummonTime = 0.5f; public bool isBack = false; //往反方向走 public float flyHeight; public float flyUpSpeed = 10; public int baseSortingOrder; int sortingOrder = 0; public float runSpeed; [Header("锁魂塔")] public bool isReturnSoulTower; public Vector3 origSoulPos; public bool isRecorded; [Header("友方单位组件")] public SearchState searchState; public Collider soulCollector; [Header("攻击")] public float attackDistance; public float maxAttackDis, minAttackDis; public bool needToChange; [Header("八卦")] public float adsorbSpeed; //八卦吸附的速度 [HideInInspector] public Vector3 adsorbTarget; //八卦胖子吸附时目标位置的X private float adsorbTime; //八卦吸附中的时间 public GameObject effectPrefab; //八卦卦象效果 [Header("掉落魂")] public int dropSoulMax = 3; public int dropSoulMin = 1; public float dropSoulAngle = 60f; [Header("验证功能开关")] public bool upFirstAfterWeaknessOrNot; //虚弱结束后是否先升高 public bool isBeBlownUp; //被击飞 private void Start() { if (needToChange) { attackDistance = Random.Range(minAttackDis, maxAttackDis); } } private void OnDisable() { PlayersInput.instance[playerID].OnDemonicRecycle(this); } public override void FixedUpdate() { if (!attackController.isNonAttack) { OnSearchState(); } OnState(); } public bool SearchTarget() { targetCharacter = searchTrigger.GetMinDisTarget(attackController.targetTypes, attackController.canHitFly); if (targetCharacter != null) { return true; } else { return false; } } public void ChangeSearchState(SearchState newState) { switch (searchState) { case SearchState.NoTarget: break; case SearchState.InSearchScope: break; case SearchState.InAttackScope: break; default: break; } searchState = newState; switch (searchState) { case SearchState.NoTarget: targetCharacter = null; break; case SearchState.InSearchScope: break; case SearchState.InAttackScope: break; default: break; } } public void OnSearchState() { switch (searchState) { case SearchState.NoTarget: if (SearchTarget()) { ChangeSearchState(SearchState.InSearchScope); break; } //向玩家基地移动 break; case SearchState.InSearchScope: if (!SearchTarget()) { targetCharacter = null; ChangeSearchState(SearchState.NoTarget); break; } if (targetCharacter != null && Mathf.Abs(targetCharacter.transform.position.x - transform.position.x) <= attackDistance) { ChangeSearchState(SearchState.InAttackScope); break; } break; case SearchState.InAttackScope: if (targetCharacter != null) { if (!targetCharacter.gameObject.activeInHierarchy || targetCharacter.isDie || Mathf.Abs(targetCharacter.transform.position.x - transform.position.x) > attackDistance) { ChangeSearchState(SearchState.NoTarget); } } else { ChangeSearchState(SearchState.NoTarget); } break; default: break; } } public override Vector3 GetMoveDir() { Vector3 moveDir = Vector3.zero; if (canMove) { if (!isTran) { switch (searchState) { case SearchState.NoTarget: if (TowerMap.enemyTowers.Count == 0) { moveDir = Vector3.left; break; } float minDistance = Mathf.Infinity; int id = -1; for (int i = 0; i < TowerMap.enemyTowers.Count; i++) { EnemyTower enemyTower = TowerMap.enemyTowers[i].GetComponent(); if (transform.position.y > enemyTower.transform.position.y + enemyTower.height) { continue; } float distance = Vector3.Distance(transform.position, TowerMap.enemyTowers[i].transform.position); if (distance < minDistance) { minDistance = distance; id = i; } } if (id == -1) { moveDir = Vector3.left; break; } if (bodyTrans.position.x > TowerMap.enemyTowers[id].transform.position.x) { moveDir = Vector3.left; } else { moveDir = Vector3.right; } break; case SearchState.InSearchScope: if (targetCharacter) { if (targetCharacter.transform.position.x - transform.position.x < 0) { moveDir = Vector3.left; } else { moveDir = Vector3.right; } } else { moveDir = Vector3.zero; } break; case SearchState.InAttackScope: if (targetCharacter) { if (targetCharacter.transform.position.x - transform.position.x < 0) { moveDir = Vector3.left; } else { moveDir = Vector3.right; } } else { moveDir = Vector3.zero; } break; default: break; } } else { if (pc == null) { pc = GetComponentInParent(); } moveDir = pc.GetMoveDir(); } } if (!isBack) { return moveDir; } return -moveDir; } public bool GetAttack() { if (searchState == SearchState.InAttackScope) { return true; } return false; } public bool AdjustHeight() { if (canFly) { if (transform.position.y - flyHeight > 0.1f) { Vector3 pos = transform.position; pos.y -= flyUpSpeed * Time.deltaTime; transform.position = pos; return false; } else if (transform.position.y - flyHeight < -0.1f) { Vector3 pos = transform.position; pos.y += flyUpSpeed * Time.deltaTime; transform.position = pos; return false; } } return true; } public override void OnState() { base.OnState(); //hurtKeepTime -= Time.deltaTime; dieKeepTime -= Time.deltaTime; invincibleTime -= Time.deltaTime; weakTime -= Time.deltaTime; beRepelValue += Time.deltaTime; Vector3 leftDir = GetMoveDir(); bool isAttack = GetAttack(); switch (state) { case CharacterState.Idle: if (isAttack) { Attack_march(); break; } if (!foot.TrigGround && !canFly) { if (rb.velocity.y > 0) { ChangeState(CharacterState.Rise); break; } else { ChangeState(CharacterState.Fall); break; } } if (leftDir.x > 0.3f || leftDir.x < -0.3f) { ChangeState(CharacterState.Run); break; } if (!upFirstAfterWeaknessOrNot) { if (canFly) { rb.constraints = RigidbodyConstraints.FreezeRotation | RigidbodyConstraints.FreezePositionZ | RigidbodyConstraints.FreezePositionY; rb.useGravity = false; AdjustHeight(); } } rb.velocity = Vector3.right * velocityAddition; break; case CharacterState.Run: if (isAttack) { Attack_march(); break; } if (!foot.TrigGround && !canFly) { if (rb.velocity.y > 0) { ChangeState(CharacterState.Rise); break; } else { ChangeState(CharacterState.Fall); break; } } if (leftDir.x < 0.3f && leftDir.x > -0.3f) { ChangeState(CharacterState.Idle); break; } if (leftDir.x > 0.3f) { //rb.velocity += Vector3.right * moveAcc * Time.deltaTime; rb.velocity = Vector3.right * (moveSpeed + velocityAddition); //if (rb.velocity.x > maxMoveSpeed) //{ // rb.velocity = new Vector3(maxMoveSpeed, rb.velocity.y, rb.velocity.z); //} if (bodyTrans.localScale.x > 0) { Turn(); } } else if (leftDir.x < -0.3f) { //rb.velocity -= Vector3.right * moveAcc * Time.deltaTime; rb.velocity = Vector3.right * (-moveSpeed + velocityAddition); //if (rb.velocity.x < -maxMoveSpeed) //{ // rb.velocity = new Vector3(-maxMoveSpeed, rb.velocity.y, rb.velocity.z); //} if (bodyTrans.localScale.x < 0) { Turn(); } } if (!upFirstAfterWeaknessOrNot) { if (canFly) { rb.constraints = RigidbodyConstraints.FreezeRotation | RigidbodyConstraints.FreezePositionZ | RigidbodyConstraints.FreezePositionY; rb.useGravity = false; AdjustHeight(); } } break; case CharacterState.Rush: if (isAttack) { Attack_march(); break; } if (!foot.TrigGround && !canFly) { if (rb.velocity.y > 0) { ChangeState(CharacterState.Rise); break; } else { ChangeState(CharacterState.Fall); break; } } if (leftDir.x < 0.3f && leftDir.x > -0.3f) { ChangeState(CharacterState.Idle); break; } if (leftDir.x > 0.3f) { //rb.velocity += Vector3.right * moveAcc * Time.deltaTime; rb.velocity = Vector3.right * runSpeed; //if (rb.velocity.x > maxMoveSpeed) //{ // rb.velocity = new Vector3(maxMoveSpeed, rb.velocity.y, rb.velocity.z); //} if (bodyTrans.localScale.x > 0) { Turn(); } } else if (leftDir.x < -0.3f) { //rb.velocity -= Vector3.right * moveAcc * Time.deltaTime; rb.velocity = Vector3.left * runSpeed; //if (rb.velocity.x < -maxMoveSpeed) //{ // rb.velocity = new Vector3(-maxMoveSpeed, rb.velocity.y, rb.velocity.z); //} if (bodyTrans.localScale.x < 0) { Turn(); } } //AdjustHeight(); break; case CharacterState.Rise: if (rb.velocity.y <= 0) { ChangeState(CharacterState.Fall); break; } //if (btnJumpPress || cacheJumpTime > 0) //{ // if (!airJumped && rb.velocity.y < airJumpSpeed) // { // airJumped = true; // AirJump(); // break; // } //} rb.velocity += Vector3.up * extraRiseGravity * Time.deltaTime; break; case CharacterState.Fall: if (foot.TrigGround || canFly) { ChangeState(CharacterState.Idle); break; } Vector3 velocity = rb.velocity; velocity.y += extraFallGravity * Time.deltaTime; if (leftDir.x > 0.3f) { velocity.x = moveSpeed; if (bodyTrans.localScale.x > 0) { Turn(); } } else if (leftDir.x < -0.3f) { velocity.x = -moveSpeed; if (bodyTrans.localScale.x < 0) { Turn(); } } rb.velocity = velocity; break; case CharacterState.Coma: pastComaTime += Time.deltaTime; if (pastComaTime >= comaTime) { ChangeState(CharacterState.Idle); } break; case CharacterState.Attack: attackController.attackTime -= Time.deltaTime; attackController.attackKeyCount += Time.deltaTime; if (!attackController.isAttackTriggerOn && attackController.attackKeyCount >= attackController.nextStartKeyTime && attackController.attackKeyCount <= attackController.nextEndKeyTime) { attackController.isAttackTriggerOn = true; attackController.attackTrigger.gameObject.SetActive(true); } else if (attackController.isAttackTriggerOn && attackController.attackKeyCount >= attackController.nextEndKeyTime) { attackController.isAttackTriggerOn = false; attackController.attackTrigger.gameObject.SetActive(false); attackController.SetNextKeyTimes(); } if (attackController.attackTime <= 0) { if (isInSoulTower) { ChangeState(CharacterState.LockSoul); } else { ChangeState(CharacterState.Idle); } break; } rb.velocity = new Vector3(velocityAddition, rb.velocity.y, rb.velocity.z); break; case CharacterState.Die: if (dieKeepTime <= 0) { if (!isSpirit) { Corpse.allCorpsesNum += 1; Corpse.isChange = true; } gameObject.SetActive(false); break; } break; case CharacterState.Weak: if (rb.velocity.magnitude > 1) { if (!isBeBlownUp) { isBeBlownUp = true; ani.Play("hitted", 0, 0); } Vector3 vel = rb.velocity; if (foot.TrigGround && vel.y <= 0) { vel = Vector3.zero; } else { vel.x -= vel.x * decelerationRatio * Time.deltaTime; vel.y += extraFallGravity * Time.deltaTime; } //vel.y = vel.y * (1 - decelerationRatio * Time.deltaTime); //vel.x = vel.x * (1 - decelerationRatio * Time.deltaTime); rb.velocity = vel; } else { if (isBeBlownUp) { isBeBlownUp = false; } if (weakTime <= -0.1) { if (upFirstAfterWeaknessOrNot) { if (AdjustHeight()) { ChangeState(CharacterState.Idle); } else { if (ani.GetCurrentAnimatorClipInfo(0)[0].clip.name != "walk") { ani.Play("walk", 0, 0); } } } else { ChangeState(CharacterState.Idle); } break; } else { if (ani.GetCurrentAnimatorClipInfo(0)[0].clip.name != "weak") { ani.Play("weak", 0, 0); rb.velocity = Vector3.zero; } } } break; case CharacterState.LockSoul: if (!isReturnSoulTower) { if (targetCharacter != null && targetCharacter.gameObject.layer == 8 && targetCharacter.isInSoulTower) { ChangeState(CharacterState.Idle); } else { isReturnSoulTower = true; } } else { if (transform.position.x - origSoulPos.x >= 0.2f) { rb.velocity = Vector3.right * (-moveSpeed + velocityAddition); if (bodyTrans.localScale.x < 0) { Turn(); } } else if (origSoulPos.x - transform.position.x >= 0.2f) { rb.velocity = Vector3.right * (moveSpeed + velocityAddition); if (bodyTrans.localScale.x > 0) { Turn(); } } else { ani.Play("idle", 0, 0); rb.velocity = Vector3.zero; transform.position = origSoulPos; isReturnSoulTower = false; targetCharacter = null; FaceToEneTower(); } //锁魂塔内使魔返回原地过程中扫描到敌人时,停止返回并索敌攻击 if (targetCharacter != null && targetCharacter.gameObject.layer == 8 && targetCharacter.isInSoulTower) { ChangeState(CharacterState.Idle); } } break; default: break; } } private void FaceToEneTower() { float dis = 1000000; GameObject to = null; foreach (GameObject g in TowerMap.enemyTowers) { float k = Vector3.Distance(g.transform.position, transform.position); if (k < dis) { dis = k; to = g; } } if (to != null && to.transform.position.x < transform.position.x) { if (bodyTrans.localScale.x < 0) { Turn(); } } else { if (bodyTrans.localScale.x > 0) { Turn(); } } } public override void ChangeState(CharacterState newState) { if (state == newState) { return; } switch (state) { case CharacterState.Idle: break; case CharacterState.Run: rb.velocity = Vector3.zero; break; case CharacterState.Rush: rb.velocity = Vector3.zero; break; case CharacterState.Rise: if (!canFly) { bodyCollider.SetActive(true); } break; case CharacterState.Fall: rb.velocity = Vector3.zero; break; //case CharacterState.Hurt: // break; case CharacterState.Coma: canMove = true; break; case CharacterState.Attack: break; case CharacterState.Die: isDie = false; break; case CharacterState.Weak: beRepelValue = totalBeRepelValue; newTotalWeakTime = totalWeakTime; if (canFly) { rb.constraints = RigidbodyConstraints.FreezeRotation | RigidbodyConstraints.FreezePositionZ | RigidbodyConstraints.FreezePositionY; rb.useGravity = false; } break; case CharacterState.Float: canMove = true; break; case CharacterState.LockSoul: //isReturnSoulTower = true; break; default: break; } CharacterState oldState = state; state = newState; switch (newState) { case CharacterState.Idle: ani.Play("idle", 0, 0); rb.velocity = Vector3.zero; //animalAni.SetInteger("state", (int)PlayerState.Idle); break; case CharacterState.Run: ani.Play("walk", 0, 0); //animalAni.SetInteger("state", (int)PlayerState.Walk); break; case CharacterState.Rush: ani.Play("rush", 0, 0); break; case CharacterState.Fall: ani.Play("fall", 0, 0); //animalAni.SetInteger("state", (int)PlayerState.Fall); break; //case CharacterState.Hurt: // ani.Play("hitted", 0, 0); // aniCollider.Play("Hurt", 0, 0); // invincibleTime = totalInvincibleTime; // hurtKeepTime = minHurtKeepTime; // //ani.Play("Invincible", 2, 0); // break; case CharacterState.Coma: //ani.Play("Coma", 0, 0); ani.Play("idle", 0, 0); pastComaTime = 0; rb.velocity = Vector3.zero; break; case CharacterState.Attack: break; case CharacterState.Die: ani.Play("die", 0, 0); isDie = true; dieKeepTime = totalDieKeepTime; break; case CharacterState.Weak: weakTime = newTotalWeakTime; rb.AddForce(weakForce); if (canFly) { rb.constraints = RigidbodyConstraints.FreezeRotation | RigidbodyConstraints.FreezePositionZ; rb.useGravity = true; flyHeight = Random.Range(minHeight, maxHeight); } break; case CharacterState.Float: canMove = false; break; case CharacterState.LockSoul: rb.velocity = Vector3.zero; ani.Play("walk", 0, 0); //FaceToEneTower(); break; default: break; } } public void Attack_summon() { attackController.Attack_summon(); Vector3 moveDir; if (PlayersInput.instance[playerID].bodyTrans.localScale.x > 0) { moveDir = Vector3.left; } else { moveDir = Vector3.right; } if (moveDir.x > 0.3f) { if (bodyTrans.localScale.x > 0) { Turn(); } } else if (moveDir.x < -0.3f) { if (bodyTrans.localScale.x < 0) { Turn(); } } invincibleTime = totalAttack_summonTime; attackTarget = targetCharacter; } public void Attack_march() { attackController.Attack_march(); attackTarget = targetCharacter; } public void DropSouls() { int dropSoulNum = Random.Range(dropSoulMin, dropSoulMax + 1); if (dropSoulNum > 1) { for (int i = 0; i < dropSoulNum; i++) { float angleInterval = dropSoulAngle / (float)(dropSoulNum - 1); float angle = 90 + ((float)i - (float)(dropSoulNum - 1) / 2) * angleInterval; angle = angle / 180 * Mathf.PI; GameObject soulObj = PoolManager.Instantiate(soulPrefab, transform.position); Vector3 dir = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle), 0); Soul soul = soulObj.GetComponent(); soul.Burst(dir * soulStartSpeed); } } else { GameObject soulObj = PoolManager.Instantiate(soulPrefab, transform.position); Vector3 dir = Vector3.up; Soul soul = soulObj.GetComponent(); soul.Burst(dir * soulStartSpeed); } } }