NLDClient-yudde/ProjectNLD/Assets/Editor/LevelEditor/LevelEditorWindow.cs

444 lines
14 KiB
C#
Raw Normal View History

2023-10-19 15:00:19 +08:00
using cfg.LevelCfg;
2023-08-22 19:08:45 +08:00
using Framework;
using Gameplay;
using Gameplay.Level;
using Sirenix.OdinInspector;
using Sirenix.OdinInspector.Editor;
using Sirenix.Utilities;
using Sirenix.Utilities.Editor;
using System;
using System.Collections.Generic;
using System.Linq;
2024-01-15 12:47:59 +08:00
using Gameplay.Utils;
using TGS;
2023-08-22 19:08:45 +08:00
using UnityEditor;
using UnityEngine;
using UnityEngine.Serialization;
using Constants = Framework.Constants;
2023-08-22 19:08:45 +08:00
using ObjectFieldAlignment = Sirenix.OdinInspector.ObjectFieldAlignment;
2023-11-21 15:04:56 +08:00
//todo 序列化bug
2023-08-22 19:08:45 +08:00
public class LevelEditorWindow : OdinEditorWindow
{
private static readonly Color regionColor = MapUtils.GetRGBAColor("FF960072");
2023-08-22 19:08:45 +08:00
[Serializable]
public class RegionData
{
[LabelText("出战区")]
[OnValueChanged("OnRegionChanged")]
public int preparingRegionId;
[LabelText("出战区朝向")]
public LevelData.CharacterToward preparingRegionToward;
[LabelText("撤退区")]
public int fallbackRegionId;
[LabelText("敌方撤退区")]
public int enemyFallbackRegionId;
2023-12-26 18:19:05 +08:00
[LabelText("PVP防守区")]
public int pvpDefendRegionId;
[LabelText("PVP防守方朝向")]
public LevelData.CharacterToward pvpDefendToward;
private void OnRegionChanged()
{
2023-12-22 15:26:48 +08:00
var regionslist = currWindow._curMap.MapData.regions;
2023-11-21 15:04:56 +08:00
for (int i = 0; i < regionslist.Count; i++)
{
2023-12-22 15:26:48 +08:00
currWindow._curMap.SetRegionColor(i, false, regionColor);
}
2023-11-21 15:04:56 +08:00
2023-12-22 15:26:48 +08:00
currWindow._curMap.SetRegionColor(preparingRegionId, true, regionColor);
}
}
[Serializable]
public class NPCEditorInfo
{
[HideLabel]
public LevelData.NPCInfo npcInfo;
private bool _isEditing;
public NPCEditorInfo(LevelData.NPCInfo npcInfo)
{
this.npcInfo = npcInfo;
}
[Button("开始编辑巡逻信息")]
[HideIf("_isEditing")]
private void StartEditNPC()
{
LevelEditorWindow.currWindow.StartEditPatrolInfo(npcInfo);
_isEditing = true;
}
[Button("完成编辑巡逻信息")]
[ShowIf("_isEditing")]
private void FinishEditNPC()
{
LevelEditorWindow.currWindow.FinishEditPatrolInfo();
_isEditing = false;
}
}
2023-08-22 19:08:45 +08:00
2023-11-21 15:04:56 +08:00
// private static LevelPresentation currentLevelPresentation;
2023-12-18 19:42:46 +08:00
private MapManager _mapManager;
2023-12-22 15:26:48 +08:00
private Dictionary<Vector2Int, GameObject> _npcDic;
2023-08-22 19:08:45 +08:00
private Map _curMap;
2023-10-19 15:00:19 +08:00
2023-12-22 15:26:48 +08:00
public static LevelEditorWindow currWindow;
2023-11-21 15:04:56 +08:00
private LevelEditor _levelEditor;
2023-12-22 15:26:48 +08:00
private LevelData.NPCInfo _currEditingNPCInfo;
public bool IsEditingPatrolInfo => _currEditingNPCInfo != null;
private bool ResponseClickOnCell => isEditingNPC || IsEditingPatrolInfo;
2023-12-26 18:19:05 +08:00
// [LabelText("关卡名称"), Indent]
// public string levelName;
2023-12-22 15:26:48 +08:00
2023-11-21 15:04:56 +08:00
[LabelText("当前关卡数据"), Indent]
2023-08-22 19:08:45 +08:00
[OnValueChanged("OnCurrentLevelDataChanged")]
public LevelData currentLevelData = null;
2023-12-22 15:26:48 +08:00
2023-11-21 15:04:56 +08:00
[LabelText("当前地区数据"), Indent]
[OnValueChanged("OnCurrentLevelDataChanged")]
public RegionData curRegionData = null;
2023-12-22 15:26:48 +08:00
[LabelText("添加NPC")]
[LabelWidth(100)]
2023-11-21 15:04:56 +08:00
[SerializeField]
2023-12-22 15:26:48 +08:00
public bool isEditingNPC;
2023-11-21 15:04:56 +08:00
[PreviewField(150, ObjectFieldAlignment.Center)]
2023-12-22 15:26:48 +08:00
[AssetList(Path = (Constants.LEVEL_NPC_PATH_WITHOUT_ASSET), CustomFilterMethod = "IsNPCPrefabValid")]
[ShowIf("isEditingNPC")]
[LabelText("选择NPC")]
public GameObject npcObject;
2023-12-21 12:48:58 +08:00
private bool IsNPCPrefabValid(GameObject prefab)
{
var monsterClasses = EditorTableManager.instance.tables.MonsterClass;
var prefabPath = AssetDatabase.GetAssetPath(prefab);
foreach (var monsterClassCfg in monsterClasses.DataList)
{
2024-01-15 12:47:59 +08:00
var combinePath = PathEx.GetEnemySrcModelPath(monsterClassCfg.NameId);
if (combinePath == prefabPath)
2023-12-21 12:48:58 +08:00
return true;
}
return false;
}
2023-12-22 15:26:48 +08:00
public List<NPCEditorInfo> CurrentNpcInfo = null;
2023-08-22 19:08:45 +08:00
[Indent]
[Button("保存当前关卡")]
private void SaveCurrentLevel()
{
CheckCorrectLevel();
2023-11-21 15:04:56 +08:00
//var configFilePath = string.Format(Constants.LEVEL_CONFIG_FORMAT_PATH, currentLevelData.id);
currentLevelData.preparingRegionId = curRegionData.preparingRegionId;
currentLevelData.fallbackRegionId = curRegionData.fallbackRegionId;
currentLevelData.enemyFallbackRegionId = curRegionData.enemyFallbackRegionId;
currentLevelData.preparingRegionToward = curRegionData.preparingRegionToward;
2023-12-26 18:19:05 +08:00
currentLevelData.pvpDefendRegionId = curRegionData.pvpDefendRegionId;
currentLevelData.pvpDefendToward = curRegionData.pvpDefendToward;
2023-11-21 15:04:56 +08:00
//NPC列表
2023-12-22 15:26:48 +08:00
currentLevelData.npcInfos = CurrentNpcInfo.Select(editorNPCInfo => editorNPCInfo.npcInfo).ToList();
2023-11-21 15:04:56 +08:00
_levelEditor.SaveLevelData();
}
2023-08-22 19:08:45 +08:00
2023-11-21 15:04:56 +08:00
public static void OpenWindow(LevelEditor levelEditor)
2023-08-22 19:08:45 +08:00
{
MapEditorSettings.Init();
2023-12-22 15:26:48 +08:00
currWindow = GetWindow<LevelEditorWindow>();
currWindow.position = GUIHelper.GetEditorWindowRect().AlignCenter(800, 600);
currWindow.currentLevelData = null;
currWindow._levelEditor = levelEditor;
currWindow.LoadLevel(levelEditor.LevelData);
2023-08-22 19:08:45 +08:00
}
public const string preparingRegionErrorMessage = "关卡出战区设置错误,<{0}>地图没有:<{1}>号地区。\n";
public const string fallbackRegionErrorMessage = "关卡撤退区设置错误,<{0}>地图没有:<{1}>号地区。\n";
public const string enemyFallbackRegionErrorMessage = "关卡敌方撤退区设置错误,<{0}>地图没有:<{1}>号地区。\n";
public const string fixedMessage = "已将错误区域设置为<0>号地区。";
private void CheckCorrectLevel()
{
if (_curMap == null)
2023-08-22 19:08:45 +08:00
{
return;
}
2023-11-20 14:10:18 +08:00
var regionList = _curMap.MapData.regions;
2023-08-22 19:08:45 +08:00
var errorMessage = string.Empty;
2023-11-21 15:04:56 +08:00
if (!_curMap.MapData.IsRegionExist(currentLevelData.preparingRegionId))
2023-08-22 19:08:45 +08:00
{
2023-11-21 15:04:56 +08:00
errorMessage += string.Format(preparingRegionErrorMessage, null,
currentLevelData.preparingRegionId);
2023-08-22 19:08:45 +08:00
currentLevelData.preparingRegionId = 0;
}
2023-11-21 15:04:56 +08:00
if (!_curMap.MapData.IsRegionExist(currentLevelData.fallbackRegionId))
2023-08-22 19:08:45 +08:00
{
2023-11-21 15:04:56 +08:00
errorMessage += string.Format(fallbackRegionErrorMessage, null,
currentLevelData.fallbackRegionId);
2023-08-22 19:08:45 +08:00
currentLevelData.fallbackRegionId = 0;
}
2023-11-21 15:04:56 +08:00
if (!_curMap.MapData.IsRegionExist(currentLevelData.enemyFallbackRegionId))
2023-08-22 19:08:45 +08:00
{
2023-11-21 15:04:56 +08:00
errorMessage += string.Format(enemyFallbackRegionErrorMessage, null,
currentLevelData.enemyFallbackRegionId);
2023-08-22 19:08:45 +08:00
currentLevelData.enemyFallbackRegionId = 0;
}
if (!string.IsNullOrEmpty(errorMessage))
2023-08-22 19:08:45 +08:00
{
CustomPopUpWindow.PopUp(errorMessage + fixedMessage);
}
}
2023-12-20 15:55:42 +08:00
private void Awake()
{
2023-12-22 15:26:48 +08:00
SceneView.duringSceneGui += OnSceneGUI;
2023-12-20 15:55:42 +08:00
}
2023-10-19 15:00:19 +08:00
protected override void OnEnable()
{
2023-11-15 17:59:47 +08:00
TerrainTypeConfig.Load();
_npcDic = new Dictionary<Vector2Int, GameObject>();
2023-10-19 15:00:19 +08:00
base.OnEnable();
}
2023-12-22 15:26:48 +08:00
2023-08-22 19:08:45 +08:00
protected override void OnDisable()
{
2023-12-22 15:26:48 +08:00
currWindow = null;
2023-12-18 19:42:46 +08:00
//MapEditorUtils.UnLoadMap(EditorMap.Instance);
2023-11-21 15:04:56 +08:00
//DestroyImmediate(GameObject.Find("Main Camera"));
DestroyNpcPrefab();
_npcDic = null;
2023-08-22 19:08:45 +08:00
base.OnDisable();
}
2023-11-21 15:04:56 +08:00
protected override void OnDestroy()
2023-08-22 19:08:45 +08:00
{
2023-11-21 15:04:56 +08:00
base.OnDestroy();
2023-12-22 15:26:48 +08:00
if (_curMap != null)
2023-11-21 15:04:56 +08:00
_curMap.TerrainGridSystem.OnMouseClickOnGrid -= OnCellClick;
2023-12-22 15:26:48 +08:00
SaveCurrentLevel();
SceneView.duringSceneGui -= OnSceneGUI;
2023-08-22 19:08:45 +08:00
}
2023-11-21 15:04:56 +08:00
private bool banSaveLevelList = false;
2023-08-22 19:08:45 +08:00
private void OnCurrentLevelDataChanged()
{
Debug.Log($"{GetType()}.OnCurrentLevelDataChanged");
}
2023-10-19 15:00:19 +08:00
private const string descKey = "LevelDesc";
private const string nameKey = "LevelName";
2023-11-21 15:04:56 +08:00
private void LoadLevel(LevelData levelData)
2023-08-22 19:08:45 +08:00
{
DestroyNpcPrefab();
_npcDic.Clear();
2023-11-21 15:04:56 +08:00
currentLevelData = levelData;
//加载地区信息
curRegionData = new RegionData();
curRegionData.preparingRegionId = currentLevelData.preparingRegionId;
curRegionData.fallbackRegionId = currentLevelData.fallbackRegionId;
curRegionData.enemyFallbackRegionId = currentLevelData.enemyFallbackRegionId;
curRegionData.preparingRegionToward = currentLevelData.preparingRegionToward;
2023-12-26 18:19:05 +08:00
curRegionData.pvpDefendRegionId = currentLevelData.pvpDefendRegionId;
curRegionData.pvpDefendToward = currentLevelData.pvpDefendToward;
2023-12-18 19:42:46 +08:00
_mapManager = FindObjectOfType<MapManager>();
_curMap = _mapManager.Map;
2023-11-21 15:04:56 +08:00
_curMap.TerrainGridSystem.OnMouseClickOnGrid += OnCellClick;
//加载NPC到场景中
2023-12-22 15:26:48 +08:00
CurrentNpcInfo = new();
foreach (var npcInfo in currentLevelData.npcInfos)
{
2023-12-22 15:26:48 +08:00
CurrentNpcInfo.Add(new(npcInfo));
string npcId = string.Format("P_E{0}", npcInfo.id.ToString().Substring(1));
var npc = AssetDatabase.LoadAssetAtPath<GameObject>(string.Format(Constants.LEVEL_NPC_PATH, npcId));
var position = _curMap.BlockPosition2WorldPosition(npcInfo.position);
_npcDic.Add(npcInfo.position, Instantiate(npc, position, npc.transform.rotation));
}
}
private void OnCellClick(TerrainGridSystem tgs, int cellindex, int buttonindex)
{
2023-12-22 15:26:48 +08:00
if (!ResponseClickOnCell) return;
2023-11-21 15:04:56 +08:00
var clickPosition = _curMap.TGSCellIndex2BlockPosition(cellindex);
2023-11-21 15:04:56 +08:00
int leftButton = 0;
int rightButton = 1;
2023-12-22 15:26:48 +08:00
if (buttonindex != leftButton && buttonindex != rightButton)
return;
bool opTrue = buttonindex == leftButton;
if (IsEditingPatrolInfo)
{
if (opTrue)
AddPatrolInfo(clickPosition);
else
RemovePatrolInfo(clickPosition);
}
else if (isEditingNPC)
{
2023-12-22 15:26:48 +08:00
if (opTrue)
{
2023-12-22 15:26:48 +08:00
AddNPC(clickPosition);
}
2023-12-22 15:26:48 +08:00
else
{
2023-12-22 15:26:48 +08:00
RemoveNPC(clickPosition);
}
2023-12-22 15:26:48 +08:00
}
}
2023-11-21 15:04:56 +08:00
2023-12-22 15:26:48 +08:00
private void AddNPC(Vector2Int clickPosition)
{
if (npcObject == null)
{
DebugUtil.LogError("请选择正确的NPC!!");
return;
}
2023-11-21 15:04:56 +08:00
2023-12-22 15:26:48 +08:00
if (_npcDic.ContainsKey(clickPosition))
{
DebugUtil.LogError("该位置已有NPC存在,请重新选!!!");
return;
}
2023-12-22 15:26:48 +08:00
LevelData.NPCInfo npcInfo = new LevelData.NPCInfo();
string npcId = npcObject.name.Replace("P_E", "1");
npcInfo.id = int.Parse(npcId);
npcInfo.position = clickPosition;
//默认等级为1
npcInfo.level = 1;
CurrentNpcInfo.Add(new(npcInfo));
var position = _curMap.BlockPosition2WorldPosition(npcInfo.position);
_npcDic.Add(npcInfo.position, Instantiate(npcObject, position, npcObject.transform.rotation));
DebugUtil.Log("添加了[{0}]NPC到[ {1} ]位置上", npcObject.name, npcInfo.position);
}
private void RemoveNPC(Vector2Int clickPosition)
{
if (_npcDic.TryGetValue(clickPosition, out var npcObj))
{
2023-12-22 15:26:48 +08:00
var npc = CurrentNpcInfo.FirstOrDefault(npc => npc.npcInfo.position == clickPosition);
if (npc != null)
{
2023-12-22 15:26:48 +08:00
CurrentNpcInfo.Remove(npc);
DebugUtil.Log("从[ {0} ]位置上移除了[{1}]NPC", clickPosition, npcObj.name);
DestroyImmediate(npcObj);
_npcDic.Remove(clickPosition);
}
}
}
2023-12-22 15:26:48 +08:00
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);
}
public void StartEditPatrolInfo(LevelData.NPCInfo npcInfo)
{
_currEditingNPCInfo = npcInfo;
}
public void FinishEditPatrolInfo()
{
_currEditingNPCInfo = null;
}
private void DestroyNpcPrefab()
{
foreach (var npc in _npcDic)
{
DestroyImmediate(npc.Value);
}
2023-08-22 19:08:45 +08:00
}
2023-12-22 15:26:48 +08:00
protected override void OnGUI()
{
base.OnGUI();
if (_levelEditor == null || _mapManager == null || _mapManager.Map != _curMap ||
_levelEditor.LevelData != currentLevelData)
{
Debug.LogError("数据已变更,请重新打开关卡编辑器");
Close();
}
}
private void OnSceneGUI(SceneView sceneView)
{
DrawPatrolPath();
}
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;
2023-12-26 18:19:05 +08:00
EditorUtil.DrawArrowInScene(lastWorldPos, worldPos, 0.5f);
2023-12-22 15:26:48 +08:00
}
//Handles.color = Color.black;
2023-12-26 18:19:05 +08:00
Handles.Label(worldPos, i.ToString());
2023-12-22 15:26:48 +08:00
lastWorldPos = worldPos;
}
}
2023-08-22 19:08:45 +08:00
}