21.屏幕坐标转UI局部坐标

21.UGUI进阶-屏幕坐标转UI相对坐标


21.1 知识点

RectTransformUtility类

RectTransformUtility类是一个RectTransform的辅助类,主要用于进行一些坐标的转换等操作。其中对于我们目前来说最重要的函数是将屏幕空间上的点转换成UI本地坐标下的点。

将屏幕坐标转换为UI本地坐标系下的点

RectTransformUtility.ScreenPointToLocalPointInRectangl方法 将屏幕坐标点转换为父对象的本地坐标系中的点

  • 参数一:相对父对象
  • 参数二:屏幕点坐标
  • 参数三:摄像机
  • 参数四:最终得到的点坐标

一般配合拖拽事件使用。

让脚本继承拖拽接口,挂载到要被拖拽的对象上,在拖拽方法中用转换方法写逻辑,让被拖拽的对象跟着鼠标动。

public class Lesson21_UGUI进阶_屏幕坐标转UI相对坐标 : MonoBehaviour,IDragHandler
{    
    public RectTransform parent; //父对象

    public void OnDrag(PointerEventData eventData)
    {
        // 方法:RectTransformUtility.ScreenPointToLocalPointInRectangle
        // 将屏幕坐标点转换为父对象的本地坐标系中的点
        // 参数一:相对父对象
        // 参数二:屏幕点坐标
        // 参数三:摄像机
        // 参数四:最终得到的点坐标
        // 一般配合拖拽事件使用

        Vector2 nowPos;//当前位置

        //执行完这个函数后 会把屏幕坐标转换成UI本地坐标系下的值赋值给nowPos
        RectTransformUtility.ScreenPointToLocalPointInRectangle(
            parent, // 相对父对象
            eventData.position, // 屏幕点坐标
            eventData.enterEventCamera, // 摄像机
            out nowPos); // 最终得到的点坐标

        this.transform.localPosition = nowPos; // 将当前对象的本地位置设置为转换后的坐标

        //之前的做法 以后就不用这样做了 选择这种方法更准确
        //this.transform.position += new Vector3(eventData.delta.x, eventData.delta.y, 0);
        // 根据鼠标/触摸滑动的位移,调整当前对象的世界坐标位置
    }
}

21.2 知识点代码

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

public class Lesson21_UGUI进阶_屏幕坐标转UI相对坐标 : MonoBehaviour,IDragHandler
{
    public RectTransform parent; //父对象

    void Start()
    {
        #region 知识点一 RectTransformUtility类
        //RectTransformUtility 公共类是一个RectTransform的辅助类
        //主要用于进行一些 坐标的转换等等操作
        //其中对于我们目前来说 最重要的函数是 将屏幕空间上的点,转换成UI本地坐标下的点
        #endregion
    }

    public void OnDrag(PointerEventData eventData)
    {
        #region 知识点二 将屏幕坐标转换为UI本地坐标系下的点

        // 方法:RectTransformUtility.ScreenPointToLocalPointInRectangle
        // 将屏幕坐标点转换为父对象的本地坐标系中的点
        // 参数一:相对父对象
        // 参数二:屏幕点坐标
        // 参数三:摄像机
        // 参数四:最终得到的点坐标
        // 一般配合拖拽事件使用

        Vector2 nowPos;//当前位置

        //执行完这个函数后 会把屏幕坐标转换成UI本地坐标系下的值赋值给nowPos
        RectTransformUtility.ScreenPointToLocalPointInRectangle(
            parent, // 相对父对象
            eventData.position, // 屏幕点坐标
            eventData.enterEventCamera, // 摄像机
            out nowPos); // 最终得到的点坐标

        this.transform.localPosition = nowPos; // 将当前对象的本地位置设置为转换后的坐标

        //之前的做法 以后就不用这样做了 选择这种方法更准确
        //this.transform.position += new Vector3(eventData.delta.x, eventData.delta.y, 0);
        // 根据鼠标/触摸滑动的位移,调整当前对象的世界坐标位置

        #endregion
    }

}

21.3 练习题

在上节课的练习题基础上,修改其中的代码,用新学的屏幕坐标转UI坐标的知识,制作一个UGUI摇杆可以控制场景上的对象移动

修改GamePanel脚本中摇杆事件函数,调用了 RectTransformUtility 类的 ScreenPointToLocalPointInRectangle 方法,将屏幕坐标点转换为图标父对象的本地坐标系中的点,并将结果保存在 nowPos 变量中。把nowPos变量赋值给当前摇杆点位置。注释掉以前加上鼠标偏移计算摇杆点位置的代码

//定义一个私有方法JoyDrag,在摇杆被拖动时执行,接受一个BaseEventData类型的参数data,表示拖动事件的数据
private void JoyDrag(BaseEventData data)
{
    //将data强制转换为PointerEventData类型,并赋值给eventData变量,表示拖动事件的指针数据
    PointerEventData eventData = data as PointerEventData;

    //以前的知识 是通过加上 鼠标偏移位置 让图标动起来
    //imgJoy.position += new Vector3(eventData.delta.x, eventData.delta.y, 0);

    //用新知识点来制作
    //定义一个Vector2类型的变量nowPos,表示当前位置
    Vector2 nowPos;
    //调用RectTransformUtility类中的ScreenPointToLocalPointInRectangle静态方法,将屏幕坐标转换为矩形变换中的本地坐标,并将结果赋值给nowPos变量
    RectTransformUtility.ScreenPointToLocalPointInRectangle(
        //传入imgJoy对象的parent属性强制转换为RectTransform类型,表示摇杆图标的父对象的矩形变换组件
        imgJoy.parent as RectTransform,
        //传入eventData对象的position属性,表示拖动事件的屏幕坐标
        eventData.position,
        //传入eventData对象的enterEventCamera属性,表示拖动事件的相机
        eventData.enterEventCamera,
        //传出nowPos变量,表示当前位置
        out nowPos);

    //将imgJoy对象的localPosition属性赋值为nowPos变量,表示摇杆图标的本地位置
    imgJoy.localPosition = nowPos;

    //我们有专门的参数 得到相对于锚点的点
    //如果imgJoy对象的anchoredPosition属性的magnitude属性大于170,表示摇杆图标超出了摇杆背景圆形范围
    if (imgJoy.anchoredPosition.magnitude > 170)
    {
        //拉回来
        //单位向量 乘以 长度 = 临界位置
        //将imgJoy对象的anchoredPosition属性赋值为imgJoy对象的anchoredPosition属性的normalized属性乘以170,表示将摇杆图标拉回到摇杆背景圆形边缘
        imgJoy.anchoredPosition = imgJoy.anchoredPosition.normalized * 170;
    }

    //让玩家移动
    //调用player对象的Move方法,传入imgJoy对象的anchoredPosition属性,表示让玩家根据摇杆图标相对于锚点的位置进行移动
    player.Move(imgJoy.anchoredPosition);
}

21.4 练习题代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class GamePanel : MonoBehaviour
{
    public Light light;

    public static GamePanel panel;

    public Button btnAtk;

    //音效开关
    public Toggle togOn;
    public Toggle togOff;
    public ToggleGroup tg;
    //音效大小
    public Slider sliderSound;

    public Text txtName;
    public Button btnChangeName;

    public PlayerObject player;

    //背包按钮
    public Button btnBag;

    //白天黑夜的切换
    public Dropdown ddChange;

    //关联长按功能按钮 
    public LongPress longPress;

    //进度条跟对象 用于控制显隐
    public GameObject imgRoot;
    //进度条对象 用于控制进度
    public RectTransform imgBk;
    //是否按下
    private bool isDown = false;
    //计时
    private float nowTime = 0;
    //增加速度
    public float addSpeed = 10;
    //当前血量
    private int hp = 10;

    //摇杆的位置
    public RectTransform imgJoy;
    //摇杆上的事件相关
    public EventTrigger et;


    private void Awake()
    {
        panel = this;
    }

    void Start()
    {
        btnAtk.onClick.AddListener(() =>
        {
            //得到玩家对象 进行开火
            player.Fire();
        });

        btnChangeName.onClick.AddListener(()=> {
            //显示改名面板
            ChangeNamePanel.panel.gameObject.SetActive(true);
        });


        togOn.onValueChanged.AddListener(TogChangeValue);
        togOff.onValueChanged.AddListener(TogChangeValue);

        //初始化 我们滑动条的值 通过数据初始化
        sliderSound.value = MusicData.SoundValue;
        //监听滑动条改变的事件
        sliderSound.onValueChanged.AddListener((v) =>
        {
            //处理音效的大小
            MusicData.SoundValue = v;
        });


        btnBag.onClick.AddListener(() => {
            //打开背包面板
            BagPanel.panel.gameObject.SetActive(true);
        });


        ddChange.onValueChanged.AddListener((index) => {
            switch (index)
            {
                case 0:
                    light.intensity = 1;
                    break;
                case 1:
                    light.intensity = 0.3f;
                    break;
            }
        });

        longPress.downEvent += BtnDown;
        longPress.upEvent += BtnUp;

        //一开始隐藏蓄能条
        imgRoot.gameObject.SetActive(false);


        //为摇杆注册事件
        //拖动中
        EventTrigger.Entry en = new EventTrigger.Entry();
        en.eventID = EventTriggerType.Drag;
        en.callback.AddListener(JoyDrag);
        et.triggers.Add(en);

        //结束拖动
        en = new EventTrigger.Entry();
        en.eventID = EventTriggerType.EndDrag;
        en.callback.AddListener(EndJoyDrag);
        et.triggers.Add(en);
    }

    //定义一个私有方法JoyDrag,在摇杆被拖动时执行,接受一个BaseEventData类型的参数data,表示拖动事件的数据
    private void JoyDrag(BaseEventData data)
    {
        //将data强制转换为PointerEventData类型,并赋值给eventData变量,表示拖动事件的指针数据
        PointerEventData eventData = data as PointerEventData;


        //以前的知识 是通过加上 鼠标偏移位置 让图标动起来
        //imgJoy.position += new Vector3(eventData.delta.x, eventData.delta.y, 0);

        //用新知识点来制作
        //定义一个Vector2类型的变量nowPos,表示当前位置
        Vector2 nowPos;
        //调用RectTransformUtility类中的ScreenPointToLocalPointInRectangle静态方法,将屏幕坐标转换为矩形变换中的本地坐标,并将结果赋值给nowPos变量
        RectTransformUtility.ScreenPointToLocalPointInRectangle(
            //传入imgJoy对象的parent属性强制转换为RectTransform类型,表示摇杆图标的父对象的矩形变换组件
            imgJoy.parent as RectTransform,
            //传入eventData对象的position属性,表示拖动事件的屏幕坐标
            eventData.position,
            //传入eventData对象的enterEventCamera属性,表示拖动事件的相机
            eventData.enterEventCamera,
            //传出nowPos变量,表示当前位置
            out nowPos);


        //将imgJoy对象的localPosition属性赋值为nowPos变量,表示摇杆图标的本地位置
        imgJoy.localPosition = nowPos;

        //我们有专门的参数 得到相对于锚点的点
        //如果imgJoy对象的anchoredPosition属性的magnitude属性大于170,表示摇杆图标超出了摇杆背景圆形范围
        if (imgJoy.anchoredPosition.magnitude > 170)
        {
            //拉回来
            //单位向量 乘以 长度 = 临界位置
            //将imgJoy对象的anchoredPosition属性赋值为imgJoy对象的anchoredPosition属性的normalized属性乘以170,表示将摇杆图标拉回到摇杆背景圆形边缘
            imgJoy.anchoredPosition = imgJoy.anchoredPosition.normalized * 170;
        }

        //让玩家移动
        //调用player对象的Move方法,传入imgJoy对象的anchoredPosition属性,表示让玩家根据摇杆图标相对于锚点的位置进行移动
        player.Move(imgJoy.anchoredPosition);
    }


    private void EndJoyDrag(BaseEventData data)
    {
        //回归中心点
        imgJoy.anchoredPosition = Vector2.zero;

        //停止移动 传0向量进去 即可
        player.Move(Vector2.zero);
    }

    
    private void BtnDown()
    {
        isDown = true;
        nowTime = 0;
        //蓄能条清空
        imgBk.sizeDelta = new Vector2(0, 40);
    }

    private void BtnUp()
    {
        isDown = false;
        imgRoot.gameObject.SetActive(false);
    }

    private void Update()
    {
        if(isDown)
        {
            //计时
            nowTime += Time.deltaTime;
            if( nowTime >= 0.2f )
            {
                imgRoot.gameObject.SetActive(true);
                //蓄能条增加
                imgBk.sizeDelta += new Vector2(addSpeed * Time.deltaTime, 0);
                if( imgBk.sizeDelta.x >= 800 )
                {
                    //HP增加 条清空
                    hp += 10;
                    print("当前hp" + hp);
                    imgBk.sizeDelta = new Vector2(0, 40);
                }
            }
        }
    }

    private void TogChangeValue(bool v)
    {
        //得到当前激活的Toggle
        foreach (Toggle item in tg.ActiveToggles())
        {
            if(item == togOn)
            {
                MusicData.SoundIsOpen = true;
            }
            else if(item == togOff)
            {
                MusicData.SoundIsOpen = false;
            }
        }
    }
}


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

×

喜欢就点赞,疼爱就打赏