38.坐标系统

38.FGUI基础-Unity中的使用必备-坐标系统


38.1 知识点

所有坐标系概念

  • Unity世界坐标:相对于世界
  • Unity局部坐标:相对于父对象的坐标
  • Unity屏幕坐标:以左下角为原点,Game窗口的屏幕尺寸
  • FGUI屏幕坐标:以左上角为原点,Game窗口的屏幕尺寸
  • FGUI编辑器坐标:FGUI组件在GRoot上的坐标,或者在和GRoot分辨率自适应下的坐标
  • FGUI局部坐标:FGUI相对于父对象的坐标,各个控件在父组件上的坐标,控件的position属性和x或y得到的就是局部坐标

FGUI的屏幕坐标原点

  • FairyGUI的屏幕坐标是以屏幕左上角为原点的
  • Unity的屏幕坐标是以左下角为原点
  • 如果Unity的屏幕坐标想转化FairyGUI的屏幕坐标
  • 先得到鼠标点 得到的是Unity的屏幕坐标(左下角为原点)
    Vector3 screenPos = Input.mousePosition;
    
  • 转换成左上角为原点 转换后的坐标系FairyGUI的屏幕坐标系(左上角为原点)
    screenPos.y = Screen.height - screenPos.y;
    

FGUI编辑器坐标、FGUI屏幕坐标和FGUI元件局部坐标的坐标转换

设置好面板并发布,在unity中显示

//显示面板
TeachPanel panel =UIManager.Instance.ShowPanel<TeachPanel>("Teach");

FGUI元件在当前元件的FGUI父对象坐标系下的坐标



//1.FGUI元件在当前元件的FGUI父对象坐标系下的坐标
//GObject直接得到xy或position 得到的是元件在FGUI编辑器下相对于父对象的坐标
//得到某图形相对于TeachPanel在FGUI编辑器下的坐标 因为TeachPanel是他的直接父对象
print(panel.m_graphTest.x);//209
print(panel.m_graphTest.y);//3
print(panel.m_graphTest.position); //(209.0, 3.0, 0.0)
GObject n1 = panel.m_svTest.GetChild("n1");
//得到滚动视图下第一个Item在FGUI编辑器下相对于滚动视图的坐标 因为滚动容器是他的父对象
print(n1.x);//11
print(n1.y);//1
print(n1.position);// (11.0, 1.0, 0.0)

FGUI元件局部坐标系转FGUI屏幕坐标系

//2.FGUI元件局部坐标系转FGUI屏幕坐标系
//GObject的LocalToGlobal方法 对象调用时传入相对于自身的偏移值 得到当前对象加上偏移坐标在FairyGUI的屏幕坐标系(左上角为原点)下的坐标
//偏移值传(0,0)代表自身左上角 一般是轴心和锚点
Vector2 pos = n1.LocalToGlobal(Vector2.zero);
print("n1在FairyGUI的屏幕坐标系下坐标" + pos);
//注意:FGUI编辑器坐标和FairyGUI的屏幕坐标值不一样 是因为面板分辨率和Game窗口的大小不一致 Unity做了分辨率自适应
//可以用鼠标点击n1进行测试 但是点击得到的是Unity的屏幕坐标系下的坐标 y值要看一下屏幕高进行转换对比
//if (Input.GetMouseButtonDown(0))print("鼠标在Unity的屏幕坐标系下坐标" + Input.mousePosition);




x值差不多,y值符合公式 screenPos.y = Screen.height - screenPos.y,两个y轴加起来差不多就是406

FGUI屏幕坐标系转FGUI元件局部坐标系

//3.FGUI屏幕坐标系转FGUI元件局部坐标系
//GObject的GlobalToLocal方法 对象调用时传入某个在FairyGUI的屏幕坐标系下的坐标 得到这个坐标相对于对象的偏移坐标
//因为刚刚的pos是n1在FairyGUI的屏幕坐标系下坐标 现在又把pos从FairyGUI的屏幕坐标系转成n1坐标系下的位置 当然是原点
//就是说刚刚把(0,0)传进去转成屏幕坐标,现在再转回来肯定还是(0.0, 0.0)
pos = n1.GlobalToLocal(pos);
print("pos在n1坐标系下的位置" + pos);//(0.0, 0.0)

FGUI屏幕坐标系转FGUI编辑器坐标系

//4.FGUI屏幕坐标系转FGUI编辑器坐标系
//注释刚刚FGUI屏幕坐标系转FGUI元件局部坐标系的代码,假设现在pos的值还是FGUI屏幕坐标系下的值(440.9.194)
//GRoot.inst.GlobalToLocal方法 传入某个在FairyGUI的屏幕坐标系下的坐标 FairyGUI的屏幕坐标系转成FGUI编辑器坐标系
print("把n1在FairyGUI的屏幕坐标系下的坐标转成FGUI编辑器坐标系下的坐标" + GRoot.inst.GlobalToLocal(pos) );//(834.0, 367.0)


假设当前TeachPanel就是GRoot,因为和GRoot建立了分辨率自适应的联系,所以可以这样认为。FGUI编辑器坐标系值的就是n1在TeachPanel坐标系下的值。把一个元件摆在(834.0, 367.0)上,刚好发现对准了n1左上角。

FGUI元件局部坐标系转FGUI编辑器坐标系

//5.FGUI元件局部坐标系转FGUI编辑器坐标系
//GObject的LocalToRoot方法 对象调用时传入相对于自身的偏移值和根对象 得到在FGUI编辑器坐标系的坐标
pos = n1.LocalToRoot(Vector2.zero, GRoot.inst);
print("n1在FGUI编辑器下的坐标系" + pos);//(834.0, 367.0)

和FGUI屏幕坐标系转FGUI编辑器坐标系类似,传入Vector2.zero,代表传入n1左上角锚点在GRoot进行计算。和在TeachPanel坐标系下的值一致。

FGUI编辑器坐标系转FGUI元件局部坐标系

//6.FGUI编辑器坐标系转FGUI元件局部坐标系
//现在pos是(834.0, 367.0)
//GObject的RootToLocal方法 对象调用时传入某在FGUI编辑器坐标系下的坐标和根对象 得到相对于当前对象局部坐标系的坐标
pos = n1.RootToLocal(pos, GRoot.inst);
print("pos在n1坐标系下的位置" + pos);//(0,0)

刚好和FGUI元件局部坐标系转FGUI编辑器坐标系相反的转换

A对象在B对象坐标系下的坐标

//7.A对象在B对象坐标系下的坐标
//n1作为A对象 在(834.0, 367.0)
//panel.m_imgTest作为B对象 在(9,6)
//GObject的TransformPoint  A对象调用时传入相对于A对象自身的偏移值和B对象 得到A对象在B对象局部坐标系下的坐标
pos = n1.TransformPoint(Vector2.zero, panel.m_imgTest);
print("n1在m_imgTest坐标系下的位置是" + pos); //(825.0, 361.0)

世界坐标转换

Unity世界坐标转FGUI编辑器坐标

  • Unity世界坐标->Unity屏幕坐标->FairyGUI屏幕坐标->FGUI编辑器坐标系
  • Unity世界坐标转Unity屏幕坐标
    screenPos = Camera.main.WorldToScreenPoint(this.transform.position);
    
  • Unity屏幕坐标转FairyGUI屏幕坐标
    screenPos.y = Screen.height - screenPos.y;
    
  • FGUI屏幕坐标转FGUI编辑器坐标
    pos = GRoot.inst.GlobalToLocal(screenPos);
    print("Unity世界坐标转FGUI编辑器坐标" + pos);
    

FGUI编辑器坐标转Unity世界坐标

  • FGUI编辑器坐标系->FairyGUI屏幕坐标->Unity屏幕坐标->Unity世界坐标
  • FGUI编辑器坐标系转FGUI屏幕坐标系
    pos = GRoot.inst.LocalToGlobal(pos);
    
  • FairyGUI屏幕坐标转Unity屏幕坐标
    pos.y = Screen.height - pos.y;
    
  • 一般情况下,还需要提供距离摄像机视野正前方distance长度的参数作为screenPos.z(如果需要,将screenPos改为Vector3类型)
  • 就是说不设置Z轴的话 对象默认离摄像机的z轴位置是0,比如当前对象在摄像机10个单位外,就传10
    screenPos = new Vector3(pos.x, pos.y, 0);
    
  • Unity屏幕坐标转Unity世界坐标
    Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos);
    print("FGUI编辑器坐标转Unity世界坐标" + worldPos);
    

38.2 知识点代码

using FairyGUI;
using System.Collections;
using System.Collections.Generic;
using Teach;
using UnityEngine;

public class Lesson38_FGUI基础_Unity中的使用必备_坐标系统 : MonoBehaviour
{
    void Start()
    {
        #region 知识点一 坐标原点

        //FairyGUI的屏幕坐标是以屏幕左上角为原点的
        //Unity的屏幕坐标是以左下角为原点

        //如果Unity的屏幕坐标想转化FairyGUI的屏幕坐标
        //先得到鼠标点 得到的是Unity的屏幕坐标(左下角为原点)
        Vector3 screenPos = Input.mousePosition;
        //转换成左上角为原点 转换后的坐标系FairyGUI的屏幕坐标系(左上角为原点)  
        screenPos.y = Screen.height - screenPos.y;

        #endregion

        #region 知识点二 FGUI编辑器坐标、FGUI屏幕坐标和FGUI元件局部坐标的坐标转换

        //显示面板
        TeachPanel panel =UIManager.Instance.ShowPanel<TeachPanel>("Teach");

        //1.FGUI元件在当前元件的FGUI父对象坐标系下的坐标
        //GObject直接得到xy或position 得到的是元件在FGUI编辑器下相对于父对象的坐标
        //得到某图形相对于TeachPanel在FGUI编辑器下的坐标 因为TeachPanel是他的直接父对象
        print(panel.m_graphTest.x);//209
        print(panel.m_graphTest.y);//3
        print(panel.m_graphTest.position); //(209.0, 3.0, 0.0)
        GObject n1 = panel.m_svTest.GetChild("n1");
        //得到滚动视图下第一个Item在FGUI编辑器下相对于滚动视图的坐标 因为滚动容器是他的父对象
        print(n1.x);//11
        print(n1.y);//1
        print(n1.position);// (11.0, 1.0, 0.0)

        //2.FGUI元件局部坐标系转FGUI屏幕坐标系
        //GObject的LocalToGlobal方法 对象调用时传入相对于自身的偏移值 得到当前对象加上偏移坐标在FairyGUI的屏幕坐标系(左上角为原点)下的坐标
        //偏移值传(0,0)代表自身左上角 一般是轴心和锚点
        Vector2 pos = n1.LocalToGlobal(Vector2.zero);
        print("n1在FairyGUI的屏幕坐标系下坐标" + pos);
        //注意:FGUI编辑器坐标和FairyGUI的屏幕坐标值不一样 是因为面板分辨率和Game窗口的大小不一致 Unity做了分辨率自适应
        //可以用鼠标点击n1进行测试 但是点击得到的是Unity的屏幕坐标系下的坐标 y值要看一下屏幕高进行转换对比
        //if (Input.GetMouseButtonDown(0))print("鼠标在Unity的屏幕坐标系下坐标" + Input.mousePosition);

        //3.FGUI屏幕坐标系转FGUI元件局部坐标系
        //GObject的GlobalToLocal方法 对象调用时传入某个在FairyGUI的屏幕坐标系下的坐标 得到这个坐标相对于对象的偏移坐标
        //因为刚刚的pos是n1在FairyGUI的屏幕坐标系下坐标 现在又把pos从FairyGUI的屏幕坐标系转成n1坐标系下的位置 当然是原点
        //pos = n1.GlobalToLocal(pos);
        //print("pos在n1坐标系下的位置" + pos);//(0.0, 0.0)

        //4.FGUI屏幕坐标系转FGUI编辑器坐标系
        //GRoot.inst.GlobalToLocal方法 传入某个在FairyGUI的屏幕坐标系下的坐标 FairyGUI的屏幕坐标系转成FGUI编辑器坐标系
        print("把n1在FairyGUI的屏幕坐标系下的坐标转成FGUI编辑器坐标系下的坐标" + GRoot.inst.GlobalToLocal(pos) );//(834.0, 367.0)

        //5.FGUI元件局部坐标系转FGUI编辑器坐标系
        //GObject的LocalToRoot方法 对象调用时传入相对于自身的偏移值和根对象 得到在FGUI编辑器坐标系的坐标
        pos = n1.LocalToRoot(Vector2.zero, GRoot.inst);
        print("n1在FGUI编辑器下的坐标系" + pos);//(834.0, 367.0)

        //6.FGUI编辑器坐标系转FGUI元件局部坐标系
        //GObject的RootToLocal方法 对象调用时传入某在FGUI编辑器坐标系下的坐标和根对象 得到相对于当前对象局部坐标系的坐标
        pos = n1.RootToLocal(pos, GRoot.inst);
        print("pos在n1坐标系下的位置" + pos);//(0,0)

        //7.A对象在B对象坐标系下的坐标
        //n1作为A对象 在(834.0, 367.0)
        //panel.m_imgTest作为B对象 在(9,6)
        //GObject的TransformPoint  A对象调用时传入相对于A对象自身的偏移值和B对象 得到A对象在B对象局部坐标系下的坐标
        pos = n1.TransformPoint(Vector2.zero, panel.m_imgTest);
        print("n1在m_imgTest坐标系下的位置是" + pos); //(825.0, 361.0)

        #endregion

        #region 知识点三 世界坐标转换

        //1.Unity世界坐标转FGUI编辑器坐标
        //Unity世界坐标->Unity屏幕坐标->FairyGUI屏幕坐标->FGUI编辑器坐标系
        //Unity世界坐标转Unity屏幕坐标
        screenPos = Camera.main.WorldToScreenPoint(this.transform.position);
        //Unity屏幕坐标转FairyGUI屏幕坐标
        screenPos.y = Screen.height - screenPos.y;
        //FGUI屏幕坐标转FGUI编辑器坐标
        pos = GRoot.inst.GlobalToLocal(screenPos);
        print("Unity世界坐标转FGUI编辑器坐标" + pos);

        //2.FGUI编辑器坐标转Unity世界坐标
        //FGUI编辑器坐标系->FairyGUI屏幕坐标->Unity屏幕坐标->Unity世界坐标
        //FGUI编辑器坐标系转FGUI屏幕坐标系
        pos = GRoot.inst.LocalToGlobal(pos);
        //FairyGUI屏幕坐标转Unity屏幕坐标
        pos.y = Screen.height - pos.y;
        //一般情况下,还需要提供距离摄像机视野正前方distance长度的参数作为screenPos.z(如果需要,将screenPos改为Vector3类型)
        //就是说不设置Z轴的话 对象默认离摄像机的z轴位置是0
        //比如当前对象在摄像机10个单位外
        screenPos = new Vector3(pos.x, pos.y, 0);
        //Unity屏幕坐标转Unity世界坐标
        Vector3 worldPos = Camera.main.ScreenToWorldPoint(screenPos);
        print("FGUI编辑器坐标转Unity世界坐标" + worldPos);
        #endregion
    }

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
            print("鼠标在Unity的屏幕坐标系下坐标" + Input.mousePosition);
    }
}

38.3 练习题

在上节课的练习题基础上,请用现在所学知识,制作一个这样的功能,面板上有一张图片,它会一直跟随鼠标移动

在练习题面板多创建一个图片

ExercisesPanel脚本中得到图片

public GImage m_imgF;
m_imgF = GetChild("imgF").asImage;

ExercisesPanel脚本创建更新图片位置方法

/// <summary>
/// 更新图片位置 
/// </summary>
/// <param name="inputPos">鼠标位置</param>
public void UpdateImgPos(Vector3 inputPos)
{
    //要把屏幕坐标(鼠标位置)转换成UI坐标 不停的赋值给跟随移动的图片
    //相对于FGUI坐标系的 物理坐标
    inputPos.y = Screen.height - inputPos.y;
    //物理坐标 转 逻辑坐标(UI坐标)
    m_imgF.position = GRoot.inst.GlobalToLocal(inputPos);
}

Exercises脚本每一帧更新图片位置

void Update()
{
    panel.UpdateImgPos(Input.mousePosition);
}

38.4 练习题代码

ExercisesPanel

/** This is an automatically generated class by FairyGUI. Please do not modify it. **/

using FairyGUI;
using FairyGUI.Utils;
using UnityEngine;

namespace Teach
{
    public partial class ExercisesPanel : GComponent
    {
        public Controller m_RadioGroup;
        public GRichTextField m_richTxt1;
        public GRichTextField m_richTxt2;
        public GTextInput m_inputTxt;
        public GTextField m_txtInfo;
        public GTextField m_txtName;
        public GButton m_btnFire;
        public GButton m_checkBoxMusic;
        public GButton m_radioBoxOpen;
        public GButton m_radioBoxClose;
        public GSlider m_soundSlider;
        public GButton m_btnBag;
        public GImage m_imgF;
        public const string URL = "ui://wrs19joehkfz2s";

        private Player player;

        public static ExercisesPanel CreateInstance()
        {
            return (ExercisesPanel)UIPackage.CreateObject("Teach", "ExercisesPanel");
        }

        public override void ConstructFromXML(XML xml)
        {
            base.ConstructFromXML(xml);

            m_RadioGroup = GetControllerAt(0);
            m_richTxt1 = (GRichTextField)GetChildAt(0);
            m_richTxt2 = (GRichTextField)GetChildAt(1);
            m_inputTxt = (GTextInput)GetChildAt(3);
            m_txtInfo = (GTextField)GetChildAt(4);
            m_txtName = (GTextField)GetChildAt(7);
            m_btnFire = (GButton)GetChildAt(15);
            m_checkBoxMusic = (GButton)GetChildAt(16);
            m_radioBoxOpen = (GButton)GetChildAt(17);
            m_radioBoxClose = (GButton)GetChildAt(18);
            m_soundSlider = (GSlider)GetChildAt(19);
            m_btnBag = (GButton)GetChildAt(20);
            m_imgF = GetChild("imgF").asImage;

            m_richTxt1.onClickLink.Add(Exercises.ClickLinkOpenPanel);
            m_richTxt2.onClickLink.Add(Exercises.ClickLinkOpenPanel);

            //输入文本练习题相关
            m_inputTxt.onChanged.Add(() =>
            {
                //让文本控件的内容和输入的内容一致
                m_txtInfo.text = m_inputTxt.text;
            });

            m_btnFire.onClick.Add(() =>
            {
                player.Fire();
            });

            m_checkBoxMusic.onChanged.Add(() =>
            {
                if (m_checkBoxMusic.selected)
                    GRoot.inst.EnableSound();
                else
                    GRoot.inst.DisableSound();
            });

            Controller c = this.GetController("RadioGroup");
            c.onChanged.Add(() =>
            {
                if (c.selectedIndex == 0)
                    GRoot.inst.EnableSound();
                else
                    GRoot.inst.DisableSound();
            });

            m_soundSlider.onChanged.Add(() => {
                GRoot.inst.soundVolume = (float)m_soundSlider.value;
            });

            m_btnBag.onClick.Add(() =>
            {
                //ExercisesBagPanel bagPanel = ExercisesBagPanel.CreateInstance();
                //GRoot.inst.AddChild(bagPanel);
                //显示背包面板
                UIManager.Instance.ShowPanel<ExercisesBagPanel>("Teach");
            });
        }

        /// <summary>
        /// 更新图片位置 
        /// </summary>
        /// <param name="inputPos">鼠标位置</param>
        public void UpdateImgPos(Vector3 inputPos)
        {
            //要把屏幕坐标(鼠标位置)转换成UI坐标 不停的赋值给跟随移动的图片
            //相对于FGUI坐标系的 物理坐标
            inputPos.y = Screen.height - inputPos.y;
            //物理坐标 转 逻辑坐标(UI坐标)
            m_imgF.position = GRoot.inst.GlobalToLocal(inputPos);
        }

        public void SetPlayer(Player player)
        {
            this.player = player;
        }
    }
}

Exercises

using FairyGUI;
using FairyGUI.Utils;
using System.Collections;
using System.Collections.Generic;
using Teach;
using UnityEngine;

public class Exercises : MonoBehaviour
{
    public Player player;

    ExercisesPanel panel;
    
    void Start()
    {
        //UIConfig.defaultFont = "Other/STHUPO";
        //HtmlParseOptions.DefaultLinkColor = Color.red;

        ////设置适配相关
        //GRoot.inst.SetContentScaleFactor(1365, 768, UIContentScaler.ScreenMatchMode.MatchHeight);
        ////包和依赖包的加载
        //UIPackage package = UIPackage.AddPackage("UI/Teach");
        //foreach (var item in package.dependencies)
        //{
        //    UIPackage.AddPackage(item["name"]);
        //}
        ////设置默认按钮音效
        //UIConfig.buttonSound = (NAudioClip)UIPackage.GetItemAssetByURL("ui://Teach/btnMusic");
        ////设置默认按钮音效大小
        //UIConfig.buttonSoundVolumeScale = 0.5f;

        ////一定要先注册
        //TeachBinder.BindAll();
        ////再显示
        //ExercisesPanel panel = ExercisesPanel.CreateInstance();
        ////再添加
        //GRoot.inst.AddChild(panel);
        ////关联玩家
        //panel.SetPlayer(player);


        panel = UIManager.Instance.ShowPanel<ExercisesPanel>("Teach");
        panel.SetPlayer(player);
    }


    public static void ClickLinkOpenPanel(EventContext eventData)
    {
        string info = eventData.data.ToString();
        switch (info)
        {
            case "1":
                print("打开任务面板");
                break;
            case "2":
                print("打开装备面板");
                break;
            case "3":
                print("打开PVP面板");
                break;
            case "4":
                print("打开商店面板");
                break;
            default:
                print("数据未知");
                break;
        }
    }

    void Update()
    {
        panel.UpdateImgPos(Input.mousePosition);
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏