1531 lines
48 KiB
C#
1531 lines
48 KiB
C#
using TGS;
|
||
using System;
|
||
using Gameplay;
|
||
using Framework;
|
||
using System.IO;
|
||
using UnityEditor;
|
||
using UnityEngine;
|
||
using System.Linq;
|
||
using Gameplay.Utils;
|
||
using Gameplay.Level;
|
||
using Sirenix.Utilities;
|
||
using Sirenix.OdinInspector;
|
||
using Sirenix.Utilities.Editor;
|
||
using System.Collections.Generic;
|
||
using cfg;
|
||
using cfg.FightCfg;
|
||
using cfg.MonsterCfg;
|
||
using cfg.VehicleCfg;
|
||
using Sirenix.OdinInspector.Editor;
|
||
using Level = cfg.LevelCfg.Level;
|
||
using ObjectFieldAlignment = Sirenix.OdinInspector.ObjectFieldAlignment;
|
||
|
||
public class LevelEditorWindow : OdinEditorWindow
|
||
{
|
||
public static void OpenWindow(LevelEditor levelEditor)
|
||
{
|
||
MapEditorSettings.Init();
|
||
currWindow = GetWindow<LevelEditorWindow>();
|
||
currWindow.position = GUIHelper.GetEditorWindowRect().AlignCenter(800, 600);
|
||
currWindow.currentLevelData = null;
|
||
currWindow._levelEditor = levelEditor;
|
||
currWindow.LoadLevel(levelEditor.LevelData);
|
||
|
||
var level = Path.GetFileNameWithoutExtension(levelEditor.LevelDataJson.name);
|
||
currWindow.levelID = level.Substring(level.Length - 6);
|
||
currWindow.GetLevelMonsterClass();
|
||
DebugUtil.Log("关卡数据:{0}", currWindow.levelID);
|
||
}
|
||
|
||
#region 编辑器类
|
||
|
||
[Serializable]
|
||
public class RegionData
|
||
{
|
||
[LabelText("出战区")] [OnValueChanged("OnRegionChanged")]
|
||
public int preparingRegionId;
|
||
|
||
[LabelText("出战区朝向")] public LevelData.CharacterToward preparingRegionToward;
|
||
|
||
[LabelText("撤退区")] public int fallbackRegionId;
|
||
|
||
[LabelText("敌方撤退区")] public int enemyFallbackRegionId;
|
||
|
||
[LabelText("PVP防守区")] public int pvpDefendRegionId;
|
||
|
||
[LabelText("PVP防守方朝向")] public LevelData.CharacterToward pvpDefendToward;
|
||
|
||
private void OnRegionChanged()
|
||
{
|
||
var regionsList = currWindow._curMap.MapData.regions;
|
||
for (int i = 0; i < regionsList.Count; i++)
|
||
{
|
||
currWindow._curMap.SetRegionColor(i, false, RegionColor);
|
||
}
|
||
|
||
currWindow._curMap.SetRegionColor(preparingRegionId, true, RegionColor);
|
||
}
|
||
}
|
||
|
||
[Serializable]
|
||
public class NpcEditorInfo
|
||
{
|
||
[HideInInspector] public bool selfNpc;
|
||
[ReadOnly] [LabelText("序号ID")] public int id;
|
||
|
||
[LabelText("MonsterID")] [ValueDropdown("GetMonsterIDs")] [OnValueChanged("ChangeNpcID")]
|
||
public int monsterId;
|
||
|
||
private IEnumerable<int> GetMonsterIDs()
|
||
{
|
||
if (!selfNpc)
|
||
return currWindow.GetMonsterIDs();
|
||
return currWindow.GetSelfNpcIDs();
|
||
}
|
||
|
||
private void ChangeNpcID()
|
||
{
|
||
if (!selfNpc)
|
||
currWindow.ChangeNpcID(npcInfo, monsterId);
|
||
else
|
||
currWindow.ChangeFightNpcID(npcInfo, monsterId);
|
||
}
|
||
|
||
[LabelText("朝向")] [OnValueChanged("NpcTowardOnChange")]
|
||
public LevelData.CharacterToward npcToward;
|
||
|
||
private void NpcTowardOnChange()
|
||
{
|
||
npcInfo.npcToward = npcToward;
|
||
if (!selfNpc)
|
||
currWindow.ChangeNpcToward(npcInfo.position, npcToward);
|
||
else
|
||
currWindow.ChangeSelfNpcToward(npcInfo.position, npcToward);
|
||
}
|
||
|
||
[HideLabel] public LevelData.NPCInfo npcInfo;
|
||
|
||
public NpcEditorInfo(LevelData.NPCInfo npcInfo, int index, bool isSelfNpc = false)
|
||
{
|
||
this.npcInfo = npcInfo;
|
||
monsterId = npcInfo.id;
|
||
id = index;
|
||
selfNpc = isSelfNpc;
|
||
npcToward = this.npcInfo.npcToward;
|
||
}
|
||
|
||
[LabelText("位置调整")] [OnValueChanged("ChangeNpcPos")]
|
||
public bool isChangePos;
|
||
|
||
private void ChangeNpcPos()
|
||
{
|
||
if (isChangePos)
|
||
{
|
||
currWindow.isEditingPatrolInfo = false;
|
||
if (currWindow._currEditingNpcInfo != null)
|
||
DebugUtil.LogWarning("检查其他怪物是否处于位置调整或编辑巡逻信息状态");
|
||
}
|
||
|
||
currWindow.isEditingNpcPos = isChangePos;
|
||
currWindow._currEditingNpcInfo = isChangePos ? npcInfo : null;
|
||
}
|
||
|
||
[LabelText("显示该怪物序号")] [OnValueChanged("ShowNpcID")]
|
||
public bool isShowNpcID;
|
||
|
||
private void ShowNpcID()
|
||
{
|
||
if (isShowNpcID && !currWindow._showNpcInfos.Contains(this))
|
||
currWindow._showNpcInfos.Add(this);
|
||
else
|
||
{
|
||
currWindow._showNpcInfos.Remove(this);
|
||
}
|
||
}
|
||
|
||
private bool _isEditing;
|
||
|
||
[Button("开始编辑巡逻信息")]
|
||
[HideIf("_isEditing")]
|
||
private void StartEditNpc()
|
||
{
|
||
currWindow.StartEditPatrolInfo(npcInfo);
|
||
_isEditing = true;
|
||
}
|
||
|
||
[Button("完成编辑巡逻信息")]
|
||
[ShowIf("_isEditing")]
|
||
private void FinishEditNpc()
|
||
{
|
||
currWindow.FinishEditPatrolInfo();
|
||
_isEditing = false;
|
||
}
|
||
}
|
||
|
||
[Serializable]
|
||
public class CaptureEditorInfo
|
||
{
|
||
[LabelText("占领点位")] public Vector2Int capturePoint;
|
||
|
||
[LabelText("占领时间")] public int captureProgress;
|
||
}
|
||
|
||
[Serializable]
|
||
public class FlagEditorInfo
|
||
{
|
||
[LabelText("扛旗起点")] public List<Vector2Int> flagStartPoints = new();
|
||
|
||
[LabelText("扛旗终点")] public List<Vector2Int> flagEndPoints = new();
|
||
|
||
[LabelText("添加起点")] [OnValueChanged("EditingStartPoints")]
|
||
public bool isEditingStart;
|
||
|
||
[LabelText("添加终点")] [OnValueChanged("EditingEndPoints")]
|
||
public bool isEditingEnd;
|
||
|
||
private void EditingStartPoints()
|
||
{
|
||
currWindow.isEditingFlagStart = isEditingStart;
|
||
if (isEditingStart)
|
||
{
|
||
isEditingEnd = false;
|
||
currWindow.isEditingFlagEnd = false;
|
||
}
|
||
}
|
||
|
||
private void EditingEndPoints()
|
||
{
|
||
currWindow.isEditingFlagEnd = isEditingEnd;
|
||
if (isEditingEnd)
|
||
{
|
||
isEditingStart = false;
|
||
currWindow.isEditingFlagStart = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
[Serializable]
|
||
public class FallbackEditorInfo
|
||
{
|
||
[LabelText("单次撤离点")] public List<Vector2Int> fallbackSinglePoints = new();
|
||
|
||
[LabelText("复用撤离点")] public List<Vector2Int> fallbackReusablePoints = new();
|
||
|
||
[LabelText("添加单次撤离点")] [OnValueChanged("EditingFallbackPoints")]
|
||
public bool isEditingSinglePoints;
|
||
|
||
[LabelText("添加复用撤离点")] [OnValueChanged("EditingMultiplexPoint")]
|
||
public bool isEditingReusablePoints;
|
||
|
||
private void EditingFallbackPoints()
|
||
{
|
||
currWindow.isEditingFallbackSingle = isEditingSinglePoints;
|
||
if (isEditingSinglePoints)
|
||
{
|
||
isEditingReusablePoints = false;
|
||
currWindow.isEditingFallbackReusable = false;
|
||
}
|
||
}
|
||
|
||
private void EditingMultiplexPoint()
|
||
{
|
||
currWindow.isEditingFallbackReusable = isEditingReusablePoints;
|
||
if (isEditingReusablePoints)
|
||
{
|
||
isEditingSinglePoints = false;
|
||
currWindow.isEditingFallbackSingle = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 配置表
|
||
|
||
private Level LevelCfg => EditorTableManager.instance.tables.Level;
|
||
private Monster MonsterCfg => EditorTableManager.instance.tables.Monster;
|
||
private VehicleConfig VehicleCfg => EditorTableManager.instance.tables.VehicleConfig;
|
||
private FightNPCConfig FightNpcCfg => EditorTableManager.instance.tables.FightNPCConfig;
|
||
|
||
#endregion
|
||
|
||
private const int SelfID = 200;
|
||
|
||
private static readonly Color RegionColor = MapUtils.GetRGBAColor("FF960072");
|
||
|
||
private static LevelEditorWindow currWindow;
|
||
|
||
private MapManager _mapManager;
|
||
|
||
private Dictionary<Vector2Int, GameObject> _npcObjectDic;
|
||
|
||
private Dictionary<Vector2Int, GameObject> _selfNpcObjectDic;
|
||
|
||
private Map _curMap;
|
||
|
||
private LevelEditor _levelEditor;
|
||
|
||
private LevelData.NPCInfo _currEditingNpcInfo;
|
||
|
||
private bool isEditingPatrolInfo;
|
||
|
||
private bool isEditingNpcPos;
|
||
|
||
private bool isEditingFlagStart;
|
||
|
||
private bool isEditingFlagEnd;
|
||
|
||
private bool isEditingFallbackSingle;
|
||
|
||
private bool isEditingFallbackReusable;
|
||
|
||
private bool IsShowNpcID => _showNpcInfos != null && _showNpcInfos.Count > 0;
|
||
|
||
private List<NpcEditorInfo> _showNpcInfos;
|
||
|
||
private bool ResponseClickOnCell =>
|
||
isEditingNpc || isEditingSelfNpc || isEditingNpcPos || isEditingPatrolInfo || isEditingFlagStart ||
|
||
isEditingFlagEnd || isEditingCapture ||
|
||
isEditingFallbackReusable || isEditingFallbackSingle;
|
||
|
||
[LabelText("当前关卡数据"), Indent] [OnValueChanged("OnCurrentLevelDataChanged")]
|
||
public LevelData currentLevelData = null;
|
||
|
||
[LabelText("当前占领数据"), Indent] [ShowIf("EditorCaptureInfo")]
|
||
public List<CaptureEditorInfo> captureEditorInfo = new();
|
||
|
||
[LabelText("编辑占领数据"), Indent] [ShowIf("EditorCaptureInfo")]
|
||
public bool isEditingCapture = false;
|
||
|
||
private bool EditorCaptureInfo()
|
||
{
|
||
return CheckConditionSame(ConditionType.CombatLeastOccupy);
|
||
}
|
||
|
||
[LabelText("当前扛旗数据"), Indent] [ShowIf("EditorFlagInfo")]
|
||
public FlagEditorInfo flagEditorInfo = new();
|
||
|
||
private bool EditorFlagInfo()
|
||
{
|
||
return CheckConditionSame(ConditionType.CombatSubmitFlag);
|
||
}
|
||
|
||
[LabelText("当前撤离数据"), Indent] [ShowIf("EditorFallbackInfo")]
|
||
public FallbackEditorInfo fallbackEditorInfo = new();
|
||
|
||
private bool EditorFallbackInfo()
|
||
{
|
||
return CheckConditionSame(ConditionType.CombatFallBack);
|
||
}
|
||
|
||
[LabelText("当前地区数据"), Indent] [OnValueChanged("OnCurrentLevelDataChanged")]
|
||
public RegionData curRegionData = null;
|
||
|
||
[LabelText("显示索引地图"), Indent] [LabelWidth(100)] [OnValueChanged("ShowCellCoordinates")] [SerializeField]
|
||
public bool isShowCellCoordinates;
|
||
|
||
private void ShowCellCoordinates()
|
||
{
|
||
if (_curMap == null || _curMap.TerrainGridSystem == null) return;
|
||
_curMap.TerrainGridSystem.displayCellDebugInfo =
|
||
isShowCellCoordinates ? CellDebugInfo.CellCoordinates : CellDebugInfo.Nothing;
|
||
var obj = FindObjectOfType<TerrainGridSystem>().gameObject;
|
||
|
||
Selection.activeGameObject = obj;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 关卡ID 通过关卡数据 json文件名 获得
|
||
/// </summary>
|
||
[LabelText("手动指定关卡ID"), Indent, LabelWidth(100), ShowIf("needManualInputLevelID")]
|
||
[OnValueChanged("GetLevelMonsterClass")]
|
||
[InfoBox("无法正确获得关卡ID,请手动指定")]
|
||
[SerializeField]
|
||
public string levelID;
|
||
|
||
#region 敌方Npc
|
||
|
||
[LabelText("编辑NPC"), Indent] [LabelWidth(100)] [SerializeField] [OnValueChanged("OnIsEditingNpcChanged")]
|
||
public bool isEditingNpc;
|
||
|
||
[LabelText("显示所有怪物序号ID"), Indent] [OnValueChanged("ShowAllNpcId")] [SerializeField]
|
||
public bool isShowAllNpcID;
|
||
|
||
[LabelText("怪物ID"), Indent, LabelWidth(100)]
|
||
[SerializeField]
|
||
[OnValueChanged("MonsterIDChanged")]
|
||
[ValueDropdown("GetMonsterIDs")]
|
||
[ShowIf("isEditingNpc")]
|
||
public int curMonsterID;
|
||
|
||
[PreviewField(150, ObjectFieldAlignment.Center), Indent, ReadOnly] [LabelText("NPC预制体预览图"), ShowIf("isEditingNpc")]
|
||
public GameObject npcObject;
|
||
|
||
[LabelText("当前怪物列表"), Indent, ShowIf("isEditingNpc")]
|
||
[ListDrawerSettings(HideAddButton = true, HideRemoveButton = true)]
|
||
public List<NpcEditorInfo> currentNpcInfo = null;
|
||
|
||
private IEnumerable<int> GetMonsterIDs()
|
||
{
|
||
return monsterIDs;
|
||
}
|
||
|
||
private void MonsterIDChanged()
|
||
{
|
||
var obj = LoadNpcPrefab(curMonsterID);
|
||
if (obj != null)
|
||
npcObject = obj;
|
||
}
|
||
|
||
private void OnIsEditingNpcChanged()
|
||
{
|
||
if (isEditingNpc && isEditingSelfNpc)
|
||
isEditingSelfNpc = false;
|
||
}
|
||
|
||
private void ShowAllNpcId()
|
||
{
|
||
foreach (var npc in currentNpcInfo)
|
||
{
|
||
npc.isShowNpcID = isShowAllNpcID;
|
||
if (isShowAllNpcID)
|
||
{
|
||
if (!_showNpcInfos.Contains(npc))
|
||
{
|
||
_showNpcInfos.Add(npc);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
_showNpcInfos.Remove(npc);
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 己方Npc
|
||
|
||
[LabelText("编辑己方NPC"), Indent] [LabelWidth(100)] [OnValueChanged("OnIsEditingSelfNpcChanged")] [SerializeField]
|
||
public bool isEditingSelfNpc;
|
||
|
||
[LabelText("显示所有己方序号ID"), Indent] [OnValueChanged("ShowAllSelfNpcId")] [SerializeField]
|
||
public bool isShowAllSelfNpcID;
|
||
|
||
[LabelText("己方NpcID"), Indent, LabelWidth(100)]
|
||
[SerializeField]
|
||
[OnValueChanged("SelfNpcIDChanged")]
|
||
[ValueDropdown("GetSelfNpcIDs")]
|
||
[ShowIf("isEditingSelfNpc")]
|
||
public int curSelfNpcID;
|
||
|
||
[PreviewField(150, ObjectFieldAlignment.Center), Indent, ReadOnly]
|
||
[LabelText("己方NPC预制体预览图"), ShowIf("isEditingSelfNpc")]
|
||
public GameObject selfNpcObject;
|
||
|
||
[LabelText("当前己方NPC列表"), Indent, ShowIf("isEditingSelfNpc")]
|
||
[ListDrawerSettings(HideAddButton = true, HideRemoveButton = true)]
|
||
public List<NpcEditorInfo> currentSelfNpcInfo = null;
|
||
|
||
private IEnumerable<int> GetSelfNpcIDs()
|
||
{
|
||
return selfMonsterIDs;
|
||
}
|
||
|
||
private void SelfNpcIDChanged()
|
||
{
|
||
var obj = LoadSelfNpcPrefab(curSelfNpcID);
|
||
if (obj != null)
|
||
selfNpcObject = obj;
|
||
}
|
||
|
||
private void OnIsEditingSelfNpcChanged()
|
||
{
|
||
if (isEditingNpc && isEditingSelfNpc)
|
||
isEditingNpc = false;
|
||
}
|
||
|
||
private void ShowAllSelfNpcId()
|
||
{
|
||
foreach (var npc in currentSelfNpcInfo)
|
||
{
|
||
npc.isShowNpcID = isShowAllSelfNpcID;
|
||
if (isShowAllSelfNpcID)
|
||
{
|
||
if (!_showNpcInfos.Contains(npc))
|
||
{
|
||
_showNpcInfos.Add(npc);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
_showNpcInfos.Remove(npc);
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 保存
|
||
|
||
[Button("保存当前关卡"), Indent]
|
||
private void SaveCurrentLevel()
|
||
{
|
||
CheckCorrectLevel();
|
||
|
||
// 地区
|
||
currentLevelData.preparingRegionId = curRegionData.preparingRegionId;
|
||
currentLevelData.fallbackRegionId = curRegionData.fallbackRegionId;
|
||
currentLevelData.enemyFallbackRegionId = curRegionData.enemyFallbackRegionId;
|
||
currentLevelData.preparingRegionToward = curRegionData.preparingRegionToward;
|
||
currentLevelData.pvpDefendRegionId = curRegionData.pvpDefendRegionId;
|
||
currentLevelData.pvpDefendToward = curRegionData.pvpDefendToward;
|
||
|
||
// NPC
|
||
foreach (var npcEditor in currentNpcInfo)
|
||
{
|
||
npcEditor.npcInfo.index = npcEditor.id;
|
||
}
|
||
|
||
currentLevelData.npcInfos = currentNpcInfo.Select(editorNpcInfo => editorNpcInfo.npcInfo).ToList();
|
||
|
||
// 己方NPC
|
||
foreach (var npcFightEditorInfo in currentSelfNpcInfo)
|
||
{
|
||
npcFightEditorInfo.npcInfo.index = npcFightEditorInfo.id;
|
||
}
|
||
|
||
currentLevelData.selfNpcInfos =
|
||
currentSelfNpcInfo.Select(editorFightNpcInfo => editorFightNpcInfo.npcInfo).ToList();
|
||
|
||
// 条件
|
||
ProcessCondition();
|
||
|
||
// 占领数据
|
||
currentLevelData.CapturePoints.Clear();
|
||
foreach (var captureInfo in captureEditorInfo)
|
||
{
|
||
var capture = new LevelData.CaptureInfo
|
||
{
|
||
CapturePoint = _curMap.BlockPosition2TGSCellIndex(captureInfo.capturePoint),
|
||
CaptureProgress = captureInfo.captureProgress,
|
||
};
|
||
currentLevelData.CapturePoints.Add(capture);
|
||
}
|
||
|
||
// 扛旗数据
|
||
currentLevelData.flagStartPoints.Clear();
|
||
currentLevelData.flagEndPoints.Clear();
|
||
foreach (var flag in flagEditorInfo.flagStartPoints)
|
||
{
|
||
var cellIndex = _curMap.BlockPosition2TGSCellIndex(flag);
|
||
currentLevelData.flagStartPoints.Add(cellIndex);
|
||
}
|
||
|
||
foreach (var flag in flagEditorInfo.flagEndPoints)
|
||
{
|
||
var cellIndex = _curMap.BlockPosition2TGSCellIndex(flag);
|
||
currentLevelData.flagEndPoints.Add(cellIndex);
|
||
}
|
||
|
||
// 撤离数据
|
||
currentLevelData.fallbackSinglePoints.Clear();
|
||
currentLevelData.fallbackReusablePoints.Clear();
|
||
foreach (var fallback in fallbackEditorInfo.fallbackSinglePoints)
|
||
{
|
||
var cellIndex = _curMap.BlockPosition2TGSCellIndex(fallback);
|
||
currentLevelData.fallbackSinglePoints.Add(cellIndex);
|
||
}
|
||
|
||
foreach (var fallback in fallbackEditorInfo.fallbackReusablePoints)
|
||
{
|
||
var cellIndex = _curMap.BlockPosition2TGSCellIndex(fallback);
|
||
currentLevelData.fallbackReusablePoints.Add(cellIndex);
|
||
}
|
||
|
||
_levelEditor.SaveLevelData();
|
||
}
|
||
|
||
private void ProcessCondition()
|
||
{
|
||
ProcessConditionForList(currentLevelData.stages.Select(stage => stage.successCondition));
|
||
ProcessConditionForList(currentLevelData.starTarget);
|
||
ProcessConditionForList(currentLevelData.scoreTarget);
|
||
}
|
||
|
||
private void ProcessConditionForList(IEnumerable<ConditionModifier> conditionModifiers)
|
||
{
|
||
foreach (var conditionModifier in conditionModifiers)
|
||
{
|
||
if (conditionModifier.conditionType == ConditionType.CombatKillEnemy)
|
||
{
|
||
conditionModifier.conditionArgs.Clear();
|
||
foreach (var enemy in conditionModifier.killEnemyIDList)
|
||
{
|
||
conditionModifier.conditionArgs.Add(new Param("", enemy, ""));
|
||
}
|
||
}
|
||
}
|
||
|
||
foreach (var conditionModifier in conditionModifiers)
|
||
{
|
||
if (conditionModifier.conditionType == ConditionType.CombatFallBack &&
|
||
conditionModifier.conditionArgs.Count > 0)
|
||
{
|
||
currentLevelData.fallBackCount = (int)conditionModifier.conditionArgs[0].Arg;
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
/// <summary>
|
||
/// 该关卡的怪物ID
|
||
/// </summary>
|
||
[HideInInspector] public List<int> monsterIDs;
|
||
|
||
/// <summary>
|
||
/// 该关卡的怪物ID
|
||
/// </summary>
|
||
[HideInInspector] public List<int> selfMonsterIDs;
|
||
|
||
/// <summary>
|
||
/// 该关卡的剧怪物ID
|
||
/// </summary>
|
||
[HideInInspector] public List<int> fightMonsterIDs;
|
||
|
||
/// <summary>
|
||
/// 需要手动输入关卡ID
|
||
/// </summary>
|
||
[HideInInspector] public bool needManualInputLevelID;
|
||
|
||
public void GetLevelMonsterClass()
|
||
{
|
||
if (!int.TryParse(levelID, out var levelIndex) ||
|
||
!LevelCfg.DataMap.TryGetValue(levelIndex, out var level))
|
||
{
|
||
needManualInputLevelID = true;
|
||
DebugUtil.LogError("无对应的关卡ID请手动输入关卡ID");
|
||
curMonsterID = 0;
|
||
npcObject = null;
|
||
return;
|
||
}
|
||
|
||
monsterIDs = new List<int>();
|
||
selfMonsterIDs = new List<int>();
|
||
|
||
foreach (var monster in MonsterCfg.DataMap)
|
||
{
|
||
var strID = monster.Key.ToString();
|
||
var tempID = strID.Substring(0, 6);
|
||
|
||
//关卡ID相同
|
||
if (tempID.Equals(levelID))
|
||
{
|
||
switch (monster.Value.NpcType)
|
||
{
|
||
case 2:
|
||
selfMonsterIDs.Add(monster.Key);
|
||
break;
|
||
case 3:
|
||
selfMonsterIDs.Add(monster.Key);
|
||
break;
|
||
default:
|
||
monsterIDs.Add(monster.Key);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (monsterIDs.Count <= 0)
|
||
{
|
||
DebugUtil.LogError("请检查Monster表,没有{0}关卡的怪物数据", levelID);
|
||
}
|
||
}
|
||
|
||
#region 加载
|
||
|
||
private void LoadLevel(LevelData levelData)
|
||
{
|
||
DestroyNpcPrefab();
|
||
_npcObjectDic.Clear();
|
||
_showNpcInfos.Clear();
|
||
_selfNpcObjectDic.Clear();
|
||
|
||
currentLevelData = levelData;
|
||
|
||
//加载地区信息
|
||
curRegionData = new RegionData
|
||
{
|
||
preparingRegionId = currentLevelData.preparingRegionId,
|
||
fallbackRegionId = currentLevelData.fallbackRegionId,
|
||
enemyFallbackRegionId = currentLevelData.enemyFallbackRegionId,
|
||
preparingRegionToward = currentLevelData.preparingRegionToward,
|
||
pvpDefendRegionId = currentLevelData.pvpDefendRegionId,
|
||
pvpDefendToward = currentLevelData.pvpDefendToward
|
||
};
|
||
|
||
_mapManager = FindObjectOfType<MapManager>();
|
||
_curMap = _mapManager.Map;
|
||
|
||
_curMap.TerrainGridSystem.OnMouseClickOnGrid += OnCellClick;
|
||
|
||
// 加载占领数据
|
||
captureEditorInfo = new List<CaptureEditorInfo>();
|
||
foreach (var captureInfo in currentLevelData.CapturePoints)
|
||
{
|
||
var captureEditor = new CaptureEditorInfo()
|
||
{
|
||
capturePoint = _curMap.TGSCellIndex2BlockPosition(captureInfo.CapturePoint),
|
||
captureProgress = captureInfo.CaptureProgress,
|
||
};
|
||
captureEditorInfo.Add(captureEditor);
|
||
}
|
||
|
||
// 加载扛旗数据
|
||
flagEditorInfo = new FlagEditorInfo();
|
||
foreach (var flagStartPoint in currentLevelData.flagStartPoints)
|
||
{
|
||
var pos = _curMap.TGSCellIndex2BlockPosition(flagStartPoint);
|
||
flagEditorInfo.flagStartPoints.Add(pos);
|
||
}
|
||
|
||
foreach (var flagEndPoint in currentLevelData.flagEndPoints)
|
||
{
|
||
var pos = _curMap.TGSCellIndex2BlockPosition(flagEndPoint);
|
||
flagEditorInfo.flagEndPoints.Add(pos);
|
||
}
|
||
|
||
// 加载撤离数据
|
||
fallbackEditorInfo = new FallbackEditorInfo();
|
||
foreach (var fallback in currentLevelData.fallbackSinglePoints)
|
||
{
|
||
var pos = _curMap.TGSCellIndex2BlockPosition(fallback);
|
||
fallbackEditorInfo.fallbackSinglePoints.Add(pos);
|
||
}
|
||
|
||
foreach (var fallback in currentLevelData.fallbackReusablePoints)
|
||
{
|
||
var pos = _curMap.TGSCellIndex2BlockPosition(fallback);
|
||
fallbackEditorInfo.fallbackReusablePoints.Add(pos);
|
||
}
|
||
|
||
// 加载NPC到场景中
|
||
LoadNpcInfo();
|
||
|
||
// 加载己方NPC
|
||
LoadSelfNpcInfo();
|
||
}
|
||
|
||
private void LoadNpcInfo()
|
||
{
|
||
var monsterConfigDic = MonsterCfg.DataMap;
|
||
currentNpcInfo = new();
|
||
var index = 1;
|
||
foreach (var npcInfo in currentLevelData.npcInfos)
|
||
{
|
||
if (!monsterConfigDic.TryGetValue(npcInfo.id, out var monsterClassData))
|
||
{
|
||
DebugUtil.LogError("请检查配置,没有 {0} 的怪物类ID", npcInfo.id);
|
||
continue;
|
||
}
|
||
|
||
var npcEditor = new NpcEditorInfo(npcInfo, index);
|
||
currentNpcInfo.Add(npcEditor);
|
||
|
||
npcInfo.level = monsterClassData.MonsterLevel;
|
||
|
||
var npcObj = LoadNpcPrefab(npcInfo.id);
|
||
if (npcObj != null)
|
||
{
|
||
var setPos = _curMap.BlockPosition2WorldPosition(npcInfo.position);
|
||
var yaw = LevelUtils.SetCharaterToward(npcInfo.npcToward);
|
||
_npcObjectDic.Add(npcInfo.position, Instantiate(npcObj, setPos, Quaternion.Euler(0, yaw, 0)));
|
||
}
|
||
|
||
index++;
|
||
}
|
||
}
|
||
|
||
private void LoadSelfNpcInfo()
|
||
{
|
||
var monsterConfigDic = MonsterCfg.DataMap;
|
||
currentSelfNpcInfo = new();
|
||
var index = SelfID + 1;
|
||
foreach (var selfNpcInfo in currentLevelData.selfNpcInfos)
|
||
{
|
||
if (!monsterConfigDic.TryGetValue(selfNpcInfo.id, out var monsterClassData))
|
||
{
|
||
DebugUtil.LogError("请检查配置,没有 {0} 的怪物类ID, 已经删除对应", selfNpcInfo.id);
|
||
continue;
|
||
}
|
||
|
||
var npcEditor = new NpcEditorInfo(selfNpcInfo, index, true);
|
||
currentSelfNpcInfo.Add(npcEditor);
|
||
selfNpcInfo.level = monsterClassData.MonsterLevel;
|
||
var npcObj = LoadSelfNpcPrefab(selfNpcInfo.id);
|
||
if (npcObj != null)
|
||
{
|
||
var setPos = _curMap.BlockPosition2WorldPosition(selfNpcInfo.position);
|
||
var yaw = LevelUtils.SetCharaterToward(selfNpcInfo.npcToward);
|
||
_selfNpcObjectDic.Add(selfNpcInfo.position, Instantiate(npcObj, setPos, Quaternion.Euler(0, yaw, 0)));
|
||
}
|
||
|
||
index++;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 点击添加事件
|
||
|
||
private void OnCellClick(TerrainGridSystem tgs, int cellindex, int buttonindex)
|
||
{
|
||
if (!ResponseClickOnCell) return;
|
||
|
||
var clickPosition = _curMap.TGSCellIndex2BlockPosition(cellindex);
|
||
|
||
int leftButton = 0;
|
||
int rightButton = 1;
|
||
|
||
if (buttonindex != leftButton && buttonindex != rightButton)
|
||
return;
|
||
bool opTrue = buttonindex == leftButton;
|
||
|
||
if (isEditingFlagStart)
|
||
{
|
||
EditingFlagStart(clickPosition, true, opTrue);
|
||
}
|
||
else if (isEditingFlagEnd)
|
||
{
|
||
EditingFlagStart(clickPosition, false, opTrue);
|
||
}
|
||
else if (isEditingFallbackSingle)
|
||
{
|
||
EditingFallBack(clickPosition, true, opTrue);
|
||
}
|
||
else if (isEditingFallbackReusable)
|
||
{
|
||
EditingFallBack(clickPosition, false, opTrue);
|
||
}
|
||
else if (isEditingCapture)
|
||
{
|
||
EditingCapture(clickPosition, opTrue);
|
||
}
|
||
else if (isEditingPatrolInfo)
|
||
{
|
||
if (opTrue)
|
||
AddPatrolInfo(clickPosition);
|
||
else
|
||
RemovePatrolInfo(clickPosition);
|
||
}
|
||
else if (isEditingNpcPos)
|
||
{
|
||
if (opTrue)
|
||
ChangeNpcPos(clickPosition);
|
||
}
|
||
else if (isEditingNpc)
|
||
{
|
||
EditNpc(clickPosition, opTrue);
|
||
}
|
||
else if (isEditingSelfNpc)
|
||
{
|
||
EditSelfNpc(clickPosition, opTrue);
|
||
}
|
||
}
|
||
|
||
private void EditingFallBack(Vector2Int clickPosition, bool isEditingSingle, bool isAdd)
|
||
{
|
||
if (isEditingSingle)
|
||
{
|
||
if (isAdd && !fallbackEditorInfo.fallbackSinglePoints.Contains(clickPosition))
|
||
{
|
||
DebugUtil.Log("单次撤离点添加: {0}", clickPosition);
|
||
fallbackEditorInfo.fallbackSinglePoints.Add(clickPosition);
|
||
}
|
||
else if (!isAdd && fallbackEditorInfo.fallbackSinglePoints.Contains(clickPosition))
|
||
{
|
||
DebugUtil.Log("单次撤离点移除: {0}", clickPosition);
|
||
fallbackEditorInfo.fallbackSinglePoints.Remove(clickPosition);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (isAdd && !fallbackEditorInfo.fallbackReusablePoints.Contains(clickPosition))
|
||
{
|
||
DebugUtil.Log("复用撤离点添加: {0}", clickPosition);
|
||
fallbackEditorInfo.fallbackReusablePoints.Add(clickPosition);
|
||
}
|
||
else if (!isAdd && fallbackEditorInfo.fallbackReusablePoints.Contains(clickPosition))
|
||
{
|
||
DebugUtil.Log("复用撤离点移除: {0}", clickPosition);
|
||
fallbackEditorInfo.fallbackReusablePoints.Remove(clickPosition);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void EditingFlagStart(Vector2Int clickPosition, bool isEditingStart, bool isAdd)
|
||
{
|
||
if (isEditingStart)
|
||
{
|
||
if (isAdd && !flagEditorInfo.flagStartPoints.Contains(clickPosition))
|
||
{
|
||
DebugUtil.Log("扛旗起点添加: {0}", clickPosition);
|
||
flagEditorInfo.flagStartPoints.Add(clickPosition);
|
||
}
|
||
else if (!isAdd && flagEditorInfo.flagStartPoints.Contains(clickPosition))
|
||
{
|
||
DebugUtil.Log("扛旗起点移除: {0}", clickPosition);
|
||
flagEditorInfo.flagStartPoints.Remove(clickPosition);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (isAdd && !flagEditorInfo.flagEndPoints.Contains(clickPosition))
|
||
{
|
||
DebugUtil.Log("扛旗终点添加: {0}", clickPosition);
|
||
flagEditorInfo.flagEndPoints.Add(clickPosition);
|
||
}
|
||
else if (!isAdd && flagEditorInfo.flagEndPoints.Contains(clickPosition))
|
||
{
|
||
DebugUtil.Log("扛旗终点移除: {0}", clickPosition);
|
||
flagEditorInfo.flagEndPoints.Remove(clickPosition);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void EditingCapture(Vector2Int clickPosition, bool isAdd)
|
||
{
|
||
var isExist = false;
|
||
CaptureEditorInfo existCapture = null;
|
||
foreach (var capture in captureEditorInfo)
|
||
{
|
||
if (capture.capturePoint == clickPosition)
|
||
{
|
||
isExist = true;
|
||
existCapture = capture;
|
||
}
|
||
}
|
||
|
||
if (isAdd)
|
||
{
|
||
if (!isExist)
|
||
{
|
||
DebugUtil.Log("占领点添加: {0}", clickPosition);
|
||
captureEditorInfo.Add(new CaptureEditorInfo()
|
||
{
|
||
capturePoint = clickPosition
|
||
});
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (existCapture != null)
|
||
{
|
||
DebugUtil.Log("占领点移除: {0}", clickPosition);
|
||
captureEditorInfo.Remove(existCapture);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void ChangeNpcPos(Vector2Int clickPosition)
|
||
{
|
||
var oldPos = _currEditingNpcInfo.position;
|
||
if (oldPos == clickPosition) return;
|
||
var newWorldPos = _curMap.BlockPosition2WorldPosition(clickPosition);
|
||
if (_npcObjectDic.TryGetValue(oldPos, out var npcObj))
|
||
{
|
||
npcObj.transform.position = newWorldPos;
|
||
_currEditingNpcInfo.position = clickPosition;
|
||
_npcObjectDic.Remove(oldPos);
|
||
_npcObjectDic.Add(clickPosition, npcObj);
|
||
DebugUtil.Log("怪物: [ {0} ] 移动到 [ {1} ]位置上", _currEditingNpcInfo.id, clickPosition);
|
||
}
|
||
else if (_selfNpcObjectDic.TryGetValue(oldPos, out var selfNpcObj))
|
||
{
|
||
selfNpcObj.transform.position = newWorldPos;
|
||
_currEditingNpcInfo.position = clickPosition;
|
||
_selfNpcObjectDic.Remove(oldPos);
|
||
_selfNpcObjectDic.Add(clickPosition, selfNpcObj);
|
||
DebugUtil.Log("怪物: [ {0} ] 移动到 [ {1} ]位置上", _currEditingNpcInfo.id, clickPosition);
|
||
}
|
||
else
|
||
{
|
||
DebugUtil.LogError("需要更改的旧位置上没有怪物:{0}", oldPos);
|
||
}
|
||
}
|
||
|
||
private void EditNpc(Vector2Int clickPosition, bool isAdd)
|
||
{
|
||
if (isAdd)
|
||
{
|
||
AddNpc(clickPosition);
|
||
}
|
||
else
|
||
{
|
||
RemoveNpc(clickPosition);
|
||
}
|
||
}
|
||
|
||
private void AddNpc(Vector2Int clickPosition)
|
||
{
|
||
if (npcObject == null || curMonsterID == 0)
|
||
{
|
||
DebugUtil.LogError("请选择正确的NPC!!");
|
||
return;
|
||
}
|
||
|
||
_npcObjectDic ??= new Dictionary<Vector2Int, GameObject>();
|
||
|
||
if (_npcObjectDic.ContainsKey(clickPosition))
|
||
{
|
||
DebugUtil.LogError("该位置已有NPC存在,请重新选!!!");
|
||
return;
|
||
}
|
||
|
||
LevelData.NPCInfo npcInfo = new LevelData.NPCInfo
|
||
{
|
||
id = curMonsterID,
|
||
position = clickPosition
|
||
};
|
||
|
||
var monsterConfigDic = MonsterCfg.DataMap;
|
||
if (monsterConfigDic.TryGetValue(curMonsterID, out var monster))
|
||
{
|
||
npcInfo.level = monster.MonsterLevel;
|
||
}
|
||
else
|
||
{
|
||
DebugUtil.LogError("获取怪物[{0}]配置数据错误", curMonsterID);
|
||
}
|
||
|
||
currentNpcInfo.Add(new NpcEditorInfo(npcInfo, currentNpcInfo.Count + 1));
|
||
var pos = _curMap.BlockPosition2WorldPosition(npcInfo.position);
|
||
_npcObjectDic.Add(npcInfo.position, Instantiate(npcObject, pos, npcObject.transform.rotation));
|
||
DebugUtil.Log("添加了怪物: [ {0} ] 到 [ {1} ]位置上, 其预制体为: {2}", npcInfo.id, npcInfo.position, npcObject.name);
|
||
}
|
||
|
||
private void RemoveNpc(Vector2Int clickPosition)
|
||
{
|
||
if (_npcObjectDic.TryGetValue(clickPosition, out var npcObj))
|
||
{
|
||
var npc = currentNpcInfo.FirstOrDefault(npc => npc.npcInfo.position == clickPosition);
|
||
if (npc != null)
|
||
{
|
||
currentNpcInfo.Remove(npc);
|
||
DebugUtil.Log("从[ {0} ]位置上移除了[{1}]NPC", clickPosition, npcObj.name);
|
||
DestroyImmediate(npcObj);
|
||
_npcObjectDic.Remove(clickPosition);
|
||
}
|
||
}
|
||
|
||
ReorderNpcID();
|
||
}
|
||
|
||
private void EditSelfNpc(Vector2Int clickPosition, bool isAdd)
|
||
{
|
||
if (isAdd)
|
||
{
|
||
AddSelfNpc(clickPosition);
|
||
}
|
||
else
|
||
{
|
||
RemoveSelfNpc(clickPosition);
|
||
}
|
||
}
|
||
|
||
private void AddSelfNpc(Vector2Int clickPosition)
|
||
{
|
||
if (selfNpcObject == null || curSelfNpcID == 0)
|
||
{
|
||
DebugUtil.LogError("请选择正确的己方NPC!!");
|
||
return;
|
||
}
|
||
|
||
_selfNpcObjectDic ??= new Dictionary<Vector2Int, GameObject>();
|
||
|
||
if (_selfNpcObjectDic.ContainsKey(clickPosition))
|
||
{
|
||
DebugUtil.LogError("该位置已有NPC存在,请重新选!!!");
|
||
return;
|
||
}
|
||
|
||
LevelData.NPCInfo npcInfo = new LevelData.NPCInfo
|
||
{
|
||
id = curSelfNpcID,
|
||
position = clickPosition
|
||
};
|
||
|
||
currentSelfNpcInfo.Add(new NpcEditorInfo(npcInfo, SelfID + currentSelfNpcInfo.Count + 1));
|
||
var pos = _curMap.BlockPosition2WorldPosition(npcInfo.position);
|
||
_selfNpcObjectDic.Add(npcInfo.position, Instantiate(selfNpcObject, pos, selfNpcObject.transform.rotation));
|
||
DebugUtil.Log("添加了己方Npc: [ {0} ] 到 [ {1} ]位置上, 其预制体为: {2}", npcInfo.id, npcInfo.position, selfNpcObject.name);
|
||
}
|
||
|
||
private void RemoveSelfNpc(Vector2Int clickPosition)
|
||
{
|
||
if (_selfNpcObjectDic.TryGetValue(clickPosition, out var npcObj))
|
||
{
|
||
var npc = currentSelfNpcInfo.FirstOrDefault(npcFight => npcFight.npcInfo.position == clickPosition);
|
||
if (npc != null)
|
||
{
|
||
currentSelfNpcInfo.Remove(npc);
|
||
DebugUtil.Log("从[ {0} ]位置上移除了[{1}] 己方NPC", clickPosition, npcObj.name);
|
||
DestroyImmediate(npcObj);
|
||
_selfNpcObjectDic.Remove(clickPosition);
|
||
}
|
||
}
|
||
|
||
ReorderSelfNpcID();
|
||
}
|
||
|
||
private void AddPatrolInfo(Vector2Int clickPosition)
|
||
{
|
||
_currEditingNpcInfo.patrolInfos.Add(new LevelData.PatrolInfo()
|
||
{
|
||
patrolPoint = clickPosition,
|
||
});
|
||
}
|
||
|
||
private void RemovePatrolInfo(Vector2Int clickPosition)
|
||
{
|
||
var index = _currEditingNpcInfo.patrolInfos.FindLastIndex(pInfo => pInfo.patrolPoint == clickPosition);
|
||
if (index >= 0)
|
||
_currEditingNpcInfo.patrolInfos.RemoveAt(index);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 值改变时响应时间事件
|
||
|
||
private void OnCurrentLevelDataChanged()
|
||
{
|
||
Debug.Log($"{GetType()}.OnCurrentLevelDataChanged");
|
||
}
|
||
|
||
private void StartEditPatrolInfo(LevelData.NPCInfo npcInfo)
|
||
{
|
||
isEditingPatrolInfo = true;
|
||
_currEditingNpcInfo = npcInfo;
|
||
}
|
||
|
||
private void FinishEditPatrolInfo()
|
||
{
|
||
isEditingPatrolInfo = false;
|
||
_currEditingNpcInfo = null;
|
||
}
|
||
|
||
private void ReorderNpcID()
|
||
{
|
||
for (var i = 0; i < currentNpcInfo.Count; i++)
|
||
{
|
||
currentNpcInfo[i].id = i + 1;
|
||
}
|
||
}
|
||
|
||
private void ReorderSelfNpcID()
|
||
{
|
||
for (var i = 0; i < currentSelfNpcInfo.Count; i++)
|
||
{
|
||
currentSelfNpcInfo[i].id = SelfID + i + 1;
|
||
}
|
||
}
|
||
|
||
private void ChangeNpcID(LevelData.NPCInfo npcInfo, int newMonsterID)
|
||
{
|
||
if (_npcObjectDic.TryGetValue(npcInfo.position, out var npcObj))
|
||
{
|
||
var newObj = LoadNpcPrefab(newMonsterID);
|
||
if (newObj != null)
|
||
{
|
||
npcInfo.id = newMonsterID;
|
||
_npcObjectDic[npcInfo.position] =
|
||
Instantiate(newObj, npcObj.transform.position, npcObj.transform.rotation);
|
||
DestroyImmediate(npcObj);
|
||
DebugUtil.Log("位置上[ {0} ]的怪物ID改为: [ {1} ] ", npcInfo.position, npcInfo.id);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void ChangeFightNpcID(LevelData.NPCInfo npcInfoInfo, int newMonsterID)
|
||
{
|
||
if (_selfNpcObjectDic.TryGetValue(npcInfoInfo.position, out var npcObj))
|
||
{
|
||
var newObj = LoadSelfNpcPrefab(newMonsterID);
|
||
if (newObj != null)
|
||
{
|
||
npcInfoInfo.id = newMonsterID;
|
||
_selfNpcObjectDic[npcInfoInfo.position] =
|
||
Instantiate(newObj, npcObj.transform.position, npcObj.transform.rotation);
|
||
DestroyImmediate(npcObj);
|
||
DebugUtil.Log("位置上[ {0} ]的fight怪物ID改为: [ {1} ] ", npcInfoInfo.position, npcInfoInfo.id);
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 检查关卡
|
||
|
||
private const string PreparingRegionErrorMessage = "关卡出战区设置错误,该地图没有:<{0}>号地区。\n";
|
||
private const string FallbackRegionErrorMessage = "关卡撤退区设置错误,该地图没有:<{0}>号地区。\n";
|
||
private const string EnemyFallbackRegionErrorMessage = "关卡敌方撤退区设置错误,该地图没有:<{0}>号地区。\n";
|
||
private const string FixedMessage = "已将错误区域设置为默认<0>号地区。";
|
||
private const string CaptureErrorMessage = "占领条件参数大于配置的占领区域。";
|
||
|
||
|
||
private void CheckCorrectLevel()
|
||
{
|
||
if (_curMap == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
var errorMessage = string.Empty;
|
||
|
||
if (!_curMap.MapData.IsRegionExist(curRegionData.preparingRegionId))
|
||
{
|
||
errorMessage += string.Format(PreparingRegionErrorMessage,
|
||
curRegionData.preparingRegionId);
|
||
curRegionData.preparingRegionId = 0;
|
||
}
|
||
|
||
if (!_curMap.MapData.IsRegionExist(curRegionData.fallbackRegionId))
|
||
{
|
||
errorMessage += string.Format(FallbackRegionErrorMessage,
|
||
curRegionData.fallbackRegionId);
|
||
curRegionData.fallbackRegionId = 0;
|
||
}
|
||
|
||
if (!_curMap.MapData.IsRegionExist(curRegionData.enemyFallbackRegionId))
|
||
{
|
||
errorMessage += string.Format(EnemyFallbackRegionErrorMessage,
|
||
curRegionData.enemyFallbackRegionId);
|
||
curRegionData.enemyFallbackRegionId = 0;
|
||
}
|
||
|
||
// 检查占领条件相关
|
||
if (!CheckLevelCondition())
|
||
{
|
||
CustomPopUpWindow.PopUp(CaptureErrorMessage);
|
||
}
|
||
|
||
if (!string.IsNullOrEmpty(errorMessage))
|
||
{
|
||
CustomPopUpWindow.PopUp(errorMessage + FixedMessage);
|
||
}
|
||
}
|
||
|
||
private bool CheckLevelCondition()
|
||
{
|
||
if (currentLevelData.stages.Any(stage => stage.successCondition.conditionType == ConditionType.CombatLeastOccupy
|
||
&& stage.successCondition.conditionArgs[0].Arg >
|
||
captureEditorInfo.Count))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
if (currentLevelData.starTarget.Any(modifier => modifier.conditionType == ConditionType.CombatLeastOccupy
|
||
&& modifier.conditionArgs[0].Arg > captureEditorInfo.Count))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
if (currentLevelData.scoreTarget.Any(modifier => modifier.conditionType == ConditionType.CombatLeastOccupy
|
||
&& modifier.conditionArgs[0].Arg > captureEditorInfo.Count))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 内部方法
|
||
|
||
private GameObject LoadNpcPrefab(int monsterID)
|
||
{
|
||
GameObject obj = null;
|
||
var curMonsterClassID = 0;
|
||
if (MonsterCfg.DataMap.TryGetValue(monsterID, out var monster))
|
||
{
|
||
curMonsterClassID = monster.MonsterClassID;
|
||
}
|
||
else
|
||
{
|
||
return null;
|
||
}
|
||
|
||
switch (monster.NpcType)
|
||
{
|
||
case 1:
|
||
{
|
||
if (VehicleCfg.DataMap.TryGetValue(curMonsterClassID, out var vehicle))
|
||
{
|
||
var prefabPath = PathEx.GetVehicleGameModelPath(vehicle.ID);
|
||
obj = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
|
||
if (obj == null)
|
||
{
|
||
DebugUtil.LogError("请检查载具类: {0}的预制体路径是否存在,对应的完整路径: {1}", curMonsterClassID, prefabPath);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DebugUtil.LogError("请检查载具类: {0}的配置是否存在", curMonsterClassID);
|
||
}
|
||
|
||
return obj;
|
||
}
|
||
case 0:
|
||
{
|
||
var monsterClassCfg = EditorTableManager.instance.tables.MonsterClass;
|
||
if (monsterClassCfg.DataMap.TryGetValue(curMonsterClassID, out var monsterClass))
|
||
{
|
||
var prefabPath = PathEx.GetCharacterFightModelPath(monsterClass.NameId, monsterClass.WeaponId);
|
||
obj = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
|
||
if (obj == null)
|
||
{
|
||
DebugUtil.LogError("请检查怪物类: {0}的预制体路径是否存在,对应的完整路径: {1}", curMonsterClassID, prefabPath);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DebugUtil.LogError("请检查怪物类: {0}的配置是否存在", curMonsterClassID);
|
||
}
|
||
|
||
return obj;
|
||
}
|
||
default: return null;
|
||
}
|
||
}
|
||
|
||
private GameObject LoadSelfNpcPrefab(int monsterID)
|
||
{
|
||
GameObject obj = null;
|
||
var curFightNpcID = 0;
|
||
if (MonsterCfg.DataMap.TryGetValue(monsterID, out var monster))
|
||
{
|
||
curFightNpcID = monster.MonsterClassID;
|
||
}
|
||
else
|
||
{
|
||
return null;
|
||
}
|
||
|
||
switch (monster.NpcType)
|
||
{
|
||
case 3:
|
||
{
|
||
if (VehicleCfg.DataMap.TryGetValue(curFightNpcID, out var vehicle))
|
||
{
|
||
var prefabPath = PathEx.GetVehicleGameModelPath(vehicle.ID);
|
||
obj = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
|
||
if (obj == null)
|
||
{
|
||
DebugUtil.LogError("请检查载具类: {0}的预制体路径是否存在,对应的完整路径: {1}", curFightNpcID, prefabPath);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DebugUtil.LogError("请检查载具类: {0}的配置是否存在", curFightNpcID);
|
||
}
|
||
|
||
return obj;
|
||
}
|
||
case 2:
|
||
{
|
||
if (FightNpcCfg.DataMap.TryGetValue(curFightNpcID, out var fightNpc))
|
||
{
|
||
var prefabPath = PathEx.GetCharacterFightModelPath(fightNpc.NameId, fightNpc.WeaponId);
|
||
obj = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
|
||
if (obj == null)
|
||
{
|
||
DebugUtil.LogError("请检查FightNpc类: {0}的预制体路径是否存在,对应的完整路径: {1}", curFightNpcID, prefabPath);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DebugUtil.LogError("请检查FightNpc类: {0}的配置是否存在", curFightNpcID);
|
||
}
|
||
|
||
return obj;
|
||
}
|
||
default: return null;
|
||
}
|
||
}
|
||
|
||
private void DestroyNpcPrefab()
|
||
{
|
||
foreach (var npc in _npcObjectDic)
|
||
{
|
||
DestroyImmediate(npc.Value);
|
||
}
|
||
|
||
foreach (var npc in _selfNpcObjectDic)
|
||
{
|
||
DestroyImmediate(npc.Value);
|
||
}
|
||
}
|
||
|
||
private void ChangeNpcToward(Vector2Int pos, LevelData.CharacterToward npcToward)
|
||
{
|
||
if (_npcObjectDic.TryGetValue(pos, out var npcObj))
|
||
{
|
||
var yaw = LevelUtils.SetCharaterToward(npcToward);
|
||
npcObj.transform.eulerAngles = new Vector3(0, yaw, 0);
|
||
}
|
||
}
|
||
|
||
private void ChangeSelfNpcToward(Vector2Int pos, LevelData.CharacterToward npcToward)
|
||
{
|
||
if (_selfNpcObjectDic.TryGetValue(pos, out var npcObj))
|
||
{
|
||
var yaw = LevelUtils.SetCharaterToward(npcToward);
|
||
npcObj.transform.eulerAngles = new Vector3(0, yaw, 0);
|
||
}
|
||
}
|
||
|
||
private bool CheckConditionSame(ConditionType conditionType)
|
||
{
|
||
if (currentLevelData.stages.Any(stage => stage.successCondition.conditionType == conditionType))
|
||
{
|
||
return true;
|
||
}
|
||
|
||
if (currentLevelData.starTarget.Any(modifier => modifier.conditionType == conditionType))
|
||
{
|
||
return true;
|
||
}
|
||
|
||
if (currentLevelData.scoreTarget.Any(modifier => modifier.conditionType == conditionType))
|
||
{
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region MainLife
|
||
|
||
private void Awake()
|
||
{
|
||
SceneView.duringSceneGui += OnSceneGUI;
|
||
}
|
||
|
||
protected override void OnEnable()
|
||
{
|
||
TerrainTypeConfig.Load();
|
||
_npcObjectDic = new Dictionary<Vector2Int, GameObject>();
|
||
_showNpcInfos = new List<NpcEditorInfo>();
|
||
_selfNpcObjectDic = new Dictionary<Vector2Int, GameObject>();
|
||
base.OnEnable();
|
||
}
|
||
|
||
protected override void OnDisable()
|
||
{
|
||
currWindow = null;
|
||
DestroyNpcPrefab();
|
||
_npcObjectDic = null;
|
||
_selfNpcObjectDic = null;
|
||
base.OnDisable();
|
||
}
|
||
|
||
protected override void OnDestroy()
|
||
{
|
||
base.OnDestroy();
|
||
if (_curMap != null)
|
||
_curMap.TerrainGridSystem.OnMouseClickOnGrid -= OnCellClick;
|
||
SaveCurrentLevel();
|
||
SceneView.duringSceneGui -= OnSceneGUI;
|
||
}
|
||
|
||
protected override void OnGUI()
|
||
{
|
||
base.OnGUI();
|
||
if (_levelEditor == null || _mapManager == null || _mapManager.Map != _curMap ||
|
||
_levelEditor.LevelData != currentLevelData)
|
||
{
|
||
Debug.LogError("数据已变更,请重新打开关卡编辑器");
|
||
Close();
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Draw
|
||
|
||
private void OnSceneGUI(SceneView sceneView)
|
||
{
|
||
DrawPatrolPath();
|
||
DrawNpcID();
|
||
}
|
||
|
||
private void DrawPatrolPath()
|
||
{
|
||
if (!isEditingPatrolInfo) return;
|
||
|
||
Vector3 lastWorldPos = Vector3.zero;
|
||
for (int i = 0; i < _currEditingNpcInfo.patrolInfos.Count; i++)
|
||
{
|
||
var gridPos = _currEditingNpcInfo.patrolInfos[i].patrolPoint;
|
||
var worldPos = _curMap.BlockPosition2WorldPosition(gridPos);
|
||
Handles.color = Color.blue;
|
||
Handles.DrawSolidDisc(worldPos, Vector3.up, 0.4f);
|
||
if (i > 0)
|
||
{
|
||
Handles.color = Color.yellow;
|
||
EditorUtil.DrawArrowInScene(lastWorldPos, worldPos, 0.5f);
|
||
}
|
||
|
||
//Handles.color = Color.black;
|
||
Handles.Label(worldPos, i.ToString());
|
||
lastWorldPos = worldPos;
|
||
}
|
||
}
|
||
|
||
private GUIStyle labelStyle;
|
||
|
||
private GUIStyle labelStyleSelf;
|
||
|
||
private void DrawNpcID()
|
||
{
|
||
if (!IsShowNpcID) return;
|
||
|
||
labelStyle ??= new GUIStyle
|
||
{
|
||
fontSize = 38,
|
||
fontStyle = FontStyle.Bold,
|
||
normal =
|
||
{
|
||
textColor = Color.red
|
||
}
|
||
};
|
||
|
||
labelStyleSelf ??= new GUIStyle
|
||
{
|
||
fontSize = 38,
|
||
fontStyle = FontStyle.Bold,
|
||
normal =
|
||
{
|
||
textColor = Color.green
|
||
}
|
||
};
|
||
|
||
foreach (var npc in _showNpcInfos)
|
||
{
|
||
if (_npcObjectDic.TryGetValue(npc.npcInfo.position, out var npcObj))
|
||
{
|
||
Handles.Label(npcObj.transform.position, npc.id.ToString(), labelStyle);
|
||
}
|
||
else if (_selfNpcObjectDic.TryGetValue(npc.npcInfo.position, out var selfNpcObj))
|
||
{
|
||
Handles.Label(selfNpcObj.transform.position, npc.id.ToString(), labelStyleSelf);
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
} |