215 lines
6.3 KiB
C#
215 lines
6.3 KiB
C#
/*
|
|
* @Author: 白哉
|
|
* @Description: AI 逻辑总模块
|
|
* @Date: 2025年04月01日 星期二 14:04:01
|
|
* @Modify:
|
|
*/
|
|
|
|
|
|
using System.Collections.Generic;
|
|
using Logic.CrashSight;
|
|
using NodeCanvas.BehaviourTrees;
|
|
using NodeCanvas.Framework;
|
|
using UnityEngine;
|
|
using RuntimeData;
|
|
using TH1_Core.Managers;
|
|
|
|
|
|
namespace Logic.AI
|
|
{
|
|
public enum AILogicState
|
|
{
|
|
Prepare,
|
|
Playing,
|
|
PrePlay,
|
|
Pausing,
|
|
Finished,
|
|
}
|
|
|
|
|
|
public enum AIActionType
|
|
{
|
|
Grid,
|
|
City,
|
|
Unit,
|
|
Tech,
|
|
Max,
|
|
}
|
|
|
|
|
|
public class AILogic
|
|
{
|
|
public AILogicState AILogicState;
|
|
public PlayerData PlayerData => _playerData;
|
|
|
|
private float _targetTime;
|
|
private bool _isWaitFrame;
|
|
private AIActionScoreCalculator _scoreCalculator;
|
|
private AIActionGenerator _generator;
|
|
|
|
private List<AIActionBase> RecordActions;
|
|
private AIActionBase MaxScoreAction;
|
|
|
|
private MapData _mapData;
|
|
private PlayerData _playerData;
|
|
private AIConfigAsset _cfg;
|
|
|
|
private GameObject _logicObject;
|
|
private BehaviourTreeOwner _btOwner;
|
|
private AICalculatorData _data;
|
|
|
|
public static uint CurrentAIPlayerId;
|
|
public static Dictionary<uint, List<AIRecord>> AIRecordsDict;
|
|
|
|
|
|
public AILogic()
|
|
{
|
|
AIRecordsDict = new Dictionary<uint, List<AIRecord>>();
|
|
AILogicState = AILogicState.Prepare;
|
|
RecordActions = new List<AIActionBase>();
|
|
_scoreCalculator = new AIActionScoreCalculator();
|
|
_cfg = Resources.Load<AIConfigAsset>("Export/AIConfig");
|
|
_generator = new AIActionGenerator();
|
|
|
|
_logicObject = GameObject.Find("AIBT");
|
|
_btOwner = _logicObject.GetComponent<BehaviourTreeOwner>();
|
|
var data = _btOwner.blackboard.GetVariable<AICalculatorData>("Data");
|
|
if (data.value == null)
|
|
{
|
|
_data = new AICalculatorData();
|
|
data.value = _data;
|
|
}
|
|
else _data = data.value;
|
|
}
|
|
|
|
// 开始 AI 逻辑
|
|
public void StartAILogic(MapData mapData, PlayerData playerData)
|
|
{
|
|
AILogicState = AILogicState.Playing;
|
|
_mapData = mapData;
|
|
_playerData = playerData;
|
|
var aiDiff = _cfg.GetAIDiffInfo(_mapData.MapConfig.AIDiff);
|
|
_data.AiDiffInfo = aiDiff;
|
|
_generator.Init(_mapData, _playerData);
|
|
_data.Refresh(mapData, playerData);
|
|
_btOwner.StopBehaviour();
|
|
_btOwner.StartBehaviour();
|
|
MainEditor.Instance.Data = _data;
|
|
|
|
#if UNITY_EDITOR
|
|
CurrentAIPlayerId = _playerData.Id;
|
|
if (!AIRecordsDict.ContainsKey(CurrentAIPlayerId)) AIRecordsDict[CurrentAIPlayerId] = new List<AIRecord>();
|
|
AIRecordsDict[CurrentAIPlayerId].Clear();
|
|
#endif
|
|
}
|
|
|
|
// 结束 AI 逻辑
|
|
public void FinishAILogic()
|
|
{
|
|
_playerData = null;
|
|
AILogicState = AILogicState.Prepare;
|
|
}
|
|
|
|
// 更新 AI 逻辑
|
|
public void Update()
|
|
{
|
|
if (AILogicState == AILogicState.Finished || AILogicState == AILogicState.Prepare) return;
|
|
|
|
//if (AILogicState == AILogicState.Pausing && !PresentationManager.Busy)
|
|
if (AILogicState == AILogicState.Pausing)
|
|
{
|
|
_targetTime -= Time.deltaTime;
|
|
if (_targetTime <= 0) AILogicState = AILogicState.Playing;
|
|
// if (!_isWaitFrame) _isWaitFrame = true;
|
|
// else
|
|
// {
|
|
// _targetTime -= Time.deltaTime;
|
|
// if (_targetTime <= 0) AILogicState = AILogicState.Playing;
|
|
// }
|
|
}
|
|
|
|
if (AILogicState == AILogicState.Playing)
|
|
{
|
|
var index = 0;
|
|
while (true)
|
|
{
|
|
if (MainEditor.Instance.IsEditor && !MainEditor.Instance.IsGo) return;
|
|
index++;
|
|
_data.ClearCache();
|
|
_btOwner.UpdateBehaviour();
|
|
MainEditor.Instance.IsGo = false;
|
|
|
|
if (_data.MaxAiAction != null || _data.IsFinish) break;
|
|
if (index > 100)
|
|
{
|
|
LogSystem.LogError($"死循环了,最终记录点为:{MainEditor.Instance.BTNodeId}");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (_data.MaxAiAction == null || index > 100) AILogicState = AILogicState.Finished;
|
|
else
|
|
{
|
|
_data.MaxAiAction.ActionLogic.CompleteExecute(_data.MaxAiAction.Param);
|
|
_data.MaxAiAction.CheckIsActionDuration();
|
|
_targetTime = Mathf.Max(_data.MaxAiAction.Duration, 0f);
|
|
|
|
#if UNITY_EDITOR
|
|
var records = GetCurrentAIRecords();
|
|
if (records != null && records.Count != 0)
|
|
{
|
|
var record = records[^1];
|
|
record.Action = _data.MaxAiAction;
|
|
}
|
|
#endif
|
|
|
|
_isWaitFrame = false;
|
|
MainEditor.Instance.OnActionExcuted();
|
|
_data.MaxAiAction = null;
|
|
AILogicState = AILogicState.Pausing;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
public static List<AIRecord> GetCurrentAIRecords()
|
|
{
|
|
return AIRecordsDict.GetValueOrDefault(CurrentAIPlayerId);
|
|
}
|
|
|
|
public static List<AIRecord> GetAIRecords(uint playerId)
|
|
{
|
|
return AIRecordsDict.GetValueOrDefault(playerId);
|
|
}
|
|
}
|
|
|
|
|
|
public class AIStateRecord
|
|
{
|
|
public uint ID;
|
|
public string Desc;
|
|
public bool Result;
|
|
}
|
|
|
|
|
|
public class AIRecord
|
|
{
|
|
public List<AIStateRecord> StateRecords;
|
|
public AIActionBase Action;
|
|
public bool IsFoldout;
|
|
|
|
|
|
public AIRecord()
|
|
{
|
|
IsFoldout = false;
|
|
StateRecords = new List<AIStateRecord>();
|
|
}
|
|
|
|
public string GetDesc()
|
|
{
|
|
if (Action == null) return "暂无动作";
|
|
return Action.ActionLogic.GetType().ToString();
|
|
}
|
|
}
|
|
} |