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

204 lines
9.9 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 Managers;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Tilemaps;
using Utils;
namespace Map
{
public enum MapDimension
{
Base = 0, // 对应 Landform.baseTilemap
Building = 1, // 对应 Landform.buildingTilemap
Plant = 2 // 对应 Landform.plantTilemap
}
public class BasicTerrainGeneratorConfig
{
[JsonProperty("tileDefName", Required = Required.Always)]
public string TileDefName { get; set; } = "DefaultTerrainTile"; // 瓦片的定义名称
// 将 Threshold 改为 MinThreshold并保持旧的JsonProperty名称以兼容旧JSON
[JsonProperty("threshold")]
public double MinThreshold { get; set; } // 柏林噪声的最小阈值。-1到1之间。将其默认值改为0.0以适应-1到1的噪声范围并提供更灵活的区间开始。
[JsonProperty("maxThreshold")] public double MaxThreshold { get; set; } = 1.0; // 柏林噪声的最大阈值。-1到1之间。默认为1.0以兼容旧配置。
[JsonProperty("elseTileDefName")]
public string ElseTileDefName { get; set; } // 不满足Min/MaxThreshold范围时放置的瓦片定义名称默认为null表示不放置。
[JsonProperty("scale")] public double Scale { get; set; } = 0.1; // 柏林噪声的缩放因子,控制地形特征的大小
[JsonProperty("offsetX")] public double OffsetX { get; set; } // 柏林噪声的X轴偏移
[JsonProperty("offsetY")] public double OffsetY { get; set; } // 柏林噪声的Y轴偏移
[JsonProperty("mapCellSizeX")] public int MapCellSizeX { get; set; } = 100; // 地图生成区域的宽度(单元格数量)
[JsonProperty("mapCellSizeY")] public int MapCellSizeY { get; set; } = 100; // 地图生成区域的高度(单元格数量)
[JsonProperty("targetDimension")] public MapDimension TargetDimension { get; set; } = MapDimension.Base;
// 新增地图生成区域的起始X坐标单元格数量
[JsonProperty("originX")] public int OriginX { get; set; }
// 新增地图生成区域的起始Y坐标单元格数量
[JsonProperty("originY")] public int OriginY { get; set; }
}
// MapDimension 枚举在此文件中不重复定义,因为它通常位于自己的文件中或 Map 命名空间的其他通用文件中。
// 如果它与 BasicTerrainGeneratorConfig 在同一个文件,则在 BasicTerrainGeneratorConfig 定义后。
public class BasicTerrainMapGenerator : MapGeneratorWorkClassBase
{
private BasicTerrainGeneratorConfig _config;
/// <summary>
/// 初始化地形生成器解析JSON配置字符串。
/// </summary>
/// <param name="value">包含地形生成参数的JSON字符串。</param>
public override void Init(string value)
{
try
{
_config = JsonConvert.DeserializeObject<BasicTerrainGeneratorConfig>(value);
// _config 不是单例,所以需要进行空检查。
if (_config == null)
{
Debug.LogError("基本地形生成器: 配置反序列化为空。请检查JSON格式。");
_config = new BasicTerrainGeneratorConfig();
}
if (string.IsNullOrWhiteSpace(_config.TileDefName))
{
Debug.LogWarning("基本地形生成器: 瓦片定义名称为空。使用默认值 'DefaultTerrainTile'。");
_config.TileDefName = "DefaultTerrainTile";
}
if (_config.Scale <= 0)
{
Debug.LogWarning($"基本地形生成器: 缩放值必须为正。设置为默认值 0.1。当前值: {_config.Scale}");
_config.Scale = 0.1;
}
if (_config.MapCellSizeX <= 0 || _config.MapCellSizeY <= 0)
{
Debug.LogWarning(
$"基本地形生成器: 地图单元格宽度或高度为零或负数。设置为默认值 (100, 100)。当前值: ({_config.MapCellSizeX}, {_config.MapCellSizeY})");
_config.MapCellSizeX = 100;
_config.MapCellSizeY = 100;
}
// 将阈值限定在 -1.0 到 1.0 的有效范围内
_config.MinThreshold = Math.Max(-1.0, Math.Min(1.0, _config.MinThreshold));
_config.MaxThreshold = Math.Max(-1.0, Math.Min(1.0, _config.MaxThreshold));
// 确保 MinThreshold 不大于 MaxThreshold
if (_config.MinThreshold > _config.MaxThreshold)
{
Debug.LogWarning(
$"基本地形生成器: 最小阈值 ({_config.MinThreshold}) 不能大于最大阈值 ({_config.MaxThreshold})。交换值。");
(_config.MinThreshold, _config.MaxThreshold) = (_config.MaxThreshold, _config.MinThreshold); // 交换值
}
}
catch (JsonSerializationException ex)
{
Debug.LogError($"基本地形生成器: JSON反序列化错误: {ex.Message}。输入: {value}");
_config = new BasicTerrainGeneratorConfig(); // 失败时使用默认配置
}
catch (Exception ex)
{
Debug.LogError($"基本地形生成器: Init 期间发生意外错误: {ex.Message}。输入: {value}");
_config = new BasicTerrainGeneratorConfig(); // 失败时使用默认配置
}
}
/// <summary>
/// 根据柏林噪声生成地形。此方法现在是异步的,以避免阻塞主线程。
/// </summary>
/// <param name="landform">地图生成器实例,包含要操作的瓦片地图。</param>
public override async Task Process(Landform landform)
{
// _config 不是单例,所以需要进行空检查。
if (_config == null)
{
Debug.LogError("基本地形生成器: Process 在 Init 之前调用或 Init 失败。使用默认配置。");
_config = new BasicTerrainGeneratorConfig();
}
var terrainTile = TileManager.Instance.GetTile(_config.TileDefName);
if (terrainTile == null)
{
Debug.LogError($"基本地形生成器: 无法获取瓦片定义名称: '{_config.TileDefName}'。中止生成。");
return;
}
TileBase elseTile = null;
if (!string.IsNullOrWhiteSpace(_config.ElseTileDefName))
{
elseTile = TileManager.Instance.GetTile(_config.ElseTileDefName);
if (elseTile == null)
Debug.LogWarning($"基本地形生成器: 无法获取 else-瓦片定义名称: '{_config.ElseTileDefName}'。将不会放置 else-瓦片。");
}
Tilemap targetTilemap;
switch (_config.TargetDimension) // 直接对枚举值进行 switch
{
case MapDimension.Base:
targetTilemap = landform.baseTilemap;
break;
case MapDimension.Building:
targetTilemap = landform.buildingTilemap;
break;
case MapDimension.Plant:
targetTilemap = landform.plantTilemap;
break;
default: // 理论上不会走到这里,因为 TargetDimension 是枚举类型,但以防万一
Debug.LogWarning(
$"基本地形生成器: 收到未知的目标维度枚举值 '{_config.TargetDimension}'。将使用默认的 'Base' 瓦片地图。");
targetTilemap = landform.baseTilemap;
break;
}
if (targetTilemap == null)
{
Debug.LogError(
$"基本地形生成器: 选定的 Tilemap ({_config.TargetDimension}) 为 null。请确保 Landform 对象上已正确分配 Tilemap。中止生成。");
return;
}
for (var x = 0; x < _config.MapCellSizeX; x++)
{
for (var y = 0; y < _config.MapCellSizeY; y++)
{
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);
// 核心修改部分:将 x, y 与 OriginX, OriginY 相加,用于指定瓦片的实际放置位置。
var tilePosition = new Vector3Int(x + _config.OriginX, y + _config.OriginY, 0);
if (noiseValue >= _config.MinThreshold && noiseValue <= _config.MaxThreshold)
targetTilemap.SetTile(tilePosition, terrainTile);
else if (elseTile != null)
targetTilemap.SetTile(tilePosition, elseTile);
else
targetTilemap.SetTile(tilePosition, null);
}
await Task.Yield();
}
}
/// <summary>
/// 获取当前配置的地图尺寸。
/// </summary>
/// <returns>表示地图宽度和高度的 Vector2Int。</returns>
public override Vector2Int GetSize()
{
// _config 不是单例,所以需要进行空检查。
if (_config == null)
{
Debug.LogError("BasicTerrainMapGenerator: GetSize 在 Init 之前调用或 Init 失败。返回默认尺寸 (0,0)。");
return Vector2Int.zero;
}
// 返回的是生成区域的尺寸,而不是它的起始位置。
return new Vector2Int(_config.MapCellSizeX, _config.MapCellSizeY);
}
}
}