unity ui随鼠标点击位置显示

文章目录

前言

一、工具

二、使用步骤

1.逻辑

2.拖动物体,传入鼠标坐标

3.鼠标坐标转为rect下的坐标​​​​​​​​​​​​​​


前言

内容:ui选择框随鼠标的点击,位移到移动位置,同时保证ui选择框始终全部出现在canvas下.


一、工具

unity2019.3,ugui

其中canvas的Render Mode选择Screen Space - camera模式,相机赋值为主相机,canvas Scaler选择Scale With Sceen Size模式,如下图,因为Screen Space-  overlay模式下的鼠标拖动ui没记录的,直接获取屏幕坐标就行了.

unity ui随鼠标点击位置显示_第1张图片

二、使用步骤

1.逻辑

1.使用射线判断是否点击到3D物体,判断点击到3D物体成功后,获取到鼠标点击的屏幕坐标.

2.通过RectTransformUtility.ScreenPointToLocalPointInRectangle方法,鼠标的屏幕坐标相对于Ui RectTransform下的坐标,会返回一个v2坐标,这个就是运算出的ui要移动到的坐标点.

3.最后为了让Ui按钮选择框和框的背景始终全部出现在Canvas里面,不会出现框显示一半的情况,通过框的宽高和canvas的宽高计算出一个坐标,赋值给UI,

最终效果

unity ui随鼠标点击位置显示_第2张图片

unity ui随鼠标点击位置显示_第3张图片

2.拖动物体,传入鼠标坐标

这里使用到一个信息处理机制,和拖动3D物体的代码,会标注出来.和一个修改material上shader参数的代码段,主要就是region圈起来的一行代码,获取鼠标点击坐标

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Move3DObject : MonoBehaviour
{
    private bool isClick = false;
    private Transform curTf = null;
    private Vector3 oriMousePos;
    private Vector3 oriObjectScreenPos;
    /// 
    /// 3d物体上的material,用过修改Gameobject上的shader来添加物体的一个描边效果,可以删掉引用到他的所有代码
    /// 
    private Material materShader;
    /// 
    /// 3D物体所在的layer层
    /// 
    private int layerMask;
    private void Awake()
    {
        layerMask = 1 << 8;
    }

    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray , out hit , 100, layerMask))
            {
                curTf = hit.transform;
                oriObjectScreenPos = Camera.main.WorldToScreenPoint(curTf.position);
                oriMousePos = Input.mousePosition;
                materShader = curTf.GetComponent().material;
                #region 通过射线判断点击到3D物体,把鼠标点击坐标通过信息处理机制传到设置ui坐标的脚本,也可以用单利的方式传递
                MessageCenter.PostMessage(EMessage.uiSetImagePosition , Input.mousePosition);
                #endregion
                materShader.SetFloat("_OutlineWidth" , 0.015f);
                materShader.SetFloat("_AlphaBlend" , 0.5f);
                isClick = !isClick;
            }
            
        }
        if(Input.GetMouseButtonUp(0))
        {
            if (curTf!=null)
            {
                curTf = null;
                materShader.SetFloat("_OutlineWidth" , 0);
                materShader.SetFloat("_AlphaBlend" , 1);
                isClick = !isClick;
            }
        }
        if (isClick)
        {
            if (curTf != null)
            {
                Vector3 curMousePos = Input.mousePosition;
                Vector3 mouseOffset = curMousePos - oriMousePos;
                Vector3 curObjectScreenPos = oriObjectScreenPos + mouseOffset;
                Vector3 curObjectWorldPos = Camera.main.ScreenToWorldPoint(curObjectScreenPos);
                curTf.position = curObjectWorldPos;
            }
        }
    }
}

3.鼠标坐标转为rect下的坐标​​​​​​​

1.鼠标坐标转化为rect下的坐标,其中的canvasRectTra是ui canvas的RectTransform属性,imageRectTra是设置的选择框的RectTransform属性,imagePanelV2是方法运算返回的结果.

其中选择框的锚点要设置为中间.

这样鼠标拖动ui,ui出现在鼠标点击的位置就完成了.

    /// 
    /// 参数为鼠标点击坐标
    /// 
    /// 
    private void SetImagePosition(Vector3 v3)
    {
        if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRectTra , v3 , mainCamera , out imagePanelV2))
        {
            imageRectTra.anchoredPosition = imagePanelV2;
        }
    }

2.我要的效果是选择出现在点击3d模型的旁边,并且始终全部出现在ui canvas视野内.

第一步:先通过ImagePanel的宽高向坐标点旁边位移,,让imaegpanel的左上或者右上边框点重现在点击位置上,就是上面运算出来的坐标点进行运算.

第二步 :判断选择框是否超出Canvas的视野范围,对超出的部分进行对应的位移,让他始终处于canvas内.

(其中的AddMessage(),RemoveMessage()是注册,删除信息处理机制的方法,可以不注意,通过单利调用SetImagePosition()方法,通过单利调用传参也是一样的,OnBindPanelElements()方法,放到Start()内调用是一样的,脚本继承的UiBasePanel,无所谓主要是代码逻辑)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UiSetImagePosition : UiBasePanel
{
    private float imageWidth, imageHeight;
    private RectTransform imageRectTra;
    private Camera mainCamera;
    private RectTransform canvasRectTra;
    private Vector2 imagePanelV2;
    private float halfScreenHeig = 0;
    private float screenHeightHalf
    {
        get
        {
            if (halfScreenHeig == 0)
                halfScreenHeig = (Screen.height / (Screen.width / 800f)) / 2;
            return halfScreenHeig;
        }
    }

    //public RectTransform panelRect;
    protected override void OnBindPanelElements()
    {
        imageRectTra = gameObject.FindChild("Image");
        mainCamera = Camera.main;
        imageWidth = imageRectTra.sizeDelta.x / 2;
        imageHeight = imageRectTra.sizeDelta.y / 2;
        canvasRectTra = GameObject.Find("Canvas").GetComponent();
        //screenHeightHalf = (Screen.height/(Screen.width/800f))/2;

        base.OnBindPanelElements();
    }
    protected override void AddMessage()
    {
        MessageCenter.AddMessage(EMessage.uiSetImagePosition , SetImagePosition);
        base.AddMessage();
    }
    protected override void RemoveMessage()
    {
        MessageCenter.RemoveMessage(EMessage.uiSetImagePosition , SetImagePosition);
        base.RemoveMessage();
    }
    /// 
    /// 参数为鼠标点击坐标
    /// 
    /// 
    private void SetImagePosition(Vector3 v3)
    {
        if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRectTra , v3 , mainCamera , out imagePanelV2))
        {
            //通过ImagePanel的宽高向坐标点旁边位移,,让imaegpanel的左上或者右上边框点重现在点击位置上
            imagePanelV2 = new Vector2(imagePanelV2.x + imageWidth , imagePanelV2.y - imageHeight);
            //判断ImagePanel是否超出Canvas的下边界
            if (imagePanelV2.y - imageHeight < -screenHeightHalf)
            {
                //如果超出下边界,让imagePanel的y轴坐标按超出的向量向上位移,是ImagePanel的最下边正好与Canvas的边框对齐
                imagePanelV2.y = imagePanelV2.y - ((imagePanelV2.y - imageHeight) + screenHeightHalf);
            }
            imageRectTra.anchoredPosition = imagePanelV2;
        }
    }
}

3.对上面脚本的screenHeightHalf字段的解释,

因为把canvas的Canvas Scaler的目标宽高设置为800*600,所以canvas的width和heighe会根据canvas Scaler进行限制,canvas的大小并不是我们设置的屏幕大小,

如下面这样设置canvas的宽是一直在800,高会随着我们设置的屏幕宽高进行等比例缩放,也就是宽是固定的,高不固定,(宽也会在800左右有一定的浮动值,误差不大)

so,屏幕的宽高跟Canvas的宽高有统一的比例值,可以通过屏幕的宽/Vanvas的宽计算出比例值,在计算出canvas的高.因为选择框的锚点在屏幕的中心,所以canvas视野内的最下边的点y=-canvas.height/2.这样就可以判断选择框是否超出canvas视野最下方.上下左右都可以这样判断

unity ui随鼠标点击位置显示_第4张图片

 

 

 

 

 

你可能感兴趣的:(untiy,c#,c#,unity)