【关卡编辑器】修改编辑器

main
刘涛 2024-09-05 13:26:43 +08:00
parent b27e704a42
commit 627ff1878b
15 changed files with 1135 additions and 135 deletions

View File

@ -60,15 +60,6 @@ namespace Gameplay.Level
public int id;
[Sirenix.OdinInspector.ReadOnly]
public int level;
/// <summary>
/// npc类型
/// 0 默认敌人 - 索引 MonsterClass
/// 1 载具敌人 - 索引 EnemyVehicleConfig
/// </summary>
[Sirenix.OdinInspector.ReadOnly]
public int npcType;
[Sirenix.OdinInspector.ReadOnly]
public Vector2Int position;
[LabelText("AI类型")]

View File

@ -92,15 +92,16 @@ public static class VehicleDataHelper
public static VehicleConfigData CombineEnemyConfigData(LevelData.NPCInfo npcInfo)
{
var monsterConfig = TableManager.Instance.Tables.Monster.GetOrDefault(npcInfo.id);
var configData = new VehicleConfigData();
var rawConfig = TableManager.Instance.Tables.EnemyVehicleConfig.GetOrDefault(npcInfo.id);
var rawConfig = TableManager.Instance.Tables.EnemyVehicleConfig.GetOrDefault(monsterConfig.MonsterClassID);
if (rawConfig == null)
{
DebugUtil.LogError("EnemyVehicleConfig表中没有id为{0}的配置", npcInfo.id);
return null;
}
configData.Init(rawConfig, npcInfo.level);
return null;
return configData;
}
}

View File

@ -193,7 +193,8 @@ namespace Gameplay.Unit
int troopId)
{
switch (npcInfo.npcType)
var monsterConfig = TableManager.Instance.Tables.Monster.GetOrDefault(npcInfo.id);
switch (monsterConfig.NpcType)
{
case ENpcType.ENEMY_CHARACTER:
return await _PrepareNpcEnemyCharacter(npcInfo, troopId);
@ -201,7 +202,7 @@ namespace Gameplay.Unit
return await _PrepareNpcEnemyVehicle(npcInfo, troopId);
}
DebugUtil.LogError($"未知的npc类型:{npcInfo.npcType}");
DebugUtil.LogError($"未知的npc类型:{monsterConfig.NpcType}");
return null;
}

View File

@ -77,6 +77,8 @@ namespace Gameplay.Vehicle.Impl
_fsm.Add(new VehicleStateDestroy(this));
_fsm.Add(new VehicleStateSkill(this));
_fsm.Add(new VehicleStateStop(this));
_fsm.Add(new VehicleStateWaitRemove(this));
_fsm.Add(new VehicleStateFadeOut(this));
_fsm.ChangeState(EVehicleState.Idle);
}

View File

@ -8,5 +8,7 @@ namespace Gameplay.Vehicle.State
public const int Destroy = 3;
public const int Skill = 4;
public const int Stop = 5;
public const int FadeOut = 6;
public const int WaitRemove = 7;
}
}

View File

@ -62,6 +62,13 @@ namespace Gameplay.Vehicle.State
_destroyEffectData = EffectManager.instance.PlayEffectById(owner.configData.deadEffectId, owner.transform.position, owner.transform.rotation);
_destroyEffectData.autoDestroy = false;
}
var isEnemy = owner.commonData.troopId != ETroopsId.Self;
if (isEnemy)
{
isFinished = true;
nextState = EVehicleState.FadeOut;
}
}
private void _DeadCharacters()

View File

@ -0,0 +1,140 @@
using System.Collections.Generic;
using Gameplay.Character;
using Gameplay.Vehicle.Impl;
using LTGame;
using PhxhSDK;
using UnityEngine;
namespace Gameplay.Vehicle.State
{
public class VehicleStateFadeOut : BaseVehicleState
{
private readonly float _totalTime = 1f;
private List<Material> _cacheMaterials;
private static readonly int FadeAlpha = Shader.PropertyToID("_fadeAlpha");
private static readonly int MainTex = Shader.PropertyToID("_MainTex");
private static readonly int MaskTex = Shader.PropertyToID("_MaskTex");
private static readonly int OutlineColor = Shader.PropertyToID("_OutlineColor");
private static readonly int Outline = Shader.PropertyToID("_Outline");
private static readonly int Factor = Shader.PropertyToID("_Factor");
private static readonly int ShadowScale = Shader.PropertyToID("_shadowScale");
private static readonly int SpecularScaleG = Shader.PropertyToID("_specularScaleG");
private static readonly int SpecularScaleB = Shader.PropertyToID("_specularScaleB");
private List<Renderer> _cacheRenderers;
private List<Material> _oldMaterials;
private List<GameObject> _cacheHideObjs;
public VehicleStateFadeOut(NormalVehicle vehicle) : base(vehicle, EVehicleState.FadeOut)
{
}
protected override void _OnEnter(NBaseState exitState,
object param)
{
base._OnEnter(exitState, param);
var isEnemy = owner.commonData.troopId != ETroopsId.Self;
var obj = owner.Node.GameObject;
// 获取所有meshrender
var allMeshRenders = obj.GetComponentsInChildren<UnityEngine.Renderer>();
_cacheMaterials = new List<Material>();
_cacheRenderers = new List<Renderer>();
_oldMaterials = new List<Material>();
_cacheHideObjs = new List<GameObject>();
foreach (var meshRender in allMeshRenders)
{
// 移除描边
OutlineManager.instance.RemoveRenderer(meshRender, isEnemy);
var oldMat = meshRender.material;
if (oldMat.shader.name != "NLD_URP/NLD_Charactor"
&& oldMat.shader.name != "NLD_URP/NLD_Charactor_NoRecvShadow")
{
meshRender.gameObject.SetActive(false);
_cacheHideObjs.Add(meshRender.gameObject);
continue;
}
var newShader = AssetManager.Instance.GetPreLoadResult<Shader>(Framework.Constants.SHADER_FADEOUT_PATH);
var newMat = new Material(newShader);
meshRender.material = newMat;
// 复制属性
// [MainTexture] _MainTex ("Texture", 2D) = "white" {}
// _MaskTex ("Mask", 2D) = "white" {}
// _OutlineColor("Outline Color",color)=(0.1,0.1,0.2,1)
// _Outline("Thick of Outline",range(0,0.1))=0.02
// _Factor("Factor",range(0,1)) = 0.5
// _shadowScale("ShadowScale", range(0, 1.0)) = 0.5
// _specularScaleG("SpecularScaleG", range(0, 10.0)) = 2.0
// _specularScaleB("SpecularScaleB", range(0, 10.0)) = 2.0
var oldTexture = oldMat.GetTexture(MainTex);
newMat.SetTexture(MainTex, oldTexture);
var oldMaskTex = oldMat.GetTexture(MaskTex);
newMat.SetTexture(MaskTex, oldMaskTex);
var oldOutlineColor = oldMat.GetColor(OutlineColor);
newMat.SetColor(OutlineColor, oldOutlineColor);
var oldOutline = oldMat.GetFloat(Outline);
newMat.SetFloat(Outline, oldOutline);
var oldFactor = oldMat.GetFloat(Factor);
newMat.SetFloat(Factor, oldFactor);
var oldShadowScale = oldMat.GetFloat(ShadowScale);
newMat.SetFloat(ShadowScale, oldShadowScale);
var oldSpecularScaleG = oldMat.GetFloat(SpecularScaleG);
newMat.SetFloat(SpecularScaleG, oldSpecularScaleG);
var oldSpecularScaleB = oldMat.GetFloat(SpecularScaleB);
newMat.SetFloat(SpecularScaleB, oldSpecularScaleB);
newMat.SetFloat(FadeAlpha, 1);
_cacheMaterials.Add(newMat);
_cacheRenderers.Add(meshRender);
_oldMaterials.Add(oldMat);
}
}
protected override void _OnRunning()
{
base._OnRunning();
var remainTime = Mathf.Clamp01(_totalTime - passTime);
var remainProgress = remainTime / _totalTime;
for (var i = 0; i < _cacheMaterials.Count; ++i)
{
var mat = _cacheMaterials[i];
mat.SetFloat(FadeAlpha, remainProgress);
}
if (passTime >= _totalTime)
{
isFinished = true;
nextState = EVehicleState.WaitRemove;
}
}
protected override void _OnExit(NBaseState exitState,
object param)
{
base._OnExit(exitState, param);
// 隐藏角色
owner.Node.GameObject.SetActive(false);
// 还原材质
for (var i = 0; i < _cacheRenderers.Count; ++i)
{
var renderer = _cacheRenderers[i];
renderer.sharedMaterial = _oldMaterials[i];
}
// 还原隐藏的物体
foreach (var hideObj in _cacheHideObjs)
{
hideObj.SetActive(true);
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cb2d6bf795cb418684ba7af4d14f2b50
timeCreated: 1725510112

View File

@ -0,0 +1,24 @@
using Framework;
using Gameplay.Vehicle.Impl;
using LTGame;
namespace Gameplay.Vehicle.State
{
public class VehicleStateWaitRemove : BaseVehicleState
{
public VehicleStateWaitRemove(NormalVehicle vehicle) : base(vehicle, EVehicleState.WaitRemove)
{
}
protected override void _OnEnter(NBaseState exitState,
object param)
{
base._OnEnter(exitState, param);
owner.needRemove = true;
EventManager.Instance.Send(EventManager.EventName.INFIGHT_UNIT_DEAD_OVER, owner);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 42c6e3485acb4b5f869c31a1c886586f
timeCreated: 1725510532

View File

@ -19,6 +19,7 @@ public sealed partial class DataMonster : Bright.Config.BeanBase
public DataMonster(JSONNode _json)
{
{ if(!_json["MonsterID"].IsNumber) { throw new SerializationException(); } MonsterID = _json["MonsterID"]; }
{ if(!_json["NpcType"].IsNumber) { throw new SerializationException(); } NpcType = _json["NpcType"]; }
{ if(!_json["MonsterClassID"].IsNumber) { throw new SerializationException(); } MonsterClassID = _json["MonsterClassID"]; }
{ if(!_json["AttackFix"].IsNumber) { throw new SerializationException(); } AttackFix = _json["AttackFix"]; }
{ if(!_json["HPFix"].IsNumber) { throw new SerializationException(); } HPFix = _json["HPFix"]; }
@ -29,9 +30,10 @@ public sealed partial class DataMonster : Bright.Config.BeanBase
PostInit();
}
public DataMonster(int MonsterID, int MonsterClassID, float AttackFix, float HPFix, float ShieldFix, float DefenceFix, int FindEnemyRange, int MonsterLevel )
public DataMonster(int MonsterID, int NpcType, int MonsterClassID, float AttackFix, float HPFix, float ShieldFix, float DefenceFix, int FindEnemyRange, int MonsterLevel )
{
this.MonsterID = MonsterID;
this.NpcType = NpcType;
this.MonsterClassID = MonsterClassID;
this.AttackFix = AttackFix;
this.HPFix = HPFix;
@ -52,6 +54,10 @@ public sealed partial class DataMonster : Bright.Config.BeanBase
/// </summary>
public int MonsterID { get; private set; }
/// <summary>
/// npc类型
/// </summary>
public int NpcType { get; private set; }
/// <summary>
/// 怪物类ID
/// </summary>
public int MonsterClassID { get; private set; }
@ -96,6 +102,7 @@ public sealed partial class DataMonster : Bright.Config.BeanBase
{
return "{ "
+ "MonsterID:" + MonsterID + ","
+ "NpcType:" + NpcType + ","
+ "MonsterClassID:" + MonsterClassID + ","
+ "AttackFix:" + AttackFix + ","
+ "HPFix:" + HPFix + ","

File diff suppressed because it is too large Load Diff

View File

@ -7,22 +7,23 @@
"enemyFallbackRegionId": 2,
"pvpDefendRegionId": 0,
"pvpDefendToward": 0,
"weatherType": 0,
"dayNightType": 0,
"stages": [
{
"successCondition": {
"conditionType": 4,
"conditionArgs": []
"conditionArgs": [],
"score": 0
},
"failConditions": [
{
"conditionType": 7,
"conditionArgs": []
"conditionArgs": [],
"score": 0
}
]
}
],
"scoreLevel": false,
"starTarget": [
{
"conditionType": 12,
@ -32,11 +33,13 @@
"enumType": "",
"Arg": 300.0
}
]
],
"score": 0
},
{
"conditionType": 8,
"conditionArgs": []
"conditionArgs": [],
"score": 0
},
{
"conditionType": 12,
@ -46,9 +49,11 @@
"enumType": "",
"Arg": 180.0
}
]
],
"score": 0
}
],
"scoreTarget": [],
"npcInfos": [
{
"id": 10100101,
@ -211,6 +216,36 @@
"npcToward": 5,
"patrolInfos": [],
"groups": []
},
{
"id": 10100108,
"level": 1,
"position": {
"x": 2,
"y": 12,
"magnitude": 12.1655254,
"sqrMagnitude": 148
},
"aIType": 0,
"attachAIType": 0,
"npcToward": 0,
"patrolInfos": [],
"groups": []
},
{
"id": 10100108,
"level": 1,
"position": {
"x": 1,
"y": 11,
"magnitude": 11.0453606,
"sqrMagnitude": 122
},
"aIType": 0,
"attachAIType": 0,
"npcToward": 0,
"patrolInfos": [],
"groups": []
}
],
"protectUnitInfos": []

View File

@ -1,4 +1,14 @@
{
"cameraMarginInfo": {
"leftMarginInFight": 1.5,
"rightMarginInFight": 1.5,
"topMarginInFight": 0.8999999761581421,
"bottomMarginInFight": 0.8999999761581421,
"leftMarginInPre": 1.5,
"rightMarginInPre": 1.5,
"topMarginInInPre": 0.8999999761581421,
"bottomMarginInPre": 0.8999999761581421
},
"position": {
"x": 0.0,
"y": 0.0,

View File

@ -13,6 +13,7 @@ using Sirenix.Utilities;
using Sirenix.OdinInspector;
using Sirenix.Utilities.Editor;
using System.Collections.Generic;
using Gameplay.Level.Data;
using Sirenix.OdinInspector.Editor;
using UnityEngine.Serialization;
using Constants = Framework.Constants;
@ -60,13 +61,6 @@ public class LevelEditorWindow : OdinEditorWindow
}
}
[Serializable]
public enum NpcTye
{
[LabelText("默认敌人")] Monster = 0,
[LabelText("载具敌人")] Vehicle = 1,
}
[Serializable]
public class NPCEditorInfo
{
@ -181,56 +175,6 @@ public class LevelEditorWindow : OdinEditorWindow
[LabelText("添加NPC"), Indent] [LabelWidth(100)] [SerializeField]
public bool isEditingNPC;
[LabelText("敌人单位类型"), Indent] [ShowIf("isEditingNPC")] [LabelWidth(100)] [OnValueChanged("OnChangeNPCType")]
public NpcTye npcType;
private void OnChangeNPCType()
{
if (npcType == NpcTye.Monster)
{
var levelCfg = EditorTableManager.instance.tables.Level;
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>();
var monsterCfg = EditorTableManager.instance.tables.Monster;
foreach (var monster in monsterCfg.DataMap)
{
var strID = monster.Key.ToString();
var tempID = strID.Substring(0, 6);
//关卡ID相同
if (tempID.Equals(levelID))
{
monsterIDs.Add(monster.Key);
}
}
}
else if (npcType == NpcTye.Vehicle)
{
monsterIDs = new List<int>();
var vehicleConfig = EditorTableManager.instance.tables.EnemyVehicleConfig;
foreach (var vehicle in vehicleConfig.DataMap)
{
if (!monsterIDs.Contains(vehicle.Key))
{
monsterIDs.Add(vehicle.Key);
}
}
}
}
/// <summary>
/// 关卡ID 通过关卡数据 json文件名 获得
/// </summary>
@ -264,39 +208,53 @@ public class LevelEditorWindow : OdinEditorWindow
private void MonsterIDChanged()
{
if (npcType == NpcTye.Monster)
var monsterCfg = EditorTableManager.instance.tables.Monster;
if (monsterCfg.DataMap.TryGetValue(curMonsterID, out var monster))
{
var monsterClassCfg = EditorTableManager.instance.tables.MonsterClass;
var monsterCfg = EditorTableManager.instance.tables.Monster;
if (monsterCfg.DataMap.TryGetValue(curMonsterID, out var monster))
{
_curMonsterClassID = monster.MonsterClassID;
}
_curMonsterClassID = monster.MonsterClassID;
}
else
{
return;
}
if (monsterClassCfg.DataMap.TryGetValue(_curMonsterClassID, out var monsterClass))
switch (monster.NpcType)
{
case ENpcType.ENEMY_VEHICLE:
{
var prefabPath = PathEx.GetEnemySrcModelPath(monsterClass.NameId);
npcObject = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
if (npcObject == null)
var vehicleConfig = EditorTableManager.instance.tables.EnemyVehicleConfig;
if (vehicleConfig.DataMap.TryGetValue(_curMonsterClassID, out var vehicle))
{
DebugUtil.LogError("请检查怪物类: {0}的预制体路径是否存在,对应的完整路径: {1}", _curMonsterClassID, prefabPath);
var prefabPath = PathEx.GetVehicleGameModelPath(vehicle.ID);
npcObject = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
if (npcObject == null)
{
DebugUtil.LogError("请检查载具类: {0}的预制体路径是否存在,对应的完整路径: {1}", _curMonsterClassID, prefabPath);
}
}
else
{
DebugUtil.LogError("请检查载具类: {0}的配置是否存在", _curMonsterClassID);
}
}
}
else if (npcType == NpcTye.Vehicle)
{
var enemyVehicleConfig = EditorTableManager.instance.tables.EnemyVehicleConfig;
if (enemyVehicleConfig.DataMap.TryGetValue(curMonsterID, out var vehicleConfig))
break;
case ENpcType.ENEMY_CHARACTER:
{
var prefabPath = PathEx.GetVehicleSrcModelPath(vehicleConfig.PrefabPath);
npcObject = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
if (npcObject == null)
var monsterClassCfg = EditorTableManager.instance.tables.MonsterClass;
if (monsterClassCfg.DataMap.TryGetValue(_curMonsterClassID, out var monsterClass))
{
DebugUtil.LogError("请检查怪物类: {0}的预制体路径是否存在,对应的完整路径: {1}", _curMonsterClassID, prefabPath);
var prefabPath = PathEx.GetEnemySrcModelPath(monsterClass.NameId);
npcObject = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
if (npcObject == null)
{
DebugUtil.LogError("请检查怪物类: {0}的预制体路径是否存在,对应的完整路径: {1}", _curMonsterClassID, prefabPath);
}
}
}
break;
}
}
[LabelText("当前怪物列表"), Indent] [ListDrawerSettings(HideAddButton = true, HideRemoveButton = true)]
@ -535,48 +493,47 @@ public class LevelEditorWindow : OdinEditorWindow
var npcConfigDic = EditorTableManager.instance.tables.MonsterClass.DataMap;
var monsterConfigDic = EditorTableManager.instance.tables.Monster.DataMap;
var enemyVehicleConfig = EditorTableManager.instance.tables.EnemyVehicleConfig.DataMap;
//加载NPC到场景中
currentNpcInfo = new();
foreach (var npcInfo in currentLevelData.npcInfos)
{
currentNpcInfo.Add(new(npcInfo));
if (npcInfo.npcType == 0)
if (!monsterConfigDic.TryGetValue(npcInfo.id, out var monsterClassData))
{
if (!monsterConfigDic.TryGetValue(npcInfo.id, out var monsterClassData))
{
DebugUtil.LogError("请检查配置,没有 {0} 的怪物类ID", npcInfo.id);
continue;
}
npcInfo.level = monsterClassData.MonsterLevel;
var monsterClassID = monsterClassData.MonsterClassID;
if (npcConfigDic.TryGetValue(monsterClassID, out var monster))
{
DebugUtil.Log("monsterNameId:{0}", monster.NameId);
string npcId = "P_" + monster.NameId;
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));
}
DebugUtil.LogError("请检查配置,没有 {0} 的怪物类ID", npcInfo.id);
continue;
}
else
{
if (!enemyVehicleConfig.TryGetValue(npcInfo.id, out var enemyVehicle))
{
DebugUtil.LogError("请检查配置,没有 {0} 的载具ID", npcInfo.id);
continue;
}
//TODO 载具等级
//npcInfo.level = enemyVehicle.MonsterLevel;
DebugUtil.Log("VehicleId:{0}", enemyVehicle.ID);
var prefabPath = PathEx.GetVehicleSrcModelPath(enemyVehicle.PrefabPath);
var npc = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
var position = _curMap.BlockPosition2WorldPosition(npcInfo.position);
_npcDic.Add(npcInfo.position, Instantiate(npc, position, npc.transform.rotation));
npcInfo.level = monsterClassData.MonsterLevel;
var monsterClassID = monsterClassData.MonsterClassID;
switch (monsterClassData.NpcType)
{
case ENpcType.ENEMY_CHARACTER:
{
if (npcConfigDic.TryGetValue(monsterClassID, out var monster))
{
DebugUtil.Log("monsterNameId:{0}", monster.NameId);
string npcId = "P_" + monster.NameId;
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));
}
}
break;
case ENpcType.ENEMY_VEHICLE:
{
var configDict = EditorTableManager.instance.tables.EnemyVehicleConfig.DataMap;
if (configDict.TryGetValue(monsterClassID, out var vehicleConfig))
{
var loadPath = PathEx.GetVehicleGameModelPath(vehicleConfig.ID);
var vehicle = AssetDatabase.LoadAssetAtPath<GameObject>(loadPath);
var setPos = _curMap.BlockPosition2WorldPosition(npcInfo.position);
_npcDic.Add(npcInfo.position, Instantiate(vehicle, setPos, vehicle.transform.rotation));
}
}
break;
}
}
@ -644,9 +601,34 @@ public class LevelEditorWindow : OdinEditorWindow
LevelData.NPCInfo npcInfo = new LevelData.NPCInfo();
/*string npcId = npcObject.name.Replace("P_", "");
var monsterId = 0;
var npcConfigDic = EditorTableManager.instance.tables.MonsterClass.DataMap;
var monsterConfigDic = EditorTableManager.instance.tables.Monster.DataMap;
var npcmatchingItem = npcConfigDic.FirstOrDefault(pair => pair.Value.NameId == npcId).Value;
if (npcmatchingItem != null)
{
var monsterClass = monsterConfigDic
.FirstOrDefault(pair => pair.Value.MonsterClassID == npcmatchingItem.MonsterClassID).Value;
if (monsterClass != null)
{
monsterId = monsterClass.MonsterID;
DebugUtil.Log($"匹配的对应怪物ClassID: {npcmatchingItem.MonsterClassID}, NameID: {npcmatchingItem.NameId}");
}
else
{
DebugUtil.LogError("没有相应配置请重选其怪物类ID为{0}", npcmatchingItem.MonsterClassID);
return;
}
}
if (monsterId <= 0) return;
npcInfo.id = monsterConfigDic[monsterId].MonsterID;*/
npcInfo.id = curMonsterID;
npcInfo.position = clickPosition;
npcInfo.npcType = (int)npcType;
var monsterConfigDic = EditorTableManager.instance.tables.Monster.DataMap;
if (monsterConfigDic.TryGetValue(curMonsterID, out var monster))