Unity学习笔记——虚拟摇杆实现笔记(事件触发器的使用、UGUI 坐标转换)

虚拟摇杆实现笔记(事件触发器的使用、UGUI 坐标转换)

一、核心逻辑

通过 EventTrigger 监听摇杆的拖拽/结束拖拽事件,控制摇杆位置,再将摇杆偏移量转为玩家移动方向,实现虚拟摇杆控制角色移动。

主要学习:事件触发器的使用、UGUI 坐标转换

二、代码结构与注释

1. 摇杆事件注册

csharp 复制代码
//从外部获取摇杆物体上的EventTrigger组件
public EventTrigger et;

// 为摇杆添加拖拽事件
EventTrigger.Entry entry = new EventTrigger.Entry();
entry.eventID = EventTriggerType.Drag; // 拖拽事件ID(枚举类型)
entry.callback.AddListener(JoyDrag);   // 绑定拖拽回调方法
et.triggers.Add(entry);

// 为摇杆添加结束拖拽事件
entry = new EventTrigger.Entry();
entry.eventID = EventTriggerType.EndDrag; // 结束拖拽事件ID
entry.callback.AddListener(EndJoyDrag);   // 绑定结束拖拽回调方法
et.triggers.Add(entry);

2. 拖拽事件回调(控制摇杆位置+玩家移动)

csharp 复制代码
// 摇杆拖拽时执行
private void JoyDrag(BaseEventData data)
{
    // 把基础事件数据转为指针事件数据(获取拖拽相关信息)
    PointerEventData eventData = data as PointerEventData;

    // 旧方法:通过当前摇杆位置 + 拖拽偏移量更新位置
    // 缺点:受UI相机、Canvas模式影响,多分辨率适配较差
    // imgJoy.position += new Vector3(eventData.delta.x, eventData.delta.y, 0);

    // 新方法:使用RectTransformUtility完成屏幕坐标转UI局部坐标,适配性更强
    Vector2 nowPos;
    // 将鼠标/触摸屏幕坐标,转换为摇杆父物体下的局部坐标
    RectTransformUtility.ScreenPointToLocalPointInRectangle(
        imgJoy.parent as RectTransform,  // 目标父物体RectTransform
        eventData.position,              // 原始屏幕坐标
        eventData.enterEventCamera,       // 渲染UI的相机
        out nowPos                        // 输出转换后的局部坐标
    );
    // 赋值局部坐标,实现摇杆精准跟随拖拽点
    imgJoy.localPosition = nowPos;

    // 防止摇杆超出范围:限制摇杆的锚点偏移量最大为110
    if (imgJoy.anchoredPosition.magnitude > 110)
    {
        // 将摇杆位置归一化(保持方向不变),再乘以最大范围,拉回临界位置
        imgJoy.anchoredPosition = imgJoy.anchoredPosition.normalized * 110;
    }

    // 调用玩家移动方法,传入摇杆当前偏移量作为移动方向
    player.Move(imgJoy.anchoredPosition);
}

3. 结束拖拽回调(摇杆复位+玩家停止移动)

csharp 复制代码
// 摇杆拖拽结束时执行
private void EndJoyDrag(BaseEventData data)
{
    // 摇杆锚点位置回归中心点(Vector2.zero)
    imgJoy.anchoredPosition = Vector2.zero;
    // 传入零向量,让玩家停止移动
    player.Move(Vector2.zero);
}

4. 玩家移动控制(Update 帧更新)

csharp 复制代码
void Update()
{
    // 如果当前移动方向不为零(摇杆被拖动)
    if (nowMoveDir != Vector3.zero)
    {
        // 角色沿自身前方移动,速度由 moveSpeed 控制,乘以 Time.deltaTime 保证帧率无关
        this.transform.Translate(Vector3.forward * (moveSpeed * Time.deltaTime));
        // 角色平滑转向目标方向(Slerp实现缓动效果,rotateSpeed控制转向速度)
        this.transform.rotation = Quaternion.Slerp(
            this.transform.rotation, 
            Quaternion.LookRotation(nowMoveDir), 
            rotateSpeed * Time.deltaTime
        );
    }
}

5. 移动方向设置(供摇杆调用)

csharp 复制代码
// 外部调用:将摇杆二维偏移量转为角色三维移动方向
public void Move(Vector2 dir)
{
    nowMoveDir.x = dir.x;   // 摇杆X偏移量 → 角色水平方向
    nowMoveDir.y = 0;       // Y轴(竖直方向)固定为0,不影响高度
    nowMoveDir.z = dir.y;   // 摇杆Y偏移量 → 角色前后方向
}

三、关键知识点

1. EventTrigger 事件绑定(标准四步流程)

a. EventTrigger.Entry entry = new EventTrigger.Entry(); 创建事件条目

b. entry.eventID = EventTriggerType.Drag; 绑定事件枚举类型

c. entry.callback.AddListener(JoyDrag); 绑定拖拽回调方法

d. et.triggers.Add(entry); 把事件添加到EventTrigger组件,事件正式生效

2. 两种摇杆位置更新方式对比

  • 旧方案position + delta 偏移叠加

    直接累加拖拽增量,逻辑简单,但依赖屏幕空间,不同Canvas渲染模式、分辨率下容易错位。

  • 新方案RectTransformUtility.ScreenPointToLocalPointInRectangle 坐标转换

    将屏幕坐标转为UI父物体局部坐标,适配所有UI模式,拖拽跟随更精准,是UGUI拖拽通用写法。

    参数说明:目标父物体RectTransform、屏幕坐标、UI相机、输出局部坐标。

3. 摇杆范围限制

  • anchoredPosition:UI元素相对于锚点的偏移量,适合做摇杆位置控制
  • magnitude:向量长度,用于判断摇杆是否超出最大范围
  • normalized:向量归一化,保持方向不变,仅缩放长度到1,再乘以最大范围实现"拉回"限位

4. 方向转换逻辑

  • 摇杆的二维 Vector2 偏移量 → 角色三维 Vector3 移动方向(X→水平,Y→前后,Y轴固定为0)
  • Quaternion.LookRotation:根据方向向量生成目标旋转
  • Quaternion.Slerp:实现平滑转向,避免角色瞬间转头

5. 帧率无关移动

  • 所有移动/旋转逻辑乘以 Time.deltaTime,保证不同帧率下移动速度保持一致
相关推荐
心中有国也有家9 小时前
AtomGit Flutter 鸿蒙客户端: ChangeNotifier 模式
学习·flutter·华为·harmonyos
取地址符10 小时前
C++学习笔记(基于learn-cxx)(1)
c++·经验分享·笔记·学习
ysa05103010 小时前
【板子】ST表
c++·笔记·算法·板子
恣逍信点11 小时前
主观是客观的聚焦
人工智能·学习·程序人生·生活·业界资讯·交友·哲学
打球她不香吗11 小时前
本周ALLegro学习内容的总结
学习·allegro
risc12345612 小时前
肌肉收缩会释放大量的肌细胞因子能抑制体内炎症因子
笔记
其实防守也摸鱼12 小时前
蓝队相关知识学习(1)---常用堡垒机和服务器
服务器·功能测试·学习·网络安全·网络攻击模型·攻防对抗·蓝队
冰可乐配13 小时前
fmpeg音频编码组件aac(Advanced Audio Coding (AAC) encoder)学习
学习·音视频·aac
既然如此,那就开摆13 小时前
精读笔记06_CoCa
笔记
憧憬成为java架构高手的小白13 小时前
MySQl学习
学习