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

Unity中如何让盒子精灵精准落在鼠标点击位置且无倾斜?

Unity Canvas盒子精灵倾斜问题排查与修复

我正在开发一个带Canvas的Unity项目,尝试创建盒子对象。盒子能正常创建,但放置时精灵会出现倾斜,效果如下:
演示动图

现有代码逻辑

射线检测与放置触发

用户点击Canvas时,通过相机发射射线获取鼠标位置,命中对象后验证位置并创建盒子:

Ray ray = _camera.ScreenPointToRay(Input.mousePosition);
if(Physics.Raycast(ray, out RaycastHit hitInfo, Mathf.Infinity))
{           
    if (_CheckCanDropObject(ray, hitInfo))
    {
        BuildingController.CreateBox(new Vector3(hitInfo.point.x, hitInfo.point.y, WHConstants.AboveDefaultZ), buildingInventoryController.currentBlock.BlockSprite);
    }
}

盒子创建流程

位置验证通过后,调用CreateBox遍历建筑子对象找到平面图,通过工厂模式创建盒子并添加到命令队列:

public static void CreateBox(Vector3 position, UnityEngine.Sprite sprite)
{
    List<ICommand> commands = new List<ICommand>();
    foreach (CreatorItem child in GetBuilding().children)
    {
        if (child.name.Contains(WHConstants.FLOOR_PLAN))
        {
            CreatorItem floorPlan = child;
            float height = floorPlan.GetComponent<IHasDimension>().Dimension.Height;

            string name = NamingController.GetName(WHConstants.Box, floorPlan.uiItem.Foldout.Children());
            CreatorItemCreateCommand createCommand = new CreatorItemCreateCommand(new CreatorBoxFactory(position, sprite, height), name);
            ICommand createAndAddParentCommand = new CreateCreatorItemWithParentCommand(createCommand, floorPlan.Id);
            commands.Add(createAndAddParentCommand);
        }
    }
    ICommand createBox = new MultipleCommand(commands);
    UndoRedo.AddAndExecuteCommand(createBoxs); // 注意:此处变量名疑似笔误,应为createBox
    DeselectAll();
    CreatorUIController.UnSavedProgress = true;
}

盒子工厂实现

CreatorBoxFactory负责生成盒子GameObject,包含SpriteRenderer和碰撞体:

public class CreatorBoxFactory : ICreatorItemFactory
{
    private Vector3 _position;
    private Sprite _sprite;
    private float _height;

    public CreatorBoxFactory(Vector3 position, Sprite sprite, float height)
    {
        _height = height;
        _position = position;
        _sprite = sprite;
    }

    public CreatorItem Create(string name, bool createGO = true)
    {
        Box item;
        GameObject Box = null;
        if (createGO)
        {
            UIItem uiItem = new BoxUIFactory().Create(name);
            Box = CreateBox();
            item = new Box(Box, uiItem);
        }
        else
        {
            item = new Box(null, null);
        }
        item.SetPosition(new Vector3(_position.x, _position.y, 0));
        item.SetDimension(WHConstants.DefaultBoxLength, _height, WHConstants.DefaultBox2DHeight);
        item.SetName(name);

        if (item.uiItem != null)
        {
            item.uiItem._delegate = item;
        }
        if (createGO)
        {
            item.SetTransformer();
        }
        return item;
    }

    private GameObject CreateBox()
    {
        GameObject boxGameObject = new GameObject();
        SpriteRenderer spriteRenderer = boxGameObject.AddComponent<SpriteRenderer>();
        spriteRenderer.sprite = _sprite;

        Vector2 unit = ConvertCoordinate.PixelToUnit(spriteRenderer.sprite);

        BoxCollider lineCollider = boxGameObject.AddComponent<BoxCollider>();
        lineCollider.transform.parent = spriteRenderer.transform;
        lineCollider.size = new Vector3(unit.x, unit.y, 1f);
        lineCollider.center = new Vector3(0.0f, 0.0f, 0.0f);

        boxGameObject.tag = WHConstants.METABLOCK;

        boxGameObject.transform.position = _position;
        boxGameObject.transform.localScale = new Vector3(WHConstants.DefaultBoxLength / unit.x, WHConstants.DefaultBox2DHeight / unit.y, 1);
        return boxGameObject;
    }
}

问题分析与修复方案

倾斜原因排查

  1. 父对象旋转继承:盒子被父化到floorPlan对象下,如果floorPlan本身带有旋转角度,盒子会继承该旋转,导致精灵倾斜。
  2. 碰撞体父化错误:将BoxCollider挂载到SpriteRenderer子对象上,若SpriteRenderer有旋转/缩放偏移,会带动碰撞体和视觉表现异常。
  3. 未明确重置旋转:创建盒子时未强制重置旋转状态,可能继承场景或父对象的默认旋转值。

修复步骤

  1. 强制重置盒子旋转:在创建盒子GameObject后,立即重置旋转为无角度状态:

    private GameObject CreateBox()
    {
        GameObject boxGameObject = new GameObject();
        // 重置根对象旋转,避免继承默认或父对象旋转
        boxGameObject.transform.rotation = Quaternion.identity;
        
        SpriteRenderer spriteRenderer = boxGameObject.AddComponent<SpriteRenderer>();
        spriteRenderer.sprite = _sprite;
        // ... 其余代码保持不变
    }
    
  2. 修正碰撞体挂载层级:将碰撞体直接挂载在盒子根对象上,避免受SpriteRenderer的变换影响:

    private GameObject CreateBox()
    {
        GameObject boxGameObject = new GameObject();
        boxGameObject.transform.rotation = Quaternion.identity;
        
        SpriteRenderer spriteRenderer = boxGameObject.AddComponent<SpriteRenderer>();
        spriteRenderer.sprite = _sprite;
    
        Vector2 unit = ConvertCoordinate.PixelToUnit(spriteRenderer.sprite);
    
        // 移除lineCollider.transform.parent = spriteRenderer.transform;
        BoxCollider lineCollider = boxGameObject.AddComponent<BoxCollider>();
        lineCollider.size = new Vector3(unit.x, unit.y, 1f);
        lineCollider.center = new Vector3(0.0f, 0.0f, 0.0f);
        
        // ... 其余代码保持不变
    }
    
  3. 父化后重置局部旋转:在将盒子父化到floorPlan后,确保盒子的局部旋转为无角度状态(可在CreateCreatorItemWithParentCommand的执行逻辑中添加):

    // 父化操作完成后添加
    createdItem.transform.localRotation = Quaternion.identity;
    
  4. 适配Canvas坐标系(可选):如果是纯UI Canvas项目,建议使用2D方式获取点击位置,替代3D射线检测,避免坐标系偏差:

    if (Input.GetMouseButtonDown(0))
    {
        if (RectTransformUtility.ScreenPointToLocalPointInRectangle(
            yourCanvasRectTransform, 
            Input.mousePosition, 
            _camera, 
            out Vector2 localPoint))
        {
            Vector3 worldPosition = yourCanvasRectTransform.TransformPoint(localPoint);
            worldPosition.z = WHConstants.AboveDefaultZ;
            if (_CheckCanDropObject(worldPosition))
            {
                BuildingController.CreateBox(worldPosition, buildingInventoryController.currentBlock.BlockSprite);
            }
        }
    }
    

精准定位补充

要确保盒子精准落在鼠标点击位置:

  • 检查Sprite导入设置,将Pivot设为中心(0.5,0.5),保证视觉中心点与对象原点对齐
  • 确保点击位置转换时,坐标系保持一致(3D世界空间或Canvas局部空间)
  • 避免对创建后的盒子位置进行二次偏移操作

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 09:15:01