using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using DG.Tweening; namespace BF { public class BattleControlMonster : BattleControlUnit { private CharacterSpineHelper spineHelper; private Rigidbody unitRigidbody; private Transform mainBody; private bool isMoving = false; private float checkTowardTime = 0.1f; private float checkAITargetPositionTime = 0.1f; private int horizontalTypeAI = 0; private float offsetXAI = 0.0f; private float offsetZAI = 0.0f; private Sequence airborneSeq; private bool isHitBack = true; private float hitBackTime = 0.0f; private float hitBackSpeed = 0.0f; void Awake() { InitRigidbody(); } private void InitRigidbody() { if (!gameObject.TryGetComponent(out unitRigidbody)) { unitRigidbody = gameObject.AddComponent(); } unitRigidbody.angularDrag = 0; unitRigidbody.useGravity = false; unitRigidbody.isKinematic = true; unitRigidbody.constraints = BattleConst.RIGIDBODY_CONSTRAINTS; bodyCollider = gameObject.AddComponent(); bodyCollider.isTrigger = true; } public void InitMonster(int side, CharacterSpineHelper helper, Transform body) { Side = side; BattleMgr = BF.BFMain.Instance.BattleMgr; spineHelper = helper; mainBody = body; if (ReferenceEquals(mainBody, null)) { mainBody = transform.GetChild(0); } Direction = 1; isMoving = false; IsDead = false; IsInGroundState = false; Target = null; IsDisappear = false; BattleMgr.AddToDefUnitsList(this); gameObject.layer = BattleConst.LAYER_MONSTER; } public override void InitHpBar() { if (isHaveHpBar) { return; } hpBar = BattleMgr.PoolHelper.GetHpBar(Side); hpBar.transform.localScale = Vector3.one; hpBar.RefreshHpBar(1.0f); BattleMgr.UpdateUIPosition(transform.position, HpBarAddY, hpBar.transform as RectTransform); isHaveHpBar = true; } public override void RefreshHpBar(float percent) { if (!isHaveHpBar) { return; } hpBar.RefreshHpBar(percent); } public void InitPosition(float x, float y, float z) { transform.position = new Vector3(x, y, z); } public override void EnterDisappear() { gameObject.layer = BattleConst.LAYER_DEFAULT; BattleMgr.RemoveFromDefUnitsList(this); if (isHaveHpBar) { hpBar.transform.localScale = Vector3.zero; } if (IsHaveShadow) { shadow.transform.localScale = Vector3.zero; } } public override void ExitDisappear() { gameObject.layer = BattleConst.LAYER_MONSTER; BattleMgr.AddToDefUnitsList(this); if (isHaveHpBar) { hpBar.transform.localScale = Vector3.one; } if (IsHaveShadow) { shadow.transform.localScale = Vector3.one*BodyRadius*2.0f; } } public void SetTarget(BattleControlUnit target) { Target = target; } public bool GetIsNormalMonster() { return true; } public bool GetIsBOSS() { return false; } public void StopMove() { isMoving = false; } public void StartMove() { isMoving = true; } // 秒杀 public void InstantKill() { OnDead(); } public override void PlayAirborne() { if (ReferenceEquals(airborneSeq, null)) { airborneSeq = BattleHelper.CreateSequence(); var time = BattleConfigure.TimeHitFly; var tween1 = mainBody.DOLocalMoveY(BattleConfigure.HeightHitFly, time*3.0f/5.0f).SetEase(Ease.OutQuart); tween1.intId = BattleConst.DOTWEEN_ID_BATTLE; var tween2 = mainBody.DOLocalMoveY(0.0f, time*2.0f/5.0f); tween2.intId = BattleConst.DOTWEEN_ID_BATTLE; airborneSeq.Append(tween1); airborneSeq.Append(tween2); airborneSeq.SetAutoKill(false); } else { airborneSeq.Restart(); } isHitBack = true; hitBackTime = BattleConfigure.TimeHitFly; hitBackSpeed = BattleConfigure.DistanceHitFly / hitBackTime; } public override void StopAirborne() { if (!ReferenceEquals(airborneSeq, null)) { airborneSeq.Pause(); } mainBody.localPosition = Vector3.zero; } public override void MoveWithSkillAI(int target, int horizontal, float x, float z, int refresh, int across, float speed, int endType, float endValue, int collisionType) { StartMove(); targetTypeAI = target; horizontalTypeAI = horizontal; offsetXAI = x; offsetZAI = z; keepUpdateTargetPositionAI = refresh == 1; isCanAcrossTarget = across == 1; moveSpeedAI = speed; isTeleport = moveSpeedAI < 0.000001f; endTypeAI = endType; if (endTypeAI == 1) { endValueAI = endValue*endValue; } else { endValueAI = endValue; } collisionTypeAI = collisionType; FindTargetPosition(); } private void FindTargetPosition() { if (targetTypeAI == 1) // 自身 { FindTargetPositionAISelf(); CheckTargetPositionAIOutWall(); } else if(targetTypeAI == 2) // 目标 { FindTargetPositionAITarget(); CheckTargetPositionAIOutWall(); } else if(targetTypeAI == 3) // 场地中央 { FindTargetPositionAIMiddle(); CheckTargetPositionAIOutWall(); } else { StopMove(); } } private void FindTargetPositionAITarget() { if (horizontalTypeAI == 1) { if (Target.transform.position.x < transform.position.x) // 目标在自己的左边 { targetPositionAI = Target.transform.position + new Vector3(-offsetXAI, 0.0f, offsetZAI); } else { targetPositionAI = Target.transform.position + new Vector3(offsetXAI, 0.0f, offsetZAI); } } else if(horizontalTypeAI == 2) { var deltaX = transform.position.x - Target.transform.position.x; var deltaZ = transform.position.z - Target.transform.position.z; var radian = Mathf.Atan2(deltaZ, deltaX); var x = -offsetXAI*Mathf.Cos(radian); var z = -offsetXAI*Mathf.Sin(radian); targetPositionAI = new Vector3(Target.transform.position.x + x, 0.0f, Target.transform.position.z + z); } } private void FindTargetPositionAISelf() { if (Direction == 1) { targetPositionAI = transform.position + new Vector3(offsetXAI, 0.0f, offsetZAI); } else { targetPositionAI = transform.position + new Vector3(-offsetXAI, 0.0f, offsetZAI); } } private void FindTargetPositionAIMiddle() { if (horizontalTypeAI == 1) { if (BattleConfigure.SceneMidX < transform.position.x) // 自己在场景右边 { targetPositionAI = new Vector3(-offsetXAI + BattleConfigure.SceneMidX, 0.0f, offsetZAI + BattleConfigure.SceneMidZ); } else { targetPositionAI = transform.position + new Vector3(offsetXAI + BattleConfigure.SceneMidX, 0.0f, offsetZAI + BattleConfigure.SceneMidZ); } } else if(horizontalTypeAI == 2) { var deltaX = transform.position.x - BattleConfigure.SceneMidX; var deltaZ = transform.position.z - BattleConfigure.SceneMidZ; var radian = Mathf.Atan2(deltaZ, deltaX); var x = -offsetXAI*Mathf.Cos(radian); var z = -offsetXAI*Mathf.Sin(radian); targetPositionAI = new Vector3(Target.transform.position.x + x, 0.0f, Target.transform.position.z + z); } } private void CheckTargetPositionAIOutWall() { if (targetPositionAI.x < BattleConfigure.SceneMinX) // 撞左边墙了 { targetPositionAI.x = BattleConfigure.SceneMinX; } else if (targetPositionAI.x > BattleConfigure.SceneMaxX) // 撞右边墙了 { targetPositionAI.x = BattleConfigure.SceneMaxX; } if (targetPositionAI.z < BattleConfigure.SceneMinZ) // 撞左边墙了 { targetPositionAI.z = BattleConfigure.SceneMinZ; } else if (targetPositionAI.z > BattleConfigure.SceneMaxZ) // 撞右边墙了 { targetPositionAI.z = BattleConfigure.SceneMaxZ; } } void Update() { var deltaTime = Time.deltaTime*BattleConfigure.TimeScale; if (!isMoving) { if (isHitBack) { UpdateHitBackMove(deltaTime); } CheckToward(deltaTime); return; } UpdateAIMoveing(deltaTime); } void LateUpdate() { // TODO 后续可以优化成怪物移动或者相机移动的时候更新 if (isHaveHpBar) { BattleMgr.UpdateUIPosition(transform.position, HpBarAddY, hpBar.transform as RectTransform); } } private void CheckToward(float deltaTime) { if (IsDead) { return; } checkTowardTime -= deltaTime; if (checkTowardTime < 0.0f) { checkTowardTime = BattleConfigure.CheckMonsterTowardInterval; TowardToTarget(); } } public override void TowardToTarget() { if (Target.transform.position.x <= transform.position.x) { if (Direction != -1) { Direction = -1; var bodyTransform = spineHelper.GetSpineObject().transform.parent; bodyTransform.localScale = new Vector3(BattleConfigure.MonsterScaleFactorXZ*Direction, bodyTransform.localScale.y, bodyTransform.localScale.z); } } else { if (Direction != 1) { Direction = 1; var bodyTransform = spineHelper.GetSpineObject().transform.parent; bodyTransform.localScale = new Vector3(BattleConfigure.MonsterScaleFactorXZ*Direction, bodyTransform.localScale.y, bodyTransform.localScale.z); } } } public override void ForceTowardToTarget() { if (Target.transform.position.x <= transform.position.x) { Direction = -1; var bodyTransform = spineHelper.GetSpineObject().transform.parent; bodyTransform.localScale = new Vector3(BattleConfigure.MonsterScaleFactorXZ*Direction, bodyTransform.localScale.y, bodyTransform.localScale.z); } else { Direction = 1; var bodyTransform = spineHelper.GetSpineObject().transform.parent; bodyTransform.localScale = new Vector3(BattleConfigure.MonsterScaleFactorXZ*Direction, bodyTransform.localScale.y, bodyTransform.localScale.z); } } private void UpdateAIMoveing(float deltaTime) { if (endTypeAI == 1) // 按距离结束 { if ((transform.position - targetPositionAI).sqrMagnitude < endValueAI) { FinishAIMove(); return; } } else if(endTypeAI == 2) // 按时间结束 { endValueAI -= deltaTime; if (endValueAI < 0.0f) { FinishAIMove(); return; } } else { if ((transform.position - targetPositionAI).sqrMagnitude < 0.0001) { return; } } MoveToTarget(deltaTime); if (keepUpdateTargetPositionAI) { checkAITargetPositionTime -= deltaTime; if (checkAITargetPositionTime < 0.0f) { checkAITargetPositionTime = BattleConfigure.CheckAITargetPositionInterval; FindTargetPosition(); } } } private void MoveToTarget(float deltaTime) { Vector3 moveToPosition; if (isTeleport) { if (isHitBack) { hitBackTime -= deltaTime; if (hitBackTime < 0.0f) { isHitBack = false; } } moveToPosition = targetPositionAI; } else { if (isHitBack) { hitBackTime -= deltaTime; if (hitBackTime < 0.0f) { isHitBack = false; } moveToPosition = Vector3.MoveTowards(transform.position, transform.position + new Vector3(BattleConst.UNIT_MOVE_DISTANCE_OPPOSITE*Direction, 0.0f, 0.0f), hitBackSpeed * deltaTime); } else { moveToPosition = Vector3.MoveTowards(transform.position, targetPositionAI, moveSpeedAI * deltaTime); } } if (!isCanAcrossTarget) // 不能穿过目标 { if (Target.transform.position.x <= transform.position.x) // 在目标左边 { var limitX = Target.transform.position.x + Target.BodyRadius + BodyRadius; if (moveToPosition.x < limitX) { moveToPosition.x = limitX; } } else { var limitX = Target.transform.position.x - Target.BodyRadius - BodyRadius; if (moveToPosition.x > limitX) { moveToPosition.x = limitX; } } } if (moveToPosition.x < BattleConfigure.SceneMinX) // 撞左边墙了 { moveToPosition.x = BattleConfigure.SceneMinX; } else if (moveToPosition.x > BattleConfigure.SceneMaxX) // 撞右边墙了 { moveToPosition.x = BattleConfigure.SceneMaxX; } if (moveToPosition.z < BattleConfigure.SceneMinZ) // 撞左边墙了 { moveToPosition.z = BattleConfigure.SceneMinZ; } else if (moveToPosition.z > BattleConfigure.SceneMaxZ) // 撞右边墙了 { moveToPosition.z = BattleConfigure.SceneMaxZ; } transform.position = moveToPosition; } private void UpdateHitBackMove(float deltaTime) { hitBackTime -= deltaTime; if (hitBackTime < 0.0f) { isHitBack = false; } var moveToPosition = Vector3.MoveTowards(transform.position, transform.position + new Vector3(BattleConst.UNIT_MOVE_DISTANCE_OPPOSITE*Direction, 0.0f, 0.0f), hitBackSpeed * deltaTime); if (Target.transform.position.x <= transform.position.x) // 在目标左边 { var limitX = Target.transform.position.x + Target.BodyRadius + BodyRadius; if (moveToPosition.x < limitX) { moveToPosition.x = limitX; } } else { var limitX = Target.transform.position.x - Target.BodyRadius - BodyRadius; if (moveToPosition.x > limitX) { moveToPosition.x = limitX; } } if (moveToPosition.x < BattleConfigure.SceneMinX) // 撞左边墙了 { moveToPosition.x = BattleConfigure.SceneMinX; } else if (moveToPosition.x > BattleConfigure.SceneMaxX) // 撞右边墙了 { moveToPosition.x = BattleConfigure.SceneMaxX; } if (moveToPosition.z < BattleConfigure.SceneMinZ) // 撞左边墙了 { moveToPosition.z = BattleConfigure.SceneMinZ; } else if (moveToPosition.z > BattleConfigure.SceneMaxZ) // 撞右边墙了 { moveToPosition.z = BattleConfigure.SceneMaxZ; } transform.position = moveToPosition; } public override void BeHitBack() { if (isHitBack) { return; } isHitBack = true; hitBackTime = BattleConfigure.HitBackTime; hitBackSpeed = BattleConfigure.DistanceHitBack / hitBackTime; } private void FinishAIMove() { StopMove(); luaOnFinishAIMoveFunc?.Invoke(); } public override void OnDead() { IsDead = true; IsInGroundState = false; BattleMgr.RemoveFromDefUnitsList(this); } public override void Clear() { luaOnHitTargetFunc = null; luaOnFinishAIMoveFunc = null; if (isHaveHpBar) { BattleMgr.PoolHelper.PutBackHpBar(hpBar, Side); hpBar = null; isHaveHpBar = false; } } private void OnDestroy() { luaOnHitTargetFunc = null; luaOnFinishAIMoveFunc = null; if (!ReferenceEquals(airborneSeq, null)) { airborneSeq.Kill(); } } } }