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

414 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using cfg.LevelCfg;
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;
using TGS;
using UnityEditor;
using UnityEngine;
using UnityEngine.Serialization;
using Constants = Framework.Constants;
using ObjectFieldAlignment = Sirenix.OdinInspector.ObjectFieldAlignment;
public class LevelEditorWindow : OdinEditorWindow
{
private static readonly Color regionColor = MapUtils.GetRGBAColor("FF960072");
[Serializable]
public class LevelPresentation
{
[ReadOnly] public string levelId = "temp";
[Button("编辑"), VerticalGroup("")]
public void Open()
{
if (thisWindow.currentLevelData != null && ValueValidator.IsIdValid(thisWindow.currentLevelData.id))
{
CustomPopUpWindow.PopUp($"是否保存关卡数据:{thisWindow.currentLevelData.id}",
() =>
{
thisWindow.SaveCurrentLevel();
thisWindow.LoadLevel(levelId);
currentLevelPresentation = this;
},
() =>
{
thisWindow.LoadLevel(levelId);
currentLevelPresentation = this;
}
);
}
else
{
thisWindow.LoadLevel(levelId);
currentLevelPresentation = this;
}
}
}
[Serializable]
public class RegionData
{
[LabelText("出战区")]
[OnValueChanged("OnRegionChanged")]
public int preparingRegionId;
[LabelText("出战区朝向")]
public LevelData.CharacterToward preparingRegionToward;
[LabelText("撤退区")]
public int fallbackRegionId;
[LabelText("敌方撤退区")]
public int enemyFallbackRegionId;
private void OnRegionChanged()
{
var regionslist = thisWindow._curMap.MapData.GetAllRegions();
for(int i = 0; i < regionslist.Count; i++)
{
thisWindow._curMap.SetRegionColor(i, false, regionColor);
}
thisWindow._curMap.SetRegionColor(preparingRegionId, true, regionColor);
}
}
private static LevelPresentation currentLevelPresentation;
private Dictionary<Vector2Int, GameObject> _npcDic;
private Map _curMap;
private static LevelEditorWindow thisWindow;
[TitleGroup("关卡编辑器")]
[HorizontalGroup("关卡编辑器/Split", Width = 0.4f)]
[TableList(ShowIndexLabels = true, AlwaysExpanded = true, DrawScrollView = true, ScrollViewHeight = 500),
LabelText("所有关卡")]
[OnValueChanged("OnLevelListChanged")]
public List<LevelPresentation> LevelList = null;
[VerticalGroup("关卡编辑器/Split/Right")]
[LabelText("关卡名称"), Indent]
public string levelName;
[VerticalGroup("关卡编辑器/Split/Right")]
[TextArea, LabelText("关卡描述"), Indent]
public string levelDesc;
[VerticalGroup("关卡编辑器/Split/Right")]
[LabelText("当前关卡数据"),Indent]
[OnValueChanged("OnCurrentLevelDataChanged")]
public LevelData currentLevelData = null;
[VerticalGroup("关卡编辑器/Split/Right")]
[LabelText("当前地区数据"),Indent]
[OnValueChanged("OnCurrentLevelDataChanged")]
public RegionData curRegionData = null;
[VerticalGroup("关卡编辑器/Split/Right")]
[LabelText("添加NPC")]
[LabelWidth(100)]
[SerializeField]
public bool canAddNpc;
[VerticalGroup("关卡编辑器/Split/Right")]
[PreviewField(150,ObjectFieldAlignment.Center)]
[AssetList(Path = (Constants.LEVEL_NPC_PATH_WITHOUT_ASSET))]
[ShowIf("canAddNpc")]
[LabelText("选择NPC")]
public GameObject npcObject;
[VerticalGroup("关卡编辑器/Split/Right")] [LabelText("当前NPC数据")]
public List<LevelData.NPCInfo> CurrentNpcInfo = null;
[VerticalGroup("关卡编辑器/Split/Right")]
[Indent]
[EnableIf("@this.mapPrefab != null")]
[Button("绑定地图")]
private async void BindMap()
{
currentLevelData.mapName = mapPrefab.name;
EditorMap.Instance.Current = await MapEditorUtils.LoadMap(currentLevelData.mapName);
_curMap = EditorMap.Instance.Current;
}
[VerticalGroup("关卡编辑器/Split/Right")]
[Indent]
[AssetList(Path = (Constants.MAP_ASSET_PATH_WITHOUT_ASSET))]
[PreviewField(200, ObjectFieldAlignment.Center)]
public GameObject mapPrefab = null;
[VerticalGroup("关卡编辑器/Split/Right")]
[Indent]
[Button("保存当前关卡")]
private void SaveCurrentLevel()
{
CheckCorrectLevel();
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;
//NPC列表
currentLevelData.npcInfos = CurrentNpcInfo;
JsonHelper.SaveJson(configFilePath, currentLevelData);
UpdateLevelList(currentLevelData);
CustomPopUpWindow.PopUp($"保存关卡数据成功:{configFilePath}");
}
[MenuItem("Tools/LevelEditor")]
private static void OpenWindow()
{
MapEditorSettings.Init();
thisWindow = GetWindow<LevelEditorWindow>();
thisWindow.position = GUIHelper.GetEditorWindowRect().AlignCenter(800, 600);
thisWindow.currentLevelData = null;
thisWindow.LoadLevelList();
}
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)
{
return;
}
var regionList = _curMap.MapData.GetAllRegions();
var errorMessage = string.Empty;
if (!regionList.ContainsKey(currentLevelData.preparingRegionId))
{
errorMessage += string.Format(preparingRegionErrorMessage, currentLevelData.mapName,
currentLevelData.preparingRegionId);
currentLevelData.preparingRegionId = 0;
}
if (!regionList.ContainsKey(currentLevelData.fallbackRegionId))
{
errorMessage += string.Format(fallbackRegionErrorMessage, currentLevelData.mapName,
currentLevelData.fallbackRegionId);
currentLevelData.fallbackRegionId = 0;
}
if (!regionList.ContainsKey(currentLevelData.enemyFallbackRegionId))
{
errorMessage += string.Format(enemyFallbackRegionErrorMessage, currentLevelData.mapName,
currentLevelData.enemyFallbackRegionId);
currentLevelData.enemyFallbackRegionId = 0;
}
if (!string.IsNullOrEmpty(errorMessage))
{
CustomPopUpWindow.PopUp(errorMessage + fixedMessage);
}
}
protected override void OnEnable()
{
TerrainTypeConfig.Load();
_npcDic = new Dictionary<Vector2Int, GameObject>();
base.OnEnable();
}
protected override void OnDisable()
{
thisWindow = null;
MapEditorUtils.UnLoadMap(EditorMap.Instance);
DestroyImmediate(GameObject.Find("Main Camera"));
DestroyNpcPrefab();
_npcDic = null;
base.OnDisable();
}
private void LoadLevelList()
{
banSaveLevelList = true;
var configFilePath = string.Format(Constants.LEVEL_LIST_PATH);
LevelList = JsonHelper.LoadJson<List<LevelPresentation>>(configFilePath);
if (LevelList == null)
{
LevelList = new List<LevelPresentation>(4);
}
banSaveLevelList = false;
}
private bool banSaveLevelList = false;
private void OnLevelListChanged()
{
if (!banSaveLevelList)
{
banSaveLevelList = true;
foreach (var levelPresentation in LevelList)
{
if (!ValueValidator.IsIdValid(levelPresentation.levelId))
{
Debug.Log($"{GetType()}.New Level declared : {levelPresentation.levelId}");
}
}
SaveLevelList();
Debug.Log($"{GetType()}.Save Level List");
banSaveLevelList = false;
}
}
private void OnCurrentLevelDataChanged()
{
Debug.Log($"{GetType()}.OnCurrentLevelDataChanged");
}
private void SaveLevelList()
{
var configFilePath = string.Format(Constants.LEVEL_LIST_PATH);
JsonHelper.SaveJson(configFilePath, LevelList);
}
private const string descKey = "LevelDesc";
private const string nameKey = "LevelName";
private async void LoadLevel(string id)
{
DestroyNpcPrefab();
_npcDic.Clear();
var configFilePath = string.Format(Constants.LEVEL_CONFIG_FORMAT_PATH, id);
currentLevelData = JsonHelper.LoadJson<LevelData>(configFilePath);
//加载地区信息
curRegionData = new RegionData();
curRegionData.preparingRegionId = currentLevelData.preparingRegionId;
curRegionData.fallbackRegionId = currentLevelData.fallbackRegionId;
curRegionData.enemyFallbackRegionId = currentLevelData.enemyFallbackRegionId;
curRegionData.preparingRegionToward = currentLevelData.preparingRegionToward;
if (!string.IsNullOrEmpty(currentLevelData.mapName))
{
EditorMap.Instance.Current = await MapEditorUtils.LoadMap(currentLevelData.mapName);
_curMap = EditorMap.Instance.Current;
// 显示在关卡编辑器中的地图资产
mapPrefab = await MapUtils.LoadMapAsset(currentLevelData.mapName);
_curMap.TerrainGridSystem.OnMouseClickOnGrid += OnCellClick;
}
else
{
MapEditorUtils.UnLoadMap(EditorMap.Instance);
mapPrefab = null;
}
//加载NPC到场景中
CurrentNpcInfo = new List<LevelData.NPCInfo>();
foreach (var npcInfo in currentLevelData.npcInfos)
{
CurrentNpcInfo.Add(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)
{
if (!canAddNpc) return;
var clickPosition = _curMap.TGSCellIndex2BlockPosition(cellindex);
int leftButton = 0;
int rightButton = 1;
if (canAddNpc && buttonindex == leftButton)
{
if (npcObject == null)
{
DebugUtil.LogError("请选择正确的NPC");
return;
}
if (_npcDic.ContainsKey(clickPosition))
{
DebugUtil.LogError("该位置已有NPC存在请重新选");
return;
}
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(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);
}
else if(canAddNpc && buttonindex == rightButton)
{
if (_npcDic.TryGetValue(clickPosition,out var npcObj))
{
var npc = CurrentNpcInfo.FirstOrDefault(npc => npc.position == clickPosition);
if (npc != null)
{
CurrentNpcInfo.Remove(npc);
DebugUtil.Log("从[ {0} ]位置上移除了[{1}]NPC", clickPosition, npcObj.name);
DestroyImmediate(npcObj);
_npcDic.Remove(clickPosition);
}
}
}
}
private void DestroyNpcPrefab()
{
foreach (var npc in _npcDic)
{
DestroyImmediate(npc.Value);
}
}
private void UpdateLevelList(LevelData levelData)
{
if (currentLevelPresentation != null)
{
currentLevelPresentation.levelId = levelData.id;
SaveLevelList();
}
}
}