using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.Json; using Godot; [Tool] public partial class DungeonRoomTemplate : TileMap { /// <summary> /// 默认权重值 /// </summary> public const int DefaultWeight = 100; /// <summary> /// 是否启用编辑模式 /// </summary> [Export] public bool EnableEdit = false; /// <summary> /// 房间权重, 值越大, 生成地牢是越容易出现该房间 /// </summary> [Export(PropertyHint.Range, "1, 500")] public int Weight { get => _weight; set { _weight = value; _changeWeight = true; _changeWeightTimer = 0; } } private int _weight = DefaultWeight; private bool _changeWeight = false; private float _changeWeightTimer = 0; #if TOOLS //是否悬停在线上 private bool _hover = false; //悬停点 private Vector2 _hoverPoint1; private Vector2 _hoverPoint2; private DoorDirection _hoverDirection; private bool _canPut = false; //选中点 private bool _hasActivePoint = false; //选中左/右点 private byte _activePointType = 0; private DoorAreaInfo _activeArea = null; //拖拽 private bool _isDrag = false; private float _startDragValue; private Vector2 _startDragPositionValue; private bool _dragHasCollision = false; private bool _mouseDown = false; //房间配置 private DungeonRoomInfo _dungeonRoomInfo; private Rect2 _prevRect; //是否能是否按下 private bool _clickSave = false; private DungeonTileMap _dungeonTileMap; private TileDrawHandler _tileDrawHandler; //计算导航的计时器 private float _calcTileNavTimer = 0; private partial class TileDrawHandler : Node2D { public DungeonRoomTemplate RoomTemplate; public override void _Draw() { if (!Engine.IsEditorHint() || RoomTemplate == null) { return; } if (RoomTemplate.TileSet != null) { //绘制地图轮廓 var mapRange = CalcTileRange(RoomTemplate); mapRange.Position -= new Vector2(2, 2); mapRange.Size += new Vector2(4, 4); DrawRect(mapRange, RoomTemplate._hover ? Colors.Green : new Color(0.03137255F, 0.59607846F, 0.03137255F), false, 2); //绘制悬停 if (RoomTemplate._hover && !RoomTemplate._isDrag) { if (!RoomTemplate._hasActivePoint) //这里判断是否悬停在拖动点上 { var color = RoomTemplate._canPut ? new Color(0, 1, 0, 0.2f) : new Color(1, 0, 0, 0.2f); switch (RoomTemplate._hoverDirection) { case DoorDirection.E: DrawRect( new Rect2(new Vector2(RoomTemplate._hoverPoint1.X + 2, RoomTemplate._hoverPoint1.Y), 30, RoomTemplate._hoverPoint2.Y - RoomTemplate._hoverPoint1.Y), color); DrawCircle(new Vector2(RoomTemplate._hoverPoint1.X + 2, RoomTemplate._hoverPoint1.Y), 5, color); DrawCircle(new Vector2(RoomTemplate._hoverPoint2.X + 2, RoomTemplate._hoverPoint2.Y), 5, color); break; case DoorDirection.W: DrawRect( new Rect2(new Vector2(RoomTemplate._hoverPoint1.X - 2 - 30, RoomTemplate._hoverPoint1.Y), 30, RoomTemplate._hoverPoint2.Y - RoomTemplate._hoverPoint1.Y), color); DrawCircle(new Vector2(RoomTemplate._hoverPoint1.X - 2, RoomTemplate._hoverPoint1.Y), 5, color); DrawCircle(new Vector2(RoomTemplate._hoverPoint2.X - 2, RoomTemplate._hoverPoint2.Y), 5, color); break; case DoorDirection.S: DrawRect( new Rect2(new Vector2(RoomTemplate._hoverPoint1.X, RoomTemplate._hoverPoint1.Y + 2), RoomTemplate._hoverPoint2.X - RoomTemplate._hoverPoint1.X, 30), color); DrawCircle(new Vector2(RoomTemplate._hoverPoint1.X, RoomTemplate._hoverPoint1.Y + 2), 5, color); DrawCircle(new Vector2(RoomTemplate._hoverPoint2.X, RoomTemplate._hoverPoint2.Y + 2), 5, color); break; case DoorDirection.N: DrawRect( new Rect2(new Vector2(RoomTemplate._hoverPoint1.X, RoomTemplate._hoverPoint1.Y - 30 - 2), RoomTemplate._hoverPoint2.X - RoomTemplate._hoverPoint1.X, 30), color); DrawCircle(new Vector2(RoomTemplate._hoverPoint1.X, RoomTemplate._hoverPoint1.Y - 2), 5, color); DrawCircle(new Vector2(RoomTemplate._hoverPoint2.X, RoomTemplate._hoverPoint2.Y - 2), 5, color); break; } } } //绘制区域 if (RoomTemplate._dungeonRoomInfo != null && RoomTemplate._dungeonRoomInfo.DoorAreaInfos != null) { var color2 = new Color(0, 1, 0, 0.8f); //绘制已经存在的 foreach (var doorAreaInfo in RoomTemplate._dungeonRoomInfo.DoorAreaInfos) { var flag = RoomTemplate._hasActivePoint && RoomTemplate._activeArea == doorAreaInfo; var color3 = (flag && RoomTemplate._activePointType == 0) ? (RoomTemplate._isDrag ? (RoomTemplate._dragHasCollision ? new Color(1, 0, 0, 0.8f) : new Color(0.2F, 0.4117647F, 0.8392157F, 0.8f)) : new Color(1, 1, 1, 0.8f)) : color2; var color4 = (flag && RoomTemplate._activePointType == 1) ? (RoomTemplate._isDrag ? (RoomTemplate._dragHasCollision ? new Color(1, 0, 0, 0.8f) : new Color(0.2F, 0.4117647F, 0.8392157F, 0.8f)) : new Color(1, 1, 1, 0.8f)) : color2; switch (doorAreaInfo.Direction) { case DoorDirection.E: DrawRect( new Rect2( new Vector2(mapRange.Position.X + mapRange.Size.X, mapRange.Position.Y + doorAreaInfo.Start + 2), 30, doorAreaInfo.End - doorAreaInfo.Start), color2); DrawCircle( new Vector2(mapRange.Position.X + mapRange.Size.X, mapRange.Position.Y + doorAreaInfo.Start + 2), 5, color3); DrawCircle( new Vector2(mapRange.Position.X + mapRange.Size.X, mapRange.Position.Y + doorAreaInfo.End + 2), 5, color4); break; case DoorDirection.W: DrawRect( new Rect2( new Vector2(mapRange.Position.X - 30, mapRange.Position.Y + doorAreaInfo.Start + 2), 30, doorAreaInfo.End - doorAreaInfo.Start), color2); DrawCircle(new Vector2(mapRange.Position.X, mapRange.Position.Y + doorAreaInfo.Start + 2), 5, color3); DrawCircle(new Vector2(mapRange.Position.X, mapRange.Position.Y + doorAreaInfo.End + 2), 5, color4); break; case DoorDirection.S: DrawRect( new Rect2( new Vector2(mapRange.Position.X + doorAreaInfo.Start + 2, mapRange.Position.Y + mapRange.Size.Y), doorAreaInfo.End - doorAreaInfo.Start, 30), color2); DrawCircle( new Vector2(mapRange.Position.X + doorAreaInfo.Start + 2, mapRange.Position.Y + mapRange.Size.Y), 5, color3); DrawCircle( new Vector2(mapRange.Position.X + doorAreaInfo.End + 2, mapRange.Position.Y + mapRange.Size.Y), 5, color4); break; case DoorDirection.N: DrawRect( new Rect2( new Vector2(mapRange.Position.X + doorAreaInfo.Start + 2, mapRange.Position.Y - 30), doorAreaInfo.End - doorAreaInfo.Start, 30), color2); DrawCircle(new Vector2(mapRange.Position.X + doorAreaInfo.Start + 2, mapRange.Position.Y), 5, color3); DrawCircle(new Vector2(mapRange.Position.X + doorAreaInfo.End + 2, mapRange.Position.Y), 5, color4); break; } } } //绘制导航, 现在有点问题, 绘制的内容会被自身的 tile 所挡住 if (RoomTemplate._dungeonTileMap != null) { var result = RoomTemplate._dungeonTileMap.GetGenerateNavigationResult(); if (result != null) { if (result.Success) { var polygonData = RoomTemplate._dungeonTileMap.GetPolygonData(); Utils.DrawNavigationPolygon(this, polygonData, 2); } else { var color = new Color(1, 0, 0, 0.5f); var tileCellSize = GameConfig.TileCellSize; var point = (result.Exception.Point + new Vector2(0.5f, 0.5f)) * tileCellSize; DrawCircle(point, 4, color); DrawLine(point + new Vector2(-tileCellSize / 2f, -tileCellSize / 2f), point + new Vector2(tileCellSize / 2f, tileCellSize / 2f), color, 2); DrawLine(point + new Vector2(-tileCellSize / 2f, tileCellSize / 2f), point + new Vector2(tileCellSize / 2f, -tileCellSize / 2f), color, 2); } } } } } } public override void _Ready() { if (!Engine.IsEditorHint()) { return; } EnableEdit = false; } public override void _Process(double delta) { if (!Engine.IsEditorHint()) { return; } if (TileSet == null) { return; } if (_dungeonTileMap == null) { _dungeonTileMap = new DungeonTileMap(this); _dungeonTileMap.SetFloorAtlasCoords(new List<Vector2I>() { new Vector2I(0, 8) }); OnTileChanged(); var callable = new Callable(this, nameof(OnTileChanged)); if (!IsConnected("changed", callable)) { Connect("changed", callable); } } if (_tileDrawHandler == null) { _tileDrawHandler = GetNodeOrNull<TileDrawHandler>("TileDrawHandler"); if (_tileDrawHandler == null) { _tileDrawHandler = new TileDrawHandler(); _tileDrawHandler.RoomTemplate = this; _tileDrawHandler.Name = "TileDrawHandler"; _tileDrawHandler.ZIndex = 100; AddChild(_tileDrawHandler); } else { _tileDrawHandler.RoomTemplate = this; } } //导航计算 if (_calcTileNavTimer > 0) { _calcTileNavTimer -= (float)delta; //重新计算导航 if (_calcTileNavTimer <= 0) { _dungeonTileMap.GenerateNavigationPolygon(0); } } //加载配置 var initConfigs = false; if (_dungeonRoomInfo == null) { initConfigs = true; var path = SceneFilePath; if (!string.IsNullOrEmpty(path)) { var start = GameConfig.RoomTileDir.Length + 6; var name = path.Substring(start, path.Length - start - 5); ReadConfig(CalcTileRange(this), name); } } //按键检测 var isClick = false; if (Input.IsMouseButtonPressed(MouseButton.Left)) { if (!_mouseDown) { _mouseDown = true; isClick = true; } } else if (_mouseDown) { _mouseDown = false; isClick = false; } if (Input.IsMouseButtonPressed(MouseButton.Middle)) //中键移除门 { if (EnableEdit && _activeArea != null) { RemoveDoorArea(_activeArea); _hasActivePoint = false; _activeArea = null; } } else if (TileSet != null) //编辑操作 { var mapRect = CalcTileRange(this); var mousePosition = GetLocalMousePosition(); if (mapRect != _prevRect) { if (!initConfigs) { OnMapRectChange(); } } _prevRect = mapRect; if (EnableEdit) { var tileSize = TileSet.TileSize; if (_isDrag) //拖拽中 { if (_activeArea != null) { //拖拽节点操作 if (_activeArea.Direction == DoorDirection.N || _activeArea.Direction == DoorDirection.S) { if (_activePointType == 0) { var mouseOffset = Approach(mousePosition.X, tileSize.X); _activeArea.StartPosition = new Vector2(mouseOffset, _activeArea.StartPosition.Y); _activeArea.Start = mouseOffset - mapRect.Position.X; _dragHasCollision = _activeArea.StartPosition.X <= mapRect.Position.X || _activeArea.StartPosition.X + 3 * tileSize.X >= _activeArea.EndPosition.X || CheckDoorCollision(_activeArea.Direction, _activeArea); } else { var mouseOffset = Approach(mousePosition.X, tileSize.X); _activeArea.EndPosition = new Vector2(mouseOffset, _activeArea.EndPosition.Y); _activeArea.End = mouseOffset - mapRect.Position.X; _dragHasCollision = _activeArea.EndPosition.X >= mapRect.Position.X + mapRect.Size.X || _activeArea.EndPosition.X - 3 * tileSize.X <= _activeArea.StartPosition.X || CheckDoorCollision(_activeArea.Direction, _activeArea); } } else { if (_activePointType == 0) { var mouseOffset = Approach(mousePosition.Y, tileSize.Y); _activeArea.StartPosition = new Vector2(_activeArea.StartPosition.X, mouseOffset); _activeArea.Start = mouseOffset - mapRect.Position.Y; _dragHasCollision = _activeArea.StartPosition.Y <= mapRect.Position.Y || _activeArea.StartPosition.Y + 3 * tileSize.Y >= _activeArea.EndPosition.Y || CheckDoorCollision(_activeArea.Direction, _activeArea); } else { var mouseOffset = Approach(mousePosition.Y, tileSize.Y); _activeArea.EndPosition = new Vector2(_activeArea.EndPosition.X, mouseOffset); _activeArea.End = mouseOffset - mapRect.Position.Y; _dragHasCollision = _activeArea.EndPosition.Y >= mapRect.Position.Y + mapRect.Size.Y || _activeArea.EndPosition.Y - 3 * tileSize.Y <= _activeArea.StartPosition.Y || CheckDoorCollision(_activeArea.Direction, _activeArea); } } } } else { if (Mathf.Abs(mousePosition.Y - mapRect.Position.Y) <= 8 && mousePosition.X >= mapRect.Position.X && mousePosition.X <= mapRect.Position.X + mapRect.Size.X) //上 { _hover = true; _hoverDirection = DoorDirection.N; var mouseOffset = Approach(mousePosition.X, tileSize.X); _hoverPoint1 = new Vector2(mouseOffset - tileSize.X * 2, mapRect.Position.Y); _hoverPoint2 = new Vector2(_hoverPoint1.X + tileSize.X * 4, _hoverPoint1.Y); //判断是否能放下新的门 if (_hoverPoint1.X <= mapRect.Position.X || _hoverPoint2.X >= mapRect.Position.X + mapRect.Size.X || CheckDoorCollision()) { _canPut = false; FindHoverPoint(mouseOffset); } else { _canPut = true; _hasActivePoint = false; _activeArea = null; } } else if (Mathf.Abs(mousePosition.X - mapRect.Position.X) <= 8 && mousePosition.Y >= mapRect.Position.Y && mousePosition.Y <= mapRect.Position.Y + mapRect.Size.Y) //左 { _hover = true; _hoverDirection = DoorDirection.W; var mouseOffset = Approach(mousePosition.Y, tileSize.Y); _hoverPoint1 = new Vector2(mapRect.Position.X, mouseOffset - tileSize.Y * 2); _hoverPoint2 = new Vector2(_hoverPoint1.X, _hoverPoint1.Y + tileSize.X * 4); //判断是否能放下新的门 if (_hoverPoint1.Y <= mapRect.Position.Y || _hoverPoint2.Y >= mapRect.Position.Y + mapRect.Size.Y || CheckDoorCollision()) { _canPut = false; FindHoverPoint(mouseOffset); } else { _canPut = true; _hasActivePoint = false; _activeArea = null; } } else if (Mathf.Abs(mousePosition.Y - (mapRect.Position.Y + mapRect.Size.Y)) <= 8 && mousePosition.X >= mapRect.Position.X && mousePosition.X <= mapRect.Position.X + mapRect.Size.X) //下 { _hover = true; _hoverDirection = DoorDirection.S; var mouseOffset = Approach(mousePosition.X, tileSize.X); _hoverPoint1 = new Vector2(mouseOffset - tileSize.X * 2, mapRect.Position.Y + mapRect.Size.Y); _hoverPoint2 = new Vector2(_hoverPoint1.X + tileSize.X * 4, _hoverPoint1.Y); //判断是否能放下新的门 if (_hoverPoint1.X <= mapRect.Position.X || _hoverPoint2.X >= mapRect.Position.X + mapRect.Size.X || CheckDoorCollision()) { _canPut = false; FindHoverPoint(mouseOffset); } else { _canPut = true; _hasActivePoint = false; _activeArea = null; } } else if (Mathf.Abs(mousePosition.X - (mapRect.Position.X + mapRect.Size.X)) <= 8 && mousePosition.Y >= mapRect.Position.Y && mousePosition.Y <= mapRect.Position.Y + mapRect.Size.Y) //右 { _hover = true; _hoverDirection = DoorDirection.E; var mouseOffset = Approach(mousePosition.Y, tileSize.Y); _hoverPoint1 = new Vector2(mapRect.Position.X + mapRect.Size.X, mouseOffset - tileSize.Y * 2); _hoverPoint2 = new Vector2(_hoverPoint1.X, _hoverPoint1.Y + tileSize.X * 4); //判断是否能放下新的门 if (_hoverPoint1.Y <= mapRect.Position.Y || _hoverPoint2.Y >= mapRect.Position.Y + mapRect.Size.Y || CheckDoorCollision()) { _canPut = false; FindHoverPoint(mouseOffset); } else { _canPut = true; _hasActivePoint = false; _activeArea = null; } } else { ClearState(); } } if (isClick && _canPut) //判断是否可以创建新的点 { CreateDoorArea(mapRect); } else if (_mouseDown && !_isDrag) //拖拽节点 { _isDrag = true; _dragHasCollision = false; if (_activeArea != null) { if (_activePointType == 0) { _startDragValue = _activeArea.Start; _startDragPositionValue = _activeArea.StartPosition; } else { _startDragValue = _activeArea.End; _startDragPositionValue = _activeArea.EndPosition; } } } else if (!_mouseDown && _isDrag) //松开拖拽的点 { _isDrag = false; if (_activeArea != null) //提交拖拽结果 { if (_dragHasCollision) { if (_activePointType == 0) { _activeArea.Start = _startDragValue; _activeArea.StartPosition = _startDragPositionValue; } else { _activeArea.End = _startDragValue; _activeArea.EndPosition = _startDragPositionValue; } } //OnDoorAreaChange(); } _dragHasCollision = false; } } else { ClearState(); } _tileDrawHandler.QueueRedraw(); } else { ClearState(); } //按下 ctrl + s 保存 if (Input.IsKeyPressed(Key.Ctrl) && Input.IsKeyPressed(Key.S)) { if (!_clickSave) { TriggerSave(); } _clickSave = true; // if (_canSave) // { // _canSave = false; // TriggerSave(); // } } else { _clickSave = false; } //权重发生改变 if (_changeWeight) { _changeWeightTimer += (float)delta; if (_changeWeightTimer > 1) { _changeWeightTimer = 0; _changeWeight = false; //权重改变, 保存数据 TriggerSave(); } } } private void ClearState() { _hover = false; _canPut = false; _hasActivePoint = false; _activeArea = null; } private void OnTileChanged() { _calcTileNavTimer = 1f; } //创建门 private void CreateDoorArea(Rect2 mapRect) { var doorAreaInfo = new DoorAreaInfo(); doorAreaInfo.Direction = _hoverDirection; doorAreaInfo.StartPosition = _hoverPoint1; doorAreaInfo.EndPosition = _hoverPoint2; switch (_hoverDirection) { case DoorDirection.E: case DoorDirection.W: doorAreaInfo.Start = _hoverPoint1.Y - mapRect.Position.Y; doorAreaInfo.End = _hoverPoint2.Y - mapRect.Position.Y; break; case DoorDirection.N: case DoorDirection.S: doorAreaInfo.Start = _hoverPoint1.X - mapRect.Position.X; doorAreaInfo.End = _hoverPoint2.X - mapRect.Position.X; break; } _dungeonRoomInfo.DoorAreaInfos.Add(doorAreaInfo); //OnDoorAreaChange(); } //移除门 private void RemoveDoorArea(DoorAreaInfo doorAreaInfo) { _dungeonRoomInfo.DoorAreaInfos.Remove(doorAreaInfo); //OnDoorAreaChange(); } //检查门是否有碰撞 private bool CheckDoorCollision() { foreach (var doorAreaInfo in _dungeonRoomInfo.DoorAreaInfos) { if (doorAreaInfo.Direction == _hoverDirection) { switch (_hoverDirection) { case DoorDirection.E: case DoorDirection.W: if (CheckValueCollision(doorAreaInfo.StartPosition.Y, doorAreaInfo.EndPosition.Y, _hoverPoint1.Y, _hoverPoint2.Y)) { return true; } break; case DoorDirection.S: case DoorDirection.N: if (CheckValueCollision(doorAreaInfo.StartPosition.X, doorAreaInfo.EndPosition.X, _hoverPoint1.X, _hoverPoint2.X)) { return true; } break; } } } return false; } //检查门是否有碰撞 private bool CheckDoorCollision(DoorDirection direction, DoorAreaInfo info) { foreach (var doorAreaInfo in _dungeonRoomInfo.DoorAreaInfos) { if (doorAreaInfo.Direction == direction && info != doorAreaInfo && CheckValueCollision(doorAreaInfo.Start, doorAreaInfo.End, info.Start, info.End)) { return true; } } return false; } private bool CheckValueCollision(float o1, float o2, float h1, float h2) { var size = TileSet.TileSize.X; return !(h2 < o1 - 3 * size || o2 + 3 * size < h1); } private void FindHoverPoint(float mouseOffset) { if (_isDrag) { return; } //检测是否有碰撞的点 var flag = false; foreach (var doorAreaInfo in _dungeonRoomInfo.DoorAreaInfos) { if (doorAreaInfo.Direction == _hoverDirection) { if (_hoverDirection == DoorDirection.N || _hoverDirection == DoorDirection.S) { if (Math.Abs(doorAreaInfo.StartPosition.X - mouseOffset) < 0.0001f) { _hasActivePoint = true; _activePointType = 0; _activeArea = doorAreaInfo; flag = true; break; } else if (Math.Abs(doorAreaInfo.EndPosition.X - mouseOffset) < 0.0001f) { _hasActivePoint = true; _activePointType = 1; _activeArea = doorAreaInfo; flag = true; break; } } else { if (Math.Abs(doorAreaInfo.StartPosition.Y - mouseOffset) < 0.0001f) { _hasActivePoint = true; _activePointType = 0; _activeArea = doorAreaInfo; flag = true; break; } else if (Math.Abs(doorAreaInfo.EndPosition.Y - mouseOffset) < 0.0001f) { _hasActivePoint = true; _activePointType = 1; _activeArea = doorAreaInfo; flag = true; break; } } } } if (!flag) { _hasActivePoint = false; _activeArea = null; } } private float Approach(float value, float period) { var temp = value % period; if (Mathf.Abs(temp) >= period / 2) { return ((int)(value / period) + (value >= 0 ? 1 : -1)) * period; } return (int)(value / period) * period; } //地图大小改变 private void OnMapRectChange() { _dungeonRoomInfo.DoorAreaInfos.Clear(); _canPut = false; _hasActivePoint = false; _activeArea = null; //OnDoorAreaChange(); } // //区域数据修改 // private void OnDoorAreaChange() // { // _canSave = true; // } //触发保存操作 private void TriggerSave() { //如果没有找到对应的场景文件,则不保存 var path = _dungeonRoomInfo.GroupName + "/" + DungeonRoomTypeToString(_dungeonRoomInfo.RoomType) + "/" + _dungeonRoomInfo.FileName; if (!File.Exists(GameConfig.RoomTileDir + path + ".tscn")) { return; } //计算导航网格 _dungeonTileMap.GenerateNavigationPolygon(0); var polygonData = _dungeonTileMap.GetPolygonData(); var rect = GetUsedRect(); SaveConfig(_dungeonRoomInfo.DoorAreaInfos, rect.Position, rect.Size, polygonData.ToList(), _dungeonRoomInfo.GroupName, _dungeonRoomInfo.RoomType, Name, Weight); } /// <summary> /// 计算tile所占区域 /// </summary> /// <returns></returns> public static Rect2 CalcTileRange(TileMap tileMap) { var usedRect = tileMap.GetUsedRect(); var pos = usedRect.Position * tileMap.TileSet.TileSize; var size = usedRect.Size * tileMap.TileSet.TileSize; return new Rect2(tileMap.ToLocal(pos), size); } /// <summary> /// 保存房间配置 /// </summary> public static void SaveConfig(List<DoorAreaInfo> doorConfigs, Vector2I position, Vector2I size, List<NavigationPolygonData> polygonData, string groupName, DungeonRoomType roomType, string fileName, int weight) { //存入本地 var path = GameConfig.RoomTileDataDir + groupName + "/" + DungeonRoomTypeToString(roomType); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } var roomInfo = new DungeonRoomInfo(); roomInfo.Position = new SerializeVector2(position); roomInfo.Size = new SerializeVector2(size); roomInfo.DoorAreaInfos = doorConfigs; roomInfo.NavigationList = polygonData; roomInfo.RoomType = roomType; roomInfo.GroupName = groupName; roomInfo.FileName = fileName; roomInfo.Weight = weight; var config = new JsonSerializerOptions(); config.WriteIndented = true; path += "/" + fileName + ".json"; var jsonStr = JsonSerializer.Serialize(roomInfo, config); File.WriteAllText(path, jsonStr); GD.Print("保存房间配置成功!路径为:" + path); } /// <summary> /// 读取房间配置 /// </summary> private void ReadConfig(Rect2 mapRect, string name) { var path = GameConfig.RoomTileDataDir + name + ".json"; if (File.Exists(path)) { var text = File.ReadAllText(path); try { _dungeonRoomInfo = DeserializeDungeonRoomInfo(text); //填充 StartPosition 和 EndPosition 数据 foreach (var doorAreaInfo in _dungeonRoomInfo.DoorAreaInfos) { doorAreaInfo.CalcPosition(mapRect.Position, mapRect.Size); } Weight = _dungeonRoomInfo.Weight; } catch (Exception e) { GD.PrintErr($"加载房间数据'{path}'发生异常: " + e); } } } /// <summary> /// 反序列化 DungeonRoomInfo /// </summary> public static DungeonRoomInfo DeserializeDungeonRoomInfo(string text) { // 下面这句代码在 Godot4.0_rc2的编辑器模式下, 重载脚本会导致编辑器一直报错!, 所以暂时先用下面的方法 //var roomInfo = JsonSerializer.Deserialize<DungeonRoomInfo>(text); var obj = Json.ParseString(text).AsGodotDictionary(); var roomInfo = new DungeonRoomInfo(); if (obj.ContainsKey("Position")) { var position = obj["Position"].AsGodotDictionary(); roomInfo.Position = new SerializeVector2(position["X"].AsInt32(), position["Y"].AsInt32()); } if (obj.ContainsKey("Size")) { var size = obj["Size"].AsGodotDictionary(); roomInfo.Size = new SerializeVector2(size["X"].AsInt32(), size["Y"].AsInt32()); } if (obj.ContainsKey("RoomType")) { var roomType = obj["RoomType"].AsInt32(); roomInfo.RoomType = (DungeonRoomType)roomType; } if (obj.ContainsKey("GroupName")) { roomInfo.GroupName = obj["GroupName"].AsString(); } if (obj.ContainsKey("FileName")) { roomInfo.FileName = obj["FileName"].AsString(); } if (obj.ContainsKey("Weight")) { roomInfo.Weight = obj["Weight"].AsInt32(); } if (obj.ContainsKey("DoorAreaInfos")) { var doorAreaInfos = obj["DoorAreaInfos"].AsGodotArray<Variant>(); roomInfo.DoorAreaInfos = new List<DoorAreaInfo>(); foreach (var item in doorAreaInfos) { var temp = item.AsGodotDictionary(); var doorInfo = new DoorAreaInfo(); doorInfo.Direction = (DoorDirection)temp["Direction"].AsInt32(); doorInfo.Start = temp["Start"].AsInt32(); doorInfo.End = temp["End"].AsInt32(); roomInfo.DoorAreaInfos.Add(doorInfo); } } if (obj.ContainsKey("NavigationList")) { var navigationArray = obj["NavigationList"].AsGodotArray<Variant>(); roomInfo.NavigationList = new List<NavigationPolygonData>(); for (var i = 0; i < navigationArray.Count; i++) { var navigation = navigationArray[i].AsGodotDictionary(); var polygonData = new NavigationPolygonData(); polygonData.Type = (NavigationPolygonType)navigation["Type"].AsInt32(); polygonData.Points = new List<SerializeVector2>(); var pointArray = navigation["Points"].AsGodotArray<Variant>(); for (var j = 0; j < pointArray.Count; j++) { var point = pointArray[j].AsGodotDictionary(); polygonData.Points.Add(new SerializeVector2(point["X"].AsInt32(), point["Y"].AsInt32())); } roomInfo.NavigationList.Add(polygonData); } } return roomInfo; } /// <summary> /// 将房间类型枚举转为字符串 /// </summary> public static string DungeonRoomTypeToString(DungeonRoomType roomType) { switch (roomType) { case DungeonRoomType.Battle: return "battle"; case DungeonRoomType.Inlet: return "inlet"; case DungeonRoomType.Outlet: return "outlet"; case DungeonRoomType.Boss: return "boss"; case DungeonRoomType.Reward: return "reward"; case DungeonRoomType.Shop: return "shop"; case DungeonRoomType.Event: return "event"; } return "battle"; } /// <summary> /// 将房间类型枚举转为描述字符串 /// </summary> public static string DungeonRoomTypeToDescribeString(DungeonRoomType roomType) { switch (roomType) { case DungeonRoomType.Battle: return "战斗房间"; case DungeonRoomType.Inlet: return "起始房间"; case DungeonRoomType.Outlet: return "结束房间"; case DungeonRoomType.Boss: return "boss战房间"; case DungeonRoomType.Reward: return "奖励房间"; case DungeonRoomType.Shop: return "商店房间"; case DungeonRoomType.Event: return "事件房间"; } return "战斗房间"; } #endif /// <summary> /// 获取所有标记数据 /// </summary> public ActivityMark[] GetMarks() { var list = new List<ActivityMark>(); foreach (var child in GetChildren()) { EachAndGetMarks(child, list); } return list.ToArray(); } private void EachAndGetMarks(Node node, List<ActivityMark> list) { if (node is ActivityMark mark) { list.Add(mark); } foreach (var child in node.GetChildren()) { EachAndGetMarks(child, list); } } }