关卡编辑器修改

main
zhangaotian 2025-12-22 15:33:08 +08:00
parent a0857e5ea5
commit 953be02588
3 changed files with 160 additions and 134 deletions

View File

@ -46,9 +46,8 @@ public partial class LevelEditorWindow
/// <summary>
/// 显示全部地区
/// </summary>
[LabelText("全部")]
All = CaptureRegion | RetreatRegion | EnemyRetreatRegion | FlagStratRegion |
FlagEndRegion | MinesRegion | DefenseRegion | BlockRegion,
[LabelText("全部")] All = CaptureRegion | RetreatRegion | EnemyRetreatRegion | FlagStratRegion |
FlagEndRegion | MinesRegion | DefenseRegion | BlockRegion,
}
#endregion
@ -1367,6 +1366,16 @@ public partial class LevelEditorWindow
#region NPC编辑器类
/// <summary>
/// 该关卡的 MonsterID
/// </summary>
private readonly Dictionary<string, int> _allMonsterIDs = new Dictionary<string, int>();
/// <summary>
/// 筛选列表 MonsterID
/// </summary>
private readonly List<string> _selectMonsterIDs = new List<string>();
[Serializable]
public class NpcEditorInfo
{
@ -1376,12 +1385,14 @@ public partial class LevelEditorWindow
[ReadOnly] [LabelText("序号ID")] public int id;
[FoldoutGroup("详细信息")] [LabelText("MonsterID")] [ValueDropdown("GetMonsterIDs")] [OnValueChanged("ChangeNpcID")]
public int monsterId;
public string monsterIdStr;
[HideInInspector] public int monsterId;
[FoldoutGroup("详细信息")] [LabelText("等级")] [ReadOnly]
public int level;
private IEnumerable<int> GetMonsterIDs()
private IEnumerable<string> GetMonsterIDs()
{
return npcTroopId switch
{
@ -1394,6 +1405,13 @@ public partial class LevelEditorWindow
private void ChangeNpcID()
{
if (currWindow._allMonsterIDs.TryGetValue(monsterIdStr, out var id))
{
DebugUtil.LogError($"更改错误,没有该怪物:{monsterIdStr}");
return;
}
monsterId = id;
switch (npcTroopId)
{
case ETroopsId.Neutral: // 中立
@ -1438,29 +1456,24 @@ public partial class LevelEditorWindow
[FoldoutGroup("详细信息")]
[LabelText("编组")]
[ShowInInspector]
[OnValueChanged("OnGroupsChanged", true)]
private List<int> GroupsForInspector
{
get => npcInfo.groups ?? (npcInfo.groups = new List<int>(4));
set => npcInfo.groups = value ?? new List<int>(4);
}
private void OnGroupsChanged()
{
currWindow?.RefreshEnemyNpcGroups();
}
[FoldoutGroup("详细信息")] [HideLabel] public NPCInfo npcInfo;
[FoldoutGroup("详细信息")] [LabelText("AI预设")] [ReadOnly]
public string aiType;
public NpcEditorInfo(NPCInfo npcInfo, int index, int level, int aiType, int npcTroopId)
public NpcEditorInfo(NPCInfo npcInfo, int index, int level, int aiType, int npcTroopId, string name)
{
this.npcInfo = npcInfo;
this.level = level;
this.aiType = GetAITypeData(aiType);
monsterId = npcInfo.id;
monsterIdStr = $"{monsterId} - {name}";
id = index;
this.npcTroopId = npcTroopId;
npcToward = this.npcInfo.npcToward;

View File

@ -9,6 +9,7 @@ using Gameplay;
using Gameplay.Character;
using Gameplay.Utils;
using System.Collections.Generic;
using System.IO;
using static Gameplay.Level.LevelData;
public partial class LevelEditorWindow
@ -335,7 +336,14 @@ public partial class LevelEditorWindow
}
else
{
RemoveEnemyNpc(clickPosition);
if (Event.current != null && (Event.current.control || Event.current.command))
{
RemoveEnemyNpc(clickPosition);
}
else
{
Debug.LogWarning("删除NPC需要按住Ctrl键");
}
}
}
@ -359,18 +367,21 @@ public partial class LevelEditorWindow
var level = 0;
var aiType = 0;
var monsterName = "";
var monsterConfigDic = MonsterCfg.DataMap;
if (monsterConfigDic.TryGetValue(curEnemyMonsterID, out var monster))
{
level = monster.MonsterLevel;
aiType = monster.AIType;
monsterName = monster.NameRead;
}
else
{
DebugUtil.LogError("获取怪物[{0}]配置数据错误", curEnemyMonsterID);
}
var npcEditor = new NpcEditorInfo(npcInfo, currentEnemyNpcInfo.Count + 1, level, aiType, ETroopsId.Enemy);
var npcEditor = new NpcEditorInfo(npcInfo, currentEnemyNpcInfo.Count + 1, level, aiType, ETroopsId.Enemy,
monsterName);
currentEnemyNpcInfo.Add(npcEditor);
var pos = _curMap.BlockPosition2WorldPosition(npcInfo.position);
@ -429,7 +440,7 @@ public partial class LevelEditorWindow
#endregion
#region 已NPC编辑方法
#region 已NPC编辑方法
private void EditSelfNpc(Vector2Int clickPosition, bool isAdd)
{
@ -439,7 +450,14 @@ public partial class LevelEditorWindow
}
else
{
RemoveSelfNpc(clickPosition);
if (Event.current != null && (Event.current.control || Event.current.command))
{
RemoveSelfNpc(clickPosition);
}
else
{
Debug.LogWarning("删除NPC需要按住Ctrl键");
}
}
}
@ -468,11 +486,13 @@ public partial class LevelEditorWindow
var level = 0;
var aiType = 0;
var monsterName = "";
var monsterConfigDic = MonsterCfg.DataMap;
if (monsterConfigDic.TryGetValue(curSelfNpcID, out var monster))
{
level = monster.MonsterLevel;
aiType = monster.AIType;
monsterName = monster.NameRead;
}
else
{
@ -480,7 +500,7 @@ public partial class LevelEditorWindow
}
currentSelfNpcInfo.Add(new NpcEditorInfo(npcInfo, SelfID + currentSelfNpcInfo.Count + 1, level, aiType,
ETroopsId.Self));
ETroopsId.Self, monsterName));
var pos = _curMap.BlockPosition2WorldPosition(npcInfo.position);
var obj = Instantiate(selfNpcObject, pos, selfNpcObject.transform.rotation);
if (selfObjRoot != null)
@ -518,7 +538,16 @@ public partial class LevelEditorWindow
if (isAdd)
AddMidNpc(clickPosition);
else
RemoveMidNpc(clickPosition);
{
if (Event.current != null && (Event.current.control || Event.current.command))
{
RemoveMidNpc(clickPosition);
}
else
{
Debug.LogWarning("删除NPC需要按住Ctrl键");
}
}
}
private void AddMidNpc(Vector2Int clickPosition)
@ -542,18 +571,21 @@ public partial class LevelEditorWindow
var level = 0;
var aiType = 0;
var monsterName = "";
var monsterConfigDic = MonsterCfg.DataMap;
if (monsterConfigDic.TryGetValue(curMidMonsterID, out var monster))
{
level = monster.MonsterLevel;
aiType = monster.AIType;
monsterName = monster.NameRead;
}
else
{
DebugUtil.LogError("获取怪物[{0}]配置数据错误", curMidMonsterID);
}
var npcEditor = new NpcEditorInfo(npcInfo, currentMidNpcInfo.Count + 1, level, aiType, ETroopsId.Neutral);
var npcEditor = new NpcEditorInfo(npcInfo, currentMidNpcInfo.Count + 1, level, aiType, ETroopsId.Neutral,
monsterName);
currentMidNpcInfo.Add(npcEditor);
var pos = _curMap.BlockPosition2WorldPosition(npcInfo.position);
@ -801,6 +833,9 @@ public partial class LevelEditorWindow
// 加载关卡广播
listAIBroadcastData = currentLevelData.listAIBroadcastData.Select(a => new AIBroadcastDataEditor(a)).ToList();
// 加载当前关卡的Monster配置
LoadAllNpcConfig();
// 加载敌方NPC到场景中
LoadEnemyNpcInfo();
@ -814,6 +849,20 @@ public partial class LevelEditorWindow
LoadBlockSphereInfo();
}
private void LoadAllNpcConfig()
{
var monsterConfigDic = MonsterCfg.DataList;
var levelName = Path.GetFileNameWithoutExtension(_levelEditor.LevelDataJson.name);
_allMonsterIDs.Clear();
foreach (var dataMonster in monsterConfigDic)
{
if (!dataMonster.LevelJsonName.EndsWith(levelName))
continue;
var monsterName = $"{dataMonster.MonsterID} - {dataMonster.NameRead}";
_allMonsterIDs.Add(monsterName, dataMonster.MonsterID);
}
}
private void LoadEnemyNpcInfo()
{
var monsterConfigDic = MonsterCfg.DataMap;
@ -828,7 +877,7 @@ public partial class LevelEditorWindow
}
var npcEditor = new NpcEditorInfo(npcInfo, index, monsterClassData.MonsterLevel, monsterClassData.AIType,
ETroopsId.Enemy);
ETroopsId.Enemy, monsterClassData.NameRead);
currentEnemyNpcInfo.Add(npcEditor);
var npcObj = LoadEnemyNpcPrefab(npcInfo.id);
@ -876,7 +925,7 @@ public partial class LevelEditorWindow
}
var npcEditor = new NpcEditorInfo(npcInfo, index, monsterClassData.MonsterLevel, monsterClassData.AIType,
ETroopsId.Neutral);
ETroopsId.Neutral, monsterClassData.NameRead);
currentMidNpcInfo.Add(npcEditor);
var npcObj = LoadMidNpcPrefab(npcInfo.id);
@ -920,7 +969,7 @@ public partial class LevelEditorWindow
}
var npcEditor = new NpcEditorInfo(selfNpcInfo, index, monsterClassData.MonsterLevel,
monsterClassData.AIType, ETroopsId.Self);
monsterClassData.AIType, ETroopsId.Self, monsterClassData.NameRead);
currentSelfNpcInfo.Add(npcEditor);
var npcObj = LoadSelfNpcPrefab(selfNpcInfo.id);
if (npcObj != null)
@ -975,13 +1024,14 @@ public partial class LevelEditorWindow
{
foreach (var taskInfoEditor in taskInfos)
{
if(taskInfoEditor.isErrorTaskID){
if (taskInfoEditor.isErrorTaskID)
{
DebugUtil.LogError($"有错误任务ID {taskInfoEditor.taskID}, 无法保存关卡");
CustomPopUpWindow.PopUp($"有错误任务ID {taskInfoEditor.taskID}, 无法保存关卡");
return false;
}
}
/*if (!IsTaskInvalid(successTaskID))
{
DebugUtil.LogError("胜利条件错误, 无法保存关卡");

View File

@ -224,10 +224,7 @@ public partial class LevelEditorWindow : OdinEditorWindow
{ ShowRegionType.BlockRegion, Color.blue },
};
[FoldoutGroup("地区相关")]
[LabelText("显示地区颜色")]
[EnumToggleButtons]
[OnValueChanged(nameof(OnShowRegionTypeChanged))]
[FoldoutGroup("地区相关")] [LabelText("显示地区颜色")] [EnumToggleButtons] [OnValueChanged(nameof(OnShowRegionTypeChanged))]
public ShowRegionType showRegionType;
/// <summary>
@ -708,7 +705,9 @@ public partial class LevelEditorWindow : OdinEditorWindow
[OnValueChanged("EnemyMonsterIDChanged")]
[ValueDropdown("GetEnemyMonsterIDs")]
[ShowIf("isEditingEnemyNpc")]
public int curEnemyMonsterID;
public string curEnemyMonsterIDStr;
private int curEnemyMonsterID;
[BoxGroup("敌方Npc")]
[PreviewField(150, ObjectFieldAlignment.Center), Indent, ReadOnly]
@ -720,47 +719,25 @@ public partial class LevelEditorWindow : OdinEditorWindow
/// </summary>
[HideInInspector] public List<NpcEditorInfo> currentEnemyNpcInfo = null;
/// <summary>
/// 该关卡的敌方NPCID
/// </summary>
[HideInInspector] public List<int> enemyMonsterIDs;
private IEnumerable<int> GetEnemyMonsterIDs()
private IEnumerable<string> GetEnemyMonsterIDs()
{
enemyMonsterIDs ??= new List<int>();
enemyMonsterIDs.Clear();
if (null == selectEnemyMonsterId)
return enemyMonsterIDs;
foreach (var monster in MonsterCfg.DataMap)
if (string.IsNullOrEmpty(selectEnemyMonsterId))
return _allMonsterIDs.Keys;
_selectMonsterIDs.Clear();
foreach (var enemyMonster in _allMonsterIDs.Keys)
{
string strID = monster.Key.ToString();
if (!strID.StartsWith(selectEnemyMonsterId))
continue;
switch (monster.Value.NpcType)
{
case EMonsterType.EnemyCharacter:
case EMonsterType.Vehicle:
case EMonsterType.FightBuild:
{
enemyMonsterIDs.Add(monster.Key);
}
break;
case EMonsterType.SelfCharacter:
break;
default:
DebugUtil.LogError($"未处理类型:{monster.Value.NpcType}");
break;
}
if (enemyMonster.Contains(selectEnemyMonsterId))
_selectMonsterIDs.Add(enemyMonster);
}
return enemyMonsterIDs;
return _selectMonsterIDs;
}
private void EnemyMonsterIDChanged()
{
if (!_allMonsterIDs.TryGetValue(curEnemyMonsterIDStr, out var id))
return;
curEnemyMonsterID = id;
var obj = LoadEnemyNpcPrefab(curEnemyMonsterID);
if (obj != null)
enemyNpcObject = obj;
@ -768,10 +745,16 @@ public partial class LevelEditorWindow : OdinEditorWindow
private void OnIsEditingEnemyNpcChanged()
{
if (isEditingEnemyNpc && isEditingSelfNpc && isEditingMidNpc)
if (isEditingEnemyNpc)
{
isEditingSelfNpc = false;
isEditingMidNpc = false;
return;
}
foreach (var npcEditorInfo in currentEnemyNpcInfo)
{
npcEditorInfo.isChangePos = false;
}
}
@ -794,6 +777,14 @@ public partial class LevelEditorWindow : OdinEditorWindow
}
}
[BoxGroup("敌方Npc")]
[Button("刷新编组"), Indent]
[ShowIf("isEditingEnemyNpc")]
public void OnGroupsChanged()
{
RefreshEnemyNpcGroups();
}
/// <summary>
/// 敌方 NPC 的分组展示数据
/// </summary>
@ -832,7 +823,9 @@ public partial class LevelEditorWindow : OdinEditorWindow
[OnValueChanged("SelfNpcIDChanged")]
[ValueDropdown("GetSelfNpcIDs")]
[ShowIf("isEditingSelfNpc")]
public int curSelfNpcID;
public string curSelfNpcIDStr;
private int curSelfNpcID;
[BoxGroup("己方Npc")]
[PreviewField(150, ObjectFieldAlignment.Center), Indent, ReadOnly]
@ -844,47 +837,25 @@ public partial class LevelEditorWindow : OdinEditorWindow
[ListDrawerSettings(HideAddButton = true, HideRemoveButton = true)]
public List<NpcEditorInfo> currentSelfNpcInfo = null;
/// <summary>
/// 该关卡的己方NPCID
/// </summary>
[HideInInspector] public List<int> selfMonsterIDs;
private IEnumerable<int> GetSelfNpcIDs()
private IEnumerable<string> GetSelfNpcIDs()
{
selfMonsterIDs ??= new List<int>();
selfMonsterIDs.Clear();
if (null == selectSelfMonsterId)
return selfMonsterIDs;
foreach (var monster in MonsterCfg.DataMap)
if (string.IsNullOrEmpty(selectSelfMonsterId))
return _allMonsterIDs.Keys;
_selectMonsterIDs.Clear();
foreach (var enemyMonster in _allMonsterIDs.Keys)
{
string strID = monster.Key.ToString();
if (!strID.StartsWith(selectSelfMonsterId))
continue;
switch (monster.Value.NpcType)
{
case EMonsterType.SelfCharacter:
case EMonsterType.Vehicle:
case EMonsterType.FightBuild:
{
selfMonsterIDs.Add(monster.Key);
}
break;
case EMonsterType.EnemyCharacter:
break;
default:
DebugUtil.LogError($"未处理类型:{monster.Value.NpcType}");
break;
}
if (enemyMonster.Contains(selectSelfMonsterId))
_selectMonsterIDs.Add(enemyMonster);
}
return selfMonsterIDs;
return _selectMonsterIDs;
}
private void SelfNpcIDChanged()
{
if (!_allMonsterIDs.TryGetValue(curSelfNpcIDStr, out var id))
return;
curSelfNpcID = id;
var obj = LoadSelfNpcPrefab(curSelfNpcID);
if (obj != null)
selfNpcObject = obj;
@ -892,10 +863,16 @@ public partial class LevelEditorWindow : OdinEditorWindow
private void OnIsEditingSelfNpcChanged()
{
if (isEditingEnemyNpc && isEditingSelfNpc && isEditingMidNpc)
if (isEditingSelfNpc)
{
isEditingEnemyNpc = false;
isEditingMidNpc = false;
return;
}
foreach (var npcEditorInfo in currentSelfNpcInfo)
{
npcEditorInfo.isChangePos = false;
}
}
@ -930,7 +907,7 @@ public partial class LevelEditorWindow : OdinEditorWindow
private Dictionary<int, Dictionary<NpcEditorInfo, GameObject>> _midNpcObjectWaveDic;
[BoxGroup("中立Npc")]
[LabelText("编辑NPC"), Indent]
[LabelText("编辑中立NPC"), Indent]
[LabelWidth(100)]
[SerializeField]
[OnValueChanged("OnIsEditingMidNpcChanged")]
@ -948,7 +925,9 @@ public partial class LevelEditorWindow : OdinEditorWindow
[OnValueChanged("MidMonsterIDChanged")]
[ValueDropdown("GetMidMonsterIDs")]
[ShowIf("isEditingMidNpc")]
public int curMidMonsterID;
public string curMidMonsterIDStr;
private int curMidMonsterID;
[BoxGroup("中立Npc")]
[PreviewField(150, ObjectFieldAlignment.Center), Indent, ReadOnly]
@ -960,47 +939,25 @@ public partial class LevelEditorWindow : OdinEditorWindow
[ListDrawerSettings(HideAddButton = true, HideRemoveButton = true, ShowFoldout = true)]
public List<NpcEditorInfo> currentMidNpcInfo = null;
/// <summary>
/// 该关卡的中立NPCID
/// </summary>
[HideInInspector] public List<int> midMonsterIDs;
private IEnumerable<int> GetMidMonsterIDs()
private IEnumerable<string> GetMidMonsterIDs()
{
midMonsterIDs ??= new List<int>();
midMonsterIDs.Clear();
if (null == selectMidMonsterId)
return midMonsterIDs;
foreach (var monster in MonsterCfg.DataMap)
if (string.IsNullOrEmpty(selectMidMonsterId))
return _allMonsterIDs.Keys;
_selectMonsterIDs.Clear();
foreach (var enemyMonster in _allMonsterIDs.Keys)
{
string strID = monster.Key.ToString();
if (!strID.StartsWith(selectMidMonsterId))
continue;
switch (monster.Value.NpcType)
{
case EMonsterType.Vehicle:
case EMonsterType.FightBuild:
{
midMonsterIDs.Add(monster.Key);
}
break;
case EMonsterType.EnemyCharacter:
case EMonsterType.SelfCharacter:
break;
default:
DebugUtil.LogError($"未处理类型:{monster.Value.NpcType}");
break;
}
if (enemyMonster.Contains(selectMidMonsterId))
_selectMonsterIDs.Add(enemyMonster);
}
return midMonsterIDs;
return _selectMonsterIDs;
}
private void MidMonsterIDChanged()
{
if (!_allMonsterIDs.TryGetValue(curMidMonsterIDStr, out var id))
return;
curMidMonsterID = id;
var obj = LoadMidNpcPrefab(curMidMonsterID);
if (obj != null)
midNpcObject = obj;
@ -1008,10 +965,16 @@ public partial class LevelEditorWindow : OdinEditorWindow
private void OnIsEditingMidNpcChanged()
{
if (isEditingEnemyNpc && isEditingSelfNpc && isEditingMidNpc)
if (isEditingMidNpc)
{
isEditingEnemyNpc = false;
isEditingSelfNpc = false;
return;
}
foreach (var npcEditorInfo in currentMidNpcInfo)
{
npcEditorInfo.isChangePos = false;
}
}