278 lines
8.3 KiB
C#
278 lines
8.3 KiB
C#
using System;
|
|
using Gameplay;
|
|
using Framework;
|
|
using Gameplay.AI;
|
|
using UnityEngine;
|
|
using Gameplay.Unit;
|
|
using Gameplay.Level;
|
|
using Gameplay.BT.Variables;
|
|
using Cysharp.Threading.Tasks;
|
|
using System.Collections.Generic;
|
|
using BehaviorDesigner.Runtime.Tasks;
|
|
using Action = BehaviorDesigner.Runtime.Tasks.Action;
|
|
|
|
public class BTMoveAround : Action
|
|
{
|
|
public SharedBattleInfo SharedBattleInfo;
|
|
private GameUnit _owner;
|
|
private GameUnit _target;
|
|
private Map map;
|
|
|
|
private EStage _stage = EStage.None;
|
|
private int _stageTargetCellIndex = -1;
|
|
private int _targetCellIndex = -1;
|
|
private int attackDistance;
|
|
|
|
private Vector2Int targetV2;
|
|
private Vector2Int ownerV2;
|
|
|
|
private bool needCheck;
|
|
|
|
// 格子,原来的通行等级
|
|
private Dictionary<int, int> crossLevelCells = new Dictionary<int, int>();
|
|
|
|
private enum EStage
|
|
{
|
|
None,
|
|
Stage1,
|
|
Stage2,
|
|
}
|
|
|
|
public override void OnStart()
|
|
{
|
|
_owner = GameUnitManager.instance.infightUnits.Search(SharedBattleInfo.Value.ownerId);
|
|
_target = GameUnitManager.instance.infightUnits.Search(SharedBattleInfo.Value.theChosenOneId);
|
|
|
|
map = LevelManager.Instance.CurrentLevel.Map;
|
|
_stageTargetCellIndex = -1;
|
|
_targetCellIndex = -1;
|
|
}
|
|
|
|
public override TaskStatus OnUpdate()
|
|
{
|
|
if (_owner == null) return TaskStatus.Failure;
|
|
|
|
// 避开其他AI
|
|
AvoidOtherUnit();
|
|
|
|
if (SharedBattleInfo.Value.theChosenOneId != Constants.INVALID_UINT_ID)
|
|
{
|
|
if (_owner?.controlData.targetEnemy == null && _stage == EStage.Stage2)
|
|
{
|
|
// 继续追击目标
|
|
var enemy = GameUnitManager.instance.infightUnits.Search(SharedBattleInfo.Value.theChosenOneId);
|
|
if (enemy != null && !enemy.statusData.isDead)
|
|
{
|
|
if (_targetCellIndex != enemy.transData.cellIndex)
|
|
{
|
|
_target = enemy;
|
|
_targetCellIndex = -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ResetCells();
|
|
SharedBattleInfo.Value.theChosenOneId = Constants.INVALID_UINT_ID;
|
|
return TaskStatus.Failure;
|
|
}
|
|
}
|
|
|
|
if (HasTargetMoved())
|
|
{
|
|
RememberTarget();
|
|
|
|
switch (_stage)
|
|
{
|
|
case EStage.None:
|
|
_stageTargetCellIndex = GetStageTargetCell();
|
|
_stage = EStage.Stage1;
|
|
FindPath(_stageTargetCellIndex);
|
|
AIUtils.CheckAndMove(_owner, _stageTargetCellIndex);
|
|
break;
|
|
|
|
case EStage.Stage1:
|
|
_stageTargetCellIndex = GetStageTargetCell();
|
|
FindPath(_stageTargetCellIndex);
|
|
AIUtils.CheckAndMove(_owner, _stageTargetCellIndex);
|
|
break;
|
|
|
|
case EStage.Stage2:
|
|
_stageTargetCellIndex = _target.transData.cellIndex;
|
|
AIUtils.CheckAndMove(_owner, _target.transData.cellIndex);
|
|
break;
|
|
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
|
|
return TaskStatus.Running;
|
|
}
|
|
|
|
if (HasStageArrived() && !AIUtils.IsNeedStop(_owner))
|
|
{
|
|
switch (_stage)
|
|
{
|
|
case EStage.Stage1:
|
|
_stage = EStage.Stage2;
|
|
_stageTargetCellIndex = _target.transData.cellIndex;
|
|
AIUtils.CheckAndMove(_owner, _target.transData.cellIndex);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return TaskStatus.Running;
|
|
}
|
|
|
|
return TaskStatus.Failure;
|
|
}
|
|
|
|
private int GetStageTargetCell()
|
|
{
|
|
attackDistance = _target.fightData.attackDistance / 2;
|
|
targetV2 = map.TGSCellIndex2BlockPosition(_target.transData.cellIndex);
|
|
ownerV2 = map.TGSCellIndex2BlockPosition(_owner.transData.cellIndex);
|
|
|
|
var correctPos = targetV2;
|
|
if (targetV2.y > ownerV2.y && targetV2.x > ownerV2.x) //左下
|
|
{
|
|
var x = targetV2.x + attackDistance;
|
|
var y = targetV2.y + attackDistance + 1;
|
|
|
|
while (x >= map.MapData.Height)
|
|
{
|
|
x--;
|
|
}
|
|
|
|
while (y >= map.MapData.Width)
|
|
{
|
|
y--;
|
|
}
|
|
|
|
correctPos = new Vector2Int(x, y);
|
|
// DebugUtil.Log("在目标的左下方,获取到的正确位置是:{0}", correctPos);
|
|
}
|
|
|
|
if (targetV2.y > ownerV2.y && targetV2.x < ownerV2.x) //左上
|
|
{
|
|
var x1 = targetV2.x - attackDistance;
|
|
var y1 = targetV2.y + attackDistance + 1;
|
|
while (x1 < 0)
|
|
{
|
|
x1++;
|
|
}
|
|
|
|
while (y1 >= map.MapData.Width)
|
|
{
|
|
y1--;
|
|
}
|
|
|
|
correctPos = new Vector2Int(x1, y1);
|
|
// DebugUtil.LogError("在目标的左上方,获取到的正确位置是:{0}", correctPos);
|
|
}
|
|
|
|
if (targetV2.y < ownerV2.y && targetV2.x > ownerV2.x) //右下
|
|
{
|
|
var x = targetV2.x + attackDistance;
|
|
var y = targetV2.y - attackDistance + 1;
|
|
while (x >= map.MapData.Height)
|
|
{
|
|
x--;
|
|
}
|
|
|
|
while (y < 0)
|
|
{
|
|
y++;
|
|
}
|
|
|
|
correctPos = new Vector2Int(x, y);
|
|
// DebugUtil.LogError("在目标的右下方,获取到的正确位置是:{0}", correctPos);
|
|
}
|
|
|
|
if (targetV2.y < ownerV2.y && targetV2.x < ownerV2.x) //右上
|
|
{
|
|
var x1 = targetV2.x - attackDistance;
|
|
var y2 = targetV2.y - attackDistance + 1;
|
|
while (x1 < 0)
|
|
{
|
|
x1++;
|
|
}
|
|
|
|
while (y2 < 0)
|
|
{
|
|
y2++;
|
|
}
|
|
|
|
correctPos = new Vector2Int(x1, y2);
|
|
// DebugUtil.LogError("在目标的右上方,获取到的正确位置是:{0}", correctPos);
|
|
}
|
|
|
|
var targetCellIndex = map.BlockPosition2TGSCellIndex(correctPos);
|
|
if (!AIUtils.CheckPathExits(_owner, targetCellIndex))
|
|
{
|
|
targetCellIndex = AIUtils.GetCanReachCellAround(map, _owner, targetCellIndex);
|
|
if (targetCellIndex == -1)
|
|
targetCellIndex = _owner.transData.cellIndex;
|
|
}
|
|
|
|
return targetCellIndex;
|
|
}
|
|
|
|
private bool HasTargetMoved()
|
|
{
|
|
return _targetCellIndex != _target.transData.cellIndex;
|
|
}
|
|
|
|
private void RememberTarget()
|
|
{
|
|
_targetCellIndex = _target.transData.cellIndex;
|
|
}
|
|
|
|
private void FindPath(int cellIndex)
|
|
{
|
|
// 将敌人周围一圈的通行级别设高
|
|
var cells = AIUtils.SetCellCrossLevel(map, _owner, _targetCellIndex);
|
|
foreach (var cell in cells)
|
|
{
|
|
crossLevelCells[cell.Key] = cell.Value;
|
|
}
|
|
|
|
_owner.pathData.FindOrCache(cellIndex);
|
|
|
|
ResetCells();
|
|
}
|
|
|
|
private bool HasStageArrived()
|
|
{
|
|
return _stageTargetCellIndex == _owner?.transData.cellIndex;
|
|
}
|
|
|
|
private void ResetCells()
|
|
{
|
|
// 还原通行级别
|
|
AIUtils.SetCellCrossLevel(map, crossLevelCells);
|
|
crossLevelCells.Clear();
|
|
}
|
|
|
|
private async void AvoidOtherUnit()
|
|
{
|
|
if (AIUtils.IsNeedStop(_owner)) return;
|
|
|
|
if (_owner.statusData.isMoveing && !needCheck)
|
|
{
|
|
needCheck = true;
|
|
}
|
|
|
|
if (needCheck && !_owner.statusData.isMoveing &&
|
|
_owner.controlData.targetCellIndex == -1)
|
|
{
|
|
needCheck = false;
|
|
|
|
// 随机等待 防止同步
|
|
var randomDelay = UnityEngine.Random.Range(0f, 1f);
|
|
await UniTask.Delay((int)(randomDelay * 1000));
|
|
|
|
AIUtils.CheckAreaIsOtherEnemyUnit(_owner, SharedBattleInfo.Value.theChosenOneId);
|
|
}
|
|
}
|
|
|
|
} |