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