Files
Gen_Hack-and-Slash-Roguelite/Client/Assets/Scripts/Managers/TileManager.cs

190 lines
8.2 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.

// Managers/TileManager.cs
using System;
using Data;
using Utils;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Map;
using UnityEngine;
using UnityEngine.Tilemaps;
using Object = UnityEngine.Object;
namespace Managers
{
public class TileManager : Singleton<TileManager>, ILaunchManager
{
public string StepDescription => "正在加载瓦片";
// 缓存所有根据定义生成的RuleTile实例
private Dictionary<string, RuleTile> _cachedTiles = new();
// 地图生成器工作类映射Key: MapGeneratorDef.defName, Value: MapGeneratorWorkClassBase
private Dictionary<string,MapGeneratorWorkClassBase> _mapGeneratorWorkClassMap = new();
public void Init()
{
// 如果已缓存瓦片,则直接返回
if (_cachedTiles.Any())
return;
var tileDefs = DefineManager.Instance.QueryDefinesByType<TileDef>();
// 第一次遍历创建RuleTile实例并填充除特定瓦片引用specificTileName外的所有简单字段
foreach (var def in tileDefs)
{
if (string.IsNullOrEmpty(def.defName))
{
Debug.LogWarning($"发现未定义名称或defName的TileDef已跳过。");
continue;
}
var tileName = def.defName;
var ruleTile = ScriptableObject.CreateInstance<RuleTile>();
ruleTile.name = tileName; // 设置ScriptableObject的名称
ruleTile.m_DefaultColliderType = def.collider;
ruleTile.m_DefaultSprite = PackagesImageManager.Instance.GetSprite(def.texture);
ruleTile.m_TilingRules = GetTileRules(def.rules);
_cachedTiles[tileName] = ruleTile;
}
var generatorDefs = DefineManager.Instance.QueryDefinesByType<MapGeneratorDef>();
foreach (var mapGeneratorDef in generatorDefs)
{
var workClass = StringUtils.CreateMapGeneratorInstance(mapGeneratorDef.workClass);
if(workClass == null)
{
Debug.LogWarning($"无法为地图生成器 '{mapGeneratorDef.defName}' 创建工作类 '{mapGeneratorDef.workClass}',已跳过。");
continue;
}
workClass.Init(mapGeneratorDef.value);
_mapGeneratorWorkClassMap[mapGeneratorDef.defName] = workClass;
}
}
public void Clear()
{
foreach (var tile in _cachedTiles.Values)
{
if (tile != null)
{
Object.Destroy(tile);
}
}
_cachedTiles.Clear();
_mapGeneratorWorkClassMap.Clear(); // 清空地图生成器工作类映射
}
private static List<RuleTile.TilingRule> GetTileRules(RuleTileRuleDef[] rules)
{
return rules.Select(GetTileRule).ToList();
}
/// <summary>
/// 将自定义的 RuleTileRuleDef 转换为 Unity 的 RuleTile.TilingRule。
/// </summary>
/// <param name="ruleDef">自定义的 RuleTileRuleDef 规则定义。</param>
/// <returns>转换后的 RuleTile.TilingRule 实例。</returns>
private static RuleTile.TilingRule GetTileRule(RuleTileRuleDef ruleDef)
{
var tilingRule = new RuleTile.TilingRule
{
m_Sprites = PackagesImageManager.Instance.GetSprites(ruleDef.animationTextures.ToArray()),
m_Output = ruleDef.outputType,
m_ColliderType = ruleDef.outputCollider,
m_PerlinScale = ruleDef.chance,
m_MaxAnimationSpeed = ruleDef.animationSpeed,
m_MinAnimationSpeed = ruleDef.animationSpeed,
m_RuleTransform = ruleDef.transform
};
var tilePositions = new List<Vector3Int>();
for (var i = 0; i < ruleDef.neighborConditions.Length && i < 8; i++)
{
switch(ruleDef.neighborConditions[i])
{
case RuleTileRuleDef.NeighborConditionType.NotThis:
tilingRule.m_Neighbors.Add(RuleTile.TilingRuleOutput.Neighbor.NotThis);
break;
case RuleTileRuleDef.NeighborConditionType.This:
tilingRule.m_Neighbors.Add(RuleTile.TilingRuleOutput.Neighbor.This);
break;
case RuleTileRuleDef.NeighborConditionType.Any:
default:
// 忽略 Any 类型因为其不会添加到m_Neighbors中
continue;
}
tilePositions.Add(tilingRule.m_NeighborPositions[i]);
}
tilingRule.m_NeighborPositions = tilePositions;
return tilingRule;
}
/// <summary>
/// 根据名称获取一个 RuleTile 实例。
/// </summary>
/// <param name="tileName">瓦片的名称 (TileDef.defName)</param>
/// <returns>对应的 RuleTile 实例,如果找不到则返回 null。</returns>
public TileBase GetTile(string tileName)
{
if (_cachedTiles.TryGetValue(tileName, out var tile))
{
return tile;
}
Debug.LogWarning($"瓦片 '{tileName}' 未在TileManager缓存中找到。");
return null;
}
/// <summary>
/// 应用指定的地图生成器,现在是非阻塞的异步操作。
/// </summary>
/// <param name="generatorName">要应用的生成器名称。</param>
/// <param name="mapGenerator">可选:指定要使用的 MapGenerator 实例。如果为 null将尝试从 Program.Instance.FocusedDimension 获取。</param>
/// <returns>一个表示异步操作完成的 Task。</returns>
public async Task ApplyMapGenerator(string generatorName, MapGenerator mapGenerator = null) // <-- 返回 Task并标记为 async
{
if (mapGenerator == null)
{
// 尝试从 Program.Instance.FocusedDimension 获取 mapGenerator
// 假设 Program 和 FocusedDimension 结构存在
mapGenerator = Program.Instance?.FocusedDimension?.mapGenerator;
if (mapGenerator == null)
{
Debug.LogError($"ApplyMapGenerator: 无法找到地图生成器 '{generatorName}' 对应的 mapGenerator。Program.Instance、FocusedDimension 或其 mapGenerator 可能为空。");
return; // async Task 方法直接 return; 意味着返回 Task.CompletedTask
}
}
if (_mapGeneratorWorkClassMap == null)
{
Debug.LogError($"ApplyMapGenerator: _mapGeneratorWorkClassMap 未初始化,无法找到生成器 '{generatorName}'。");
return;
}
if (_mapGeneratorWorkClassMap.TryGetValue(generatorName, out var mapGeneratorWorkClass))
{
if (mapGeneratorWorkClass == null)
{
Debug.LogError($"ApplyMapGenerator: 为生成器 '{generatorName}' 找到了一个空的 IMapGeneratorWorkClass 实例。这表明 _mapGeneratorWorkClassMap 配置存在问题。");
return;
}
try
{
await mapGeneratorWorkClass.Process(mapGenerator); // <-- 使用 await 调用异步 Process 方法
}
catch (Exception ex)
{
Debug.LogError($"ApplyMapGenerator: 地图生成器 '{generatorName}' 异步处理过程中发生错误: {ex.Message}");
// 可以在这里根据需要决定是否重新抛出异常
throw; // 抛出异常以通知调用者,或者根据实际情况选择捕获并完全处理
}
}
else
{
Debug.LogError($"ApplyMapGenerator: 未找到名为 '{generatorName}' 的 IMapGeneratorWorkClass。请确保该生成器已在 _mapGeneratorWorkClassMap 中注册。");
}
}
}
}