备份CatanBuilding瘦身独立工程
This commit is contained in:
175
Assets/Scripts/HexGrid/BuildingManager.cs
Normal file
175
Assets/Scripts/HexGrid/BuildingManager.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
|
||||
namespace HexGrid
|
||||
{
|
||||
|
||||
public interface IBuildMediator
|
||||
{
|
||||
void Build();
|
||||
void CheckForBuilding(List<HexSubZone> zoneDataSubZones);
|
||||
}
|
||||
|
||||
public class HexBuildingData
|
||||
{
|
||||
public string buildingPrefabName;
|
||||
|
||||
public Vector3 position;
|
||||
}
|
||||
|
||||
public class BuildingData
|
||||
{
|
||||
//
|
||||
public string BuildingName;
|
||||
// 地块状态
|
||||
public Dictionary<string, int> TileStateMap;
|
||||
|
||||
public Vector3 position;
|
||||
}
|
||||
|
||||
public class BuildingManager : MonoBehaviour,IHexGridMediatable
|
||||
{
|
||||
//
|
||||
private IHexGridMediator _mediator;
|
||||
|
||||
// public List<string> conditions = new List<string>();
|
||||
// private List<HexBuilding> _buildings;
|
||||
//[zoneId,[[build1,[tile1,tile2,tile3,....],],[build1,[tile1,tile2,tile3,....],]]
|
||||
private readonly Dictionary<int ,List<BuildingData>> _unFinishBuildMap= new ();
|
||||
//<zoneId, [build1,build2,...]>
|
||||
private readonly Dictionary<int ,List<BuildingData>> _finishBuildMaps = new ();
|
||||
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
// conditions.Clear();
|
||||
}
|
||||
|
||||
public async void Build(Transform root,BuildingData buildingData)
|
||||
{
|
||||
// var build = Instantiate(buildingData.buildModel,root);
|
||||
//var build = await Addressables.InstantiateAsync("BuildModel", root, true).Task;
|
||||
//build.transform.localPosition = buildingData.position;
|
||||
//build.name = "highbuilding";
|
||||
Log($"Build-> {root} {buildingData}");
|
||||
var buildTrans = root.Find(buildingData.BuildingName);
|
||||
if (buildTrans)
|
||||
{
|
||||
buildTrans.gameObject.SetActive(true);
|
||||
}
|
||||
// await RunBuildAnimation(buildingData);
|
||||
}
|
||||
|
||||
public async Task RunBuildAnimation(BuildingData buildingData)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void LoadBuildings(List<HexBuilding> buildings)
|
||||
{
|
||||
// _buildings = buildings;
|
||||
_finishBuildMaps.Clear();
|
||||
_unFinishBuildMap.Clear();
|
||||
|
||||
foreach (var hexBuilding in buildings)
|
||||
{
|
||||
var tileStateMap = hexBuilding.hasTiles.ToDictionary(tile => tile, tile => 0);
|
||||
_unFinishBuildMap.TryGetValue(hexBuilding.zoneId, out var buildingDatas);
|
||||
if (buildingDatas == null)
|
||||
{
|
||||
buildingDatas = new List<BuildingData>();
|
||||
_unFinishBuildMap.Add(hexBuilding.zoneId, buildingDatas);
|
||||
}
|
||||
buildingDatas.Add(new BuildingData()
|
||||
{
|
||||
BuildingName = hexBuilding.buildingName,
|
||||
TileStateMap = tileStateMap,
|
||||
});
|
||||
}
|
||||
Log($"LoadBuildings -> {_unFinishBuildMap}");
|
||||
}
|
||||
public void CheckForBuilding(List<HexSubZone> zoneDataSubZones)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void CheckBuildingAfterBuildImme(HexTile tiler)
|
||||
{
|
||||
if (_unFinishBuildMap.TryGetValue(tiler.zoneId, out var buildingDatas))
|
||||
{
|
||||
foreach (var buildingData in buildingDatas.Where(buildingData => buildingData.TileStateMap.ContainsKey(tiler.tileId)))
|
||||
{
|
||||
buildingData.TileStateMap[tiler.tileId] = 1;
|
||||
var full = buildingData.TileStateMap.Values.All(value => value == 1);
|
||||
if (full)
|
||||
{
|
||||
buildingDatas.Remove(buildingData);
|
||||
AddFinishBuilding(tiler.zoneId,buildingData);
|
||||
_mediator.Build(tiler.zoneId, buildingData,true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
public async Task CheckBuildingAfterBuild(HexTile tiler)
|
||||
{
|
||||
Log($"CheckBuildingAfterBuild ->{tiler}");
|
||||
//tiler.zoneId;
|
||||
|
||||
if (_unFinishBuildMap.TryGetValue(tiler.zoneId, out var buildingDatas))
|
||||
{
|
||||
foreach (var buildingData in buildingDatas.Where(buildingData => buildingData.TileStateMap.ContainsKey(tiler.tileId)))
|
||||
{
|
||||
buildingData.TileStateMap[tiler.tileId] = 1;
|
||||
var full = buildingData.TileStateMap.Values.All(value => value == 1);
|
||||
if (full)
|
||||
{
|
||||
buildingDatas.Remove(buildingData);
|
||||
AddFinishBuilding(tiler.zoneId,buildingData);
|
||||
await Awaiters.Seconds(0.5f);
|
||||
_mediator.Build(tiler.zoneId, buildingData,false);
|
||||
await Awaiters.Seconds(0.5f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// _unFinishBuildMap.
|
||||
// conditions.Add(tiler.tileId);
|
||||
// if (conditions.Contains("cube012") && conditions.Contains("cube011"))
|
||||
// {
|
||||
// _mediator.Build(tiler.zoneId);
|
||||
// conditions.Clear();
|
||||
// }
|
||||
}
|
||||
private void AddFinishBuilding(int zoneId, BuildingData buildingData)
|
||||
{
|
||||
_finishBuildMaps.TryGetValue(zoneId, out var buildingDatas);
|
||||
if (buildingDatas == null)
|
||||
{
|
||||
buildingDatas = new List<BuildingData>();
|
||||
_finishBuildMaps.Add(zoneId, buildingDatas);
|
||||
}
|
||||
buildingDatas.Add(buildingData);
|
||||
}
|
||||
|
||||
private static void Log(object t)
|
||||
{
|
||||
Debug.Log($"<color=orange>BuildingManager -> {t} </color>");
|
||||
}
|
||||
|
||||
public void SetMediator(IHexGridMediator mediator)
|
||||
{
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
// public HexBuildingData GetCurBuildModelData()
|
||||
// {
|
||||
// return BuildingData;
|
||||
// }
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/HexGrid/BuildingManager.cs.meta
Normal file
3
Assets/Scripts/HexGrid/BuildingManager.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad81263d39f54f98b6d374b986975206
|
||||
timeCreated: 1757386930
|
||||
3
Assets/Scripts/HexGrid/Cameras.meta
Normal file
3
Assets/Scripts/HexGrid/Cameras.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8cfab14f64f4801a84d7e41065515da
|
||||
timeCreated: 1757574639
|
||||
897
Assets/Scripts/HexGrid/Cameras/CompleteCameraMove.cs
Normal file
897
Assets/Scripts/HexGrid/Cameras/CompleteCameraMove.cs
Normal file
@@ -0,0 +1,897 @@
|
||||
using com.fpnn.livedata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HexGrid
|
||||
{
|
||||
|
||||
public class CompleteCameraMove : MonoBehaviour
|
||||
{
|
||||
[Header("移动设置")]
|
||||
[SerializeField] private float moveSpeed = 10f;
|
||||
[SerializeField] private float dragSpeed = 4f;
|
||||
|
||||
[Header("缩放设置")]
|
||||
[SerializeField] private float zoomSpeed = 20f;
|
||||
[SerializeField] private float minZoom = 5f;
|
||||
[SerializeField] private float maxZoom = 20f;
|
||||
[SerializeField] private bool smoothZoom = true;
|
||||
[SerializeField] private float zoomSmoothSpeed = 10f;
|
||||
[SerializeField] private float touchZoomFactor = 0.025f;
|
||||
|
||||
[Header("旋转设置")]
|
||||
public float rotationSpeed = 2f;
|
||||
public float touchRotationSpeed = 1f;
|
||||
public float minRotationY = -60f;
|
||||
public float maxRotationY = 60f;
|
||||
|
||||
|
||||
[Header("调试")] [SerializeField] private bool showDebugInfo = false;
|
||||
|
||||
// 拖拽相关变量
|
||||
private bool isDragging = false;
|
||||
private Vector3 lastMousePosition;
|
||||
private Vector3 lastTouchPosition;
|
||||
|
||||
// 移动的值,
|
||||
private Vector3 _moveValue;
|
||||
// 旋转最终的值,注意是直接改变位置
|
||||
private Vector3 _rotateCameraPos;
|
||||
// 缩放偏移值
|
||||
private Vector3 _rotateDelta;
|
||||
// 缩放的偏移值
|
||||
private Vector3 _zoomDelta;
|
||||
|
||||
// 缩放相关变量
|
||||
private float currentZoomDistance;
|
||||
private float targetZoomDistance;
|
||||
private Camera cam;
|
||||
private Vector3 fixedLookDirection; // 固定的观察方向
|
||||
|
||||
// 旋转的值
|
||||
private bool isRotating = false;
|
||||
private Vector3 targetPosition;
|
||||
private float distanceCameraToTarget;
|
||||
private float currentYaw = 0f;
|
||||
private float currentPitch = 0f;
|
||||
private bool initialized = false;
|
||||
|
||||
// 触摸旋转相关
|
||||
// private Vector2 lastTouchPosition;
|
||||
// private bool isTouchRotating = false;
|
||||
|
||||
private enum InputState
|
||||
{
|
||||
None,
|
||||
KeyboardMove,
|
||||
MouseDrag,
|
||||
MouseRotate,
|
||||
MouseZoom,
|
||||
TouchMove,
|
||||
TouchZoomRotate
|
||||
}
|
||||
private InputState currentState = InputState.None;
|
||||
|
||||
// 输入状态
|
||||
// private Vector3 lastMousePosition;
|
||||
private Vector2 lastTouchCenter;
|
||||
private float lastTouchDistance;
|
||||
private bool wasTwoFingerActive = false;
|
||||
|
||||
|
||||
|
||||
void Start()
|
||||
{
|
||||
// 初始化相机和缩放
|
||||
cam = GetComponent<Camera>();
|
||||
if (cam == null)
|
||||
{
|
||||
cam = Camera.main;
|
||||
}
|
||||
if (cam != null)
|
||||
{
|
||||
// 记录初始的观察方向(从相机指向目标的方向)
|
||||
fixedLookDirection = transform.forward;
|
||||
InitializeRotation();
|
||||
targetZoomDistance = distanceCameraToTarget;
|
||||
currentZoomDistance = targetZoomDistance;
|
||||
Log($"相机控制器初始化完成 - 初始缩放距离: {targetZoomDistance}");
|
||||
Log($"固定观察方向: {fixedLookDirection}");
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeRotation()
|
||||
{
|
||||
UpdateRotation();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// HandleKeyboardInput();
|
||||
// HandleMouseInput();
|
||||
// HandleTouchInput();
|
||||
// HandleZoomInput();
|
||||
// UpdateZoom();
|
||||
// UpdateRotation();
|
||||
//
|
||||
// if (!isDragging)
|
||||
// {
|
||||
// // 触摸输入优先
|
||||
// HandleMouseRotation();
|
||||
// }
|
||||
|
||||
UpdateInputState();
|
||||
HandleCurrentInput();
|
||||
UpdateCameraTransform();
|
||||
|
||||
if (showDebugInfo && Input.GetKeyDown(KeyCode.F1))
|
||||
{
|
||||
Log($"相机位置: {transform.position}, 当前缩放: {currentZoomDistance}");
|
||||
Log($"观察方向: {transform.forward}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UpdateInputState()
|
||||
{
|
||||
InputState newState = InputState.None;
|
||||
// 触摸输入优先级最高
|
||||
if (Input.touchCount > 0)
|
||||
{
|
||||
newState = Input.touchCount == 1 ? InputState.TouchMove : InputState.TouchZoomRotate;
|
||||
}
|
||||
// 鼠标输入次之
|
||||
else if (Input.GetMouseButton(1))
|
||||
{
|
||||
newState = InputState.MouseRotate;
|
||||
}
|
||||
else if (Input.GetMouseButton(0))
|
||||
{
|
||||
newState = InputState.MouseDrag;
|
||||
}
|
||||
else if (Mathf.Abs(Input.GetAxis("Mouse ScrollWheel")) > 0.01f)
|
||||
{
|
||||
newState = InputState.MouseZoom;
|
||||
}
|
||||
// 键盘输入最后
|
||||
else if (IsAnyMovementKeyPressed())
|
||||
{
|
||||
newState = InputState.KeyboardMove;
|
||||
}
|
||||
|
||||
if (newState != currentState)
|
||||
{
|
||||
OnInputStateChanged(currentState, newState);
|
||||
currentState = newState;
|
||||
}
|
||||
}
|
||||
|
||||
void HandleCurrentInput()
|
||||
{
|
||||
switch (currentState)
|
||||
{
|
||||
case InputState.KeyboardMove:
|
||||
HandleKeyboardInput();
|
||||
break;
|
||||
|
||||
case InputState.MouseDrag:
|
||||
HandleMouseDrag();
|
||||
break;
|
||||
|
||||
case InputState.MouseRotate:
|
||||
HandleMouseRotation();
|
||||
break;
|
||||
case InputState.MouseZoom:
|
||||
HandleMouseZoom();
|
||||
break;
|
||||
|
||||
case InputState.TouchMove:
|
||||
HandleSingleTouchMove();
|
||||
break;
|
||||
|
||||
case InputState.TouchZoomRotate:
|
||||
HandleTwoFingerGestures();
|
||||
break;
|
||||
}
|
||||
}
|
||||
private void UpdateCameraTransform()
|
||||
{
|
||||
// 移动的值
|
||||
if (_moveValue != Vector3.zero)
|
||||
{
|
||||
transform.position += _moveValue;
|
||||
_rotateCameraPos = transform.position;
|
||||
_moveValue = Vector3.zero;
|
||||
// CalcTargetPosition(); // 更新
|
||||
}
|
||||
// else
|
||||
// {
|
||||
if (_rotateDelta != Vector3.zero)
|
||||
{
|
||||
transform.position += _rotateDelta;
|
||||
_rotateDelta = Vector3.zero;
|
||||
transform.LookAt(targetPosition);
|
||||
}
|
||||
//
|
||||
if (_zoomDelta != Vector3.zero)
|
||||
{
|
||||
transform.position += _zoomDelta;
|
||||
_zoomDelta = Vector3.zero;
|
||||
transform.LookAt(targetPosition);
|
||||
}
|
||||
|
||||
// }
|
||||
UpdateRotation();
|
||||
}
|
||||
|
||||
void OnInputStateChanged(InputState oldState, InputState newState)
|
||||
{
|
||||
if (showDebugInfo)
|
||||
{
|
||||
Log($"🎮 输入状态变化: {oldState} → {newState}");
|
||||
}
|
||||
|
||||
// 开始旋转时锁定旋转中心
|
||||
if (newState == InputState.MouseRotate || newState == InputState.TouchZoomRotate)
|
||||
{
|
||||
// 锁定当前的旋转中心
|
||||
// currentRotationCenter = CalculateViewportCenter();
|
||||
// currentDistanceToCenter = Vector3.Distance(transform.position, currentRotationCenter);
|
||||
// targetDistanceToCenter = currentDistanceToCenter;
|
||||
// if (showDebugInfo)
|
||||
// {
|
||||
// Log($"🔒 锁定旋转中心: {currentRotationCenter}, 距离: {currentDistanceToCenter:F2}");
|
||||
// }
|
||||
// UpdateRotation();
|
||||
}
|
||||
|
||||
// 状态特定的初始化
|
||||
switch (newState)
|
||||
{
|
||||
case InputState.MouseRotate:
|
||||
lastMousePosition = Input.mousePosition;
|
||||
Cursor.lockState = CursorLockMode.Locked;
|
||||
break;
|
||||
|
||||
case InputState.TouchZoomRotate:
|
||||
if (Input.touchCount >= 2)
|
||||
{
|
||||
InitializeTwoFingerGesture();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// 退出状态的清理
|
||||
if (oldState == InputState.MouseRotate)
|
||||
{
|
||||
Cursor.lockState = CursorLockMode.None;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void InitializeTwoFingerGesture()
|
||||
{
|
||||
if (Input.touchCount >= 2)
|
||||
{
|
||||
Touch touch1 = Input.GetTouch(0);
|
||||
Touch touch2 = Input.GetTouch(1);
|
||||
|
||||
lastTouchCenter = (touch1.position + touch2.position) * 0.5f;
|
||||
lastTouchDistance = Vector2.Distance(touch1.position, touch2.position);
|
||||
wasTwoFingerActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsAnyMovementKeyPressed()
|
||||
{
|
||||
return Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.S) ||
|
||||
Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.D);
|
||||
}
|
||||
|
||||
// 键盘移动(保持原来的逻辑)
|
||||
void HandleKeyboardInput()
|
||||
{
|
||||
Vector3 move = Vector3.zero;
|
||||
|
||||
if (Input.GetKey(KeyCode.W)) move.z += 1;
|
||||
if (Input.GetKey(KeyCode.S)) move.z -= 1;
|
||||
if (Input.GetKey(KeyCode.A)) move.x -= 1;
|
||||
if (Input.GetKey(KeyCode.D)) move.x += 1;
|
||||
|
||||
if (move != Vector3.zero)
|
||||
{
|
||||
// 基于当前相机方向进行移动
|
||||
Vector3 forward = transform.forward;
|
||||
Vector3 right = transform.right;
|
||||
|
||||
// 计算移动方向(保持在水平面)
|
||||
Vector3 moveDirection = (forward * move.z + right * move.x).normalized;
|
||||
moveDirection.y = 0; // 确保只在水平面移动
|
||||
//transform.position += moveDirection * moveSpeed * Time.deltaTime;
|
||||
|
||||
_moveValue = moveDirection * moveSpeed * Time.deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
void HandleMouseDrag()
|
||||
{
|
||||
if (Input.GetMouseButtonDown(0))
|
||||
{
|
||||
lastMousePosition = Input.mousePosition;
|
||||
}
|
||||
else if (Input.GetMouseButton(0))
|
||||
{
|
||||
Vector3 currentMousePos = Input.mousePosition;
|
||||
Vector3 mouseDelta = lastMousePosition - currentMousePos;
|
||||
Vector3 worldDelta = ScreenToWorldDelta(mouseDelta);
|
||||
// transform.position += worldDelta * dragSpeed * Time.deltaTime;
|
||||
_moveValue = worldDelta * dragSpeed * Time.deltaTime;
|
||||
|
||||
// 移动后重新计算距离
|
||||
// currentDistanceToCenter = Vector3.Distance(transform.position, currentRotationCenter);
|
||||
// targetDistanceToCenter = currentDistanceToCenter;
|
||||
lastMousePosition = currentMousePos;
|
||||
}
|
||||
}
|
||||
|
||||
// 鼠标拖拽移动
|
||||
// void HandleMouseInput()
|
||||
// {
|
||||
// // 忽略触摸输入时的鼠标输入
|
||||
// if (Input.touchCount > 0) return;
|
||||
// if (Input.GetMouseButtonDown(0))
|
||||
// {
|
||||
// isDragging = true;
|
||||
// lastMousePosition = Input.mousePosition;
|
||||
//
|
||||
// if (showDebugInfo)
|
||||
// {
|
||||
// Log("开始鼠标拖拽");
|
||||
// }
|
||||
// }
|
||||
// else if (Input.GetMouseButtonUp(0))
|
||||
// {
|
||||
// isDragging = false;
|
||||
//
|
||||
// if (showDebugInfo)
|
||||
// {
|
||||
// Log("结束鼠标拖拽");
|
||||
// }
|
||||
// }
|
||||
// if (isDragging)
|
||||
// {
|
||||
// Vector3 currentMousePosition = Input.mousePosition;
|
||||
// Vector3 deltaScreenPosition = lastMousePosition - currentMousePosition;
|
||||
//
|
||||
// // 将屏幕空间的移动转换为世界空间
|
||||
// Vector3 worldDelta = ScreenToWorldDelta(deltaScreenPosition);
|
||||
//
|
||||
// // 移动相机(保持观察角度)
|
||||
// transform.position += worldDelta * dragSpeed * Time.deltaTime;
|
||||
//
|
||||
// // 更新记录位置
|
||||
// lastMousePosition = currentMousePosition;
|
||||
//
|
||||
// if (showDebugInfo)
|
||||
// {
|
||||
// Log($"鼠标拖拽移动: {worldDelta}");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// 触摸拖拽移动
|
||||
// void HandleTouchInput()
|
||||
// {
|
||||
// if (Input.touchCount == 1)
|
||||
// {
|
||||
// var touch = Input.GetTouch(0);
|
||||
// if (touch.phase == TouchPhase.Began)
|
||||
// {
|
||||
// isDragging = true;
|
||||
// lastTouchPosition = touch.position;
|
||||
//
|
||||
// if (showDebugInfo)
|
||||
// {
|
||||
// Log("开始触摸拖拽");
|
||||
// }
|
||||
// }
|
||||
// else if (touch.phase == TouchPhase.Ended)
|
||||
// {
|
||||
// isDragging = false;
|
||||
//
|
||||
// if (showDebugInfo)
|
||||
// {
|
||||
// Log("结束触摸拖拽");
|
||||
// }
|
||||
// }
|
||||
// else if (touch.phase == TouchPhase.Moved && isDragging)
|
||||
// {
|
||||
// Vector3 currentTouchPosition = touch.position;
|
||||
// Vector3 deltaScreenPosition = lastTouchPosition - currentTouchPosition;
|
||||
//
|
||||
// // Vector2 deltaPosition = touch.deltaPosition;
|
||||
// // 将屏幕空间的移动转换为世界空间
|
||||
// Vector3 worldDelta = ScreenToWorldDelta(deltaScreenPosition);
|
||||
// // 移动相机(保持观察角度)
|
||||
// transform.position += worldDelta * dragSpeed * Time.deltaTime;
|
||||
//
|
||||
// // 更新记录位置
|
||||
// lastTouchPosition = currentTouchPosition;
|
||||
//
|
||||
// if (showDebugInfo)
|
||||
// {
|
||||
// Log($"触摸拖拽移动: {worldDelta}");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else if (Input.touchCount == 2)
|
||||
// {
|
||||
// // 双指捏合缩放
|
||||
// HandlePinchZoom();
|
||||
// HandleTouchRotation();
|
||||
// isDragging = false; // 停止拖拽
|
||||
// }
|
||||
// else if (Input.touchCount > 2)
|
||||
// {
|
||||
// // 多点触控时停止所有操作
|
||||
// isDragging = false;
|
||||
// }
|
||||
// }
|
||||
|
||||
// 处理缩放输入(鼠标滚轮 + 双指捏合)
|
||||
// void HandleZoomInput()
|
||||
// {
|
||||
// // 鼠标滚轮缩放
|
||||
// float scrollInput = Input.GetAxis("Mouse ScrollWheel");
|
||||
// if (scrollInput != 0)
|
||||
// {
|
||||
// var zoomChange = -scrollInput * zoomSpeed; // 负号使滚轮向上为放大
|
||||
// targetZoomDistance = Mathf.Clamp(targetZoomDistance + zoomChange, minZoom, maxZoom);
|
||||
//
|
||||
// if (showDebugInfo)
|
||||
// {
|
||||
// Log($"滚轮缩放: {scrollInput} -> 目标缩放距离: {targetZoomDistance}");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 键盘缩放(备选)
|
||||
// if (Input.GetKey(KeyCode.Q))
|
||||
// {
|
||||
// targetZoomDistance = Mathf.Clamp(targetZoomDistance - zoomSpeed * Time.deltaTime, minZoom, maxZoom);
|
||||
// }
|
||||
//
|
||||
// if (Input.GetKey(KeyCode.E))
|
||||
// {
|
||||
// targetZoomDistance = Mathf.Clamp(targetZoomDistance + zoomSpeed * Time.deltaTime, minZoom, maxZoom);
|
||||
// }
|
||||
// }
|
||||
|
||||
void HandleTwoFingerRotation(Vector2 currentCenter)
|
||||
{
|
||||
Vector2 centerDelta = currentCenter - lastTouchCenter;
|
||||
if (centerDelta.magnitude > 3f)
|
||||
{
|
||||
float deltaX = centerDelta.x * 0.2f;
|
||||
float deltaY = centerDelta.y * 0.2f;
|
||||
ApplyRotationDelta(deltaX, deltaY,touchRotationSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
void HandlePinchZoom(float currentTouchDistance)
|
||||
{
|
||||
float distanceDelta = currentTouchDistance - lastTouchDistance;
|
||||
if (Mathf.Abs(distanceDelta) > 5f)
|
||||
{
|
||||
float zoomDelta = -distanceDelta * zoomSpeed * touchZoomFactor;
|
||||
targetZoomDistance = Mathf.Clamp(targetZoomDistance + zoomDelta, minZoom, maxZoom);
|
||||
}
|
||||
ApplyZoom();
|
||||
}
|
||||
|
||||
// 双指捏合缩放
|
||||
// void HandlePinchZoom()
|
||||
// {
|
||||
// Log("HandePinchZoom");
|
||||
//
|
||||
// Touch touch1 = Input.GetTouch(0);
|
||||
// Touch touch2 = Input.GetTouch(1);
|
||||
//
|
||||
// // 计算当前两指距离
|
||||
// float currentDistance = Vector2.Distance(touch1.position, touch2.position);
|
||||
//
|
||||
// // 计算上一帧两指距离
|
||||
// Vector2 touch1PrevPos = touch1.position - touch1.deltaPosition;
|
||||
// Vector2 touch2PrevPos = touch2.position - touch2.deltaPosition;
|
||||
// float prevDistance = Vector2.Distance(touch1PrevPos, touch2PrevPos);
|
||||
//
|
||||
// // 计算缩放变化
|
||||
// if (prevDistance > 0)
|
||||
// {
|
||||
// float deltaDistance = currentDistance - prevDistance;
|
||||
// float zoomChange = deltaDistance * zoomSpeed * 0.01f; // 调整灵敏度
|
||||
// targetZoomDistance = Mathf.Clamp(targetZoomDistance - zoomChange, minZoom, maxZoom); // 注意符号
|
||||
// if (showDebugInfo)
|
||||
// {
|
||||
// Log($"捏合缩放: 距离变化={deltaDistance} -> 目标缩放距离: {targetZoomDistance}");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
//
|
||||
private void Log(string t)
|
||||
{
|
||||
Debug.Log($"<color=yellow> CompleteCameraMove: {t} </color>");
|
||||
}
|
||||
|
||||
// 更新旋转
|
||||
void UpdateRotation()
|
||||
{
|
||||
CalcTargetPosition();
|
||||
// 计算初始参数
|
||||
Vector3 direction = transform.position - targetPosition;
|
||||
distanceCameraToTarget = direction.magnitude;
|
||||
currentYaw = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg;
|
||||
currentPitch = Mathf.Asin(direction.y / distanceCameraToTarget) * Mathf.Rad2Deg;
|
||||
_rotateCameraPos = transform.position;
|
||||
}
|
||||
|
||||
private void CalcTargetPosition()
|
||||
{
|
||||
Ray ray = new Ray(transform.position, transform.forward);
|
||||
float groundHeight = 0f;
|
||||
Plane groundPlane = new Plane(Vector3.up, new Vector3(0, groundHeight, 0));
|
||||
if (groundPlane.Raycast(ray, out float enter) )
|
||||
{
|
||||
Vector3 hitPoint = ray.GetPoint(enter);
|
||||
// Log($"数学检测到地面点: {hitPoint} {enter}");
|
||||
targetPosition = hitPoint;
|
||||
}
|
||||
}
|
||||
|
||||
// 更新缩放效果(关键修改:保持视角方向不变)
|
||||
void ApplyZoom()
|
||||
{
|
||||
if (cam == null) return;
|
||||
if (Mathf.Abs(currentZoomDistance - targetZoomDistance) > 0.01f)
|
||||
{
|
||||
if (smoothZoom)
|
||||
{
|
||||
// 平滑缩放
|
||||
currentZoomDistance = Mathf.Lerp(currentZoomDistance, targetZoomDistance,
|
||||
zoomSmoothSpeed * Time.deltaTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 直接缩放
|
||||
currentZoomDistance = targetZoomDistance;
|
||||
}
|
||||
|
||||
ApplyPerspectiveZoom(currentZoomDistance);
|
||||
}
|
||||
}
|
||||
|
||||
// 透视相机缩放的具体实现
|
||||
void ApplyPerspectiveZoom(float zoomDistance)
|
||||
{
|
||||
var targetPoint = targetPosition;
|
||||
// 计算从目标点到相机的方向(当前观察方向的反向)
|
||||
Vector3 directionToCamera = -transform.forward;
|
||||
// 根据缩放距离重新定位相机
|
||||
Vector3 newPosition = targetPoint + directionToCamera * zoomDistance;
|
||||
// 只更新位置,保持旋转不变
|
||||
// transform.position = newPosition;
|
||||
_rotateCameraPos = newPosition;
|
||||
// _zoomDelta = directionToCamera * zoomDistance;
|
||||
_zoomDelta = newPosition - transform.position;
|
||||
|
||||
// if (showDebugInfo)
|
||||
// {
|
||||
// Log($"透视缩放 - 目标点: {targetPoint}, 新位置: {newPosition}, 距离: {zoomDistance}");
|
||||
// }
|
||||
}
|
||||
|
||||
Vector3 ScreenTargetPoint()
|
||||
{
|
||||
Vector3 screenCenter = new Vector3(Screen.width * 0.5f, Screen.height * 0.5f, 0);
|
||||
Ray ray = cam.ScreenPointToRay(screenCenter);
|
||||
// 假设地面在Y=0,计算射线与地面的交点
|
||||
Vector3 targetPoint = Vector3.zero;
|
||||
if (ray.direction.y != 0)
|
||||
{
|
||||
float t = -ray.origin.y / ray.direction.y;
|
||||
if (t > 0)
|
||||
{
|
||||
targetPoint = ray.origin + ray.direction * t;
|
||||
}
|
||||
}
|
||||
return targetPoint;
|
||||
}
|
||||
|
||||
// 将屏幕空间的移动差值转换为世界空间
|
||||
Vector3 ScreenToWorldDelta(Vector3 screenDelta)
|
||||
{
|
||||
// 根据当前缩放级别调整移动灵敏度
|
||||
float scaleFactor = currentZoomDistance * 0.01f;
|
||||
|
||||
// 基于相机的当前方向向量进行转换
|
||||
Vector3 right = transform.right;
|
||||
Vector3 forward = transform.forward;
|
||||
|
||||
// 计算世界空间移动(保持在水平面)
|
||||
Vector3 worldDelta = (right * screenDelta.x + forward * screenDelta.y) * scaleFactor;
|
||||
worldDelta.y = 0; // 确保只在水平面移动
|
||||
|
||||
return worldDelta;
|
||||
}
|
||||
|
||||
// 公共接口
|
||||
public void SetZoom(float zoom)
|
||||
{
|
||||
targetZoomDistance = Mathf.Clamp(zoom, minZoom, maxZoom);
|
||||
}
|
||||
|
||||
public float GetZoom()
|
||||
{
|
||||
return currentZoomDistance;
|
||||
}
|
||||
|
||||
public void ZoomIn(float amount = 1f)
|
||||
{
|
||||
targetZoomDistance = Mathf.Clamp(targetZoomDistance - amount, minZoom, maxZoom);
|
||||
}
|
||||
|
||||
public void ZoomOut(float amount = 1f)
|
||||
{
|
||||
targetZoomDistance = Mathf.Clamp(targetZoomDistance + amount, minZoom, maxZoom);
|
||||
}
|
||||
|
||||
// 重置观察方向(如果需要的话)
|
||||
public void SetLookDirection(Vector3 direction)
|
||||
{
|
||||
fixedLookDirection = direction.normalized;
|
||||
transform.forward = fixedLookDirection;
|
||||
}
|
||||
|
||||
|
||||
void HandleMouseRotation()
|
||||
{
|
||||
float deltaX = Input.GetAxis("Mouse X");
|
||||
float deltaY = Input.GetAxis("Mouse Y");
|
||||
ApplyRotationDelta(deltaX,deltaY,rotationSpeed);
|
||||
}
|
||||
|
||||
void HandleMouseZoom()
|
||||
{
|
||||
float scrollInput = Input.GetAxis("Mouse ScrollWheel");
|
||||
if (scrollInput != 0)
|
||||
{
|
||||
var zoomChange = -scrollInput * zoomSpeed; // 负号使滚轮向上为放大
|
||||
targetZoomDistance = Mathf.Clamp(targetZoomDistance + zoomChange, minZoom, maxZoom);
|
||||
if (showDebugInfo)
|
||||
{
|
||||
Log($"滚轮缩放: {scrollInput} -> 目标缩放距离: {targetZoomDistance}");
|
||||
}
|
||||
}
|
||||
ApplyZoom();
|
||||
}
|
||||
|
||||
void HandleSingleTouchMove()
|
||||
{
|
||||
Touch touch = Input.GetTouch(0);
|
||||
|
||||
if (touch.phase == TouchPhase.Began)
|
||||
{
|
||||
lastTouchCenter = touch.position;
|
||||
wasTwoFingerActive = false;
|
||||
}
|
||||
else if (touch.phase == TouchPhase.Moved)
|
||||
{
|
||||
// Vector2 touchDelta = lastTouchCenter - touch.position;
|
||||
// Vector3 worldDelta = CalculateWorldDragDirection(touchDelta);
|
||||
// transform.position += worldDelta * dragSpeed * Time.deltaTime;
|
||||
// Vector3 currentMousePos = lastTouchCenter;
|
||||
// Vector3 mouseDelta = lastMousePosition - currentMousePos;
|
||||
if (!wasTwoFingerActive)
|
||||
{
|
||||
Vector2 touchDelta = lastTouchCenter - touch.position;
|
||||
Vector3 worldDelta = ScreenToWorldDelta(touchDelta);
|
||||
// transform.position += worldDelta * dragSpeed * Time.deltaTime;
|
||||
_moveValue = worldDelta * dragSpeed * Time.deltaTime;
|
||||
}
|
||||
|
||||
// 移动后重新计算距离
|
||||
// currentDistanceToCenter = Vector3.Distance(transform.position, currentRotationCenter);
|
||||
// targetDistanceToCenter = currentDistanceToCenter;
|
||||
// lastMousePosition = currentMousePos;
|
||||
// 移动后重新计算距离
|
||||
// currentDistanceToCenter = Vector3.Distance(transform.position, currentRotationCenter);
|
||||
// targetDistanceToCenter = currentDistanceToCenter;
|
||||
|
||||
lastTouchCenter = touch.position;
|
||||
}
|
||||
}
|
||||
|
||||
void HandleTwoFingerGestures()
|
||||
{
|
||||
if (Input.touchCount < 2) return;
|
||||
|
||||
Touch touch1 = Input.GetTouch(0);
|
||||
Touch touch2 = Input.GetTouch(1);
|
||||
|
||||
Vector2 currentCenter = (touch1.position + touch2.position) * 0.5f;
|
||||
float currentDistance = Vector2.Distance(touch1.position, touch2.position);
|
||||
|
||||
if (wasTwoFingerActive)
|
||||
{
|
||||
// HandleTwoFingerRotation(currentCenter);
|
||||
HandlePinchZoom(currentDistance);
|
||||
}
|
||||
|
||||
lastTouchCenter = currentCenter;
|
||||
lastTouchDistance = currentDistance;
|
||||
wasTwoFingerActive = true;
|
||||
}
|
||||
// void HandleTouchRotation()
|
||||
// {
|
||||
// if (Input.touchCount == 2)
|
||||
// {
|
||||
// Touch touch1 = Input.GetTouch(0);
|
||||
// Touch touch2 = Input.GetTouch(1);
|
||||
// // 只在两个手指都在移动时旋转
|
||||
// if (touch1.phase == TouchPhase.Moved && touch2.phase == TouchPhase.Moved)
|
||||
// {
|
||||
// // 取两个手指移动的平均值
|
||||
// Vector2 avgDelta = (touch1.deltaPosition + touch2.deltaPosition) * 0.5f;
|
||||
// float deltaX = avgDelta.x * 0.01f * touchRotationSpeed;
|
||||
// float deltaY = -avgDelta.y * 0.01f * touchRotationSpeed;
|
||||
// RotateCamera(deltaX, deltaY,touchRotationSpeed);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// isTouchRotating = false;
|
||||
// }
|
||||
// }
|
||||
|
||||
void ApplyRotationDelta(float deltaX, float deltaY, float speed)
|
||||
{
|
||||
Log($"ApplyRotationDelta -> {deltaX} {deltaY} {speed}");
|
||||
// 更新角度
|
||||
currentYaw += deltaX * speed;
|
||||
currentPitch -= deltaY * speed;
|
||||
// 限制垂直角度
|
||||
currentPitch = Mathf.Clamp(currentPitch, minRotationY, maxRotationY);
|
||||
|
||||
// Log($"UpdateRotationDelta -> {currentPitch}");
|
||||
// 计算新位置
|
||||
float yawRad = currentYaw * Mathf.Deg2Rad;
|
||||
float pitchRad = currentPitch * Mathf.Deg2Rad;
|
||||
|
||||
float x = distanceCameraToTarget * Mathf.Cos(pitchRad) * Mathf.Sin(yawRad);
|
||||
float y = distanceCameraToTarget * Mathf.Sin(pitchRad);
|
||||
float z = distanceCameraToTarget * Mathf.Cos(pitchRad) * Mathf.Cos(yawRad);
|
||||
|
||||
var newPosition = targetPosition + new Vector3(x, y, z);
|
||||
_rotateDelta = newPosition - transform.position;
|
||||
|
||||
Log($"UpdateRotationDelta ->{distanceCameraToTarget} {currentPitch} {_rotateDelta}");
|
||||
}
|
||||
|
||||
// void RotateCamera(float deltaX, float deltaY, float speed)
|
||||
// {
|
||||
// Log($"RotateCamera ->{deltaX} {deltaY} {speed}");
|
||||
//
|
||||
// if (!initialized) return;
|
||||
//
|
||||
// // 更新角度
|
||||
// currentYaw += deltaX * speed;
|
||||
// currentPitch -= deltaY * speed;
|
||||
//
|
||||
// // 限制垂直角度
|
||||
// currentPitch = Mathf.Clamp(currentPitch, -80f, 80f);
|
||||
//
|
||||
// // 计算新位置
|
||||
// float yawRad = currentYaw * Mathf.Deg2Rad;
|
||||
// float pitchRad = currentPitch * Mathf.Deg2Rad;
|
||||
//
|
||||
// float x = distanceCameraToTarget * Mathf.Cos(pitchRad) * Mathf.Sin(yawRad);
|
||||
// float y = distanceCameraToTarget * Mathf.Sin(pitchRad);
|
||||
// float z = distanceCameraToTarget * Mathf.Cos(pitchRad) * Mathf.Cos(yawRad);
|
||||
//
|
||||
// // 更新相机位置和朝向
|
||||
// transform.position = targetPosition + new Vector3(x, y, z);
|
||||
// transform.LookAt(targetPosition);
|
||||
// }
|
||||
|
||||
Color GetStateColor(InputState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case InputState.None: return Color.gray;
|
||||
case InputState.KeyboardMove: return Color.green;
|
||||
case InputState.MouseDrag: return Color.blue;
|
||||
case InputState.MouseRotate: return Color.red;
|
||||
case InputState.TouchMove: return Color.cyan;
|
||||
case InputState.TouchZoomRotate: return Color.magenta;
|
||||
default: return Color.white;
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
if (!showDebugInfo || !Application.isEditor) return;
|
||||
|
||||
GUI.backgroundColor = new Color(0, 0, 0, 0.8f);
|
||||
GUI.Box(new Rect(10, 10, 450, 220), "");
|
||||
GUI.backgroundColor = Color.white;
|
||||
|
||||
GUI.color = Color.yellow;
|
||||
GUI.Label(new Rect(20, 20, 430, 25), "🎯 视口中心旋转相机控制器",
|
||||
new GUIStyle(GUI.skin.label) { fontSize = 14, fontStyle = FontStyle.Bold });
|
||||
GUI.color = Color.white;
|
||||
|
||||
GUI.color = Color.white;
|
||||
var labelStyle = new GUIStyle(GUI.skin.label) { fontSize = 12 };
|
||||
|
||||
int yPos = 50;
|
||||
GUI.color = GetStateColor(currentState);
|
||||
GUI.Label(new Rect(20, yPos, 430, 20), $"🎮 输入状态: {currentState}", labelStyle);
|
||||
yPos += 20;
|
||||
GUI.color = Color.cyan;
|
||||
GUI.Label(new Rect(20, yPos, 430, 20),
|
||||
$"📏 距离旋转中心: {targetPosition:F2} → {distanceCameraToTarget:F2} {currentZoomDistance}", labelStyle);
|
||||
yPos += 20;
|
||||
GUI.color = Color.cyan;
|
||||
GUI.Label(new Rect(20, yPos, 430, 20),
|
||||
$"📏 移动旋转缩放: {_moveValue:F2} → {_rotateDelta:F2} {_zoomDelta}", labelStyle);
|
||||
// yPos += 20;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// var labelStyle = new GUIStyle(GUI.skin.label) { fontSize = 11 };
|
||||
}
|
||||
// 调试可视化
|
||||
void OnDrawGizmos()
|
||||
{
|
||||
if (Application.isPlaying && cam != null)
|
||||
{
|
||||
// 绘制当前观察方向
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawRay(transform.position, transform.forward * 5f);
|
||||
|
||||
// 绘制缩放中心点
|
||||
// Vector3 screenCenter = new Vector3(Screen.width * 0.5f, Screen.height * 0.5f, 0);
|
||||
// Ray ray = cam.ScreenPointToRay(screenCenter);
|
||||
// if (ray.direction.y != 0)
|
||||
{
|
||||
// float t = -ray.origin.y / ray.direction.y;
|
||||
// if (t > 0)
|
||||
{
|
||||
// Vector3 targetPoint = ray.origin + ray.direction * t;
|
||||
var targetPoint = targetPosition;
|
||||
Gizmos.color = Color.green;
|
||||
Gizmos.DrawWireSphere(targetPoint, 1f);
|
||||
|
||||
// 连线显示缩放关系
|
||||
Gizmos.color = Color.yellow;
|
||||
Gizmos.DrawLine(transform.position, targetPoint);
|
||||
}
|
||||
}
|
||||
|
||||
// if (initialized)
|
||||
// {
|
||||
// Gizmos.color = Color.red;
|
||||
// Gizmos.DrawWireSphere(targetPosition, 1f);
|
||||
// }
|
||||
// 缩放信息
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.Handles.Label(transform.position + Vector3.up * 2,
|
||||
$"缩放: {currentZoomDistance:F1} (目标: {targetZoomDistance:F1})");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f3be3f122a2040dc9ec1cc47700c0dd9
|
||||
timeCreated: 1757576580
|
||||
3
Assets/Scripts/HexGrid/Data.meta
Normal file
3
Assets/Scripts/HexGrid/Data.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c3b48a6c8cf493290afceba8a55464a
|
||||
timeCreated: 1757337898
|
||||
29
Assets/Scripts/HexGrid/Data/HexBuilding.cs
Normal file
29
Assets/Scripts/HexGrid/Data/HexBuilding.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HexGrid
|
||||
{
|
||||
public class Condtion{
|
||||
|
||||
};
|
||||
|
||||
|
||||
[System.Serializable]
|
||||
public class HexBuilding
|
||||
{
|
||||
public int zoneId;
|
||||
//public int tileId;
|
||||
public int buildingId;
|
||||
public int level;
|
||||
public string buildingName;
|
||||
// 直接使用的坐标
|
||||
public Vector3 buildingPosition; //
|
||||
public string buildCenterTileId;
|
||||
//TODO:LF 是否使用坐标
|
||||
public Vector2Int buildPosition;
|
||||
public List<Condtion> condtions;
|
||||
public List<string> hasTiles;
|
||||
// public GameObject buildModel;
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/HexGrid/Data/HexBuilding.cs.meta
Normal file
3
Assets/Scripts/HexGrid/Data/HexBuilding.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ae04bca5282b4ac9a1f57f0c3636146c
|
||||
timeCreated: 1757504293
|
||||
19
Assets/Scripts/HexGrid/Data/HexSubZone.cs
Normal file
19
Assets/Scripts/HexGrid/Data/HexSubZone.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace HexGrid
|
||||
{
|
||||
[System.Serializable]
|
||||
public class HexSubZone
|
||||
{
|
||||
//
|
||||
public int zoneId; // 属于哪个zone
|
||||
public int subZoneId;
|
||||
//public List<HexTile> tiles= new ();
|
||||
// 当前包括的地块Id
|
||||
public List<string> tileNames = new();
|
||||
//todo:LF 使用ID 比较好,效率更好一点
|
||||
// public List<int> tileIds = new();
|
||||
//TODO:LF 建筑列表
|
||||
// public List<HexBuilding> buildings = new();
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/HexGrid/Data/HexSubZone.cs.meta
Normal file
3
Assets/Scripts/HexGrid/Data/HexSubZone.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a2c69a061a164687896f45bc691fee8a
|
||||
timeCreated: 1757322216
|
||||
39
Assets/Scripts/HexGrid/Data/HexTile.cs
Normal file
39
Assets/Scripts/HexGrid/Data/HexTile.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
|
||||
// 应该移动到Data 中去
|
||||
namespace HexGrid
|
||||
{
|
||||
public enum TileType
|
||||
{
|
||||
None,
|
||||
Grass,
|
||||
Road,
|
||||
Water
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class HexTile
|
||||
{
|
||||
//可变的值
|
||||
//0 未激活 1 可建造 2 已经建造完成
|
||||
public int tileStatus;
|
||||
// 固定的值
|
||||
public int id; // 记录地块的Id,取代字符串,引入HexMath 的时候使用
|
||||
public int zoneId; // 保留 一下zoneId,可以快速找到zone
|
||||
public int subZoneIndex; // 子区域的索引
|
||||
public string zoneName;
|
||||
public string tileOriName; // 块的原始名,
|
||||
public string tileId; // 考虑是坐标合并(x_y) tile_0_0
|
||||
public SerializableVector2Int tileCoords; // 在 Chunk 内的坐标
|
||||
public TileType type;
|
||||
public GameObject visual;
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{tileId} -> {tileCoords} {type} -> tileStatus:{tileStatus}";
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/HexGrid/Data/HexTile.cs.meta
Normal file
3
Assets/Scripts/HexGrid/Data/HexTile.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b56b1822990b4b81802eb5e71412a047
|
||||
timeCreated: 1757322316
|
||||
26
Assets/Scripts/HexGrid/Data/HexZone.cs
Normal file
26
Assets/Scripts/HexGrid/Data/HexZone.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace HexGrid
|
||||
{
|
||||
|
||||
[System.Serializable]
|
||||
public class HexZone
|
||||
{
|
||||
//
|
||||
public int zoneId;
|
||||
public string zoneName;
|
||||
public bool isUnlocked;
|
||||
// 只渲染边缘即可,暂时保留
|
||||
public GameObject zoneObject; // Prefab / 解锁未建的时候构建一下
|
||||
public List<HexSubZone> subZones = new();
|
||||
public List<HexTile> tiles= new ();
|
||||
|
||||
public HexTile AddTile(HexTile tile)
|
||||
{
|
||||
tiles.Add(tile);
|
||||
return tile;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/HexGrid/Data/HexZone.cs.meta
Normal file
3
Assets/Scripts/HexGrid/Data/HexZone.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4732739fb4c44dcc89ec4712de280e7e
|
||||
timeCreated: 1757322148
|
||||
33
Assets/Scripts/HexGrid/Data/SerializableVector2Int.cs
Normal file
33
Assets/Scripts/HexGrid/Data/SerializableVector2Int.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using UnityEngine;
|
||||
namespace HexGrid
|
||||
{
|
||||
|
||||
[System.Serializable]
|
||||
public class SerializableVector2Int
|
||||
{
|
||||
public int x;
|
||||
public int y;
|
||||
|
||||
public SerializableVector2Int(int x, int y)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
// 隐式转换,方便使用
|
||||
public static implicit operator Vector2Int(SerializableVector2Int v)
|
||||
{
|
||||
return new Vector2Int(v.x, v.y);
|
||||
}
|
||||
|
||||
public static implicit operator SerializableVector2Int(Vector2Int v)
|
||||
{
|
||||
return new SerializableVector2Int(v.x, v.y);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"({x},{y})";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b763fe890be432b87f12145969ddd1a
|
||||
timeCreated: 1757939498
|
||||
3
Assets/Scripts/HexGrid/Editor.meta
Normal file
3
Assets/Scripts/HexGrid/Editor.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 26e7d1599e26438dbf61884703bfaaf0
|
||||
timeCreated: 1757931277
|
||||
486
Assets/Scripts/HexGrid/Editor/HexMapEditorWindow.cs
Normal file
486
Assets/Scripts/HexGrid/Editor/HexMapEditorWindow.cs
Normal file
@@ -0,0 +1,486 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using HexGrid.Math;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace HexGrid.Editor
|
||||
{
|
||||
public class HexMapEditorWindow: EditorWindow
|
||||
{
|
||||
private const string WindowName = "HexMapEditor";
|
||||
//
|
||||
private GameObject _tileRoot;
|
||||
//
|
||||
private GameObject _prefabTileRoot;
|
||||
|
||||
private Transform _rootForDelTrans;
|
||||
|
||||
// 当前的数量
|
||||
private int buttonCount = 0;
|
||||
private int selectedButton = 0;
|
||||
private string[] buttonLabels = {"选项1", "选项2", "选项3", "选项4"};
|
||||
|
||||
private int selectedIndex = 0;
|
||||
private List<string> buttonList = new List<string>();
|
||||
private string newButtonName = "新按钮";
|
||||
|
||||
|
||||
[MenuItem("Tools/HexMap/Editor")]
|
||||
static void OpenWindow()
|
||||
{
|
||||
// 创建窗口
|
||||
var window = GetWindow<HexMapEditorWindow>(WindowName);
|
||||
window.Show();
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
|
||||
HexMath.SetHexMapOrigin(Vector3.zero);
|
||||
HexMath.SetGridSize(1.52f);
|
||||
|
||||
//EditorGUILayout.Label("编辑器设置", EditorStyles.boldLabel);
|
||||
// GUILayout.Label("编辑器设置", EditorStyles.boldLabel);
|
||||
|
||||
// PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
|
||||
PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
|
||||
GameObject mapRootGo;
|
||||
if (!prefabStage)
|
||||
{
|
||||
|
||||
var sceneName = SceneManager.GetActiveScene().name;
|
||||
GUILayout.Label($"场景名: {sceneName}",EditorStyles.boldLabel);
|
||||
_tileRoot = EditorGUILayout.ObjectField("地图节点",_tileRoot,typeof(GameObject),true) as GameObject;
|
||||
mapRootGo = _tileRoot;
|
||||
_rootForDelTrans = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var prefabName = PrefabStageUtility.GetCurrentPrefabStage()?.prefabContentsRoot?.name?? "";
|
||||
GUILayout.Label("Prefab 编辑模式");
|
||||
GUILayout.Label($"prefabName: {prefabName}",EditorStyles.boldLabel);
|
||||
_prefabTileRoot = EditorGUILayout.ObjectField("Prefab地图节点",_prefabTileRoot,typeof(GameObject),true) as GameObject;
|
||||
mapRootGo = _prefabTileRoot;
|
||||
_rootForDelTrans = PrefabStageUtility.GetCurrentPrefabStage().prefabContentsRoot.transform;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(5f);
|
||||
|
||||
|
||||
EditorGUILayout.Space(10);
|
||||
if (GUILayout.Button("检查",GUILayout.Height(30)))
|
||||
{
|
||||
if (!mapRootGo)
|
||||
{
|
||||
EditorUtility.DisplayDialog("提示", "请设置地图节点", "确定");
|
||||
return;
|
||||
}
|
||||
CheckFatherTile(mapRootGo.transform);
|
||||
|
||||
}
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (GUILayout.Button("添加到Top",GUILayout.Height(30)))
|
||||
{
|
||||
if (!mapRootGo)
|
||||
{
|
||||
EditorUtility.DisplayDialog("提示", "请设置地图节点", "确定");
|
||||
return;
|
||||
}
|
||||
// ApplySettings(mapRootGo);
|
||||
MoveTerrainToMap(mapRootGo.transform);
|
||||
}
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (GUILayout.Button("从Top移除父类",GUILayout.Height(30)))
|
||||
{
|
||||
if (!_tileRoot)
|
||||
{
|
||||
EditorUtility.DisplayDialog("提示", "请设置地图节点", "确定");
|
||||
return;
|
||||
}
|
||||
RemoveFromTop();
|
||||
}
|
||||
|
||||
// EditorGUILayout.Space(10);
|
||||
// GUILayout.Label("动态按钮创建示例", EditorStyles.boldLabel);
|
||||
// EditorGUILayout.Space(5);
|
||||
//
|
||||
//
|
||||
// GUILayout.Label("动态 Selection Grid 示例", EditorStyles.boldLabel);
|
||||
//
|
||||
// // 添加按钮的控制区域
|
||||
// GUILayout.BeginHorizontal();
|
||||
// newButtonName = GUILayout.TextField(newButtonName, GUILayout.Width(150));
|
||||
// if (GUILayout.Button("添加按钮", GUILayout.Width(80)))
|
||||
// {
|
||||
// AddButton(newButtonName);
|
||||
// }
|
||||
// GUILayout.EndHorizontal();
|
||||
//
|
||||
// GUILayout.Space(10);
|
||||
//
|
||||
// // 只有当列表中有按钮时才显示 SelectionGrid
|
||||
// if (buttonList.Count > 0)
|
||||
// {
|
||||
// // 将 List 转换为数组传给 SelectionGrid[1][2]
|
||||
// selectedIndex = GUILayout.SelectionGrid(
|
||||
// selectedIndex,
|
||||
// buttonList.ToArray(), // 转换为数组
|
||||
// 3, // 每行3个按钮
|
||||
// GUILayout.Height(100)
|
||||
// );
|
||||
//
|
||||
// // 确保选中索引在有效范围内
|
||||
// if (selectedIndex >= buttonList.Count)
|
||||
// {
|
||||
// selectedIndex = buttonList.Count - 1;
|
||||
// }
|
||||
//
|
||||
// GUILayout.Space(10);
|
||||
// GUILayout.Label($"当前选中: {buttonList[selectedIndex]} (索引: {selectedIndex})");
|
||||
//
|
||||
// // 删除选中的按钮
|
||||
// if (GUILayout.Button("删除选中的按钮"))
|
||||
// {
|
||||
// RemoveSelectedButton();
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// GUILayout.Label("暂无按钮,请添加新按钮");
|
||||
// }
|
||||
//
|
||||
// // 清空所有按钮
|
||||
// if (buttonList.Count > 0 && GUILayout.Button("清空所有"))
|
||||
// {
|
||||
// ClearAll();
|
||||
// }
|
||||
|
||||
// // 主按钮 - 用于创建新按钮
|
||||
// if (GUILayout.Button("点击创建新按钮", GUILayout.Height(30)))
|
||||
// {
|
||||
// CreateNewButton();
|
||||
// }
|
||||
//
|
||||
// // 使用ScrollView以防按钮过多
|
||||
// if (buttonCount > 0)
|
||||
// {
|
||||
// GUILayout.Label($"已创建 {buttonCount} 个按钮:");
|
||||
//
|
||||
// // 显示所有动态创建的按钮
|
||||
// for (int i = 0; i < buttonCount; i++)
|
||||
// {
|
||||
// int index = i; // 捕获当前索引
|
||||
// if (GUILayout.Button($"动态按钮 #{index + 1}", GUILayout.Height(25)))
|
||||
// {
|
||||
// OnDynamicButtonClick(index);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// EditorGUILayout.Space(10);
|
||||
// // 清除所有按钮
|
||||
// if (buttonCount > 0 && GUILayout.Button("清除所有按钮"))
|
||||
// {
|
||||
// buttonCount = 0;
|
||||
// Repaint();
|
||||
// }
|
||||
//
|
||||
// // 使用水平布局
|
||||
// GUILayout.BeginHorizontal();
|
||||
// if (GUILayout.Button("创建普通按钮", GUILayout.Width(120),GUILayout.Height(120)))
|
||||
// {
|
||||
// // CreateButton("普通");
|
||||
// }
|
||||
// if (GUILayout.Button("创建特殊按钮", GUILayout.Width(120)))
|
||||
// {
|
||||
// // CreateButton("特殊");
|
||||
// }
|
||||
// GUILayout.EndHorizontal();
|
||||
|
||||
// // 使用SelectionGrid创建按钮组
|
||||
// int selected = GUILayout.SelectionGrid(-1, new string[] {"按钮1", "按钮2", "按钮3","按钮4"}, 3,
|
||||
// GUILayout.Width(300), // 设置总宽度为200
|
||||
// GUILayout.Height(100) // 设置总高度为100
|
||||
// );
|
||||
//
|
||||
// if (selected >= 0)
|
||||
// {
|
||||
// Debug.Log($"选择了按钮 {selected + 1}");
|
||||
// }
|
||||
//
|
||||
// GUILayout.Label("带样式的 Selection Grid");
|
||||
//
|
||||
// // 创建自定义样式
|
||||
// GUIStyle gridStyle = new GUIStyle(GUI.skin.button);
|
||||
//
|
||||
// // 未选中按钮样式
|
||||
// gridStyle.normal.textColor = Color.gray;
|
||||
//
|
||||
// // 选中按钮样式(on前缀表示选中状态)
|
||||
// gridStyle.onNormal.textColor = Color.cyan;
|
||||
// gridStyle.fontStyle = FontStyle.Bold;
|
||||
//
|
||||
// // 创建带自定义样式的选择网格
|
||||
// selectedButton = GUILayout.SelectionGrid(
|
||||
// selectedButton,
|
||||
// buttonLabels,
|
||||
// 3, // 每行2个按钮
|
||||
// gridStyle, // 使用自定义样式[1][2]
|
||||
// GUILayout.Width(300),
|
||||
// GUILayout.Height(100)
|
||||
// );
|
||||
//
|
||||
// GUILayout.Space(10);
|
||||
// GUILayout.Label($"当前选中: {buttonLabels[selectedButton]}");
|
||||
}
|
||||
|
||||
void AddButton(string name)
|
||||
{
|
||||
buttonList.Add($"{name} {buttonList.Count + 1}");
|
||||
Repaint();
|
||||
}
|
||||
|
||||
void RemoveSelectedButton()
|
||||
{
|
||||
if (selectedIndex >= 0 && selectedIndex < buttonList.Count)
|
||||
{
|
||||
buttonList.RemoveAt(selectedIndex);
|
||||
// 调整选中索引
|
||||
if (selectedIndex >= buttonList.Count && buttonList.Count > 0)
|
||||
{
|
||||
selectedIndex = buttonList.Count - 1;
|
||||
}
|
||||
Repaint();
|
||||
}
|
||||
}
|
||||
|
||||
void ClearAll()
|
||||
{
|
||||
buttonList.Clear();
|
||||
selectedIndex = 0;
|
||||
Repaint();
|
||||
}
|
||||
private void CreateNewButton()
|
||||
{
|
||||
buttonCount++;
|
||||
Debug.Log($"创建了新按钮,当前按钮总数:{buttonCount}");
|
||||
Repaint(); // 重绘窗口以显示新按钮
|
||||
}
|
||||
|
||||
private void OnDynamicButtonClick(int index)
|
||||
{
|
||||
Log($"点击了动态按钮 #{index + 1}");
|
||||
}
|
||||
|
||||
private static void Log(string s)
|
||||
{
|
||||
Debug.Log($"<color=yellow>FishingChallengeManager -> {s} </color>");
|
||||
}
|
||||
|
||||
|
||||
private void RemoveFromTop()
|
||||
{
|
||||
if (Selection.gameObjects.Length == 0)
|
||||
{
|
||||
Debug.LogWarning("请先选择一个或多个对象");
|
||||
return;
|
||||
}
|
||||
|
||||
var list = new List<Object>();
|
||||
foreach (var t in Selection.gameObjects)
|
||||
{
|
||||
var paGameObj = t.transform.parent?.gameObject;
|
||||
if (paGameObj && paGameObj.name.StartsWith("top"))
|
||||
{
|
||||
Undo.SetTransformParent(t.transform, null, "Remove Parent of " + t.gameObject.name ?? "");
|
||||
t.transform.SetParent(_rootForDelTrans, true);
|
||||
list.Add(t);
|
||||
}
|
||||
}
|
||||
Selection.objects = list.ToArray();
|
||||
FocusSelectinHierarchy();
|
||||
}
|
||||
|
||||
private void Test()
|
||||
{
|
||||
// var enumerable = Selection.gameObjects.Select(elem => elem.transform).ToList();
|
||||
// var mapRoot = _tileRoot.transform;
|
||||
// foreach (var child in enumerable)
|
||||
// {
|
||||
// // child.SetParent(mapRoot,true);
|
||||
// Undo.SetTransformParent(child,mapRoot,$"Reparent {child.gameObject.name}");
|
||||
// child.SetParent(mapRoot,true);
|
||||
// }
|
||||
|
||||
// var obj = Selection.activeGameObject;
|
||||
// EditorApplication.delayCall += () =>
|
||||
// {
|
||||
// EditorGUIUtility.PingObject(obj);
|
||||
// Selection.activeGameObject = obj;
|
||||
// };
|
||||
|
||||
}
|
||||
|
||||
private void CheckFatherTile(Transform mapRoot)
|
||||
{
|
||||
|
||||
var mapTiles = mapRoot.GetComponentsInChildren<Transform>(true);
|
||||
var list = new List<Object>();
|
||||
var enumerable = Selection.gameObjects.Where(elem => elem.transform != mapRoot).Select(elem => elem.transform).ToList();
|
||||
foreach (var pos in enumerable.Select(child => HexMath.PixelToAxial(child.position)))
|
||||
{
|
||||
foreach (Transform tile in mapTiles)
|
||||
{
|
||||
// if(tile.Equals(mapRoot)) continue;
|
||||
// if()
|
||||
var hexGridController = tile.GetComponent<HexGridTiler>();
|
||||
if(!hexGridController) continue;
|
||||
var tilePos = HexMath.PixelToAxial(tile.position);
|
||||
if (tilePos.Equals(pos))
|
||||
{
|
||||
var onTop = tile.Find("on/top");
|
||||
ExpandParentHierarchy(onTop);
|
||||
list.Add(tile.gameObject);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list.AddRange(Selection.objects);
|
||||
Selection.objects = list.ToArray();
|
||||
FocusSelectinHierarchy();
|
||||
}
|
||||
//
|
||||
private void MoveTerrainToMap(Transform mapRoot)
|
||||
{
|
||||
|
||||
Undo.IncrementCurrentGroup();
|
||||
Undo.SetCurrentGroupName("Reparent");
|
||||
var mapTiles = mapRoot.GetComponentsInChildren<Transform>(true);
|
||||
|
||||
var list = new List<GameObject>();
|
||||
var enumerable = Selection.gameObjects.Select(elem => elem.transform).ToList();
|
||||
foreach (var child in enumerable)
|
||||
{
|
||||
var pos = HexMath.PixelToAxial(child.position);
|
||||
foreach (Transform tile in mapTiles)
|
||||
{
|
||||
var tilePos = HexMath.PixelToAxial(tile.position);
|
||||
if (tilePos.Equals(pos))
|
||||
{
|
||||
var onTop = tile.Find("on/top");
|
||||
Undo.SetTransformParent(child,onTop,$"$Reparent {child.gameObject.name}");
|
||||
child.SetParent(onTop,true);
|
||||
list.Add(child.gameObject);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// var tile = HexMath.PixelToAxial(terr.position)
|
||||
}
|
||||
Selection.objects = list.ToArray();
|
||||
FocusSelectinHierarchy();
|
||||
|
||||
}
|
||||
|
||||
private static void ExpandParentHierarchy(Transform target)
|
||||
{
|
||||
if (!target) return;
|
||||
|
||||
List<GameObject> path = new List<GameObject>();
|
||||
Transform current = target;
|
||||
|
||||
// 收集从目标到根的路径
|
||||
path.Add(current.gameObject);
|
||||
// 从根到目标依次展开
|
||||
for (int i = path.Count - 1; i >= 0; i--)
|
||||
{
|
||||
// 使用内部方法展开 Hierarchy 中的对象
|
||||
var type = typeof(EditorWindow).Assembly.GetType("UnityEditor.SceneHierarchyWindow");
|
||||
var window = EditorWindow.GetWindow(type);
|
||||
var expandMethod = type.GetMethod("SetExpandedRecursive");
|
||||
|
||||
if (expandMethod != null)
|
||||
{
|
||||
expandMethod.Invoke(window, new object[] { path[i].GetInstanceID(), true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void FocusSelectinHierarchy()
|
||||
{
|
||||
SceneView sceneView = SceneView.lastActiveSceneView;
|
||||
sceneView.Focus();
|
||||
sceneView.FrameSelected();
|
||||
|
||||
var selected = Selection.activeGameObject;
|
||||
if (selected)
|
||||
{
|
||||
// EditorGUIUtility.PingObject(selected);
|
||||
EditorApplication.delayCall += () =>
|
||||
{
|
||||
// ExpandParentHierarchy(selected.transform);
|
||||
EditorGUIUtility.PingObject(selected);
|
||||
};
|
||||
}
|
||||
}
|
||||
private void ApplySettings(Transform mapRoot)
|
||||
{
|
||||
MoveTerrainToMap(mapRoot);
|
||||
|
||||
// PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
//
|
||||
// GameObject prefabRoot = prefabStage.prefabContentsRoot;
|
||||
//
|
||||
// Debug.Log($"当前Prefab根节点: {prefabRoot.name}");
|
||||
// // 选中根节点
|
||||
// Selection.activeGameObject = prefabRoot;
|
||||
|
||||
// 检查是否在Prefab模式
|
||||
// PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
// if (prefabStage != null)
|
||||
// {
|
||||
// // 在Prefab模式中
|
||||
// GameObject prefabRoot = prefabStage.prefabContentsRoot;
|
||||
// Debug.Log($"Prefab根节点: {prefabRoot.name}");
|
||||
// Selection.activeGameObject = prefabRoot;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // 在场景模式中
|
||||
// Scene activeScene = SceneManager.GetActiveScene();
|
||||
// GameObject[] sceneRoots = activeScene.GetRootGameObjects();
|
||||
//
|
||||
// Debug.Log($"场景 '{activeScene.name}' 的根节点:");
|
||||
// foreach (var root in sceneRoots)
|
||||
// {
|
||||
// Debug.Log($"- {root.name}");
|
||||
// }
|
||||
// Selection.objects = sceneRoots;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// GameObject[] rootGameObjects = SceneManager.GetActiveScene().GetRootGameObjects();
|
||||
//
|
||||
// foreach (GameObject root in rootGameObjects)
|
||||
// {
|
||||
// Debug.Log("根节点: " + root.name);
|
||||
// }
|
||||
|
||||
// if (Selection.activeGameObject)
|
||||
// {
|
||||
// Undo.RecordObject(Selection.activeGameObject, "Apply Settings");
|
||||
// // 应用设置到选中的对象
|
||||
// // Selection.activeGameObject.name = objectName;
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/HexGrid/Editor/HexMapEditorWindow.cs.meta
Normal file
3
Assets/Scripts/HexGrid/Editor/HexMapEditorWindow.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1791b26af7cd42d3a08f13f1f73b8038
|
||||
timeCreated: 1758249532
|
||||
3
Assets/Scripts/HexGrid/Editor/Tests.meta
Normal file
3
Assets/Scripts/HexGrid/Editor/Tests.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d0e13fbedff0461faabb401366c92767
|
||||
timeCreated: 1757930649
|
||||
94
Assets/Scripts/HexGrid/Editor/Tests/AxialToPixelTests.cs
Normal file
94
Assets/Scripts/HexGrid/Editor/Tests/AxialToPixelTests.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
// using NUnit.Framework;
|
||||
// using UnityEngine;
|
||||
//
|
||||
namespace HexGrid.Tests
|
||||
{
|
||||
// public class AxialToPixelTests
|
||||
// {
|
||||
// // 假设的网格大小和原点位置,应与被测试代码中的值一致
|
||||
// private const float _gridSize = 1.0f; // 根据实际情况调整
|
||||
// private static readonly Vector3 _originPos = Vector3.zero; // 根据实际情况调整
|
||||
//
|
||||
// [Test]
|
||||
// public void TestAxialToPixel_Origin()
|
||||
// {
|
||||
// // 测试原点坐标 (0, 0)
|
||||
// Vector3 result = AxialToPixel(0, 0);
|
||||
// Vector3 expected = _originPos;
|
||||
// Assert.AreEqual(expected, result, "原点坐标转换不正确");
|
||||
// }
|
||||
//
|
||||
// [Test]
|
||||
// public void TestAxialToPixel_QDirection()
|
||||
// {
|
||||
// // 测试沿Q轴方向的移动
|
||||
// Vector3 result = AxialToPixel(2, 0);
|
||||
// Vector3 expected = new Vector3(_gridSize * Mathf.Sqrt(3f) * 2, 0, 0) + _originPos;
|
||||
// Assert.AreEqual(expected, result, "Q轴方向坐标转换不正确");
|
||||
// }
|
||||
//
|
||||
// [Test]
|
||||
// public void TestAxialToPixel_RDirection()
|
||||
// {
|
||||
// // 测试沿R轴方向的移动
|
||||
// Vector3 result = AxialToPixel(0, 2);
|
||||
// Vector3 expected = new Vector3(0, 0, _gridSize * 1.5f * 2) + _originPos;
|
||||
// Assert.AreEqual(expected, result, "R轴方向坐标转换不正确");
|
||||
// }
|
||||
//
|
||||
// [Test]
|
||||
// public void TestAxialToPixel_BothDirections()
|
||||
// {
|
||||
// // 测试同时沿Q轴和R轴移动
|
||||
// Vector3 result = AxialToPixel(2, 3);
|
||||
//
|
||||
// float expectedX = _gridSize * Mathf.Sqrt(3f) * (2 + 3 / 2f);
|
||||
// float expectedZ = _gridSize * 1.5f * 3;
|
||||
// Vector3 expected = new Vector3(expectedX, 0, expectedZ) + _originPos;
|
||||
//
|
||||
// Assert.AreEqual(expected, result, "Q+R方向坐标转换不正确");
|
||||
// }
|
||||
//
|
||||
// [Test]
|
||||
// public void TestAxialToPixel_NegativeValues()
|
||||
// {
|
||||
// // 测试负值坐标
|
||||
// Vector3 result = AxialToPixel(-2, -3);
|
||||
//
|
||||
// float expectedX = _gridSize * Mathf.Sqrt(3f) * (-2 + -3 / 2f);
|
||||
// float expectedZ = _gridSize * 1.5f * -3;
|
||||
// Vector3 expected = new Vector3(expectedX, 0, expectedZ) + _originPos;
|
||||
//
|
||||
// Assert.AreEqual(expected, result, "负值坐标转换不正确");
|
||||
// }
|
||||
//
|
||||
// [Test]
|
||||
// public void TestAxialToPixel_WithDifferentGridSize()
|
||||
// {
|
||||
// // 如果_gridSize可配置,测试不同的网格大小
|
||||
// // 注意:这需要你能修改_gridSize的值
|
||||
// // float originalGridSize = _gridSize;
|
||||
// // _gridSize = 2.0f;
|
||||
//
|
||||
// // Vector3 result = AxialToPixel(1, 1);
|
||||
// // float expectedX = 2.0f * Mathf.Sqrt(3f) * (1 + 1 / 2f);
|
||||
// // float expectedZ = 2.0f * 1.5f * 1;
|
||||
// // Vector3 expected = new Vector3(expectedX, 0, expectedZ) + _originPos;
|
||||
//
|
||||
// // Assert.AreEqual(expected, result, "不同网格大小下的坐标转换不正确");
|
||||
//
|
||||
// // _gridSize = originalGridSize; // 恢复原始值
|
||||
//
|
||||
// // 如果_gridSize不可修改,可以跳过这个测试或添加注释说明
|
||||
// Assert.Pass("网格大小不可配置,跳过此测试");
|
||||
// }
|
||||
//
|
||||
// // 这是被测试的函数副本,用于测试
|
||||
// public static Vector3 AxialToPixel(int q, int r)
|
||||
// {
|
||||
// var x = _gridSize * Mathf.Sqrt(3f) * (q + r / 2f);
|
||||
// var z = _gridSize * 1.5f * r;
|
||||
// return new Vector3(x, 0, z) + _originPos;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: efbe296c664a45f79d6e940de63e03fe
|
||||
timeCreated: 1757930665
|
||||
23
Assets/Scripts/HexGrid/HexGridMap.cs
Normal file
23
Assets/Scripts/HexGrid/HexGridMap.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
// 状态的存储用的是PlayFab 吗?
|
||||
namespace HexGrid
|
||||
{
|
||||
[CreateAssetMenu(fileName = "HexGridMap", menuName = "ScriptableObjects/HexMap")]
|
||||
public class HexGridMap:ScriptableObject
|
||||
{
|
||||
public int width = 10;
|
||||
public int height = 10;
|
||||
//
|
||||
public List<HexBuilding> buildings = new();
|
||||
public List<HexZone> zones = new();
|
||||
//
|
||||
public void Clear()
|
||||
{
|
||||
buildings.Clear();
|
||||
zones.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/HexGrid/HexGridMap.cs.meta
Normal file
3
Assets/Scripts/HexGrid/HexGridMap.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e0c331f9403c40c8b10fc9591c52e558
|
||||
timeCreated: 1757319406
|
||||
126
Assets/Scripts/HexGrid/HexGridMediator.cs
Normal file
126
Assets/Scripts/HexGrid/HexGridMediator.cs
Normal file
@@ -0,0 +1,126 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using DG.Tweening;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HexGrid
|
||||
{
|
||||
// 调停者
|
||||
// 进度管理器
|
||||
public class HexGridMediator : MonoBehaviour,IHexGridMediator
|
||||
{
|
||||
|
||||
private HexZoneManager _zoneManager;
|
||||
//
|
||||
private BuildingManager _buildingManager;
|
||||
|
||||
public void RegisterZoneManager(HexZoneManager zoneManager)
|
||||
{
|
||||
_zoneManager = zoneManager;
|
||||
}
|
||||
|
||||
public void RegisterBuildingManager(BuildingManager buildMamanger)
|
||||
{
|
||||
_buildingManager = buildMamanger;
|
||||
}
|
||||
|
||||
public async void OnHexCellClicked(HexTile tiler)
|
||||
{
|
||||
if (_zoneManager.OnHexTileData(tiler))
|
||||
{
|
||||
await Awaiters.Seconds(0.2f);
|
||||
await CheckBuildingAfterBuild(tiler);
|
||||
await OnActiveNextTile(tiler);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task OnActiveNextTile(HexTile tiler)
|
||||
{
|
||||
await _zoneManager.OnActiveNextTile(tiler);
|
||||
}
|
||||
|
||||
public async Task CheckBuildingAfterBuild(HexTile tiler)
|
||||
{
|
||||
await _buildingManager.CheckBuildingAfterBuild(tiler);
|
||||
}
|
||||
|
||||
public void CheckBuildingAfterBuildImme(HexTile tile)
|
||||
{
|
||||
_buildingManager.CheckBuildingAfterBuildImme(tile);
|
||||
}
|
||||
|
||||
public void LoadZones(List<HexZone> zones)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//-
|
||||
public void LoadBuildings(List<HexBuilding> buildings)
|
||||
{
|
||||
_buildingManager.LoadBuildings(buildings);
|
||||
}
|
||||
|
||||
public async void Build(int zoneId,BuildingData buildingData,bool isImme)
|
||||
{
|
||||
Log($"Build-> {zoneId} {buildingData.BuildingName}");
|
||||
|
||||
var root = _zoneManager.GetBuildingRoot(zoneId);
|
||||
if (!root) return;
|
||||
//_buildingManager.Build(root.transform, buildingData);
|
||||
var buildTrans = root.transform.Find(buildingData.BuildingName);
|
||||
var endPos = buildTrans.position;
|
||||
var tileNames = buildingData.TileStateMap.Keys;
|
||||
var duration = 0.5f;
|
||||
|
||||
foreach (var tileName in tileNames)
|
||||
{
|
||||
var tile = _zoneManager.GetTileByName(zoneId, tileName);
|
||||
if (tile.visual)
|
||||
{
|
||||
var top = tile.visual.transform.Find("on/top");
|
||||
if (top)
|
||||
{
|
||||
if (isImme)
|
||||
{
|
||||
top.gameObject.SetActive(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
top.DOMove(endPos, duration).SetEase(Ease.InSine).OnComplete(() =>
|
||||
{
|
||||
top.gameObject.SetActive(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isImme)
|
||||
{
|
||||
await Awaiters.Seconds(duration);
|
||||
}
|
||||
if (buildTrans)
|
||||
{
|
||||
buildTrans.gameObject.SetActive(true);
|
||||
}
|
||||
if (isImme)
|
||||
{
|
||||
buildTrans.localScale = Vector3.one;
|
||||
}
|
||||
else
|
||||
{
|
||||
var ani = buildTrans.GetComponent<Animation>();
|
||||
if (ani)
|
||||
{
|
||||
ani.Play("grow");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void Log(string t)
|
||||
{
|
||||
Debug.Log($"<color=orange>HexGridMediator -> {t} </color>");
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/HexGrid/HexGridMediator.cs.meta
Normal file
3
Assets/Scripts/HexGrid/HexGridMediator.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d14371ef6ed24213bad2610af429598e
|
||||
timeCreated: 1757391856
|
||||
127
Assets/Scripts/HexGrid/HexGridTiler.cs
Normal file
127
Assets/Scripts/HexGrid/HexGridTiler.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using com.fpnn.livedata;
|
||||
using HexGrid.MapHelper;
|
||||
using HexGrid.Math;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HexGrid
|
||||
{
|
||||
// 看看用来触发事件可行吗
|
||||
public class HexGridTiler : MonoBehaviour
|
||||
{
|
||||
//
|
||||
private HexTile _tileData;
|
||||
|
||||
//组件
|
||||
private Transform _on;
|
||||
private Transform _off;
|
||||
// 坐标显示
|
||||
private TMP_Text _textCoords;
|
||||
|
||||
// 调停者
|
||||
private IHexGridMediator _mediator;
|
||||
// 动画
|
||||
private Animation _animation;
|
||||
private void Awake()
|
||||
{
|
||||
Log($"Awake ->{gameObject.name}");
|
||||
//
|
||||
_on = transform.Find("on");
|
||||
_off = transform.Find("off");
|
||||
_textCoords = transform.Find("text_coords").GetComponent<TMP_Text>();
|
||||
//
|
||||
_animation = GetComponent<Animation>();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
Log($"Start()-> {gameObject.name}: {_tileData}");
|
||||
}
|
||||
|
||||
public void SetMediator(IHexGridMediator mediator)
|
||||
{
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
public void LoadTileData(HexTile tile)
|
||||
{
|
||||
Log($"LoadTileData() ->{tile}");
|
||||
_tileData = tile;
|
||||
UpdateName();
|
||||
UpdateCoordsText();
|
||||
}
|
||||
|
||||
private void UpdateCoordsText()
|
||||
{
|
||||
if (_textCoords)
|
||||
{
|
||||
_textCoords.text = _tileData.tileCoords.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateName()
|
||||
{
|
||||
// var tileName = $"tile{_tileData.tileCoords}";
|
||||
var tileName = HexUtils.MakeTileId(_tileData.tileCoords);
|
||||
Log($"UpdateName()-> {tileName}");
|
||||
gameObject.name = tileName;
|
||||
}
|
||||
|
||||
//
|
||||
public async void OnHexCellClicked()
|
||||
{
|
||||
if (_tileData == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 放到调停者当中去
|
||||
if (_tileData.tileStatus == 1)
|
||||
{
|
||||
_animation.Play("rotation");
|
||||
}
|
||||
|
||||
_mediator.OnHexCellClicked(_tileData);
|
||||
|
||||
}
|
||||
|
||||
public void UpdateVisual()
|
||||
{
|
||||
Log("UpdateVisual -> ");
|
||||
|
||||
var status = _tileData.tileStatus;
|
||||
if (status == 0)
|
||||
{
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
gameObject.SetActive(true);
|
||||
if (status == 1)
|
||||
{
|
||||
_on.gameObject.SetActive(true);
|
||||
_off.gameObject.SetActive(true);
|
||||
_off.localScale = Vector3.one;
|
||||
_on.localScale = new Vector3(0, 0, 0);
|
||||
_on.rotation = Quaternion.Euler(0,60,270);
|
||||
}
|
||||
else if (status == 2)
|
||||
{
|
||||
_on.gameObject.SetActive(true);
|
||||
_off.gameObject.SetActive(false);
|
||||
_off.localScale = Vector3.zero;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void Log(object t)
|
||||
{
|
||||
Debug.Log($"<color=yellow>HexGridTiler -> {t} </color>");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
3
Assets/Scripts/HexGrid/HexGridTiler.cs.meta
Normal file
3
Assets/Scripts/HexGrid/HexGridTiler.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 40b5bb603e91485d88cc2cee57ccab0c
|
||||
timeCreated: 1757335157
|
||||
47
Assets/Scripts/HexGrid/HexMapAct.cs
Normal file
47
Assets/Scripts/HexGrid/HexMapAct.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using asap.core;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UniRx;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using System.Threading.Tasks;
|
||||
using GameCore;
|
||||
|
||||
namespace HexGrid
|
||||
{
|
||||
public class HexMapAct :AGameAct
|
||||
{
|
||||
//
|
||||
public string mapName = "hex_build_01";
|
||||
// 地图 Prefab
|
||||
private GameObject _obj;
|
||||
public override async Task<bool> StartAsync()
|
||||
{
|
||||
_obj = await Addressables.InstantiateAsync(mapName).Task;
|
||||
Input.multiTouchEnabled = true;
|
||||
GetUI();
|
||||
return await base.StartAsync();
|
||||
}
|
||||
private async void GetUI()
|
||||
{
|
||||
await Task.Delay(400);
|
||||
await UIManager.Instance.ShowUI(new UIType("HexMapPanel"));
|
||||
}
|
||||
public override async Task StopAsync()
|
||||
{
|
||||
if (_obj)
|
||||
{
|
||||
Addressables.Release(_obj);
|
||||
DestroyImmediate(_obj);
|
||||
}
|
||||
Input.multiTouchEnabled = false;
|
||||
UIManager.Instance.DestroyUI("HexMapPanel");
|
||||
await Awaiters.NextFrame;
|
||||
}
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
Debug.Log("HexGridAct Destroyed!");
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/HexGrid/HexMapAct.cs.meta
Normal file
3
Assets/Scripts/HexGrid/HexMapAct.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ac9b12025b39414f8d1ff8d076c7091d
|
||||
timeCreated: 1757329066
|
||||
196
Assets/Scripts/HexGrid/HexMapManager.cs
Normal file
196
Assets/Scripts/HexGrid/HexMapManager.cs
Normal file
@@ -0,0 +1,196 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using asap.core;
|
||||
using Cinemachine;
|
||||
using Newtonsoft.Json;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
// 格子管理
|
||||
// 作为 调停者 使用
|
||||
namespace HexGrid{
|
||||
|
||||
public class HexGridMapUserData
|
||||
{
|
||||
//
|
||||
private int zoneNum = 2;
|
||||
//
|
||||
public int zoneCurrentIndex = 0; // [0,1];
|
||||
//
|
||||
public int subZoneCurrentIndex = 0; // []
|
||||
// 已经完成的地块
|
||||
public List<string> completeTiles = new();
|
||||
// 属性
|
||||
public Dictionary<string, int> Properties1 = new();
|
||||
//
|
||||
public Dictionary<string, int> Properties2 = new();
|
||||
|
||||
// 当前tile块的数值
|
||||
// <Id,status>
|
||||
// private Dictionary<int, int> tiles = new Dictionary<int, int>();
|
||||
// private Dictionary<int, int> buildings = new Dictionary<int, int>();
|
||||
|
||||
}
|
||||
public class HexMapDataManager
|
||||
{
|
||||
public const string SaveKey = "HexMapData";
|
||||
public HexGridMapUserData UserMapData { get; private set; }
|
||||
|
||||
public void Init()
|
||||
{
|
||||
UserMapData ??= new HexGridMapUserData
|
||||
{
|
||||
zoneCurrentIndex = 0,
|
||||
subZoneCurrentIndex = 0
|
||||
};
|
||||
SaveUserData();
|
||||
}
|
||||
|
||||
public void ClearMapData()
|
||||
{
|
||||
UserMapData = null;
|
||||
SaveUserData();
|
||||
}
|
||||
//
|
||||
public void SaveUserData()
|
||||
{
|
||||
PlayFabMgr.Instance.UpdateUserDataValue(SaveKey, JsonConvert.SerializeObject(UserMapData));
|
||||
}
|
||||
|
||||
public void LoadUserData(string dataValue)
|
||||
{
|
||||
UserMapData = JsonConvert.DeserializeObject<HexGridMapUserData>(dataValue);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
public class HexMapManager : MonoBehaviour
|
||||
{
|
||||
//
|
||||
public HexZoneManager zoneManager;
|
||||
public TerrainManager terrainManager;
|
||||
public BuildingManager buildingManager;
|
||||
public HexGridMediator hexGridMediator;
|
||||
public Transform hexMapRoot;
|
||||
public Camera mainCamera;
|
||||
public string mapName = "hex_build_01";
|
||||
|
||||
// 设置的
|
||||
private CinemachineVirtualCamera _vCam;
|
||||
// 数据
|
||||
private HexGridMap _mapInfo;
|
||||
private HexMapDataManager _dataManager;
|
||||
//
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
mainCamera = Camera.main;
|
||||
_dataManager = GContext.container.Resolve<HexMapDataManager>();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
zoneManager.SetRoot(hexMapRoot);
|
||||
zoneManager.SetMediator(hexGridMediator);
|
||||
zoneManager.SetHexMapManager(this);
|
||||
//
|
||||
buildingManager.SetMediator(hexGridMediator);
|
||||
//
|
||||
hexGridMediator.RegisterZoneManager(zoneManager);
|
||||
hexGridMediator.RegisterBuildingManager(buildingManager);
|
||||
_ = InitMapInfo();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (Input.touchCount > 0 )
|
||||
{
|
||||
if (Input.GetTouch(0).phase == TouchPhase.Began)
|
||||
{
|
||||
CheckHit(Input.GetTouch(0).position);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 鼠标点击(PC)
|
||||
if (Input.GetMouseButtonDown(0))
|
||||
{
|
||||
CheckHit(Input.mousePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void OnDisable()
|
||||
{
|
||||
if (_vCam)
|
||||
{
|
||||
_vCam.m_Lens.Orthographic = false;
|
||||
if (!Camera.main) return;
|
||||
var brain = Camera.main.GetComponent<CinemachineBrain>();
|
||||
brain?.ManualUpdate();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 检测点击或触摸位置击中了哪个物体
|
||||
/// </summary>
|
||||
private void CheckHit(Vector3 screenPosition)
|
||||
{
|
||||
if (mainCamera == null)
|
||||
mainCamera = Camera.main;
|
||||
var ray = mainCamera.ScreenPointToRay(screenPosition);
|
||||
if (Physics.Raycast(ray, out RaycastHit hit))
|
||||
{
|
||||
Debug.Log("点击到了: " + hit.collider.name);
|
||||
var hexGridTiler = hit.collider.GetComponent<HexGridTiler> ();
|
||||
if (hexGridTiler)
|
||||
{
|
||||
hexGridTiler.OnHexCellClicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
public void UnlockZone(int zoneId)
|
||||
{
|
||||
var zone = zoneManager.GetZoneById(zoneId);
|
||||
if (zone != null && !zone.isUnlocked)
|
||||
{
|
||||
// if (GameManager.Instance.SpendMoney(zone.unlockCost))
|
||||
{
|
||||
zone.isUnlocked = true;
|
||||
zone.zoneObject.SetActive(true);
|
||||
terrainManager.UpdateTerrainForZone(zoneId);
|
||||
// 假设用 zoneId 推导 Chunk 坐标
|
||||
Vector2Int chunkCoord = new Vector2Int(zoneId % 3, zoneId / 3);
|
||||
// ChunkManager.Instance.UnlockChunk(chunkCoord);
|
||||
// cameraController.FocusOn(zone.zoneObject.transform.position);
|
||||
// FXManager.Instance.PlayUnlockEffect(zone.zoneObject.transform.position);
|
||||
//SaveMapState();
|
||||
SaveUserData();
|
||||
}
|
||||
}
|
||||
}
|
||||
private async Task InitMapInfo()
|
||||
{
|
||||
var mapInfo = mapName + "_info";
|
||||
_mapInfo = (HexGridMap)await Addressables.LoadAssetAsync<object>(mapInfo).Task;
|
||||
LoadMapInfo(_mapInfo);
|
||||
}
|
||||
|
||||
public void LoadMapInfo(HexGridMap mapInfo)
|
||||
{
|
||||
zoneManager.LoadZonesFromSave(mapInfo,_dataManager.UserMapData);
|
||||
}
|
||||
//
|
||||
public void SaveUserData()
|
||||
{
|
||||
_dataManager.SaveUserData();
|
||||
}
|
||||
//
|
||||
public void LoadUserData(string dataValue)
|
||||
{
|
||||
_dataManager.LoadUserData(dataValue);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/HexGrid/HexMapManager.cs.meta
Normal file
11
Assets/Scripts/HexGrid/HexMapManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ac6e691661dacb4fb78b36f4155cea0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
47
Assets/Scripts/HexGrid/HexMapPanel.cs
Normal file
47
Assets/Scripts/HexGrid/HexMapPanel.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using asap.core;
|
||||
using game;
|
||||
using GameCore;
|
||||
using PlayFab.Internal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace HexGrid
|
||||
{
|
||||
public class HexMapPanel : MonoBehaviour
|
||||
{
|
||||
private Button btn_close;
|
||||
private Button btnClear;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
btn_close = transform.Find("root/btn_close").GetComponent<Button>();
|
||||
btn_close.onClick.AddListener(OnClose);
|
||||
|
||||
btnClear = transform.Find("root/btn_clear").GetComponent<Button>();
|
||||
btnClear.onClick.AddListener(OnClear);
|
||||
|
||||
}
|
||||
|
||||
private void OnClear()
|
||||
{
|
||||
Log("OnClear-> ");
|
||||
var hmdm = GContext.container.Resolve<HexMapDataManager>();
|
||||
hmdm.ClearMapData();
|
||||
hmdm.Init();
|
||||
|
||||
OnClose();
|
||||
}
|
||||
private void OnClose()
|
||||
{
|
||||
GContext.Publish(new UnloadActToNextAct());
|
||||
btn_close.onClick.RemoveAllListeners();
|
||||
}
|
||||
|
||||
private static void Log(object message)
|
||||
{
|
||||
Debug.Log($"<color=orange>HexMapPanel => {message} </color>");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/HexGrid/HexMapPanel.cs.meta
Normal file
3
Assets/Scripts/HexGrid/HexMapPanel.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c1975c3f4ad44ba781f5a9214171b29a
|
||||
timeCreated: 1757384557
|
||||
212
Assets/Scripts/HexGrid/HexMapSaver.cs
Normal file
212
Assets/Scripts/HexGrid/HexMapSaver.cs
Normal file
@@ -0,0 +1,212 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Remoting.Contexts;
|
||||
using HexGrid.MapHelper;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
using HexGrid.Math;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
|
||||
namespace HexGrid
|
||||
{
|
||||
// 数据保存,不放在Manager 中处理
|
||||
// [ExecuteInEditMode]
|
||||
public class HexMapSaver : MonoBehaviour
|
||||
{
|
||||
public Transform root;
|
||||
// 标准格子
|
||||
[SerializeField] private GameObject standGridPrefab;
|
||||
private GameObject standGridGo;
|
||||
//
|
||||
private Transform rootBuilding;
|
||||
//
|
||||
public HexGridMap data;
|
||||
//
|
||||
private void Awake()
|
||||
{
|
||||
|
||||
}
|
||||
private void SetupStandGrid()
|
||||
{
|
||||
if (standGridPrefab)
|
||||
{
|
||||
standGridGo = Instantiate(standGridPrefab, Vector3.zero, Quaternion.identity, transform);
|
||||
standGridGo.name = "StandGrid";
|
||||
standGridGo.SetActive(false);
|
||||
var size = HexUtils.DetermineTileSize(standGridGo, out var bounds);
|
||||
HexMath.SetGridSize(size.z * 0.5f);
|
||||
DestroyImmediate(standGridGo); // 移除
|
||||
}
|
||||
HexMath.SetHexMapOrigin(Vector3.zero);
|
||||
}
|
||||
// 保存建筑数据
|
||||
private void SaveBuildings()
|
||||
{
|
||||
rootBuilding = root.Find("merge");
|
||||
var buildingNum = rootBuilding.childCount;
|
||||
|
||||
foreach (Transform child in rootBuilding)
|
||||
{
|
||||
// data.buildings.Add();
|
||||
var building = new HexBuilding
|
||||
{
|
||||
buildingName = child.gameObject.name,
|
||||
buildingPosition = child.position,
|
||||
hasTiles = new List<string>()
|
||||
};
|
||||
|
||||
if (building.buildingName == "Hotel")
|
||||
{
|
||||
building.hasTiles.Add(HexUtils.MakeTileId(new Vector2Int(-3, 4)));
|
||||
building.hasTiles.Add(HexUtils.MakeTileId(new Vector2Int(-2, 4)));
|
||||
}
|
||||
|
||||
if (building.buildingName == "hill")
|
||||
{
|
||||
building.hasTiles.Add("tile:(-2,6)");
|
||||
building.hasTiles.Add("tile:(-3,6)");
|
||||
building.hasTiles.Add("tile:(-1,5)");
|
||||
building.hasTiles.Add("tile:(-2,5)");
|
||||
}
|
||||
data.buildings.Add(building);
|
||||
}
|
||||
}
|
||||
private void SaveZone()
|
||||
{
|
||||
}
|
||||
|
||||
private static HexTile BuildTile(int id,Transform tileTransform,HexZone zone,HexSubZone subZone,TileType tileType)
|
||||
{
|
||||
var worldPos = tileTransform.position;
|
||||
var tileCoords = HexMath.PixelToAxial(worldPos);
|
||||
var tile = new HexTile
|
||||
{
|
||||
id = id,
|
||||
tileOriName = tileTransform.gameObject.name,
|
||||
tileId = HexUtils.MakeTileId(tileCoords),
|
||||
zoneId = zone.zoneId,
|
||||
zoneName = zone.zoneName,
|
||||
subZoneIndex = subZone?.subZoneId ?? 0,
|
||||
tileCoords = tileCoords,
|
||||
type = tileType,
|
||||
};
|
||||
return tile;
|
||||
}
|
||||
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
[ContextMenu("Save Data")]
|
||||
void SaveData()
|
||||
{
|
||||
EditorUtility.SetDirty(data);
|
||||
AssetDatabase.SaveAssets();
|
||||
Debug.Log("Data saved to asset file.");
|
||||
}
|
||||
|
||||
[ContextMenu("Save Data2")]
|
||||
void SaveData2()
|
||||
{
|
||||
SetupStandGrid();
|
||||
data.Clear();
|
||||
SaveBuildings();
|
||||
SaveZone();
|
||||
|
||||
var zone = new HexZone
|
||||
{
|
||||
zoneName = "zone_01",
|
||||
zoneId = 0,
|
||||
isUnlocked = true
|
||||
};
|
||||
var zone1 = root.Find(zone.zoneName);
|
||||
var count = 0;
|
||||
var subZoneId = 0;
|
||||
HexSubZone subZone = null;
|
||||
foreach (Transform child in zone1)
|
||||
{
|
||||
if (!child.GetComponent<HexGridTiler>())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (count % 3 == 0)
|
||||
{
|
||||
subZone = new HexSubZone();
|
||||
zone.subZones.Add(subZone);
|
||||
subZone.subZoneId = subZoneId++;
|
||||
}
|
||||
// var worldPos = child.position;
|
||||
// var tileCoords = HexMath.PixelToAxial(worldPos);
|
||||
// Debug.Log($"tileCoords -> {tileCoords.x}, {tileCoords.y}");
|
||||
// var tile = new HexTile
|
||||
// {
|
||||
// id = count,
|
||||
// tileOriName = child.gameObject.name,
|
||||
// tileId = HexUtils.MakeTileId(tileCoords),
|
||||
// zoneId = zone.zoneId,
|
||||
// zoneName = zone.zoneName,
|
||||
// subZoneIndex = subZone?.subZoneId ?? 0,
|
||||
// tileCoords = tileCoords,
|
||||
// type = TileType.Grass,
|
||||
// };
|
||||
// zone.tiles.Add(BuildTile(count,child,zone,subZone,TileType.Grass));
|
||||
var tile = zone.AddTile(BuildTile(count, child, zone, subZone, TileType.Grass));
|
||||
subZone?.tileNames.Add(tile.tileId);
|
||||
count++;
|
||||
}
|
||||
data.zones.Add(zone);
|
||||
|
||||
zone = new HexZone
|
||||
{
|
||||
zoneName = "zone_02",
|
||||
zoneId = 1,
|
||||
isUnlocked = false
|
||||
};
|
||||
data.zones.Add(zone);
|
||||
|
||||
var zoneTransform = root.Find(zone.zoneName);
|
||||
count = 0;
|
||||
subZone = null;
|
||||
subZoneId = 0;
|
||||
|
||||
foreach (Transform child in zoneTransform)
|
||||
{
|
||||
if (!child.GetComponent<HexGridTiler>())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (count % 3 == 0)
|
||||
{
|
||||
subZone = new HexSubZone();
|
||||
zone.subZones.Add(subZone);
|
||||
subZone.subZoneId = subZoneId++;
|
||||
}
|
||||
var worldPos = child.position;
|
||||
var tileCoords = HexMath.PixelToAxial(worldPos);
|
||||
Debug.Log($"tileCoords -> {tileCoords.x}, {tileCoords.y}");
|
||||
// var tile = new HexTile
|
||||
// {
|
||||
// id = count,
|
||||
// tileOriName = child.gameObject.name,
|
||||
// tileId = HexUtils.MakeTileId(tileCoords),
|
||||
// zoneId = zone.zoneId,
|
||||
// zoneName = zone.zoneName,
|
||||
// subZoneIndex = subZone?.subZoneId ?? 0,
|
||||
// tileCoords = tileCoords,
|
||||
// type = TileType.Grass,
|
||||
// };
|
||||
// zone.tiles.Add(tile);
|
||||
var tile = zone.AddTile(BuildTile(count, child, zone, subZone, TileType.Grass));
|
||||
subZone?.tileNames.Add(tile.tileId);
|
||||
count++;
|
||||
}
|
||||
SaveData();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/HexGrid/HexMapSaver.cs.meta
Normal file
3
Assets/Scripts/HexGrid/HexMapSaver.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e902553b41074d6bb40120827a5a8d05
|
||||
timeCreated: 1757324607
|
||||
18
Assets/Scripts/HexGrid/HexNpcManager.cs
Normal file
18
Assets/Scripts/HexGrid/HexNpcManager.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace HexGrid
|
||||
{
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
public class NPCManager : MonoBehaviour
|
||||
{
|
||||
public Transform targetPoint;
|
||||
private NavMeshAgent agent;
|
||||
void Start()
|
||||
{
|
||||
agent = GetComponent<NavMeshAgent>();
|
||||
if (targetPoint != null)
|
||||
agent.SetDestination(targetPoint.position);
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/HexGrid/HexNpcManager.cs.meta
Normal file
3
Assets/Scripts/HexGrid/HexNpcManager.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c7d02a00f9f043c89b7eebd926a64925
|
||||
timeCreated: 1757325680
|
||||
44
Assets/Scripts/HexGrid/HexZoneController.cs
Normal file
44
Assets/Scripts/HexGrid/HexZoneController.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HexGrid
|
||||
{
|
||||
public class HexZoneController : MonoBehaviour,IZoneController
|
||||
{
|
||||
//
|
||||
private HexZone _zoneData;
|
||||
private IBuildMediator _buildMediator;
|
||||
private void Awake()
|
||||
{
|
||||
Log("Awake()-> ");
|
||||
}
|
||||
private static void Log(object t)
|
||||
{
|
||||
Debug.Log($"<color=yellow>HexZoneController -> {t} </color>");
|
||||
}
|
||||
|
||||
public void LoadData(HexZone zoneData)
|
||||
{
|
||||
_zoneData = zoneData;
|
||||
}
|
||||
|
||||
public void UpdateZoneStatus()
|
||||
{
|
||||
Log("UpdateZoneStatus() -> ");
|
||||
}
|
||||
|
||||
public void OnHexCellClicked(HexTile tiler)
|
||||
{
|
||||
Log($"OnHexCellClicked -> {tiler}");
|
||||
|
||||
var tiles = _zoneData.tiles;
|
||||
foreach (var tileData in tiles.Where(tileData => tileData.tileId == tiler.tileId))
|
||||
{
|
||||
tileData.tileStatus = tiler.tileStatus;
|
||||
break;
|
||||
}
|
||||
// _buildMediator?.CheckForBuilding(_zoneData.subZones);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/HexGrid/HexZoneController.cs.meta
Normal file
3
Assets/Scripts/HexGrid/HexZoneController.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2448d233ec134e92896704aa5d79b779
|
||||
timeCreated: 1757339298
|
||||
579
Assets/Scripts/HexGrid/HexZoneManager.cs
Normal file
579
Assets/Scripts/HexGrid/HexZoneManager.cs
Normal file
@@ -0,0 +1,579 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using HexGrid.MapHelper;
|
||||
using HexGrid.Math;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HexGrid
|
||||
{
|
||||
// 区域管理
|
||||
public class HexZoneManager : MonoBehaviour,IHexGridMediatable
|
||||
{
|
||||
//
|
||||
private List<HexZone> _zones;
|
||||
private List<HexBuilding> _buildings;
|
||||
//
|
||||
private HexGridMapUserData _userMapData;
|
||||
//
|
||||
private Transform transformRoot;
|
||||
//
|
||||
private List<HexZoneController> zoneControllers;
|
||||
//
|
||||
private IHexGridMediator _mediator;
|
||||
//
|
||||
private HexMapManager _hexMapManager;
|
||||
|
||||
public void SetMediator(IHexGridMediator mediator)
|
||||
{
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
zoneControllers = new List<HexZoneController>();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
public void SetHexMapManager(HexMapManager manager)
|
||||
{
|
||||
_hexMapManager = manager;
|
||||
}
|
||||
//
|
||||
public void SetRoot(Transform root)
|
||||
{
|
||||
transformRoot = root;
|
||||
}
|
||||
|
||||
public HexZone GetZoneById(int zoneId)
|
||||
{
|
||||
return _zones.Find(z => z.zoneId == zoneId);
|
||||
}
|
||||
|
||||
//TODO:LF 侵入了数据块, 正式版需要分开,生成User版本,然后和固定的刷在一起提供出更好
|
||||
public void BuildMapData(HexGridMapUserData userMapData)
|
||||
{
|
||||
var currZoneIndex = userMapData.zoneCurrentIndex;
|
||||
for (var i = 0; i < currZoneIndex; ++i)
|
||||
{
|
||||
_zones[i].isUnlocked = true;
|
||||
foreach (var tile in _zones[i].tiles)
|
||||
{
|
||||
tile.tileStatus = 2;
|
||||
// _mediator.CheckBuildingAfterBuildImme(tile);
|
||||
}
|
||||
//BuildBuildingData(_zones[i].subZones);
|
||||
}
|
||||
// 全部隐藏
|
||||
for (var i = currZoneIndex + 1; i < _zones.Count; ++i)
|
||||
{
|
||||
_zones[i].isUnlocked = false;
|
||||
foreach (var tile in _zones[i].tiles)
|
||||
{
|
||||
tile.tileStatus = 0;
|
||||
}
|
||||
}
|
||||
//
|
||||
var subZoneCurrentIndex = userMapData.subZoneCurrentIndex;
|
||||
if (currZoneIndex > _zones.Count -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//
|
||||
var zoneCur = _zones[currZoneIndex];
|
||||
zoneCur.isUnlocked = true;
|
||||
for (var i = 0; i < subZoneCurrentIndex; ++i)
|
||||
{
|
||||
var tileNames = zoneCur.subZones[i].tileNames;
|
||||
foreach (var tile in tileNames.SelectMany(tileName => zoneCur.tiles.Where(tile => string.Equals(tile.tileId, tileName))))
|
||||
{
|
||||
tile.tileStatus = 2;
|
||||
// _mediator.CheckBuildingAfterBuildImme(tile);
|
||||
}
|
||||
}
|
||||
for (var i = subZoneCurrentIndex + 1; i < zoneCur.subZones.Count; ++i)
|
||||
{
|
||||
var tileNames = zoneCur.subZones[i].tileNames;
|
||||
foreach (var tile in tileNames.SelectMany(tileName => zoneCur.tiles.Where(tile => string.Equals(tile.tileId, tileName))))
|
||||
{
|
||||
tile.tileStatus = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var subZone = zoneCur.subZones[subZoneCurrentIndex];
|
||||
var curTiles = subZone.tileNames;
|
||||
var completeTiles = userMapData.completeTiles;
|
||||
|
||||
int count = 0;
|
||||
foreach (var tile in curTiles.SelectMany(tileName => zoneCur.tiles.Where(tile => string.Equals(tile.tileId, tileName))))
|
||||
{
|
||||
Log($"curTile -> {tile.tileId}");
|
||||
if (count != 0)
|
||||
{
|
||||
tile.tileStatus = 0;
|
||||
continue;
|
||||
}
|
||||
tile.tileStatus = completeTiles.Contains(tile.tileId) ? 2 : 1;
|
||||
if (tile.tileStatus == 1)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
if (tile.tileStatus == 2)
|
||||
{
|
||||
// _mediator.CheckBuildingAfterBuildImme(tile);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//TODO: 构建完成版家住的数据
|
||||
public void LoadZonesFromSave(HexGridMap mapInfo,HexGridMapUserData userMapData)
|
||||
{
|
||||
_zones = mapInfo.zones;
|
||||
_buildings = mapInfo.buildings;
|
||||
_userMapData = userMapData;
|
||||
_mediator.LoadBuildings(mapInfo.buildings);
|
||||
BuildMapData(userMapData);
|
||||
LoadZones(_zones);
|
||||
LoadBuildings();
|
||||
}
|
||||
|
||||
private void LoadBuildings()
|
||||
{
|
||||
foreach (var tile in _zones.SelectMany(zone => zone.tiles))
|
||||
{
|
||||
if (tile.tileStatus == 2)
|
||||
{
|
||||
_mediator.CheckBuildingAfterBuildImme(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadZones(List<HexZone> zones)
|
||||
{
|
||||
foreach (var zone in _zones)
|
||||
{
|
||||
var zoneTrans = transformRoot.Find(zone?.zoneName);
|
||||
if (zone != null)
|
||||
{
|
||||
var zoneObject = zoneTrans.gameObject;
|
||||
zone.zoneObject = zoneObject;
|
||||
var hexZoneController = zoneObject.GetComponent<HexZoneController>();
|
||||
if(hexZoneController == null)
|
||||
hexZoneController = zoneObject.AddComponent<HexZoneController>();
|
||||
zoneControllers.Add(hexZoneController);
|
||||
hexZoneController.LoadData(zone);
|
||||
|
||||
var statusText = zoneTrans.Find("LockStatus").GetComponent<TMP_Text>();
|
||||
statusText.text = zone.isUnlocked ? "" : "LOCK";
|
||||
foreach (var tileData in zone.tiles)
|
||||
{
|
||||
var tileTransform = zoneTrans.Find(tileData.tileOriName);
|
||||
if (!tileTransform) continue;
|
||||
tileData.visual = tileTransform.gameObject;
|
||||
var tiler = tileTransform.GetComponent<HexGridTiler>();
|
||||
if (tiler)
|
||||
{
|
||||
tiler.SetMediator(_mediator);
|
||||
tiler.LoadTileData(tileData);
|
||||
tiler.UpdateVisual();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void SaveZonesToFile()
|
||||
{
|
||||
foreach (var zone in _zones)
|
||||
{
|
||||
// PlayerPrefs.SetInt("Zone_" + zone.id, zone.isUnlocked ? 1 : 0);
|
||||
}
|
||||
// PlayerPrefs.Save();
|
||||
}
|
||||
public bool UpdateZoneStatus()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: 没有检测邻居的数值,先当前子区域里的全部显示,都完成进入下一个
|
||||
public bool UpdateSubZoneStatus(HexZone zone, int subZoneId)
|
||||
{
|
||||
Log($"UpdateSubZoneStatus -> {subZoneId}");
|
||||
//return false;
|
||||
//TODO:LF 先这样用吧.可以绑定一下或者存 MONObehavier 的 List
|
||||
var subZoneCurrentIndex = _userMapData.subZoneCurrentIndex;
|
||||
var subzone = zone?.subZones[subZoneCurrentIndex];
|
||||
var zoneTrans = zone?.zoneObject.transform;
|
||||
if (subzone?.tileNames != null)
|
||||
foreach (var tiler in (subzone?.tileNames).Select(tileName => zoneTrans.Find(tileName)).Select(tileTransform => tileTransform.GetComponent<HexGridTiler>()).Where(tiler => tiler))
|
||||
{
|
||||
//tiler.LoadTileData();
|
||||
//this.UpdateTileData(tiler);
|
||||
tiler.UpdateVisual();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool UpdateMapStatus()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool OnHexTileData(HexTile tiler)
|
||||
{
|
||||
var zone = _zones.FirstOrDefault(zone => zone.zoneId == tiler.zoneId);
|
||||
var result = zone?.tiles.FirstOrDefault(myTile => myTile.tileId == tiler.tileId);
|
||||
Log($"tiler -> {tiler} result: {result}");
|
||||
// 更新数据
|
||||
if (result != null && result.tileStatus == 1)
|
||||
{
|
||||
result.tileStatus = 2;
|
||||
_userMapData.completeTiles.Add(result.tileId);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
|
||||
// 更新View
|
||||
// var rt = UpdateSubZoneStatus(zone,tiler.subZoneIndex);
|
||||
// if (!rt) return;
|
||||
|
||||
// var rt2 = UpdateZoneStatus();
|
||||
// if (!rt2) return;
|
||||
|
||||
// var rt3 = UpdateMapStatus();
|
||||
// if (!rt3) return;
|
||||
// _userMapData.
|
||||
// UpdateUserData();
|
||||
}
|
||||
|
||||
//
|
||||
private List<HexTile> GetTilesFromName(HexZone zone,List<string> tileNames)
|
||||
{
|
||||
return zone.tiles.Where(tile => tileNames.Contains(tile.tileId)).ToList();
|
||||
}
|
||||
|
||||
public async Task OnActiveNextTile(HexTile result)
|
||||
{
|
||||
//TODO:LF 注意,这里有报错,Camera 完成之后需要修复
|
||||
|
||||
var subZoneCurrentIndex = _userMapData.subZoneCurrentIndex;
|
||||
var zone = GetZoneById(result.zoneId);
|
||||
var zoneSubTileNames = zone.subZones[subZoneCurrentIndex].tileNames;
|
||||
var rt = GetNeighborsInZone(result,zone,zone.subZones[subZoneCurrentIndex]);
|
||||
foreach (var name in rt)
|
||||
{
|
||||
Log($"{result.tileCoords} neighbor: {name}" );
|
||||
}
|
||||
|
||||
var rtList = GetTilesFromName(zone, rt);
|
||||
var nexTile = rtList.FirstOrDefault(c => c.tileStatus == 0);
|
||||
if (nexTile == null)
|
||||
{
|
||||
var subzoneTiles = GetTilesFromName(zone, zoneSubTileNames);
|
||||
nexTile = subzoneTiles.FirstOrDefault(c => c.tileStatus == 0);
|
||||
}
|
||||
|
||||
if (nexTile != null)
|
||||
{
|
||||
await ActiveHexTile(nexTile);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 进入下一个阶段
|
||||
if (CheckSubZoneFinished(zone.subZones[subZoneCurrentIndex]))
|
||||
{
|
||||
await OnActiveNextPart();
|
||||
}
|
||||
}
|
||||
DoSave();
|
||||
}
|
||||
|
||||
private async Task ActiveHexTile(HexTile nexTile)
|
||||
{
|
||||
Log($"ActiveHexTile ->{nexTile}");
|
||||
await Awaiters.Seconds(0.7f);
|
||||
ChangeTileStatus(nexTile,1);
|
||||
}
|
||||
|
||||
private static void ChangeTileStatus(HexTile nexTile,int tileStatus)
|
||||
{
|
||||
nexTile.tileStatus = tileStatus;
|
||||
nexTile.visual.GetComponent<HexGridTiler>().UpdateVisual();
|
||||
}
|
||||
|
||||
|
||||
// private async Task CheckBuilding(HexZone zone,HexSubZone subZone)
|
||||
// {
|
||||
// Log("CheckBuilding-> ");
|
||||
// var buildList = subZone.buildings;
|
||||
// var parents = zone.zoneObject;
|
||||
//
|
||||
// if (buildList is { Count: > 0 })
|
||||
// {
|
||||
// foreach (var building in buildList)
|
||||
// {
|
||||
//
|
||||
// if (true)
|
||||
// {
|
||||
// var build = Instantiate(building.buildModel, parents.transform);
|
||||
// build.transform.position = new Vector3(-1.38f, 2.69f, 8.41f);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
private bool CheckSubZoneFinished(HexSubZone zoneSubZone)
|
||||
{
|
||||
var zoneCur = _zones[_userMapData.zoneCurrentIndex];
|
||||
bool ret = true;
|
||||
foreach (var tileName in zoneSubZone.tileNames)
|
||||
{
|
||||
foreach (var tile in zoneCur.tiles.Where(tile => string.Equals(tile.tileId, tileName)))
|
||||
{
|
||||
if (tile.tileStatus != 2)
|
||||
{
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Log($"CheckSubZoneFinished ->{_userMapData.subZoneCurrentIndex}, {zoneSubZone.subZoneId } {ret}" );
|
||||
return ret;
|
||||
}
|
||||
|
||||
private async Task OnActiveNextPart()
|
||||
{
|
||||
Log("OnActiveNextSubZone -> ");
|
||||
await Awaiters.Seconds(0.7f);
|
||||
// _userMapData.subZoneCurrentIndex++;
|
||||
var nextSubzoneIndex = _userMapData.subZoneCurrentIndex + 1;
|
||||
var zoneCur = _zones[_userMapData.zoneCurrentIndex];
|
||||
if (nextSubzoneIndex >= zoneCur.subZones.Count)
|
||||
{
|
||||
StartNextZone();
|
||||
}
|
||||
else
|
||||
{
|
||||
StartSubZone();
|
||||
}
|
||||
}
|
||||
|
||||
public GameObject GetCurZoneRoot()
|
||||
{
|
||||
var currZoneIndex = _userMapData.zoneCurrentIndex;
|
||||
var zoneCur = _zones[currZoneIndex];
|
||||
if (zoneCur == null)
|
||||
return null;
|
||||
if (zoneCur.zoneObject)
|
||||
{
|
||||
return zoneCur.zoneObject;
|
||||
}
|
||||
var zoneTrans = transformRoot.Find(zoneCur?.zoneName);
|
||||
return zoneTrans.gameObject;
|
||||
}
|
||||
|
||||
public GameObject GetBuildingRoot(int id)
|
||||
{
|
||||
var mergeTrans = transformRoot.Find("merge");
|
||||
return mergeTrans.gameObject;
|
||||
}
|
||||
|
||||
public GameObject GetZoneObject(int id)
|
||||
{
|
||||
var zoneCur = GetZoneById(id);
|
||||
if (zoneCur == null)
|
||||
return null;
|
||||
if (zoneCur.zoneObject)
|
||||
{
|
||||
return zoneCur.zoneObject;
|
||||
}
|
||||
var zoneTrans = transformRoot.Find(zoneCur?.zoneName);
|
||||
return zoneTrans.gameObject;
|
||||
}
|
||||
|
||||
private void UpdateCurrZoneStatus()
|
||||
{
|
||||
|
||||
var currZoneIndex = _userMapData.zoneCurrentIndex;
|
||||
var subZoneCurrentIndex = _userMapData.subZoneCurrentIndex;
|
||||
var zoneCur = _zones[currZoneIndex];
|
||||
|
||||
var zoneObject = zoneCur.zoneObject;
|
||||
if (zoneObject)
|
||||
{
|
||||
var statusText = zoneObject.transform.Find("LockStatus").GetComponent<TMP_Text>();
|
||||
statusText.text = zoneCur.isUnlocked ? "" : "LOCK";
|
||||
}
|
||||
|
||||
for (var i = 0; i < subZoneCurrentIndex; ++i)
|
||||
{
|
||||
var tileNames = zoneCur.subZones[i].tileNames;
|
||||
foreach (var tile in tileNames.SelectMany(tileName => zoneCur.tiles.Where(tile => string.Equals(tile.tileId, tileName))))
|
||||
{
|
||||
tile.tileStatus = 2;
|
||||
}
|
||||
}
|
||||
for (var i = subZoneCurrentIndex + 1; i < zoneCur.subZones.Count; ++i)
|
||||
{
|
||||
var tileNames = zoneCur.subZones[i].tileNames;
|
||||
foreach (var tile in tileNames.SelectMany(tileName => zoneCur.tiles.Where(tile => string.Equals(tile.tileId, tileName))))
|
||||
{
|
||||
tile.tileStatus = 0;
|
||||
}
|
||||
}
|
||||
var subZone = zoneCur.subZones[subZoneCurrentIndex];
|
||||
var curTiles = subZone.tileNames;
|
||||
var completeTiles = _userMapData.completeTiles;
|
||||
int count = 0;
|
||||
foreach (var tile in curTiles.SelectMany(tileName => zoneCur.tiles.Where(tile => string.Equals(tile.tileId, tileName))))
|
||||
{
|
||||
if (count != 0)
|
||||
{
|
||||
tile.tileStatus = 0;
|
||||
continue;
|
||||
}
|
||||
tile.tileStatus = completeTiles.Contains(tile.tileId) ? 2 : 1;
|
||||
if (tile.tileStatus == 1)
|
||||
{
|
||||
tile.visual.GetComponent<HexGridTiler>().UpdateVisual();
|
||||
count++;
|
||||
}
|
||||
Log($"curTile -> {tile.tileId} : {tile.tileStatus}");
|
||||
}
|
||||
}
|
||||
private void StartNextZone()
|
||||
{
|
||||
Log("StartNextZone() -> ");
|
||||
_userMapData.zoneCurrentIndex++;
|
||||
_userMapData.subZoneCurrentIndex = 0;
|
||||
_userMapData.completeTiles.Clear();
|
||||
//
|
||||
if (_userMapData.zoneCurrentIndex > _zones.Count -1)
|
||||
{
|
||||
DoSave();
|
||||
return;
|
||||
}
|
||||
var zoneCur = _zones[_userMapData.zoneCurrentIndex];
|
||||
Log($"解锁 Zone -> {zoneCur.zoneId}");
|
||||
zoneCur.isUnlocked = true;
|
||||
UpdateCurrZoneStatus();
|
||||
}
|
||||
|
||||
private void StartSubZone()
|
||||
{
|
||||
var subZoneCurrentIndex = ++_userMapData.subZoneCurrentIndex;
|
||||
var zoneCur = _zones[_userMapData.zoneCurrentIndex];
|
||||
var subZone = zoneCur.subZones[subZoneCurrentIndex];
|
||||
var curTiles = subZone.tileNames;
|
||||
var completeTiles = _userMapData.completeTiles;
|
||||
completeTiles.Clear();
|
||||
|
||||
Log($"StartSubZone -> {subZoneCurrentIndex} {subZone.subZoneId} ");
|
||||
// 查找第一个地块,激活
|
||||
int count = 0;
|
||||
foreach (var tile in curTiles.SelectMany(tileName => zoneCur.tiles.Where(tile => string.Equals(tile.tileId, tileName))))
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
tile.tileStatus = 1;
|
||||
}
|
||||
count++;
|
||||
|
||||
var hexGridTiler = tile.visual.GetComponent<HexGridTiler>();
|
||||
if (hexGridTiler)
|
||||
{
|
||||
hexGridTiler.UpdateVisual();
|
||||
}
|
||||
|
||||
// tile.visual.GetComponent<HexGridTiler>().UpdateVisual();
|
||||
Log($"StartSubZone -> curTile -> {tile.tileId} {tile.tileStatus}");
|
||||
}
|
||||
}
|
||||
|
||||
private static List<string> GetNeighborsInZone(HexTile hexTile,HexZone zone, HexSubZone subZone)
|
||||
{
|
||||
// foreach (var neighbor in neighbors)
|
||||
// {
|
||||
// // var x = tile.tileCoords.x + neighbor.x;
|
||||
// // var y = tile.tileCoords.y + neighbor.y;
|
||||
// Vector2Int user = HexUtils.GetNeighborList(tile,i);
|
||||
// var tileCoord = new Vector2Int(x,y);
|
||||
// var tileName = HexUtils.MakeTileId(tileCoord);
|
||||
// list.AddRange(from elem in zone.tiles where elem.tileCoords == tileCoord select tileName);
|
||||
// }
|
||||
// var listNeighbor = ;
|
||||
var listNeighbor = HexUtils.GetNeighborList(hexTile).Select(HexUtils.MakeTileId).ToList();
|
||||
return listNeighbor.Intersect(subZone.tileNames).ToList();
|
||||
|
||||
// return listNeighbor.Select(HexUtils.MakeTileId).Where(tileId => zone.tiles.Any(tile => string.Equals(tile.tileId, tileId))).ToList();
|
||||
}
|
||||
// 返回邻居,需要使用HexMatrix 整体流程
|
||||
// private List<string> GetNeighbors(HexTile tile)
|
||||
// {
|
||||
// Dictionary<string, List<string>> colls = new()
|
||||
// {
|
||||
// { "cube001", new List<string> { "cube002" } },
|
||||
// { "cube002", new List<string> { "cube001","cube003","cube004","cube009","cube008" } },
|
||||
// { "cube003", new List<string> {"cube002","cube009","cube010"}},
|
||||
// { "cube004", new List<string> {"cube001","cube002","cube005","cube007","cube008"}},
|
||||
// { "cube005", new List<string> {"cube004","cube006","cube007"}},
|
||||
// { "cube006", new List<string> {"cube014","cube013","cube007","cube005"}},
|
||||
// { "cube007", new List<string> {"cube005","cube006","cube004","cube008","cube012","cube013"}},
|
||||
// { "cube008", new List<string> {"cube002","cube007","cube004","cube009","cube012","cube011"}},
|
||||
// { "cube009", new List<string> {"cube003","cube010","cube016","cube008","cube002","cube011"}},
|
||||
// { "cube010", new List<string> {"cube003","cube009","cube016"}},
|
||||
// { "cube011", new List<string> {"cube008","cube009","cube016","cube018","cube015","cube012"}},
|
||||
// { "cube012", new List<string> {"cube007","cube008","cube011","cube013","cube015"}},
|
||||
// { "cube013", new List<string> {"cube014","cube006","cube007","cube013","cube012"}},
|
||||
// { "cube014", new List<string> {"cube013","cube006"}},
|
||||
// { "cube015", new List<string> {"cube012","cube019","cube017","cube011","cube018"}},
|
||||
// { "cube016", new List<string> {"cube009","cube010","cube011","cube018","cube020"}},
|
||||
// { "cube017", new List<string> {"cube015","cube019"}},
|
||||
// { "cube018", new List<string> {"cube015","cube016","cube019","cube021","cube011","cube020"}},
|
||||
// { "cube019", new List<string> {"cube015","cube018","cube021","cube017"}},
|
||||
// { "cube020", new List<string> {"cube016","cube018","cube021"}},
|
||||
// { "cube021", new List<string> {"cube018","cube019","cube020"}},
|
||||
//
|
||||
// };
|
||||
// return colls[tile.tileId];
|
||||
// }
|
||||
// 解锁子区域,激活第一块
|
||||
private void UnlockSubZone(int zoneId, int subZoneId)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// private void UpdateUserData()
|
||||
// {
|
||||
//
|
||||
// }
|
||||
private void DoSave()
|
||||
{
|
||||
//const string saveKey = HexMapManager.SaveKey;
|
||||
//PlayFabMgr.Instance.UpdateUserDataValue(saveKey, JsonConvert.SerializeObject(_userMapData));
|
||||
_hexMapManager.SaveUserData();
|
||||
}
|
||||
private static void Log(object t)
|
||||
{
|
||||
Debug.Log($"<color=yellow>HexZoneManager -> {t} </color>");
|
||||
}
|
||||
|
||||
public HexTile GetTileByName(int zoneId, string tileName)
|
||||
{
|
||||
var zone = GetZoneById(zoneId);
|
||||
return zone.tiles.FirstOrDefault(hexTile => hexTile.tileId.Equals(tileName));
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/HexGrid/HexZoneManager.cs.meta
Normal file
3
Assets/Scripts/HexGrid/HexZoneManager.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ae8f8d112414dc3a8dedb74b921d849
|
||||
timeCreated: 1757320050
|
||||
40
Assets/Scripts/HexGrid/IHexGridMediator.cs
Normal file
40
Assets/Scripts/HexGrid/IHexGridMediator.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace HexGrid
|
||||
{
|
||||
public interface IZoneManager
|
||||
{
|
||||
void UpdateZoneStatus();
|
||||
}
|
||||
|
||||
public interface IZoneController
|
||||
{
|
||||
void UpdateZoneStatus();
|
||||
|
||||
void OnHexCellClicked(HexTile tiler);
|
||||
}
|
||||
|
||||
public interface IHexGridMediatable
|
||||
{
|
||||
void SetMediator(IHexGridMediator mediator);
|
||||
}
|
||||
|
||||
public interface IHexGridMediator
|
||||
{
|
||||
void RegisterZoneManager(HexZoneManager controller);
|
||||
void RegisterBuildingManager(BuildingManager buildManager);
|
||||
|
||||
void OnHexCellClicked(HexTile tiler);
|
||||
Task OnActiveNextTile(HexTile tiler);
|
||||
// 读取数据 zone
|
||||
void LoadZones(List<HexZone> zones);
|
||||
//读取数据Buildings
|
||||
void LoadBuildings(List<HexBuilding> buildings);
|
||||
|
||||
Task CheckBuildingAfterBuild(HexTile tile);
|
||||
void CheckBuildingAfterBuildImme(HexTile tile);
|
||||
void Build(int zoneId,BuildingData buildingData,bool isImme);
|
||||
}
|
||||
|
||||
}
|
||||
3
Assets/Scripts/HexGrid/IHexGridMediator.cs.meta
Normal file
3
Assets/Scripts/HexGrid/IHexGridMediator.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8365258c02014c51b524ed016823a444
|
||||
timeCreated: 1757391762
|
||||
3
Assets/Scripts/HexGrid/MapHelper.meta
Normal file
3
Assets/Scripts/HexGrid/MapHelper.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d7e2493464c54eb6aa493866835f7201
|
||||
timeCreated: 1757907441
|
||||
72
Assets/Scripts/HexGrid/MapHelper/HexUtils.cs
Normal file
72
Assets/Scripts/HexGrid/MapHelper/HexUtils.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HexGrid.MapHelper
|
||||
{
|
||||
public static class HexUtils
|
||||
{
|
||||
public static readonly Vector2Int[] neighbors =
|
||||
{
|
||||
new Vector2Int(1, 0),
|
||||
new Vector2Int(+1, 0),
|
||||
new Vector2Int(+1, -1),
|
||||
new Vector2Int(0, -1),
|
||||
new Vector2Int(-1, 0),
|
||||
new Vector2Int(-1, +1),
|
||||
new Vector2Int(0, +1)
|
||||
};
|
||||
|
||||
public static Vector3 DetermineTileSize(GameObject tileObject,out Bounds bounds)
|
||||
{
|
||||
var meshFilter = tileObject.GetComponentInChildren<MeshFilter>(true);
|
||||
bounds = meshFilter.sharedMesh.bounds;
|
||||
return new Vector3(bounds.size.x, 0,bounds.size.y);
|
||||
}
|
||||
// 构建地块Id
|
||||
public static string MakeTileId(Vector2Int tileCoords)
|
||||
{
|
||||
var x = tileCoords.x;
|
||||
var y = tileCoords.y;
|
||||
return $"tile:({x},{y})";
|
||||
}
|
||||
// 通过id,解析地块
|
||||
public static Vector2Int ParseTileId(string tileString)
|
||||
{
|
||||
const string prefix = "tile:";
|
||||
if (string.IsNullOrEmpty(tileString))
|
||||
return Vector2Int.zero;
|
||||
// 检查是否以 "tile:" 开头
|
||||
if (!tileString.StartsWith(prefix))
|
||||
return Vector2Int.zero;
|
||||
int startIndex = prefix.Length;
|
||||
int endIndex = tileString.Length - 1;
|
||||
if (endIndex <= startIndex)
|
||||
return Vector2Int.zero;
|
||||
|
||||
var coordsPart = tileString.Substring(startIndex,endIndex);
|
||||
var coords = coordsPart.Split(',');
|
||||
if (coords.Length != 2)
|
||||
return Vector2Int.zero;
|
||||
// 尝试解析 x 和 y 坐标
|
||||
if (int.TryParse(coords[0].Trim(), out var x) &&
|
||||
int.TryParse(coords[1].Trim(), out var y))
|
||||
{
|
||||
return new Vector2Int(x, y);
|
||||
}
|
||||
return Vector2Int.zero;
|
||||
}
|
||||
|
||||
// 获得当前模块的邻接Tile
|
||||
public static List<Vector2Int> GetNeighborList(HexTile tile)
|
||||
{
|
||||
var list = new List<Vector2Int>();
|
||||
foreach (var neighbor in neighbors)
|
||||
{
|
||||
var x = tile.tileCoords.x + neighbor.x;
|
||||
var y = tile.tileCoords.y + neighbor.y;
|
||||
list.Add(new Vector2Int(x,y));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/HexGrid/MapHelper/HexUtils.cs.meta
Normal file
3
Assets/Scripts/HexGrid/MapHelper/HexUtils.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd82ff490dfb40e08b4cb74012fcfd72
|
||||
timeCreated: 1757937441
|
||||
202
Assets/Scripts/HexGrid/MapHelper/MapRoot.cs
Normal file
202
Assets/Scripts/HexGrid/MapHelper/MapRoot.cs
Normal file
@@ -0,0 +1,202 @@
|
||||
using System;
|
||||
using HexGrid.Math;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace HexGrid.MapHelper
|
||||
{
|
||||
|
||||
public enum GridType
|
||||
{
|
||||
PointyTop,
|
||||
|
||||
// 当前仅支持尖顶
|
||||
// FlatTop,
|
||||
}
|
||||
public class MapRoot : MonoBehaviour
|
||||
{
|
||||
//
|
||||
[SerializeField] private GridType gridType;
|
||||
// 格子的大小
|
||||
[SerializeField] private float gridSize = 1.52f;
|
||||
//
|
||||
[SerializeField] private GameObject standGridPrefab;
|
||||
|
||||
private GameObject go;
|
||||
private void Awake()
|
||||
{
|
||||
if (standGridPrefab)
|
||||
{
|
||||
go = Instantiate(standGridPrefab, Vector3.zero, Quaternion.identity, this.transform);
|
||||
go.name = "grid_00";
|
||||
go.SetActive(false);
|
||||
var size = DetermineTileSize(go, out var bounds);
|
||||
gridSize = size.z * 0.5f;
|
||||
}
|
||||
// HexMath.SetHexMapOrigin( new Vector3(1.32f, 0.00f, -2.28f));
|
||||
HexMath.SetHexMapOrigin(Vector3.zero);
|
||||
HexMath.SetGridSize(gridSize);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// var worldPos0 = HexMath.AxialToPixel(0, 0, gridSize);
|
||||
// var worldPos1 = HexMath.AxialToPixel(0, 1, gridSize);
|
||||
// Log($"worldPos0 -> {worldPos0} ,worldPos1 ->{worldPos1}");
|
||||
//
|
||||
// //
|
||||
// DrawHex(worldPos0,gridSize);
|
||||
// DrawHex(worldPos1,gridSize);
|
||||
// for (int i = -5; i < 5; i++)
|
||||
// {
|
||||
// for (int j = -5; j < 5; j++)
|
||||
// {
|
||||
// Log($"Grid-({i},{j}): {HexMath.AxialToPixel(i,j)}");
|
||||
// }
|
||||
// }
|
||||
// Log($"World -> -1.29904,0,2.25 -> {HexMath.PixelToAxial(new Vector3(-1.29904f,0,2.25f))}");
|
||||
// Log($"World -> 0,0,0 -> {HexMath.PixelToAxial(Vector3.zero)}");
|
||||
// Log($"(1,1) -> World -> 3.95, 0.00, 2.28 -> {HexMath.PixelToAxial(new Vector3(3.95f, 0.00f, 2.28f))}");
|
||||
// Log($"(1,-1)-> World -> 1.32, 0.00, -2.28 -> {HexMath.PixelToAxial(new Vector3(1.32f, 0.00f, -2.28f))}");
|
||||
// Log($"(-1,1)-> World -> -1.32, 0.00, 2.28 -> {HexMath.PixelToAxial(new Vector3(-1.32f, 0.00f, 2.28f))}");
|
||||
// Log($"(-1,-1)-> World ->-3.95, 0.00, -2.28 -> {HexMath.PixelToAxial(new Vector3(-3.95f, 0.00f, -2.28f))}");
|
||||
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// var worldPos0 = HexMath.AxialToPixel(0, 0 );
|
||||
// var worldPos1 = HexMath.AxialToPixel(0, 1);
|
||||
// var worldPos2 = HexMath.AxialToPixel(0, 2);
|
||||
|
||||
//
|
||||
// var worldPos10 = HexMath.AxialToPixel(1, 0, gridSize);
|
||||
// var worldPos20 = HexMath.AxialToPixel(2, 0, gridSize);
|
||||
// var worldPos30 = HexMath.AxialToPixel(3, 0, gridSize);
|
||||
//
|
||||
// var worldPos11 = HexMath.AxialToPixel(1, 1, gridSize);
|
||||
// var worldPos21 = HexMath.AxialToPixel(2, 1, gridSize);
|
||||
// var worldPos31 = HexMath.AxialToPixel(3, 1, gridSize);
|
||||
//
|
||||
// Log(HexMath.PixelToAxial(worldPos0,gridSize));
|
||||
// Log(HexMath.PixelToAxial(worldPos1,gridSize));
|
||||
// Log(HexMath.PixelToAxial(worldPos2,gridSize));
|
||||
// Log(HexMath.PixelToAxial(worldPos10,gridSize));
|
||||
// Log(HexMath.PixelToAxial(worldPos20,gridSize));
|
||||
// Log(HexMath.PixelToAxial(worldPos30,gridSize));
|
||||
// Log(HexMath.PixelToAxial(worldPos11,gridSize));
|
||||
// Log(HexMath.PixelToAxial(worldPos21,gridSize));
|
||||
// Log(HexMath.PixelToAxial(worldPos31,gridSize));
|
||||
//
|
||||
//
|
||||
//
|
||||
// DrawHex(worldPos0,gridSize);
|
||||
// DrawHex(worldPos1,gridSize);
|
||||
// DrawHex(worldPos2,gridSize);
|
||||
//
|
||||
// DrawHex(worldPos10,gridSize,Color.green);
|
||||
// DrawHex(worldPos20,gridSize,Color.green);
|
||||
// DrawHex(worldPos30,gridSize,Color.green);
|
||||
//
|
||||
// DrawHex(worldPos11,gridSize,Color.yellow);
|
||||
// DrawHex(worldPos21,gridSize,Color.yellow);
|
||||
// DrawHex(worldPos31,gridSize,Color.yellow);
|
||||
//
|
||||
// DrawHex(HexMath.AxialToPixel(-1,1,gridSize),gridSize,Color.blue);
|
||||
// DrawHex(HexMath.AxialToPixel(-2,1,gridSize),gridSize,Color.blue);
|
||||
// DrawHex(HexMath.AxialToPixel(-3,1,gridSize),gridSize,Color.blue);
|
||||
// DrawHex(HexMath.AxialToPixel(-4,1,gridSize),gridSize,Color.blue);
|
||||
// DrawHex(HexMath.AxialToPixel(-5,1,gridSize),gridSize,Color.blue);
|
||||
//
|
||||
|
||||
}
|
||||
|
||||
private Vector3 DetermineTileSize(GameObject tileObject,out Bounds bounds)
|
||||
{
|
||||
var meshFilter = tileObject.GetComponentInChildren<MeshFilter>(true);
|
||||
bounds = meshFilter.sharedMesh.bounds;
|
||||
Log($"DetermineTileSize -> {bounds} {bounds.size}");
|
||||
// return new Vector3((bounds.extents.x * 2) * 0.75f,0, bounds.extents.y * 2);
|
||||
return new Vector3(bounds.size.x, 0,bounds.size.y);
|
||||
|
||||
// return bounds;
|
||||
}
|
||||
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void OnDrawGizmosSelected()
|
||||
{
|
||||
// GameObject[] selectedObjects = Selection.gameObjects;
|
||||
// var tile = GameObject.Find("grid_00");
|
||||
// var size = DetermineTileSize(tile,out var bounds);
|
||||
// Gizmos.color = Color.yellow;
|
||||
// Gizmos.DrawWireCube(Vector3.zero, bounds.size * 2);
|
||||
// Gizmos.DrawWireCube(Vector3.zero, size);
|
||||
}
|
||||
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
// if (Application.isPlaying && Application.isEditor)
|
||||
// {
|
||||
// Vector3 origin = Vector3.zero;
|
||||
//
|
||||
// if (go)
|
||||
// {
|
||||
// var size = DetermineTileSize(go, out var bounds);
|
||||
// Gizmos.color = Color.yellow;
|
||||
// Gizmos.DrawWireCube(origin, size);
|
||||
// gridSize = size.z * 0.5f;
|
||||
// Gizmos.color = Color.magenta;
|
||||
// DrawHex(origin, gridSize);
|
||||
// }
|
||||
// }
|
||||
|
||||
// Gizmos.color = Color.green;
|
||||
// Gizmos.DrawWireCube(Vector3.zero, size);
|
||||
}
|
||||
#endif
|
||||
// HexGrid
|
||||
private void DrawGrid(int q,int r)
|
||||
{
|
||||
// 00,01
|
||||
// Vector3 gridPos = HexMath.AxialToPixel(q, r, gridSize);
|
||||
}
|
||||
|
||||
private void DrawHex(Vector3 center, float size,Color color = default)
|
||||
{
|
||||
color = color == default ? Color.magenta : color;
|
||||
|
||||
var angleDelta = gridType == GridType.PointyTop ? 30 : 0;
|
||||
var corners = new Vector3[7];
|
||||
for (var i = 0; i < 6; i++)
|
||||
{
|
||||
float angleDeg = 60 * i + angleDelta;
|
||||
var angleRad = Mathf.Deg2Rad * angleDeg;
|
||||
corners[i] = new Vector3(
|
||||
center.x + size * Mathf.Cos(angleRad),
|
||||
0,
|
||||
center.z + size * Mathf.Sin(angleRad)
|
||||
);
|
||||
}
|
||||
corners[6] = corners[0];
|
||||
for (var i = 0; i < 6; i++)
|
||||
{
|
||||
// Gizmos.DrawLine(corners[i], corners[i + 1]);
|
||||
Debug.DrawLine(corners[i],corners[i + 1],color);
|
||||
}
|
||||
}
|
||||
// 画格子
|
||||
private void DrawHexGrid(Vector3 origin)
|
||||
{
|
||||
Log("DrawHexGrid-> {}");
|
||||
}
|
||||
// MapRoot
|
||||
private static void Log(object t)
|
||||
{
|
||||
Debug.Log($"<color=yellow> MapRoot -> {t} </color>");
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/HexGrid/MapHelper/MapRoot.cs.meta
Normal file
3
Assets/Scripts/HexGrid/MapHelper/MapRoot.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3c66c391ffdb4fdb8340fcdcffcb0b47
|
||||
timeCreated: 1757907477
|
||||
3
Assets/Scripts/HexGrid/Math.meta
Normal file
3
Assets/Scripts/HexGrid/Math.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 29adabee47ea49d0b993cd48eeffa31c
|
||||
timeCreated: 1757904468
|
||||
29
Assets/Scripts/HexGrid/Math/HexCoord.cs
Normal file
29
Assets/Scripts/HexGrid/Math/HexCoord.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
namespace HexGrid.Math
|
||||
{
|
||||
|
||||
public struct HexCoord {
|
||||
|
||||
public int q; // axial q(col)
|
||||
public int r; // axial r(row)
|
||||
public HexCoord(int q, int r) { this.q = q; this.r = r; }
|
||||
public static readonly HexCoord[] neighbors = {
|
||||
new HexCoord(+1, 0),
|
||||
new HexCoord(+1, -1),
|
||||
new HexCoord(0, -1),
|
||||
new HexCoord(-1, 0),
|
||||
new HexCoord(-1, +1),
|
||||
new HexCoord(0, +1)
|
||||
};
|
||||
public HexCoord Neighbor(int i) => new HexCoord(q + neighbors[i].q, r + neighbors[i].r);
|
||||
|
||||
public override bool Equals(object obj) {
|
||||
if (!(obj is HexCoord)) return false;
|
||||
HexCoord o = (HexCoord)obj;
|
||||
return q == o.q && r == o.r;
|
||||
}
|
||||
//??
|
||||
public override int GetHashCode() => q * 73856093 ^ r * 19349663;
|
||||
public override string ToString() => $"({q},{r})";
|
||||
}
|
||||
|
||||
}
|
||||
3
Assets/Scripts/HexGrid/Math/HexCoord.cs.meta
Normal file
3
Assets/Scripts/HexGrid/Math/HexCoord.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d569dbffffb41d382ed771b3aee08cf
|
||||
timeCreated: 1757055757
|
||||
121
Assets/Scripts/HexGrid/Math/HexMath.cs
Normal file
121
Assets/Scripts/HexGrid/Math/HexMath.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using System.Numerics;
|
||||
using PlayFab.Internal;
|
||||
using UnityEngine;
|
||||
using Vector3 = UnityEngine.Vector3;
|
||||
|
||||
// 项目中主要采用的是尖顶的 pointy-top ,平顶的 Flat-top 后续在考虑
|
||||
namespace HexGrid.Math
|
||||
{
|
||||
public static class HexMath {
|
||||
|
||||
//
|
||||
private static float _gridSize;
|
||||
private static Vector3 _originPos = Vector3.zero;
|
||||
|
||||
// size = hex radius (distance center->corner)
|
||||
// pointy-top axial coordinates on XZ plane
|
||||
// Arial坐标 ->World
|
||||
public static Vector3 AxialToPixel(int q, int r )
|
||||
{
|
||||
var x = _gridSize * Mathf.Sqrt(3f) * (q + r / 2f);
|
||||
var z = _gridSize * 1.5f * r;
|
||||
return new Vector3(x, 0, z) + _originPos;
|
||||
}
|
||||
//Arial -> World
|
||||
public static Vector2Int PixelToAxial(Vector3 pos)
|
||||
{
|
||||
var posRelative = pos - _originPos;
|
||||
Debug.Log($"posRelative->{pos}-> {posRelative}");
|
||||
var q = (Mathf.Sqrt(3f) / 3f * posRelative.x - 1f / 3f * posRelative.z) / _gridSize;
|
||||
var r = (2f / 3f * posRelative.z) / _gridSize;
|
||||
return HexRound(q, r);
|
||||
}
|
||||
private static Vector2Int HexRound(float q, float r)
|
||||
{
|
||||
float x = q;
|
||||
float z = r;
|
||||
float y = -x - z;
|
||||
|
||||
int rx = Mathf.RoundToInt(x);
|
||||
int ry = Mathf.RoundToInt(y);
|
||||
int rz = Mathf.RoundToInt(z);
|
||||
|
||||
float x_diff = Mathf.Abs(rx - x);
|
||||
float y_diff = Mathf.Abs(ry - y);
|
||||
float z_diff = Mathf.Abs(rz - z);
|
||||
|
||||
if (x_diff > y_diff && x_diff > z_diff)
|
||||
{
|
||||
rx = -ry - rz;
|
||||
}
|
||||
else if (y_diff > z_diff)
|
||||
{
|
||||
ry = -rx - rz;
|
||||
}
|
||||
else
|
||||
{
|
||||
rz = -rx - ry;
|
||||
}
|
||||
return new Vector2Int(rx, rz);
|
||||
}
|
||||
|
||||
public static Vector3 HexToWorld(HexCoord h, float size, float height=0f) {
|
||||
float x = size * (Mathf.Sqrt(3f) * h.q + Mathf.Sqrt(3f) / 2f * h.r);
|
||||
float z = size * (3f/2f * h.r);
|
||||
return new Vector3(x, height, z);
|
||||
}
|
||||
// worldPos: arbitrary world point (x,y,z). We project onto XZ plane and compute axial coords.
|
||||
public static HexCoord WorldToHexXZ(Vector3 worldPos, float size) {
|
||||
float x = worldPos.x;
|
||||
float z = worldPos.z;
|
||||
float qf = (Mathf.Sqrt(3f)/3f * x - 1f/3f * z) / size;
|
||||
float rf = (2f/3f * z) / size;
|
||||
return CubeRound(AxialToCube(qf, rf));
|
||||
}
|
||||
private struct Cube { public float x,y,z; public Cube(float x,float y,float z){this.x=x;this.y=y;this.z=z;} }
|
||||
private static Cube AxialToCube(float q, float r) {
|
||||
float x = q;
|
||||
float z = r;
|
||||
float y = -x - z;
|
||||
return new Cube(x,y,z);
|
||||
}
|
||||
private static HexCoord CubeRound(Cube c) {
|
||||
int rx = Mathf.RoundToInt(c.x);
|
||||
int ry = Mathf.RoundToInt(c.y);
|
||||
int rz = Mathf.RoundToInt(c.z);
|
||||
|
||||
float x_diff = Mathf.Abs(rx - c.x);
|
||||
float y_diff = Mathf.Abs(ry - c.y);
|
||||
float z_diff = Mathf.Abs(rz - c.z);
|
||||
|
||||
if (x_diff > y_diff && x_diff > z_diff) rx = -ry - rz;
|
||||
else if (y_diff > z_diff) ry = -rx - rz;
|
||||
else rz = -rx - ry;
|
||||
|
||||
return new HexCoord(rx, rz); // axial q = x, r = z
|
||||
}
|
||||
|
||||
public static int Distance(HexCoord a, HexCoord b) {
|
||||
int ax = a.q, az = a.r, ay = -ax - az;
|
||||
int bx = b.q, bz = b.r, by = -bx - bz;
|
||||
return Mathf.Max(Mathf.Abs(ax - bx), Mathf.Abs(ay - by), Mathf.Abs(az - bz));
|
||||
}
|
||||
|
||||
public static void SetGridSize(float gridSize)
|
||||
{
|
||||
_gridSize = gridSize;
|
||||
}
|
||||
public static float GetGridSize() => _gridSize;
|
||||
|
||||
public static void SetHexMapOrigin(Vector3 zero)
|
||||
{
|
||||
_originPos = new Vector3(zero.x,0,zero.z);
|
||||
}
|
||||
|
||||
public static void Log(object t)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
3
Assets/Scripts/HexGrid/Math/HexMath.cs.meta
Normal file
3
Assets/Scripts/HexGrid/Math/HexMath.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 97acc7f3343b470da16958a6ebcfa077
|
||||
timeCreated: 1757055818
|
||||
27
Assets/Scripts/HexGrid/TerrainManager.cs
Normal file
27
Assets/Scripts/HexGrid/TerrainManager.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace HexGrid
|
||||
{
|
||||
// 地形管理
|
||||
// 未解锁的时候,放个黑块
|
||||
public class TerrainManager : MonoBehaviour,IHexGridMediatable
|
||||
{
|
||||
[SerializeField] private Material unlockedMaterial;
|
||||
[SerializeField] private Material lockedMaterial;
|
||||
public void UpdateTerrainForZone(int zoneId)
|
||||
{
|
||||
var obj = GameObject.Find("ZoneTerrain_" + zoneId);
|
||||
if (obj != null)
|
||||
{
|
||||
var rend = obj.GetComponent<Renderer>();
|
||||
if (rend != null) rend.material = unlockedMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void SetMediator(IHexGridMediator mediator)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/HexGrid/TerrainManager.cs.meta
Normal file
3
Assets/Scripts/HexGrid/TerrainManager.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fef103e5ae714810953181d24396bd77
|
||||
timeCreated: 1757322413
|
||||
Reference in New Issue
Block a user