Unity记录7.2-界面-UI的点击、拖动与长按

汇总:Unity 记录

开源地址:asd123pwj/asdGame

摘要:UI的点击事件判断,以及拖动UI,长按UI的实现。

点击UI的边缘-2024/05/11

  • 在各种意义上都卡了挺久,本来是想实现UI窗口的手动调节,但是如何判断点击在窗口上?如何判断点击在边缘上?点击在哪个窗口上?
    • 总之现在只实现了点击在指定窗口的边缘,但可能会因窗口重叠而产生问题,但那是之后要解决的了。
  • 最终,在实现上,简言之,鼠标在UI窗口的框框内,且鼠标在比UI窗口小一点点的框框外。
    • 首先获取屏幕缩放,先获得原始分辨率,在Canvas的Canvas Scaler里有Reference Resolution,我这里是1920x1080。
    • 然后用Screen.widthScreen.height获取当前分辨率,两者相除,获取当前缩放。
    • 然后获取原始UI坐标与大小。
    • GameObject.GetComponent<RectTransform>()获取RectTransform,RectTransform.positionRectTransform.sizeDelta分别为UI的原始坐标与原始大小。
    • 将大小转换为缩放后的UI大小。
    • 用上步和上上步获取的两个数据相乘即可。
    • 将UI坐标转换为屏幕坐标,再将UI窗口的坐标原点从中心映射至左下角(仅计算)。
    • 用此代码转换为屏幕坐标: RectTransformUtility.WorldToScreenPoint(Camera.main, rect_transform.position);
    • 上面获取的是UI窗口的中心,要映射为左下角,仅需减去窗口大小的一半即可。
    • 基于上面的信息,能够获取UI的实际坐标与实际大小,进而生成一个矩形框。
    • Rect window_rect = new(UI_pos, UI_size);
    • 再定义一个边界大小,获取一个比上面矩形框小一点点的小框。
    • 判断鼠标的屏幕坐标,是否在大框内部,并且在小框外部。
  • 这份代码大概率会被优化,或者被Unity的方法替代,因为我实在不认为这种判断要这么麻烦。
    • 但我确实没找到替代方法。
  • 具体代码如下,
    • 判断鼠标点击的函数和"记录6.6"中"再次优化的即时技能"章节的方法一样,虽然想过是否要在那里判断鼠标位置,但是最终还是移至UI的交互代码中,只是稍微修改了一点。
    • 转换UI大小至实际的函数是convert_UIRect_to_screenRect(),判断是否在UI边缘的是check_border()
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections.Generic;

public class UIInteract{
    UIConfig UIConfig;
    RectTransform rect_transform;
    Vector2 UI_pos, UI_size;
    Vector2 tmp_original_resolution = new(1920f, 1080f);
    bool isInit = true;
    float border_size = 10f;

    public UIInteract(UIConfig UIConfig){
        this.UIConfig = UIConfig;
        this.rect_transform = UIConfig._self.GetComponent<RectTransform>();
        register_input_action();
    }

    public void _update(KeyPos keyPos, Dictionary<string, KeyInfo> _keyStatus){
        if (_keyStatus["fire1"].isDown){
            convert_UIRect_to_screenRect();
            if (check_border(keyPos.mouse_pos_world)){
                Debug.Log("resize");
            } 
        }
    }

    void register_input_action(){
        UIConfig._InputSystem._register_UI("Fire1", resize_rectTransform, true);
    }

    void convert_UIRect_to_screenRect(){
        Vector2 scale = new(Screen.width / tmp_original_resolution.x, Screen.height / tmp_original_resolution.y);
        UI_size = rect_transform.sizeDelta * scale;
        UI_pos = RectTransformUtility.WorldToScreenPoint(Camera.main, rect_transform.position);
        UI_pos = new(UI_pos.x - UI_size.x / 2f, UI_pos.y - UI_size.y / 2f);
    }

    bool check_border(Vector2 mouse_pos){
        Vector2 UISmall_pos = new(UI_pos.x + border_size, UI_pos.y + border_size);
        Vector2 UISmall_size = new(UI_size.x - border_size * 2f, UI_size.y - border_size * 2f);
        Rect window_rect = new(UI_pos, UI_size);
        Rect windowSmall_rect = new(UISmall_pos, UISmall_size);
        // Debug.Log(mouse_pos + " - " + window_rect + " - " + scale);
        return window_rect.Contains(mouse_pos) && !windowSmall_rect.Contains(mouse_pos);
    }

    bool resize_rectTransform(KeyPos keyPos, Dictionary<string, KeyInfo> _keyStatus){

        if (!_keyStatus["Fire1"].isFirstDown) return false;
        if (check_border(keyPos.mouse_pos_UI)){
            Debug.Log("resize");
        }
        return true;
    }

}

UI交互事件-2024/05/12

  • 改为了用Unity自带的UI事件
public class UITrigger{
    UIConfig UIConfig;
    EventTrigger eventTrigger;

    public UITrigger(UIConfig UIConfig){
        this.UIConfig = UIConfig;
        this.UIConfig._UITrigger = this;
        init_eventTrigger();
        init_eventTrigger_trigger();
    }

    void init_eventTrigger(){
        eventTrigger = UIConfig._self.GetComponent<EventTrigger>();
        if (eventTrigger == null) eventTrigger = UIConfig._self.AddComponent<EventTrigger>();
    }

    void init_eventTrigger_trigger(){
        EventTrigger.Entry entry;
        entry = new(){eventID = EventTriggerType.PointerEnter}; entry.callback.AddListener((data) =>UIConfig._UIInteract._action_pointer_enter()); eventTrigger.triggers.Add(entry);
        entry = new(){eventID = EventTriggerType.PointerExit}; entry.callback.AddListener((data) =>UIConfig._UIInteract._action_pointer_exit()); eventTrigger.triggers.Add(entry);
        entry = new(){eventID = EventTriggerType.PointerDown}; entry.callback.AddListener((data) =>UIConfig._UIInteract._action_pointer_down()); eventTrigger.triggers.Add(entry);
        entry = new(){eventID = EventTriggerType.PointerUp}; entry.callback.AddListener((data) =>UIConfig._UIInteract._action_pointer_up()); eventTrigger.triggers.Add(entry);
        entry = new(){eventID = EventTriggerType.PointerClick}; entry.callback.AddListener((data) =>UIConfig._UIInteract._action_pointer_click()); eventTrigger.triggers.Add(entry);
        entry = new(){eventID = EventTriggerType.Drag}; entry.callback.AddListener((data) =>UIConfig._UIInteract._action_drag()); eventTrigger.triggers.Add(entry);
        entry = new(){eventID = EventTriggerType.Drop}; entry.callback.AddListener((data) =>UIConfig._UIInteract._action_drop()); eventTrigger.triggers.Add(entry);
        entry = new(){eventID = EventTriggerType.Scroll}; entry.callback.AddListener((data) =>UIConfig._UIInteract._action_scroll()); eventTrigger.triggers.Add(entry);
        entry = new(){eventID = EventTriggerType.UpdateSelected}; entry.callback.AddListener((data) =>UIConfig._UIInteract._action_update_selected()); eventTrigger.triggers.Add(entry);
        entry = new(){eventID = EventTriggerType.Select}; entry.callback.AddListener((data) =>UIConfig._UIInteract._action_select()); eventTrigger.triggers.Add(entry);
        entry = new(){eventID = EventTriggerType.Deselect}; entry.callback.AddListener((data) =>UIConfig._UIInteract._action_deselect()); eventTrigger.triggers.Add(entry);
        entry = new(){eventID = EventTriggerType.Move}; entry.callback.AddListener((data) =>UIConfig._UIInteract._action_move()); eventTrigger.triggers.Add(entry);
        entry = new(){eventID = EventTriggerType.InitializePotentialDrag}; entry.callback.AddListener((data) =>UIConfig._UIInteract._action_initialize_potential_drag()); eventTrigger.triggers.Add(entry);
        entry = new(){eventID = EventTriggerType.BeginDrag}; entry.callback.AddListener((data) =>UIConfig._UIInteract._action_begin_drag()); eventTrigger.triggers.Add(entry);
        entry = new(){eventID = EventTriggerType.EndDrag}; entry.callback.AddListener((data) =>UIConfig._UIInteract._action_end_drag()); eventTrigger.triggers.Add(entry);
        entry = new(){eventID = EventTriggerType.Submit}; entry.callback.AddListener((data) =>UIConfig._UIInteract._action_submit()); eventTrigger.triggers.Add(entry);
        entry = new(){eventID = EventTriggerType.Cancel}; entry.callback.AddListener((data) =>UIConfig._UIInteract._action_cancel()); eventTrigger.triggers.Add(entry);
    }

}

UI的拖动-2024/05/12, 2024/05/17

  • 用FixedUpdate和Update里的鼠标位移来更新UI的位移,失败了。
    • 具体表现为鼠标移动一点点,UI移动一大堆,时灵时不灵。
  • 在事件内部的鼠标唯一来更新UI的位移,失败了。
    • 具体表现为鼠标移动一点点,UI十万八千里,时灵时不灵。
  • GPT4o告诉了我一个方法,能较为正常的移动了,但在移动时UI中心会到鼠标上。
    • 看来上一步的问题还是坐标系的问题,鼠标位置的宽度是1000+
    • 然而,rect_transform.position以及转换坐标系之后的位置globalMousePos,宽度60左右。
    • 差了20倍,怪不得UI乱飞。
    void drag(PointerEventData eventData) {
        if (RectTransformUtility.ScreenPointToWorldPointInRectangle(rect_transform, eventData.position, eventData.pressEventCamera, out Vector3 globalMousePos)) {
            rect_transform.position = globalMousePos;
        }
    }
  • 最终的鼠标拖动UI代码如下
    • 相较上一步,鼠标点击时,记录UI位置与鼠标位置的偏移,然后在drag时加上偏移。
    • 下面第一部分代码是一些相关信息,第二部分的代码是控制函数。
    • 代码有点乱,估计不好看,可以找gpt问问,它给的更简洁
entry = new(){eventID = EventTriggerType.PointerEnter}; 
entry.callback.AddListener((data) =>UIConfig._UIInteract._action_pointer_down((PointerEventData)data)); 
eventTrigger.triggers.Add(entry);

    public void _action_pointer_down(PointerEventData eventData){ 
        UIConfig._UIStatus._update_mouse_down(eventData); 
    }
    public void _action_drag(PointerEventData eventData){
        UIConfig._UIStatus._drag(eventData);
     }
public class UIStatus{
    Vector3 mouse_pos_offset_down = new();
    RectTransform rect_transform;

    public UIStatus(UIConfig UIConfig){
        this.rect_transform = UIConfig._self.GetComponent<RectTransform>();
    }

    public void _update_mouse_down(PointerEventData eventData){
        RectTransformUtility.ScreenPointToWorldPointInRectangle(rect_transform, eventData.position, eventData.pressEventCamera, out Vector3 globalMousePos);
        mouse_pos_offset_down = rect_transform.position - globalMousePos;
    }

    public void _drag(PointerEventData eventData){
        RectTransformUtility.ScreenPointToWorldPointInRectangle(rect_transform, eventData.position, eventData.pressEventCamera, out Vector3 globalMousePos);
        rect_transform.position = globalMousePos + mouse_pos_offset_down;
    }
}

UI的点击按键判断-2024/05/18

  • 用下面的switch判断触发事件的鼠标按键。
    public void _action_pointer_down(PointerEventData eventData){ 
        switch (eventData.button){
            case PointerEventData.InputButton.Left:
                UIConfig._UIStatus._update_mouse_down(eventData); 
                break;
            case PointerEventData.InputButton.Right:
                break;
            case PointerEventData.InputButton.Middle:
                break;
        }
    }

UI的点击时长-2024/05/18

  • 这个比较简单,鼠标按下开始计时,Update判断当前时间是否满足一个周期,满足则触发事件,松开鼠标时关闭计时。
  • 下面的代码中
    • 函数_update()即放在Update中的函数。
    • _update_mouseDownTime()开始计时。
    • _check_downTime_period()判断计时周期。
    • _update_mouseUp()取消计时。
    float mouse_down_time;
    int elapsed_period = 0;
    bool isDown = false;

    public void _update(){
        if(isDown){
            if(_check_downTime_period()){
                Debug.Log("elapsed_period: " + elapsed_period);
            }
        }
    }

    public void _update_mouseDownTime(){
        mouse_down_time = Time.time;
        elapsed_period = 0;
        isDown = true;
    }

    public bool _check_downTime_period(float period=0.5f){
        float time_now = Time.time;
        if(time_now - mouse_down_time - period * elapsed_period > period){
            elapsed_period += 1;
            return true;
        }
        return false;
    }

    public void _update_mouseUp(){
        isDown = false;
    }

版权声明:
作者:MWHLS
链接:https://mwhls.top/5010.html
来源:无镣之涯
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
打赏
< <上一篇
下一篇>>
文章目录
关闭
目 录