582 lines
19 KiB
C#
582 lines
19 KiB
C#
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<Rigidbody>(out unitRigidbody))
|
|
{
|
|
unitRigidbody = gameObject.AddComponent<Rigidbody>();
|
|
}
|
|
unitRigidbody.angularDrag = 0;
|
|
unitRigidbody.useGravity = false;
|
|
unitRigidbody.isKinematic = true;
|
|
unitRigidbody.constraints = BattleConst.RIGIDBODY_CONSTRAINTS;
|
|
bodyCollider = gameObject.AddComponent<SphereCollider>();
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
}
|