(client) feat:实现摄像机跟踪,柏林噪声改为单例,角色渲染树支持指定像素密度
chore:将UI的Tick进行了显示时显式添加并作为预制体
This commit is contained in:
@ -73,7 +73,7 @@ namespace AI
|
||||
{
|
||||
public override JobBase GetJob(Entity.Entity target)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return new TrackPlayerJob();
|
||||
}
|
||||
}
|
||||
public class RandomWander : AIBase
|
||||
@ -83,5 +83,11 @@ namespace AI
|
||||
return new WanderJob();
|
||||
}
|
||||
}
|
||||
|
||||
public class Idel : AIBase
|
||||
{
|
||||
public override JobBase GetJob(Entity.Entity target)
|
||||
{
|
||||
return new IdleJob();
|
||||
}
|
||||
}
|
||||
}
|
@ -114,6 +114,10 @@ namespace Base
|
||||
|
||||
// 显示目标窗口并更新缓存与暂停状态
|
||||
windowToShow.Show();
|
||||
var itick=windowToShow as ITickUI;
|
||||
if (itick != null)
|
||||
Base.Clock.AddTickUI(itick);
|
||||
|
||||
needUpdate = true;
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,85 @@
|
||||
using Base;
|
||||
using UnityEngine;
|
||||
|
||||
namespace CameraControl
|
||||
{
|
||||
public class CameraControl:MonoBehaviour,Base.ITick
|
||||
public class CameraControl : Utils.MonoSingleton<CameraControl>, ITick, ITickUI
|
||||
{
|
||||
public Entity.Entity focusedEntity=null;
|
||||
// 当前被聚焦的目标实体
|
||||
public Entity.Entity focusedEntity = null;
|
||||
|
||||
// Camera movement variables
|
||||
private Vector3 _dragOrigin;
|
||||
private bool _isDragging = false;
|
||||
private float _zoomSpeed = 5f;
|
||||
private float _minZoom = 2f;
|
||||
private float _maxZoom = 20f;
|
||||
|
||||
private Camera _camera;
|
||||
|
||||
protected override void OnStart()
|
||||
{
|
||||
_camera = Camera.main;
|
||||
if (_camera == null)
|
||||
{
|
||||
_camera = FindFirstObjectByType<Camera>();
|
||||
}
|
||||
}
|
||||
public void Tick()
|
||||
{
|
||||
|
||||
if (focusedEntity)
|
||||
{
|
||||
// Follow the focused entity's position
|
||||
var targetPosition = new Vector3(
|
||||
focusedEntity.Position.x,
|
||||
focusedEntity.Position.y,
|
||||
_camera.transform.position.z);
|
||||
|
||||
_camera.transform.position = Vector3.Lerp(
|
||||
_camera.transform.position,
|
||||
targetPosition,
|
||||
Time.fixedDeltaTime * 5f);
|
||||
}
|
||||
}
|
||||
|
||||
public void TickUI()
|
||||
{
|
||||
HandleMiddleMouseDrag();
|
||||
HandleMouseZoom();
|
||||
}
|
||||
|
||||
private void HandleMiddleMouseDrag()
|
||||
{
|
||||
// Start drag
|
||||
if (Input.GetMouseButtonDown(2)) // Middle mouse button
|
||||
{
|
||||
_dragOrigin = _camera.ScreenToWorldPoint(Input.mousePosition);
|
||||
_isDragging = true;
|
||||
focusedEntity = null; // Clear focus when manually moving camera
|
||||
}
|
||||
|
||||
// During drag
|
||||
if (Input.GetMouseButton(2) && _isDragging)
|
||||
{
|
||||
var difference = _dragOrigin - _camera.ScreenToWorldPoint(Input.mousePosition);
|
||||
_camera.transform.position += difference;
|
||||
}
|
||||
|
||||
// End drag
|
||||
if (Input.GetMouseButtonUp(2))
|
||||
{
|
||||
_isDragging = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleMouseZoom()
|
||||
{
|
||||
var scroll = Input.GetAxis("Mouse ScrollWheel");
|
||||
if (scroll == 0) return;
|
||||
var newSize = _camera.orthographicSize - scroll * _zoomSpeed;
|
||||
_camera.orthographicSize = Mathf.Clamp(newSize, _minZoom, _maxZoom);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -32,6 +32,7 @@ namespace Data
|
||||
public DrawNodeDef drawingOrder_left;
|
||||
public DrawNodeDef drawingOrder_right;
|
||||
public string texturePath;
|
||||
public int pixelsPerUnit = 16;
|
||||
|
||||
public DrawNodeDef GetDrawingOrder(Orientation orientation)
|
||||
{
|
||||
@ -73,7 +74,7 @@ namespace Data
|
||||
public DrawNodeType drawNodeType = DrawNodeType.Image;
|
||||
public string nodeName;
|
||||
public Vector2 position = new(0, 0);
|
||||
public float FPS = 1;
|
||||
public float FPS = 0.5f;
|
||||
|
||||
public override bool Init(XElement xmlDef)
|
||||
{
|
||||
|
@ -14,6 +14,8 @@ namespace Entity
|
||||
public Entity entity;
|
||||
|
||||
private bool _select = false;
|
||||
|
||||
public static Vector3 minimum=new(0.5f,0.5f,0.5f);
|
||||
|
||||
public void Init()
|
||||
{
|
||||
@ -42,20 +44,32 @@ namespace Entity
|
||||
/// </returns>
|
||||
public Vector3 GetSize()
|
||||
{
|
||||
// 获取所有子对象的 Renderer 组件
|
||||
var renderers = body.GetComponentsInChildren<Renderer>();
|
||||
|
||||
// 如果没有找到任何 Renderer,返回一个默认值 (-1, -1, -1)
|
||||
if (renderers.Length == 0)
|
||||
{
|
||||
return new(-1, -1);
|
||||
return minimum;
|
||||
}
|
||||
|
||||
// 初始化 totalBounds 为第一个 Renderer 的 bounds
|
||||
var totalBounds = renderers[0].bounds;
|
||||
|
||||
// 遍历剩余的 Renderer,将它们的 bounds 合并到 totalBounds 中
|
||||
for (var i = 1; i < renderers.Length; i++)
|
||||
{
|
||||
totalBounds.Encapsulate(renderers[i].bounds);
|
||||
}
|
||||
|
||||
// 获取合并后的包围盒的大小
|
||||
var size = totalBounds.size;
|
||||
|
||||
// 确保每个维度的大小都不小于 0.5
|
||||
size.x = Mathf.Max(size.x, 0.5f);
|
||||
size.y = Mathf.Max(size.y, 0.5f);
|
||||
size.z = Mathf.Max(size.z, 0.5f);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
@ -87,11 +101,11 @@ namespace Entity
|
||||
{
|
||||
var result = new List<(string name, UnityAction callback)>();
|
||||
if (entity.PlayerControlled)
|
||||
result.Add(("结束操控", () => entity.PlayerControlled = false));
|
||||
result.Add(("结束操控", EndControl));
|
||||
else
|
||||
result.Add(("手动操控", () => entity.PlayerControlled = true));
|
||||
result.Add(("手动操控", StartControl));
|
||||
result.Add(("杀死", () => entity.Kill()));
|
||||
result.Add(("变成笨蛋", () => BecomeDefault()));
|
||||
result.Add(("变成笨蛋", BecomeDefault));
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -100,5 +114,17 @@ namespace Entity
|
||||
entity.Kill();
|
||||
Managers.EntityManage.Instance.GenerateDefaultEntity(entity.Position);
|
||||
}
|
||||
|
||||
private void StartControl()
|
||||
{
|
||||
entity.PlayerControlled = true;
|
||||
CameraControl.CameraControl.Instance.focusedEntity=entity;
|
||||
}
|
||||
|
||||
private void EndControl()
|
||||
{
|
||||
entity.PlayerControlled = false;
|
||||
CameraControl.CameraControl.Instance.focusedEntity=null;
|
||||
}
|
||||
}
|
||||
}
|
@ -25,7 +25,6 @@ namespace Managers
|
||||
defaultSprite = Resources.Load<Sprite>("Default/DefaultImage");
|
||||
InitImageDef();
|
||||
InitDrawOrder();
|
||||
packagesImages = null;
|
||||
}
|
||||
|
||||
public void InitImageDef()
|
||||
@ -54,39 +53,101 @@ namespace Managers
|
||||
|
||||
public void InitDrawOrder()
|
||||
{
|
||||
var drawOrderDef = Managers.DefineManager.Instance.QueryDefinesByType<DrawingOrderDef>();
|
||||
if (drawOrderDef == null || drawOrderDef.Length == 0)
|
||||
try
|
||||
{
|
||||
return;
|
||||
}
|
||||
Dictionary<string, string> packRootSite = new();
|
||||
foreach (var drawOrder in drawOrderDef)
|
||||
{
|
||||
if (string.IsNullOrEmpty(drawOrder.texturePath) || string.IsNullOrEmpty(drawOrder.packID))
|
||||
continue;
|
||||
if (!packRootSite.ContainsKey(drawOrder.packID))
|
||||
packRootSite[drawOrder.packID] = Managers.DefineManager.Instance.GetPackagePath(drawOrder.packID);
|
||||
var rootPath= packRootSite[drawOrder.packID];
|
||||
var folderPath=Path.Combine(rootPath, drawOrder.texturePath);
|
||||
var imagePath = Configs.ConfigProcessor.GetFilesByExtensions(folderPath,
|
||||
new[]
|
||||
{
|
||||
"jpg", "jpeg", "png", "tga", "tif", "tiff", "psd", "bmp"
|
||||
});
|
||||
foreach (var path in imagePath)
|
||||
// 查询绘制顺序定义
|
||||
var drawOrderDef = Managers.DefineManager.Instance.QueryDefinesByType<DrawingOrderDef>();
|
||||
if (drawOrderDef == null || drawOrderDef.Length == 0)
|
||||
{
|
||||
var image=Configs.ConfigProcessor.LoadTextureByIO(path);
|
||||
if (image == null)
|
||||
continue;
|
||||
var spr=Sprite.Create(
|
||||
image,
|
||||
new Rect(0, 0, image.width, image.height),
|
||||
new Vector2(0.5f, 0.5f) // 中心点
|
||||
);
|
||||
var name=Path.GetFileNameWithoutExtension(path);
|
||||
InsertBodyTexture(drawOrder.packID, drawOrder.texturePath, name, spr);
|
||||
|
||||
Debug.LogWarning("No DrawingOrderDef found.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 初始化包路径字典
|
||||
Dictionary<string, string> packRootSite = new();
|
||||
|
||||
foreach (var drawOrder in drawOrderDef)
|
||||
{
|
||||
// 检查必要字段是否为空
|
||||
if (string.IsNullOrEmpty(drawOrder.texturePath) || string.IsNullOrEmpty(drawOrder.packID))
|
||||
{
|
||||
Debug.LogWarning(
|
||||
$"Skipping invalid drawOrder: texturePath or packID is null or empty. PackID: {drawOrder.packID}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取包路径
|
||||
if (!packRootSite.ContainsKey(drawOrder.packID))
|
||||
{
|
||||
var packagePath = Managers.DefineManager.Instance.GetPackagePath(drawOrder.packID);
|
||||
if (string.IsNullOrEmpty(packagePath))
|
||||
{
|
||||
Debug.LogError($"Package path not found for packID: {drawOrder.packID}");
|
||||
continue;
|
||||
}
|
||||
|
||||
packRootSite[drawOrder.packID] = packagePath;
|
||||
}
|
||||
|
||||
var rootPath = packRootSite[drawOrder.packID];
|
||||
var folderPath = Path.Combine(rootPath, drawOrder.texturePath);
|
||||
|
||||
// 获取图像文件列表
|
||||
try
|
||||
{
|
||||
var imagePath = Configs.ConfigProcessor.GetFilesByExtensions(folderPath,
|
||||
new[] { "jpg", "jpeg", "png", "tga", "tif", "tiff", "psd", "bmp" });
|
||||
|
||||
foreach (var path in imagePath)
|
||||
{
|
||||
// 加载纹理
|
||||
Texture2D image = null;
|
||||
try
|
||||
{
|
||||
image = Configs.ConfigProcessor.LoadTextureByIO(path);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"Failed to load texture from path: {path}. Error: {ex.Message}");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (image == null)
|
||||
{
|
||||
Debug.LogWarning($"Texture loaded from path: {path} is null.");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 创建精灵
|
||||
try
|
||||
{
|
||||
var spr = Sprite.Create(
|
||||
image,
|
||||
new Rect(0, 0, image.width, image.height),
|
||||
new Vector2(0.5f, 0.5f), // 中心点
|
||||
drawOrder.pixelsPerUnit
|
||||
);
|
||||
|
||||
var name = Path.GetFileNameWithoutExtension(path);
|
||||
|
||||
// 插入纹理
|
||||
InsertBodyTexture(drawOrder.packID, drawOrder.texturePath, name, spr);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"Failed to create sprite from texture: {path}. Error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"Failed to retrieve files from folder: {folderPath}. Error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"An unexpected error occurred in InitDrawOrder: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
87
Client/Assets/Scripts/Managers/TileManager.cs
Normal file
87
Client/Assets/Scripts/Managers/TileManager.cs
Normal file
@ -0,0 +1,87 @@
|
||||
using System.Collections.Generic;
|
||||
using Data;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Tilemaps;
|
||||
|
||||
namespace Managers
|
||||
{
|
||||
public class TileManager:Utils.Singleton<TileManager>
|
||||
{
|
||||
public Dictionary<string,TileBase> tileBaseMapping = new();
|
||||
public Dictionary<(int, int, int, int), TileBase> tileToTileBaseMapping = new();
|
||||
public Dictionary<string, int> tileID = new();
|
||||
public void Init()
|
||||
{
|
||||
if (tileToTileBaseMapping.Count > 0)
|
||||
return;
|
||||
Managers.PackagesImageManager.Instance.Init();
|
||||
var imagePack = Managers.PackagesImageManager.Instance;
|
||||
var tileType = Managers.DefineManager.Instance.QueryDefinesByType<TileDef>();
|
||||
for (var i = 0; i < tileType.Length; i++)
|
||||
{
|
||||
tileID.Add(tileType[i].name, i);
|
||||
}
|
||||
|
||||
var tileTextureMappingDef=Managers.DefineManager.Instance.QueryDefinesByType<TileMappingTableDef>();
|
||||
foreach (var mappingTableDef in tileTextureMappingDef)
|
||||
{
|
||||
foreach (var keyVal in mappingTableDef.tileDict)
|
||||
{
|
||||
var key = keyVal.Key;
|
||||
var val = keyVal.Value;
|
||||
var parts = key.Split('_');
|
||||
if (parts.Length != 4)
|
||||
{
|
||||
var packName = Managers.DefineManager.Instance.GetDefinePackageName(mappingTableDef);
|
||||
Debug.LogError($"来自{packName}定义的TileMappingTableDef键值{key}内容不合法!\n应该为[瓦片名称_瓦片名称_瓦片名称_瓦片名称]的格式");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(tileID.TryGetValue(parts[0], out var k1) &&
|
||||
tileID.TryGetValue(parts[1], out var k2) &&
|
||||
tileID.TryGetValue(parts[2], out var k3) &&
|
||||
tileID.TryGetValue(parts[3], out var k4)))
|
||||
{
|
||||
var packName = Managers.DefineManager.Instance.GetDefinePackageName(mappingTableDef);
|
||||
Debug.LogError($"来自{packName}定义的TileMappingTableDef键值{key}中存在未定义的瓦片名称");
|
||||
continue;
|
||||
}
|
||||
|
||||
var sprite = imagePack.GetSprite(mappingTableDef.packID,val);
|
||||
if (sprite == null)
|
||||
{
|
||||
var packName = Managers.DefineManager.Instance.GetDefinePackageName(mappingTableDef);
|
||||
Debug.LogError($"来自{packName}定义的TileMappingTableDef键值{val}中存在未定义的图片名称");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tileToTileBaseMapping.ContainsKey((k1, k2, k3, k4)))
|
||||
{
|
||||
var packName = Managers.DefineManager.Instance.GetDefinePackageName(mappingTableDef);
|
||||
Debug.LogWarning($"来自{packName}定义的TileMappingTableDef键值{(k1, k2, k3, k4)}存在重复索引,将忽略重复项");
|
||||
continue;
|
||||
}
|
||||
|
||||
var tile = LoadTile(sprite);
|
||||
tileToTileBaseMapping[(k1, k2, k3, k4)] = tile;
|
||||
tileBaseMapping[val] = tile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Reload()
|
||||
{
|
||||
tileToTileBaseMapping.Clear();
|
||||
Init();
|
||||
}
|
||||
|
||||
public TileBase LoadTile(Sprite sprite)
|
||||
{
|
||||
var newTile = ScriptableObject.CreateInstance<Tile>();
|
||||
newTile.sprite = sprite;
|
||||
newTile.color = Color.white;
|
||||
newTile.colliderType = Tile.ColliderType.Sprite;
|
||||
return newTile;
|
||||
}
|
||||
}
|
||||
}
|
3
Client/Assets/Scripts/Managers/TileManager.cs.meta
Normal file
3
Client/Assets/Scripts/Managers/TileManager.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ff3c1eb2791148068c9f03baeb04f96f
|
||||
timeCreated: 1754375678
|
@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Data;
|
||||
using Managers;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Tilemaps;
|
||||
|
||||
@ -9,23 +10,30 @@ namespace Map
|
||||
public class DoubleMap : MonoBehaviour
|
||||
{
|
||||
public List<List<int>> mapData = new();
|
||||
// public Tilemap dataLevel;
|
||||
public Tilemap textureLevel;
|
||||
|
||||
public Dictionary<string, TileBase> tileDict = new();
|
||||
|
||||
private int offsetX = 0; // 地图数据的 X 偏移量
|
||||
private int offsetY = 0; // 地图数据的 Y 偏移量
|
||||
|
||||
void Start()
|
||||
{
|
||||
TileManager.Instance.Init();
|
||||
var mapSize = 10;
|
||||
float noiseScale = 0.1f;
|
||||
|
||||
|
||||
// 设置偏移量
|
||||
offsetX = -5; // 示例:地图数据从 (-5, -5) 开始
|
||||
offsetY = -5;
|
||||
|
||||
for (int x = 0; x < mapSize; x++)
|
||||
{
|
||||
List<int> col = new();
|
||||
for (int y = 0; y < mapSize; y++)
|
||||
{
|
||||
// 计算柏林噪声值
|
||||
float noiseValue = Mathf.PerlinNoise(x * noiseScale, y * noiseScale);
|
||||
float noiseValue = Mathf.PerlinNoise((x + offsetX) * noiseScale, (y + offsetY) * noiseScale);
|
||||
if (noiseValue < 0.5f) // 小于 0.5 表示 Dirt
|
||||
{
|
||||
col.Add(TileManager.Instance.tileID.GetValueOrDefault("Dirt"));
|
||||
@ -34,11 +42,12 @@ namespace Map
|
||||
{
|
||||
col.Add(TileManager.Instance.tileID.GetValueOrDefault("Grass"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mapData.Add(col);
|
||||
UpdateTexture();
|
||||
}
|
||||
|
||||
UpdateTexture();
|
||||
}
|
||||
|
||||
public void UpdateTexture()
|
||||
@ -54,33 +63,46 @@ namespace Map
|
||||
|
||||
public int GetTile(int x, int y)
|
||||
{
|
||||
if (x < 0 || x >= mapData.Count)
|
||||
// 转换为相对于 mapData 的索引
|
||||
int relativeX = x - offsetX;
|
||||
int relativeY = y - offsetY;
|
||||
|
||||
if (relativeX < 0 || relativeX >= mapData.Count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var col = mapData[x];
|
||||
if (y < 0 || y >= mapData.Count)
|
||||
var col = mapData[relativeX];
|
||||
if (relativeY < 0 || relativeY >= mapData.Count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return col[y];
|
||||
return col[relativeY];
|
||||
}
|
||||
|
||||
public void SetTile(int x, int y, string tileName)
|
||||
{
|
||||
SetTile(x,y,TileManager.Instance.tileID.GetValueOrDefault(tileName));
|
||||
SetTile(x, y, TileManager.Instance.tileID.GetValueOrDefault(tileName));
|
||||
}
|
||||
|
||||
public void SetTile(int x, int y, int id)
|
||||
{
|
||||
mapData[x][y] = id;
|
||||
UpdateTexture(x, y);
|
||||
UpdateTexture(x, y-1);
|
||||
UpdateTexture(x-1, y);
|
||||
UpdateTexture(x-1, y-1);
|
||||
// 转换为相对于 mapData 的索引
|
||||
int relativeX = x - offsetX;
|
||||
int relativeY = y - offsetY;
|
||||
|
||||
if (relativeX >= 0 && relativeX < mapData.Count &&
|
||||
relativeY >= 0 && relativeY < mapData[relativeX].Count)
|
||||
{
|
||||
mapData[relativeX][relativeY] = id;
|
||||
UpdateTexture(x, y);
|
||||
UpdateTexture(x, y - 1);
|
||||
UpdateTexture(x - 1, y);
|
||||
UpdateTexture(x - 1, y - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新对应坐标的贴图
|
||||
/// </summary>
|
||||
@ -89,94 +111,27 @@ namespace Map
|
||||
/// <returns></returns>
|
||||
public void UpdateTexture(int x, int y)
|
||||
{
|
||||
// 转换为相对于 mapData 的索引
|
||||
int relativeX = x - offsetX;
|
||||
int relativeY = y - offsetY;
|
||||
|
||||
if (relativeX < 0 || relativeX >= mapData.Count ||
|
||||
relativeY < 0 || relativeY >= mapData[relativeX].Count)
|
||||
{
|
||||
return; // 如果超出范围,直接返回
|
||||
}
|
||||
|
||||
var lt = GetTile(x, y + 1);
|
||||
var rt = GetTile(x + 1, y + 1);
|
||||
var lb = GetTile(x, y);
|
||||
var rb = GetTile(x + 1, y);
|
||||
|
||||
if (TileManager.Instance.tileToTileBaseMapping.ContainsKey((lt, rt, lb, rb)))
|
||||
{
|
||||
textureLevel.SetTile(new(x,y),TileManager.Instance.tileToTileBaseMapping[(lt, rt, lb, rb)]);
|
||||
textureLevel.SetTile(new Vector3Int(x, y, 0),
|
||||
TileManager.Instance.tileToTileBaseMapping[(lt, rt, lb, rb)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TileManager:Utils.Singleton<TileManager>
|
||||
{
|
||||
public Dictionary<string,TileBase> tileBaseMapping = new();
|
||||
public Dictionary<(int, int, int, int), TileBase> tileToTileBaseMapping = new();
|
||||
public Dictionary<string, int> tileID = new();
|
||||
public void Init()
|
||||
{
|
||||
if (tileToTileBaseMapping.Count > 0)
|
||||
return;
|
||||
Managers.PackagesImageManager.Instance.Init();
|
||||
var imagePack = Managers.PackagesImageManager.Instance;
|
||||
var tileType = Managers.DefineManager.Instance.QueryDefinesByType<TileDef>();
|
||||
for (var i = 0; i < tileType.Length; i++)
|
||||
{
|
||||
tileID.Add(tileType[i].name, i);
|
||||
}
|
||||
|
||||
var tileTextureMappingDef=Managers.DefineManager.Instance.QueryDefinesByType<TileMappingTableDef>();
|
||||
foreach (var mappingTableDef in tileTextureMappingDef)
|
||||
{
|
||||
foreach (var keyVal in mappingTableDef.tileDict)
|
||||
{
|
||||
var key = keyVal.Key;
|
||||
var val = keyVal.Value;
|
||||
var parts = key.Split('_');
|
||||
if (parts.Length != 4)
|
||||
{
|
||||
var packName = Managers.DefineManager.Instance.GetDefinePackageName(mappingTableDef);
|
||||
Debug.LogError($"来自{packName}定义的TileMappingTableDef键值{key}内容不合法!\n应该为[瓦片名称_瓦片名称_瓦片名称_瓦片名称]的格式");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(tileID.TryGetValue(parts[0], out var k1) &&
|
||||
tileID.TryGetValue(parts[1], out var k2) &&
|
||||
tileID.TryGetValue(parts[2], out var k3) &&
|
||||
tileID.TryGetValue(parts[3], out var k4)))
|
||||
{
|
||||
var packName = Managers.DefineManager.Instance.GetDefinePackageName(mappingTableDef);
|
||||
Debug.LogError($"来自{packName}定义的TileMappingTableDef键值{key}中存在未定义的瓦片名称");
|
||||
continue;
|
||||
}
|
||||
|
||||
var sprite = imagePack.GetSprite(mappingTableDef.packID,val);
|
||||
if (sprite == null)
|
||||
{
|
||||
var packName = Managers.DefineManager.Instance.GetDefinePackageName(mappingTableDef);
|
||||
Debug.LogError($"来自{packName}定义的TileMappingTableDef键值{val}中存在未定义的图片名称");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tileToTileBaseMapping.ContainsKey((k1, k2, k3, k4)))
|
||||
{
|
||||
var packName = Managers.DefineManager.Instance.GetDefinePackageName(mappingTableDef);
|
||||
Debug.LogWarning($"来自{packName}定义的TileMappingTableDef键值{(k1, k2, k3, k4)}存在重复索引,将忽略重复项");
|
||||
continue;
|
||||
}
|
||||
|
||||
var tile = LoadTile(sprite);
|
||||
tileToTileBaseMapping[(k1, k2, k3, k4)] = tile;
|
||||
tileBaseMapping[val] = tile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Reload()
|
||||
{
|
||||
tileToTileBaseMapping.Clear();
|
||||
Init();
|
||||
}
|
||||
|
||||
public TileBase LoadTile(Sprite sprite)
|
||||
{
|
||||
var newTile = ScriptableObject.CreateInstance<Tile>();
|
||||
newTile.sprite = sprite;
|
||||
newTile.color = Color.white;
|
||||
newTile.colliderType = Tile.ColliderType.Sprite;
|
||||
return newTile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
30
Client/Assets/Scripts/Map/MapGenerator.cs
Normal file
30
Client/Assets/Scripts/Map/MapGenerator.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Tilemaps;
|
||||
|
||||
namespace Map
|
||||
{
|
||||
public class MapGenerator:MonoBehaviour
|
||||
{
|
||||
public DoubleMap baseLevel;
|
||||
public Tilemap buildLevel;
|
||||
public Tilemap plantLevel;
|
||||
|
||||
public void Start()
|
||||
{
|
||||
var perline= Utils.PerlinNoise.Instance;
|
||||
int size = 100;
|
||||
for (int i = -size; i <= size; i++)
|
||||
{
|
||||
for (int j = -size; j <= size; j++)
|
||||
{
|
||||
var val = perline.Noise(i, j);
|
||||
if (val < 0)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
Client/Assets/Scripts/Map/MapGenerator.cs.meta
Normal file
3
Client/Assets/Scripts/Map/MapGenerator.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 81339b242c794b8d9d28d7111a46bfbf
|
||||
timeCreated: 1754370253
|
@ -83,7 +83,24 @@ namespace Prefab
|
||||
|
||||
// 外部控制方法
|
||||
public void SetPaused(bool paused) => _isPaused = paused;
|
||||
public void SetSprites(Sprite[] newSprites) => _sprites = newSprites;
|
||||
public void SetSprites(Sprite[] newSprites)
|
||||
{
|
||||
_sprites = newSprites;
|
||||
|
||||
// 如果有新的精灵数组,则立即显示第一帧
|
||||
if (_sprites != null && _sprites.Length > 0)
|
||||
{
|
||||
_currentFrameIndex = 0; // 重置当前帧索引为第一帧
|
||||
_renderer.sprite = _sprites[_currentFrameIndex]; // 立即显示第一帧
|
||||
}
|
||||
else
|
||||
{
|
||||
_renderer.sprite = null; // 如果没有精灵,则清空渲染器
|
||||
}
|
||||
|
||||
// 重置帧计时器,以确保从头开始播放
|
||||
_frameTimer = 0f;
|
||||
}
|
||||
public void SetFPS(float newFPS) => _fps = Mathf.Max(0.1f, newFPS);
|
||||
public void SetStaticSprite(Sprite sprite) => _staticSprite = sprite;
|
||||
}
|
||||
|
@ -2,14 +2,19 @@ using System;
|
||||
|
||||
namespace Utils
|
||||
{
|
||||
public class PerlinNoise
|
||||
public class PerlinNoise : Utils.Singleton<PerlinNoise>
|
||||
{
|
||||
private readonly int[] _p; // 混淆表
|
||||
private int[] _p; // 混淆表
|
||||
private const int DefaultSeed = 0; // 默认种子
|
||||
|
||||
// 构造函数:初始化混淆表
|
||||
public PerlinNoise(int seed)
|
||||
public PerlinNoise()
|
||||
{
|
||||
Initialize(DefaultSeed);
|
||||
}
|
||||
|
||||
// 初始化混淆表
|
||||
private void Initialize(int seed)
|
||||
{
|
||||
// 初始化为0-255的随机排列
|
||||
_p = new int[512]; // 混淆表加倍以方便使用
|
||||
var permutation = new int[256];
|
||||
var random = new Random(seed);
|
||||
@ -34,67 +39,67 @@ namespace Utils
|
||||
}
|
||||
}
|
||||
|
||||
// 重新指定种子
|
||||
public void Reinitialize(int seed)
|
||||
{
|
||||
Initialize(seed);
|
||||
}
|
||||
|
||||
// 平滑函数 (6t^5 - 15t^4 + 10t^3)
|
||||
private double Fade(double t)
|
||||
private static double Fade(double t)
|
||||
{
|
||||
return t * t * t * (t * (t * 6 - 15) + 10);
|
||||
}
|
||||
|
||||
// 线性插值
|
||||
private double Lerp(double t, double a, double b)
|
||||
private static double Lerp(double t, double a, double b)
|
||||
{
|
||||
return a + t * (b - a);
|
||||
}
|
||||
|
||||
// 计算梯度向量和距离向量的点积
|
||||
private double Grad(int hash, double x, double y, double z)
|
||||
private static double Grad(int hash, double x, double y, double z)
|
||||
{
|
||||
// 根据hash值确定使用哪个梯度向量
|
||||
// 12个梯度向量由以下组合构成:(+/-1, +/-1, 0), (+/-1, 0, +/-1), (0, +/-1, +/-1)
|
||||
switch (hash & 0xF) // 取hash值的最后4位
|
||||
return (hash & 0xF) switch // 取hash值的最后4位
|
||||
{
|
||||
case 0x0: return x + y;
|
||||
case 0x1: return -x + y;
|
||||
case 0x2: return x - y;
|
||||
case 0x3: return -x - y;
|
||||
case 0x4: return x + z;
|
||||
case 0x5: return -x + z;
|
||||
case 0x6: return x - z;
|
||||
case 0x7: return -x - z;
|
||||
case 0x8: return y + z;
|
||||
case 0x9: return -y + z;
|
||||
case 0xA: return y - z;
|
||||
case 0xB: return -y - z;
|
||||
case 0xC: return y + x; // 这四个是重复的,但Ken Perlin的原始实现中包含它们。
|
||||
case 0xD: return -y + x; // 它们对噪声质量影响不大,但保持了表格的一致性。
|
||||
case 0xE: return y - x;
|
||||
case 0xF: return -y - x;
|
||||
default: return 0; // 不应该发生
|
||||
}
|
||||
0x0 => x + y,
|
||||
0x1 => -x + y,
|
||||
0x2 => x - y,
|
||||
0x3 => -x - y,
|
||||
0x4 => x + z,
|
||||
0x5 => -x + z,
|
||||
0x6 => x - z,
|
||||
0x7 => -x - z,
|
||||
0x8 => y + z,
|
||||
0x9 => -y + z,
|
||||
0xA => y - z,
|
||||
0xB => -y - z,
|
||||
0xC => y + x,
|
||||
0xD => -y + x,
|
||||
0xE => y - x,
|
||||
0xF => -y - x,
|
||||
_ => 0
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为给定的(x, y, z)坐标生成3D Perlin噪声。
|
||||
/// 输出值通常在-1到1之间。
|
||||
/// </summary>
|
||||
public double Noise(double x, double y, double z)
|
||||
public double Noise(double x, double y=0, double z = 0)
|
||||
{
|
||||
// 找到包含该点的单位立方体
|
||||
var X = (int)Math.Floor(x) & 255;
|
||||
var Y = (int)Math.Floor(y) & 255;
|
||||
var Z = (int)Math.Floor(z) & 255;
|
||||
|
||||
// 找到该点在立方体内的相对x, y, z坐标
|
||||
x -= Math.Floor(x);
|
||||
y -= Math.Floor(y);
|
||||
z -= Math.Floor(z);
|
||||
|
||||
// 计算x, y, z的平滑曲线
|
||||
var u = Fade(x);
|
||||
var v = Fade(y);
|
||||
var w = Fade(z);
|
||||
|
||||
// 对立方体的8个角进行哈希计算
|
||||
var A = _p[X] + Y;
|
||||
var AA = _p[A] + Z;
|
||||
var AB = _p[A + 1] + Z;
|
||||
@ -102,7 +107,6 @@ namespace Utils
|
||||
var BA = _p[B] + Z;
|
||||
var BB = _p[B + 1] + Z;
|
||||
|
||||
// 获取所有8个角的哈希值
|
||||
var H000 = _p[AA];
|
||||
var H100 = _p[BA];
|
||||
var H010 = _p[AB];
|
||||
@ -112,19 +116,14 @@ namespace Utils
|
||||
var H011 = _p[AB + 1];
|
||||
var H111 = _p[BB + 1];
|
||||
|
||||
// 计算所有8个角的点积并插值
|
||||
double x0, x1, y0, y1;
|
||||
|
||||
x0 = Lerp(u, Grad(H000, x, y, z), // (0,0,0)
|
||||
Grad(H100, x - 1, y, z)); // (1,0,0)
|
||||
x1 = Lerp(u, Grad(H010, x, y - 1, z), // (0,1,0)
|
||||
Grad(H110, x - 1, y - 1, z)); // (1,1,0)
|
||||
x0 = Lerp(u, Grad(H000, x, y, z), Grad(H100, x - 1, y, z));
|
||||
x1 = Lerp(u, Grad(H010, x, y - 1, z), Grad(H110, x - 1, y - 1, z));
|
||||
y0 = Lerp(v, x0, x1);
|
||||
|
||||
x0 = Lerp(u, Grad(H001, x, y, z - 1), // (0,0,1)
|
||||
Grad(H101, x - 1, y, z - 1)); // (1,0,1)
|
||||
x1 = Lerp(u, Grad(H011, x, y - 1, z - 1), // (0,1,1)
|
||||
Grad(H111, x - 1, y - 1, z - 1)); // (1,1,1)
|
||||
x0 = Lerp(u, Grad(H001, x, y, z - 1), Grad(H101, x - 1, y, z - 1));
|
||||
x1 = Lerp(u, Grad(H011, x, y - 1, z - 1), Grad(H111, x - 1, y - 1, z - 1));
|
||||
y1 = Lerp(v, x0, x1);
|
||||
|
||||
return Lerp(w, y0, y1);
|
||||
|
Reference in New Issue
Block a user