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

259 lines
12 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.Collections.Generic;
using System.Threading.Tasks;
using Managers;
using Newtonsoft.Json;
using UnityEngine;
using Utils;
using Random = UnityEngine.Random;
// 引入 System.Threading.Tasks
namespace Map
{
/// <summary>
/// 植物生成器配置类。
/// </summary>
public class PlantGeneratorConfig
{
/// <summary>
/// 植物瓦片的定义名称。
/// </summary>
[JsonProperty("tileDefName", Required = Required.Always)]
public string TileDefName { get; set; } = "DefaultPlantTile";
/// <summary>
/// 柏林噪声的缩放因子。
/// </summary>
[JsonProperty("scale")]
public double Scale { get; set; } = 0.08;
/// <summary>
/// 柏林噪声阈值,高于此值才可能生成植物 (-1到1之间)。
/// </summary>
[JsonProperty("threshold")]
public double Threshold { get; set; } = 0.3;
/// <summary>
/// 植物生成概率 (0-1之间),控制稀疏度。
/// </summary>
[JsonProperty("density")]
public double Density { get; set; } = 0.6;
/// <summary>
/// 柏林噪声的X轴偏移。
/// </summary>
[JsonProperty("offsetX")]
public double OffsetX { get; set; }
/// <summary>
/// 柏林噪声的Y轴偏移。
/// </summary>
[JsonProperty("offsetY")]
public double OffsetY { get; set; }
/// <summary>
/// 植物必须生长在其上的基础瓦片名称列表 (满足其中任意一个即可,可空)。
/// </summary>
[JsonProperty("requiredBaseTileDefNames")] // 属性名改为复数形式
public List<string> RequiredBaseTileDefNames { get; set; }
/// <summary>
/// 地图生成区域的宽度(单元格数量)。
/// </summary>
[JsonProperty("mapCellSizeX")]
public int MapCellSizeX { get; set; } = 100;
/// <summary>
/// 地图生成区域的高度(单元格数量)。
/// </summary>
[JsonProperty("mapCellSizeY")]
public int MapCellSizeY { get; set; } = 100;
/// <summary>
/// 是否避免植物瓦片互相重叠。
/// </summary>
[JsonProperty("preventOverlap")]
public bool PreventOverlap { get; set; } = true;
}
public class PlantMapGenerator : MapGeneratorWorkClassBase
{
private PlantGeneratorConfig _config;
private HashSet<string> _requiredBaseTileNames; // 缓存所需基底瓦片的运行时名称集合
/// <summary>
/// 初始化植物生成器解析JSON配置字符串。
/// </summary>
/// <param name="value">包含植物生成参数的JSON字符串。</param>
public override void Init(string value)
{
try
{
_config = JsonConvert.DeserializeObject<PlantGeneratorConfig>(value);
if (_config == null)
{
Debug.LogError("植物地图生成器配置反序列化为空。请检查JSON格式。将使用默认配置。");
_config = new PlantGeneratorConfig();
}
if (string.IsNullOrWhiteSpace(_config.TileDefName))
{
Debug.LogWarning("植物地图生成器:瓦片定义名称为空。将使用默认值 'DefaultPlantTile'。");
_config.TileDefName = "DefaultPlantTile";
}
if (_config.Scale <= 0)
{
Debug.LogWarning($"植物地图生成器:缩放值必须为正数。将设置为默认值 0.08。当前值: {_config.Scale}");
_config.Scale = 0.08;
}
// Unity的Mathf.PerlinNoise输出0-1如果PerlinNoise.Instance.Noise也如此这里需要修改范围
// 假设 PerlinNoise.Instance.Noise() 返回值在 -1 到 1 之间。
if (_config.Threshold < -1.0 || _config.Threshold > 1.0)
{
Debug.LogWarning($"植物地图生成器:阈值 ({_config.Threshold}) 超出柏林噪声典型范围 (-1.0到1.0)。已钳制到 0.3。");
_config.Threshold = 0.3;
}
if (_config.Density < 0 || _config.Density > 1)
{
Debug.LogWarning($"植物地图生成器:密度 ({_config.Density}) 必须在 0 到 1 之间。已钳制到 0.6。");
_config.Density = Mathf.Clamp((float)_config.Density, 0f, 1f);
}
if (_config.MapCellSizeX <= 0)
{
Debug.LogWarning($"植物地图生成器:地图宽度 ({_config.MapCellSizeX}) 必须为正数。将设置为默认值 100。");
_config.MapCellSizeX = 100;
}
if (_config.MapCellSizeY <= 0)
{
Debug.LogWarning($"植物地图生成器:地图高度 ({_config.MapCellSizeY}) 必须为正数。将设置为默认值 100。");
_config.MapCellSizeY = 100;
}
// 预加载所需的基础瓦片名称集合
if (_config.RequiredBaseTileDefNames != null && _config.RequiredBaseTileDefNames.Count > 0)
{
_requiredBaseTileNames = new HashSet<string>();
foreach (var defName in _config.RequiredBaseTileDefNames)
{
if (string.IsNullOrEmpty(defName))
{
Debug.LogWarning("植物地图生成器:配置中包含空的基底瓦片定义名称。已跳过。");
continue;
}
var baseAsset = TileManager.Instance.GetTile(defName);
if (baseAsset != null)
_requiredBaseTileNames.Add(baseAsset.name);
else
// 注意在Init阶段我们只检查资产是否存在不检查Tilemap。
Debug.LogWarning(
$"植物地图生成器:无法获取所需的基础瓦片 '{defName}' 的资产。该瓦片将不作为有效基底条件。");
}
// 如果最终没有有效基底瓦片被加载则将HashSet设为null表示不进行此条件检查
if (_requiredBaseTileNames.Count == 0) _requiredBaseTileNames = null;
}
else
{
// 如果配置中未指定基底瓦片列表或者列表为空显式设置为null以表示无需检查此条件
_requiredBaseTileNames = null;
}
}
catch (JsonSerializationException ex)
{
Debug.LogError($"植物地图生成器配置JSON反序列化错误{ex.Message}。输入JSON: '{value}'");
_config = new PlantGeneratorConfig();
}
catch (Exception ex)
{
Debug.LogError($"植物地图生成器:初始化过程中发生未预期错误:{ex.Message}。输入JSON: '{value}'");
_config = new PlantGeneratorConfig();
}
}
/// <summary>
/// 根据柏林噪声和配置参数在 `MapGenerator` 的 `plantTilemap` 上生成植物。
/// 此方法现在是异步的,以避免阻塞主线程。
/// </summary>
/// <param name="landform">MapGenerator实例包含要操作的Tilemap。</param>
public override async Task Process(Landform landform) // 标记为 async Task
{
if (_config == null)
{
Debug.LogError("植物地图生成器在Init方法调用前或Init失败后调用Process。中止生成。");
return; // async Task 方法直接 return; 意味着返回 Task.CompletedTask
}
// 检查 MapGenerator 和所有需要的 Tilemap 是否都已赋值
if (landform == null || landform.plantTilemap == null || landform.baseTilemap == null)
{
Debug.LogError("植物地图生成器MapGenerator或植物瓦片地图或基础瓦片地图为空。无法生成植物。中止。");
return;
}
var plantTile = TileManager.Instance.GetTile(_config.TileDefName);
if (plantTile == null)
{
Debug.LogError($"植物地图生成器:无法获取名称为 '{_config.TileDefName}' 的瓦片。请确保瓦片管理器返回有效瓦片。中止生成。");
return;
}
// 判断是否有基底瓦片条件被配置
var hasRequiredBaseTilesConfigured = _requiredBaseTileNames != null && _requiredBaseTileNames.Count > 0;
// 如果配置了基底瓦片要求,但基础瓦片地图不可用,则无法进行检查,视为条件无法满足,直接中止生成
// (这里的 map.baseTilemap == null 已经在函数开头检查过所以这里逻辑上它不会是null)
if (hasRequiredBaseTilesConfigured && landform.baseTilemap == null) // 理论上这个条件不会再发生
{
Debug.LogWarning("植物地图生成器:已配置基础瓦片名称列表但基础瓦片地图为空。植物生成将无法满足基础地形要求,因此不会生成任何受此条件限制的植物。");
// 此时应该终止,因为不可能满足条件
return;
}
for (var x = 0; x < _config.MapCellSizeX; x++)
{
for (var y = 0; y < _config.MapCellSizeY; y++)
{
var cellPosition = new Vector3Int(x, y, 0);
var sampleX = x / (double)_config.MapCellSizeX * _config.Scale + _config.OffsetX;
var sampleY = y / (double)_config.MapCellSizeY * _config.Scale + _config.OffsetY;
var noiseValue = PerlinNoise.Instance.Noise(sampleX, sampleY);
if (noiseValue < _config.Threshold) continue;
// 检查所需的基础瓦片 (仅当有条件被配置时)
if (hasRequiredBaseTilesConfigured)
{
var baseTileOnMap = landform.baseTilemap.GetTile(cellPosition);
// 如果当前位置没有瓦片، 或瓦片名称不在允许的条件列表中، 则条件不满足
if (baseTileOnMap == null || !_requiredBaseTileNames.Contains(baseTileOnMap.name)) continue;
}
// 检查是否重叠
if (_config.PreventOverlap)
{
var existingPlant = landform.plantTilemap.GetTile(cellPosition);
if (existingPlant != null) continue;
}
// 检查密度
if (Random.value >= _config.Density) continue;
landform.plantTilemap.SetTile(cellPosition, plantTile);
}
// 每处理完一列,就让出控制权给主线程
await Task.Yield();
}
}
public override Vector2Int GetSize()
{
if (_config == null) return Vector2Int.zero;
return new Vector2Int(_config.MapCellSizeX, _config.MapCellSizeY);
}
}
}