using System;
using System.Collections.Generic;
using System.Linq;
using ColdMint.scripts.debug;
using ColdMint.scripts.map.dateBean;
using ColdMint.scripts.utils;
using Godot;
namespace ColdMint.scripts.map.room;
///
/// Room
/// 房间模板
///
///
///The room template is like a jigsaw puzzle and participates in the map building process.
///房间模板就像一个拼图,参与到地图的构建过程中。
///
public class Room
{
private Node2D? _rootNode;
private RoomSlot?[]? _roomSlots;
private List? _tileMapLayers;
private Area2D? _area2D;
private CollisionShape2D? _collisionShape2D;
public string? EnterRoomEventHandlerId { get; set; }
public string? ExitRoomEventHandlerId { get; set; }
///
/// Get the corresponding tile layer node based on the tile name
/// 根据瓦片名称获取对应的瓦片图层节点
///
///
///We recommend using the constants defined in .
///建议使用内定义的常量。
///
///
/// Return a Layer node with the same name if it is found, otherwise null.
///如果找到了与其名称相同的Layer节点则返回它,否则返回null。
///
public TileMapLayer? GetTileMapLayer(string layerName)
{
return _tileMapLayers?.FirstOrDefault(tileMapLayer => tileMapLayer.Name == layerName);
}
///
/// When a node enters the room
/// 当有节点进入房间时
///
///
private void OnEnterRoom(Node node)
{
if (_rootNode != null)
{
LogCat.LogWithFormat("enter_the_room_debug", LogCat.LogLabel.Default, LogCat.UploadFormat, node.Name,
_rootNode.Name);
}
if (string.IsNullOrEmpty(EnterRoomEventHandlerId))
{
return;
}
var enterRoomEventHandler = RoomEventManager.GetEnterRoomEventHandler(EnterRoomEventHandlerId);
enterRoomEventHandler?.OnEnterRoom(node, this);
}
///
/// When a node exits the room
/// 当有节点退出房间时
///
///
private void OnExitRoom(Node node)
{
if (_rootNode != null)
{
LogCat.LogWithFormat("exit_the_room_debug", LogCat.LogLabel.Default, LogCat.UploadFormat, node.Name,
_rootNode.Name);
}
if (string.IsNullOrEmpty(ExitRoomEventHandlerId))
{
return;
}
var exitRoomEventHandler = RoomEventManager.GetExitRoomEventHandler(ExitRoomEventHandlerId);
exitRoomEventHandler?.OnExitRoom(node, this);
}
///
/// The collision shape of the room
/// 房间的碰撞形状
///
public CollisionShape2D? RoomCollisionShape2D
{
get => _collisionShape2D;
set => _collisionShape2D = value;
}
public Area2D? Area2D
{
get => _area2D;
set => _area2D = value;
}
public PackedScene? RoomScene
{
get => default;
set => AnalyzeRoomData(value);
}
///
/// Analyze the data of the room
/// 解析房间的数据
///
///
private void AnalyzeRoomData(PackedScene? packedScene)
{
if (packedScene == null)
{
return;
}
var node2D = NodeUtils.InstantiatePackedScene(packedScene);
if (node2D == null)
{
//The room node is not of Node2D type. An exception is thrown
//房间节点不是Node2D类型,抛出异常
LogCat.LogError("room_root_node_must_be_node2d");
return;
}
_rootNode = node2D;
var tileMapNode = node2D.GetNode("TileMap");
NodeUtils.ForEachNode(tileMapNode, node =>
{
_tileMapLayers ??= [];
_tileMapLayers.Add(node);
return false;
});
_area2D = node2D.GetNode("RoomArea");
_area2D.Monitoring = true;
_area2D.SetCollisionLayerValue(Config.LayerNumber.RoomArea, true);
//Sets the collision layer that can be detected in the current room area.
//设置当前房间区域可检测到的碰撞层。
_area2D.SetCollisionMaskValue(Config.LayerNumber.Player, true);
_area2D.BodyExited += OnExitRoom;
_area2D.BodyEntered += OnEnterRoom;
_collisionShape2D = _area2D.GetChild(0);
_roomSlots = GetRoomSlots(GetTileMapLayer(Config.TileMapLayerName.Ground), _area2D,
node2D.GetNode("RoomSlotList"));
}
public Node2D? RootNode => _rootNode;
public RoomSlot?[]? RoomSlots => _roomSlots;
///
/// GetRoomSlots
/// 在房间内获取所有插槽
///
///
///
///
///
private RoomSlot?[]? GetRoomSlots(TileMapLayer? tileMapLayer, Area2D roomArea2D, Node2D slotList)
{
if (tileMapLayer == null)
{
return null;
}
var slotCount = slotList.GetChildCount();
if (slotCount == 0)
{
return null;
}
//We calculate the midpoint of the room
//我们计算房间的中点
var roomAreaCollisionShape2D = roomArea2D.GetChild(0);
var roomAreaRect2 = roomAreaCollisionShape2D.Shape.GetRect();
var midpoint = roomAreaCollisionShape2D.Position + roomAreaRect2.Position + roomAreaRect2.Size / 2;
var roomSlots = new List();
for (var i = 0; i < slotCount; i++)
{
//Got the object in the room slot
//拿到了房间槽对象
var area2D = slotList.GetChild(i);
//Prevent other areas from detecting the room slot
//禁止其他区域检测到房间槽
area2D.Monitorable = false;
var collisionShape2D = area2D.GetChild(0);
var rect2 = collisionShape2D.Shape.GetRect();
//Round the size of the impactor to the tile size For example, the impactor size 44 is converted to the tile size 44/32=1.375 rounded to 1
//将碰撞体的尺寸四舍五入到瓦片尺寸例如:碰撞体尺寸44,转为瓦片尺寸为 44/32=1.375 四舍五入为1
var intSize = new Vector2I((int)Math.Round(rect2.Size.X / Config.CellSize),
(int)Math.Round(rect2.Size.Y / Config.CellSize));
if (intSize.X > 1 && intSize.Y > 1)
{
LogCat.LogError("width_or_height_of_room_slot_must_be_1");
continue;
}
//Gets the absolute position of the slot
//获取槽位的绝对位置
var startPosition = area2D.Position + collisionShape2D.Position + rect2.Position;
var endPosition = area2D.Position + collisionShape2D.Position + rect2.Position + rect2.Size;
var midpointOfRoomSlots = area2D.Position + collisionShape2D.Position + rect2.Position + rect2.Size / 2;
//Convert to tile map coordinates (midpoint)
//转为瓦片地图的坐标(中点)
var tileMapStartPosition = tileMapLayer.LocalToMap(startPosition);
var tileMapEndPosition = tileMapLayer.LocalToMap(endPosition);
var roomSlot = new RoomSlot
{
EndPosition = tileMapEndPosition,
StartPosition = tileMapStartPosition,
//Calculate the orientation of the slot (the midpoint of the room is the origin, the vector pointing to the midpoint of the slot)
//计算槽位的方向(房间中点为原点,指向槽位中点的向量)
DistanceToMidpointOfRoom = CoordinateUtils.VectorToOrientationArray(midpoint, midpointOfRoomSlots)
};
roomSlots.Add(roomSlot);
}
return roomSlots.ToArray();
}
}