Files
Gen_Hack-and-Slash-Roguelite/Client/Assets/Scripts/Map/Dimension.cs

137 lines
5.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Threading.Tasks;
using Configs;
using Data;
using Managers;
using UnityEngine;
using UnityEngine.Tilemaps;
namespace Map
{
/// <summary>
/// 表示游戏中的一个维度或场景区域。
/// 实体管理器将根据此维度来组织和管理实体。
/// </summary>
public class Dimension : MonoBehaviour
{
[SerializeField] private bool defaultOpen;
[SerializeField] [Tooltip("此维度的唯一标识符。如果为空将使用GameObject的名称。")]
private string _dimensionId;
[SerializeField] public Landform landform;
public Vector3 cameraPosition = new(0, 0, -10);
public Entity.Entity focusEntity;
public TileBase airWall;
public DimensionDef dimensionDefinition;
public Vector2Int DimensionSize { get; private set; }
/// <summary>
/// 获取此维度的唯一标识符。
/// </summary>
public string DimensionId
{
get
{
if (string.IsNullOrEmpty(_dimensionId)) _dimensionId = Guid.NewGuid().ToString();
return _dimensionId;
}
// 内部设置器允许在Awake中初始化或编辑器中赋值
private set => _dimensionId = value;
}
/// <summary>
/// 此维度下所有实体的根Transform。用于组织场景层级。
/// </summary>
public Transform DimensionRoot { get; private set; }
private void Awake()
{
if (!airWall) airWall = Resources.Load<TileBase>("Tile/AirWall");
var id = DimensionId; // 确保 DimensionId 已初始化
var rootObj = new GameObject($"_Entities_{id}");
rootObj.transform.SetParent(transform);
DimensionRoot = rootObj.transform;
Program.Instance.RegisterDimension(this);
if (defaultOpen) Program.Instance.SetFocusedDimension(_dimensionId);
var mapGeneratorId = ConfigManager.Instance.GetValue<string>(DimensionId);
if (!string.IsNullOrEmpty(mapGeneratorId))
{
dimensionDefinition = DefineManager.Instance.FindDefine<DimensionDef>(mapGeneratorId);
if (dimensionDefinition != null) _ = ApplyDimensionDef(dimensionDefinition);
}
}
private void OnDestroy()
{
if (Program.Instance != null) // 检查单例是否仍然存在
Program.Instance.UnregisterDimension(this);
}
public event Action<Dimension> OnDimensionLoaded;
/// <summary>
/// 应用维度定义,生成地图并设置边界。
/// </summary>
/// <param name="def">要应用的维度定义。</param>
public async Task ApplyDimensionDef(DimensionDef def)
{
dimensionDefinition = def;
landform.Clear();
var maxWidth = DimensionSize.x;
var maxHeight = DimensionSize.y;
if (def.mapGenerators != null)
{
foreach (var defMapGenerator in def.mapGenerators)
{
var workClass = TileManager.Instance.GetMapGeneratorWorkClass(defMapGenerator.defName);
if (workClass == null) continue;
var requiredSize = workClass.GetSize();
maxWidth = Mathf.Max(maxWidth, requiredSize.x);
maxHeight = Mathf.Max(maxHeight, requiredSize.y);
}
DimensionSize = new Vector2Int(maxWidth, maxHeight);
cameraPosition = new Vector3(DimensionSize.x / 2f, DimensionSize.y / 2f, -10) + transform.position;
landform.InitEntityCollisionArray(DimensionSize, new Vector2Int());
foreach (var defMapGenerator in def.mapGenerators)
await TileManager.Instance.ApplyMapGenerator(defMapGenerator.defName, landform);
}
var size = landform.GetSize();
var origin = landform.GetOrigin();
var minX = origin.x;
var minY = origin.y;
var maxX = origin.x + size.x - 1;
var maxY = origin.y + size.y - 1;
const int borderWidth = 1;
var airWallZ = origin.z;
// 绘制上下边界
for (var x = minX - borderWidth; x <= maxX + borderWidth; x++)
{
landform.SetBaseTile(airWall, new Vector3Int(x, maxY + borderWidth, airWallZ));
landform.SetBaseTile(airWall, new Vector3Int(x, minY - borderWidth, airWallZ));
}
// 绘制左右边界
for (var y = minY - borderWidth + 1; y <= maxY + borderWidth - 1; y++)
{
landform.SetBaseTile(airWall, new Vector3Int(minX - borderWidth, y, airWallZ)); // 左侧
landform.SetBaseTile(airWall, new Vector3Int(maxX + borderWidth, y, airWallZ)); // 右侧
}
OnDimensionLoaded?.Invoke(this);
}
}
}