mirror of
http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite.git
synced 2025-11-20 03:47:13 +08:00
Co-authored-by: m0_75251201 <m0_75251201@noreply.gitcode.com> Reviewed-on: http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite/pulls/57
250 lines
13 KiB
C#
250 lines
13 KiB
C#
using System.Collections.Generic;
|
||
using System.Threading.Tasks;
|
||
using Managers;
|
||
using Newtonsoft.Json;
|
||
using UnityEngine;
|
||
using UnityEngine.Tilemaps;
|
||
|
||
namespace Map
|
||
{
|
||
public class ConditionalTileGeneratorConfig
|
||
{
|
||
// ====== 生成瓦片配置 ======
|
||
[JsonProperty("outputTileDefName", Required = Required.Always)]
|
||
public string OutputTileDefName { get; set; }
|
||
[JsonProperty("outputLayer", Required = Required.Always)]
|
||
public string OutputLayer { get; set; } // "base", "building", "plant"
|
||
// ====== 条件检查配置 ======
|
||
[JsonProperty("conditionTileDefNames")] // 属性名改为复数形式
|
||
public List<string> ConditionTileDefNames { get; set; } = null; // 如果非空,则只有在目标层有此瓦片列表中的任意一个时才生成
|
||
[JsonProperty("conditionLayer")]
|
||
public string ConditionLayer { get; set; } = null; // 检查条件瓦片的层
|
||
// ====== 区域配置 ======
|
||
[JsonProperty("positionX", Required = Required.Always)]
|
||
public int PositionX { get; set; } = 0; // 起始位置X
|
||
[JsonProperty("positionY", Required = Required.Always)]
|
||
public int PositionY { get; set; } = 0; // 起始位置Y
|
||
[JsonProperty("width", Required = Required.Always)]
|
||
public int Width { get; set; } = 1; // 区域宽度
|
||
[JsonProperty("height", Required = Required.Always)]
|
||
public int Height { get; set; } = 1; // 区域高度
|
||
// ====== 柏林噪声配置 ======
|
||
[JsonProperty("usePerlinNoise")]
|
||
public bool UsePerlinNoise { get; set; } = false;
|
||
[JsonProperty("perlinScale")]
|
||
public float PerlinScale { get; set; } = 10f; // 柏林噪声频率,数值越大越粗糙
|
||
[JsonProperty("perlinThreshold")]
|
||
public float PerlinThreshold { get; set; } = 0.5f; // 柏林噪声阈值,只有噪声值高于此值才生成瓦片
|
||
[JsonProperty("perlinOffsetX")]
|
||
public float PerlinOffsetX { get; set; } = 0f; // 柏林噪声X偏移
|
||
[JsonProperty("perlinOffsetY")]
|
||
public float PerlinOffsetY { get; set; } = 0f; // 柏林噪声Y偏移
|
||
}
|
||
|
||
public class ConditionalTileGenerator : MapGeneratorWorkClassBase
|
||
{
|
||
private ConditionalTileGeneratorConfig _config;
|
||
private TileBase _outputTileBase; // 缓存要生成的实际 TileBase 资源
|
||
private HashSet<string> _conditionTileBaseNames; // 缓存条件瓦片的运行时名称集合
|
||
/// <summary>
|
||
/// 初始化条件瓦片生成器,解析JSON配置并预加载资源。
|
||
/// </summary>
|
||
/// <param name="value">包含ConditionalTileGeneratorConfig的JSON字符串。</param>
|
||
public override void Init(string value)
|
||
{
|
||
if (string.IsNullOrEmpty(value))
|
||
{
|
||
Debug.LogError("ConditionalTileGenerator: Init received empty or null JSON value.");
|
||
return;
|
||
}
|
||
try
|
||
{
|
||
_config = JsonConvert.DeserializeObject<ConditionalTileGeneratorConfig>(value);
|
||
if (_config == null)
|
||
{
|
||
Debug.LogError(
|
||
"ConditionalTileGenerator: Failed to deserialize ConditionalTileGeneratorConfig from JSON.");
|
||
return;
|
||
}
|
||
// 预加载输出瓦片
|
||
if (!string.IsNullOrEmpty(_config.OutputTileDefName))
|
||
{
|
||
_outputTileBase = TileManager.Instance.GetTile(_config.OutputTileDefName);
|
||
if (_outputTileBase == null)
|
||
{
|
||
Debug.LogWarning(
|
||
$"ConditionalTileGenerator: Output tile asset for '{_config.OutputTileDefName}' not found via TileManager. Generation may fail.");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Debug.LogError(
|
||
"ConditionalTileGenerator: OutputTileDefName is required but not provided in config.");
|
||
return;
|
||
}
|
||
// 预加载条件瓦片的名称集合 (如果指定)
|
||
if (_config.ConditionTileDefNames != null && _config.ConditionTileDefNames.Count > 0)
|
||
{
|
||
_conditionTileBaseNames = new HashSet<string>();
|
||
foreach (var defName in _config.ConditionTileDefNames)
|
||
{
|
||
if (string.IsNullOrEmpty(defName))
|
||
{
|
||
Debug.LogWarning("ConditionalTileGenerator: Found empty or null condition tile definition name in config. Skipping.");
|
||
continue;
|
||
}
|
||
var conditionAsset = TileManager.Instance.GetTile(defName);
|
||
if (conditionAsset != null)
|
||
{
|
||
_conditionTileBaseNames.Add(conditionAsset.name);
|
||
}
|
||
else
|
||
{
|
||
Debug.LogWarning(
|
||
$"ConditionalTileGenerator: Condition tile asset for '{defName}' not found via TileManager. This specific condition tile will be ignored in checks.");
|
||
}
|
||
}
|
||
// 如果最终没有有效条件瓦片被加载,则将HashSet设为null,表示不进行此条件检查
|
||
if (_conditionTileBaseNames.Count == 0)
|
||
{
|
||
_conditionTileBaseNames = null;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 如果配置中未指定条件瓦片列表,或者列表为空,显式设置为null以表示无需检查此条件
|
||
_conditionTileBaseNames = null;
|
||
}
|
||
}
|
||
catch (JsonException ex)
|
||
{
|
||
Debug.LogError($"ConditionalTileGenerator: JSON deserialization error: {ex.Message}\nJSON: {value}");
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 获取条件瓦片生成器将影响的区域大小。
|
||
/// </summary>
|
||
/// <returns>表示区域宽和高的Vector2Int。</returns>
|
||
public override Vector2Int GetSize()
|
||
{
|
||
if (_config == null)
|
||
{
|
||
return Vector2Int.zero;
|
||
}
|
||
return new Vector2Int(_config.Width, _config.Height);
|
||
}
|
||
/// <summary>
|
||
/// 执行条件瓦片生成逻辑。
|
||
/// </summary>
|
||
/// <param name="landform">MapGenerator实例,提供Tilemap和坐标转换功能。</param>
|
||
public override async Task Process(Landform landform)
|
||
{
|
||
if (_config == null || _outputTileBase == null)
|
||
{
|
||
Debug.LogError("ConditionalTileGenerator: Configuration or output tile not properly initialized.");
|
||
return;
|
||
}
|
||
if (landform == null || landform.baseTilemap == null || landform.buildingTilemap == null || landform.plantTilemap == null)
|
||
{
|
||
Debug.LogError("ConditionalTileGenerator: MapGenerator or its Tilemaps are not assigned.");
|
||
return;
|
||
}
|
||
// 获取输出层 Tilemap
|
||
var outputTilemap = GetTilemapByName(landform, _config.OutputLayer);
|
||
if (outputTilemap == null)
|
||
{
|
||
Debug.LogError(
|
||
$"ConditionalTileGenerator: Output Tilemap '{_config.OutputLayer}' not found or invalid.");
|
||
return;
|
||
}
|
||
// 获取条件层 Tilemap (如果需要检查条件瓦片)
|
||
Tilemap conditionTilemap = null;
|
||
// 只有当有实际的条件瓦片名称列表配置时才尝试获取条件层Tilemap
|
||
bool hasConditionTileNamesConfigured = (_conditionTileBaseNames != null && _conditionTileBaseNames.Count > 0);
|
||
if (hasConditionTileNamesConfigured)
|
||
{
|
||
if (string.IsNullOrEmpty(_config.ConditionLayer))
|
||
{
|
||
Debug.LogWarning(
|
||
"ConditionalTileGenerator: 'ConditionTileDefNames' specified, but 'ConditionLayer' is not. Condition check related to specific tiles will implicitly fail for the tile conditions.");
|
||
// 此时不设置 conditionTilemap,会在循环内部触发 conditionsMet = false
|
||
}
|
||
else
|
||
{
|
||
conditionTilemap = GetTilemapByName(landform, _config.ConditionLayer);
|
||
if (conditionTilemap == null)
|
||
{
|
||
Debug.LogError(
|
||
$"ConditionalTileGenerator: Condition Tilemap '{_config.ConditionLayer}' not found or invalid. Condition check related to specific tiles will implicitly fail for the tile conditions.");
|
||
// 此时不设置 conditionTilemap,会在循环内部触发 conditionsMet = false
|
||
}
|
||
}
|
||
}
|
||
for (var y = 0; y < _config.Height; y++)
|
||
{
|
||
for (var x = 0; x < _config.Width; x++)
|
||
{
|
||
var currentGridPos = new Vector3Int(_config.PositionX + x, _config.PositionY + y, 0);
|
||
var conditionsMet = true;
|
||
// 1. 检查条件瓦片 (仅当有有效的条件瓦片和条件层Tilemap时执行)
|
||
if (conditionsMet && hasConditionTileNamesConfigured) // 只有配置了条件瓦片才进行进一步检查
|
||
{
|
||
if (conditionTilemap != null) // 确保条件层Tilemap有效
|
||
{
|
||
var tileOnConditionLayer = conditionTilemap.GetTile(currentGridPos);
|
||
// 如果当前位置没有瓦片,或者瓦片名称不在允许的条件列表中,则条件不满足
|
||
if (tileOnConditionLayer == null || !_conditionTileBaseNames.Contains(tileOnConditionLayer.name))
|
||
{
|
||
conditionsMet = false; // 条件不满足
|
||
// Debug.Log($"Skipping {currentGridPos}: Condition tile not found or not in allowed list.");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 如果 hasConditionTileNamesConfigured 为 true, 但 conditionTilemap 为 null (因为_config.ConditionLayer为空或GetTilemapByName失败)
|
||
// 那么条件瓦片检查无法进行,应该视为条件不满足
|
||
conditionsMet = false;
|
||
}
|
||
}
|
||
// 2. 检查柏林噪声
|
||
if (conditionsMet && _config.UsePerlinNoise)
|
||
{
|
||
var sampleX = (currentGridPos.x + _config.PerlinOffsetX) / _config.PerlinScale;
|
||
var sampleY = (currentGridPos.y + _config.PerlinOffsetY) / _config.PerlinScale;
|
||
var perlinValue = Mathf.PerlinNoise(sampleX, sampleY);
|
||
if (perlinValue < _config.PerlinThreshold)
|
||
{
|
||
conditionsMet = false; // 噪声条件不满足
|
||
// Debug.Log($"Skipping {currentGridPos}: Perlin noise {perlinValue:F2} below threshold {_config.PerlinThreshold:F2}.");
|
||
}
|
||
}
|
||
// 如果所有条件都满足,则放置瓦片
|
||
if (conditionsMet)
|
||
{
|
||
outputTilemap.SetTile(currentGridPos, _outputTileBase);
|
||
// Debug.Log($"ConditionalTileGenerator: Placed '{_config.OutputTileDefName}' at {currentGridPos}.");
|
||
}
|
||
}
|
||
await Task.Yield(); // 允许在每行结束时暂停,避免阻塞
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 根据名称字符串获取 MapGenerator 中的对应 Tilemap。
|
||
/// </summary>
|
||
private Tilemap GetTilemapByName(Landform landform, string tilemapName)
|
||
{
|
||
switch (tilemapName?.ToLower()) // 使用ToLower以便不区分大小写
|
||
{
|
||
case "base":
|
||
return landform.baseTilemap;
|
||
case "building":
|
||
return landform.buildingTilemap;
|
||
case "plant":
|
||
return landform.plantTilemap;
|
||
default:
|
||
Debug.LogWarning($"ConditionalTileGenerator: Unknown Tilemap name '{tilemapName}'.");
|
||
return null;
|
||
}
|
||
}
|
||
}
|
||
} |