美文网首页unity3D技术分享
2、屏幕坐标、世界坐标、视口坐标、UI坐标系

2、屏幕坐标、世界坐标、视口坐标、UI坐标系

作者: GameObjectLgy | 来源:发表于2020-09-01 23:58 被阅读0次
    1、世界坐标系:World Space

    获取得到的位置和旋转信息都是基于世界坐标系的,在场景中大部分时候都是使用世界坐标系。

    2、视口坐标:View Port

    摄像机占据的视口空间,如果有多个摄像机,那么就有多个视口。
    值范围:左下角为(0,0),右上角为(1,1)

    3、屏幕坐标:Screen Space

    屏幕坐标就是以整个硬件屏幕为基础的坐标系,和屏幕分辨率有关。
    值范围:屏幕的左下角为(0,0),但右上角为(screen.width,screen.height),screen.width表示屏幕宽度,screen.height表示屏幕高度

    4、三者之间的转化
    • 全局坐标与屏幕坐标互转
      Camera.ScreenToWorldPoint(Vector3 position): 将屏幕坐标转换为全局坐标
      Camera.WorldToScreenPoint(Vector3 position):将全局坐标转换为屏幕坐标
    • 屏幕坐标系与视口坐标系互转
      Camera.ScreenToViewportPoint(Vector3 position):将屏幕坐标转换为视口坐标
      Camera.ViewportToScreenPoint(Vector3 position):将视口坐标转换为屏幕坐标
    • 全局坐标系与视口坐标系
      Camera.WorldToViewportPoint(Vector3 position):将全局坐标转换为视口坐标
      Camera.ViewportToWorldPoint(Vector3 position):将视口坐标转换为全局坐标
    5、UI坐标系

    GUI界面坐标系:这个坐标系与屏幕坐标系相似,不同的是该坐标系以屏幕的左上角为(0,0)点,右下角为(Screen.width,Screen.height)

    6、全局坐标与局部坐标
        transform.TransformPoint(transform.localPosition);
        //局部坐标转世界坐标
        transform.parent.InverseTransformPoint(transform.position);
        //世界坐标转局部坐标
    
    常见相关应用

    屏幕坐标系应用:1、2D游戏中物体跟随鼠标位置

    获取鼠标位置的时候,Input.mousePosition来获取鼠标的位置,这里获取到的鼠标位置是基于屏幕坐标的。通过该函数返回的是Vector3类型的变量,但z分量始终为0。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class DragMove : MonoBehaviour
    {
        public Transform foodT;
        //拖拽物体移动
        private bool isMouseDown;
        private bool isFreeMove;
        private Vector3 lastMousePosition = Vector3.zero;
        private Vector3 currentMousePos = Vector3.zero;//当前鼠标的世界坐标
        private Vector3 offsetV3 = Vector3.zero;//偏移向量
        
        void Start()
        {
            isFreeMove = false;
        }
    
        void Update()
        {
            DraggingFoodMove();
        }
    
        private void DraggingFoodMove()
        {
    
            if (Input.GetMouseButtonDown(0))
            {
                Debug.Log("鼠标按下");
                currentMousePos = Input.mousePosition;//直接用鼠标位置就行
                Debug.Log("鼠标点击点到食物中心点距离 = " + Vector3.Distance(currentMousePos, foodT.position));
                if (Vector3.Distance(currentMousePos, foodT.position) > 80)//判断是否有效在触碰范围之内
                {
                    return;
                }
                else
                {
                    offsetV3 = currentMousePos - foodT.localPosition;
                }
    
                isMouseDown = true;
                isFreeMove = false;
            }
            if (Input.GetMouseButtonUp(0))
            {
                isMouseDown = false;
                isFreeMove = true;
            }
            if (isMouseDown)
            {
                foodT.localPosition = Input.mousePosition - offsetV3;
            }
        }
    }
    
    
    2、视口坐标系在2D游戏中的应用

    在上面的工程当中设置出一个视口区域,不让物体超出视口范围。


    image.png

    如上图制作了一下限制了摄像机的视口范围。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class DragMove : MonoBehaviour
    {
        public Transform foodT;
        //拖拽物体移动
        private bool isMouseDown;
        private bool isFreeMove;
        private Vector3 lastMousePosition = Vector3.zero;
        private Vector3 currentMousePos = Vector3.zero;//当前鼠标的世界坐标
        private Vector3 offsetV3 = Vector3.zero;//偏移向量
        
        void Start()
        {
            isFreeMove = false;
            leftBtm_cornerPos = Camera.main.ViewportToWorldPoint(new Vector3(0f, 0f, Mathf.Abs(-Camera.main.transform.position.z))); //这里的z轴在正交视图下意义不大
            rightTop_cornerPos = Camera.main.ViewportToWorldPoint(new Vector3(1f, 1f, Mathf.Abs(-Camera.main.transform.position.z)));
    
            leftBorder = leftBtm_cornerPos.x;
            Debug.Log("leftBorder = " + leftBorder);
            rightBorder = rightTop_cornerPos.x;
            Debug.Log("rightBorder = " + rightBorder);
            topBorder = rightTop_cornerPos.y;
            Debug.Log("topBorder = " + topBorder);
            bottomBorder = leftBtm_cornerPos.y;
            Debug.Log("bottomBorder = " + bottomBorder);
        }
    
        void Update()
        {
            DraggingFoodMove();
            LimitViewPort();
        }
    
        private void DraggingFoodMove()
        {
    
            if (Input.GetMouseButtonDown(0))
            {
                Debug.Log("鼠标按下");
                currentMousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);//直接用鼠标位置就行
                Debug.Log("currentMousePos = " + currentMousePos);
                Debug.Log("鼠标点击点到食物中心点距离 = " + Vector3.Distance(currentMousePos, foodT.position));
                if (Vector3.Distance(currentMousePos, foodT.position) > 80)//判断是否有效在触碰范围之内
                {
                    return;
                }
                else
                {
                    offsetV3 = currentMousePos - foodT.localPosition;
                }
    
                isMouseDown = true;
                isFreeMove = false;
            }
            if (Input.GetMouseButtonUp(0))
            {
                isMouseDown = false;
                isFreeMove = true;
            }
            if (isMouseDown)
            {
                foodT.localPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition) - offsetV3;
            }
    
        }
    
    
        public float leftBorder;
        public float rightBorder;
        public float topBorder;
        public float bottomBorder;
    
        Vector3 leftBtm_cornerPos;
        Vector3 rightTop_cornerPos;
    
        private Vector3 tempPos = Vector3.zero;
        private void LimitViewPort()
        {
            tempPos = foodT.position;
            //Debug.Log(tempPos);
            if (tempPos.x <= leftBorder)
            {
                tempPos.x = leftBorder;
            }
            else if (tempPos.x >= rightBorder)
            {
                tempPos.x = rightBorder;
            }
    
            if (tempPos.y <= bottomBorder)
            {
                tempPos.y = bottomBorder;
            }
            else if (tempPos.y >= topBorder)
            {
                tempPos.y = topBorder;
            }
            foodT.position = tempPos;
        }
    }
    
    

    这里采用了2DSprite,采用的是场景中物体的世界坐标。注意不是UI坐标系里的坐标哦,是不一样的。


    image.png

    结果如下:

    [图片上传中...(2.gif-146127-1598975264125-0)] 3.gif
    3、3D场景中鼠标拖拽物体
        /// <summary>
        /// 这里是3D物体的移动,注意坐标系的转换即可。
        /// </summary>
        /// <returns></returns>
        //注意世界坐标系转化为屏幕坐标系,Z轴是不变的
        IEnumerator OnMouseDown()
        {
            //将物体由世界坐标系转化为屏幕坐标系,由vector3 结构体变量ScreenSpace存储,以用来明确屏幕坐标系Z轴的位置
            Vector3 ScreenSpace = Camera.main.WorldToScreenPoint(transform.position);
            //完成了两个步骤,1由于鼠标的坐标系是2维的,需要转化成3维的世界坐标系,2只有三维的情况下才能来计算鼠标位置与物体的距离,offset即是距离
            Vector3 offset = transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, ScreenSpace.z));
            Debug.Log("down");
            //当鼠标左键按下时
            while (Input.GetMouseButton(0))
            {
                //得到现在鼠标的2维坐标系位置
                Vector3 curScreenSpace = new Vector3(Input.mousePosition.x, Input.mousePosition.y, ScreenSpace.z);
                //将当前鼠标的2维位置转化成三维的位置,再加上鼠标的移动量
                Vector3 CurPosition = Camera.main.ScreenToWorldPoint(curScreenSpace) + offset;
                //CurPosition就是物体应该的移动向量赋给transform的position属性
                transform.position = CurPosition;
                yield return new WaitForFixedUpdate();
            }
        }
    

    相关文章

      网友评论

        本文标题:2、屏幕坐标、世界坐标、视口坐标、UI坐标系

        本文链接:https://www.haomeiwen.com/subject/yfgpjktx.html