You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在圆周生成等距点位,解决Unity圆形网格tile放置抖动问题

问题排查与修复方案

核心问题

你的实现思路本身是可行的,出现抖动、偏移问题是代码存在三处逻辑疏漏:

  • 量化步长计算顺序错误:原代码计算周长circumference时使用的是上一帧的radius值,而非当前帧的目标圈层半径,导致角度量化步长和当前圈层不匹配,触发提前偏移。
  • 角度范围处理异常:Mathf.Atan2返回的角度范围是[-π, π](对应-180°~180°),在正负角度交界的0°位置会出现359°到1°的跳变,直接取整会导致判定逻辑混乱,出现抖动。
  • 非整数tile数量问题:原代码计算出的每层tile数量可能为小数,无法保证tile严格等距排列,会出现累积偏移。

修复后代码

customGrid.cs

using UnityEngine;

public class customGrid : MonoBehaviour
{
    [SerializeField] private Camera mainCamera;
    [SerializeField] private LayerMask layerMask;

    public GameObject structure;
    Vector3 truePos;
    public int maxLayers = 1;
    public int minLayers = 0;
    public float objectSize = 1.5f;

    void LateUpdate()
    {
        Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
        if (Physics.Raycast(ray, out RaycastHit raycastHit, float.MaxValue, layerMask))
        {
            // 先计算当前鼠标点的角度和距离
            float angleRadian = Mathf.Atan2(raycastHit.point.x, raycastHit.point.z);
            float cursorDistanceFromOrigin = Vector3.Distance(Vector3.zero, new Vector3(raycastHit.point.x, 0, raycastHit.point.z));
            
            // 计算目标圈层半径
            float objectDistanceFromOrigin = Mathf.Floor(cursorDistanceFromOrigin / objectSize) * objectSize;
            var maxDistance = objectSize * maxLayers;
            var minDistance = objectSize * minLayers;
            float radius = Mathf.Clamp(objectDistanceFromOrigin, minDistance, maxDistance);
            
            if (radius < 1) return;
            
            // 基于当前半径计算角度量化步长,强制tile数量为整数
            var circumference = 2 * Mathf.PI * radius;
            int tileCount = Mathf.RoundToInt(circumference / objectSize);
            float quantization = 360f / tileCount;

            // 角度归一化到0~360度,避免跨0度跳变
            var degree = angleRadian * Mathf.Rad2Deg;
            if (degree < 0) degree += 360f;
            
            degree = Mathf.Round(degree / quantization) * quantization;
            angleRadian = degree * Mathf.Deg2Rad;
            
            truePos.x = Mathf.Sin(angleRadian) * radius;
            truePos.y = 0;
            truePos.z = Mathf.Cos(angleRadian) * radius;

            RepositionObject();
        }
    }

    private void RepositionObject()
    {
        structure.transform.position = truePos;
        var dir = truePos - Vector3.zero;
        dir = Vector3.Normalize(dir);
        structure.transform.rotation = Quaternion.LookRotation(dir);
    }
}

可选优化

如果需要相邻圈层的tile严格对齐,可以将每层的tile数量设置为第一层tile数量的整数倍,避免层与层之间的错位。

内容的提问来源于stack exchange,提问作者Abcd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 07:24:02