问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Unity2D 模拟手柄实现玩家移动

创作时间:
作者:
@小白创作中心

Unity2D 模拟手柄实现玩家移动

引用
CSDN
1.
https://m.blog.csdn.net/qq_43209531/article/details/138752307

本文介绍了一种在Unity2D游戏中实现虚拟手柄控制玩家移动的方法,包括按钮模式和摇杆模式的实现。虽然文章发布于2024年5月,但其基本原理和实现方法仍然具有参考价值。需要注意的是,Unity引擎的版本更新可能会影响某些API的使用,因此在实际开发中请根据具体情况进行调整。

1. 创建控制器UI

首先需要创建一个控制器UI,用于显示虚拟手柄的界面。这通常包括一个摇杆和一些方向按钮。

2. 挂载脚本

将编写好的脚本挂载到玩家游戏对象上,以便控制其移动。

3. 脚本编写

基本要素

[Tooltip("玩家游戏体")]
public Rigidbody2D player;
[Tooltip("玩家速度")]
public float speed = 1f;
[Tooltip("玩家动画")]
public Animator animator;
public enum Mode {
    BUTTON,
    ROCKER,
}
[Tooltip("模式")]
public Mode mode = Mode.ROCKER;

模式切换

Start()方法中根据mode的值,设置相关物体的Active状态。

基本移动逻辑

因为需要不断的更新移动(长按不松开),而Update方法每帧都在执行,所以在Update方法中执行移动操作。

void Update()
{
    doMove();
}

具体移动逻辑

private void doMove()
{
    if (player == null) {
        return;
    }
    // 获取方向
    Vector2 dir = getDir();
    if (dir == Vector2.zero) return;
    Vector2 pos = player.position;
    // 10是随便设置的一个控制值,不然太慢
    pos.y += Time.deltaTime * speed * 10 * dir.y;
    pos.x += Time.deltaTime * speed * 10 * dir.x;
    
    player.MovePosition(pos);
}
private Vector2 getDir()
{
    if (mode == Mode.BUTTON)
    {
        if (curPointerObj == null) return Vector2.zero;
        switch(curPointerObj.name)
        {
            case "Up":
                return Vector2.up;
            case "Down":
                return Vector2.down;
            case "Left":
                return Vector2.left;
            default:
                return Vector2.right;
        }
    }
    return rockerDir;
}

3.1 按钮模式实现

基本逻辑

监听触摸事件,按下(IPointerDownHandler)为开始移动,抬起(IPointerUpHandler)为结束移动,实现按下按钮并松开的移动过程。

脚本

// 值为当前按下的按钮
private GameObject curPointerObj = null;

按下

public void OnPointerDown(PointerEventData eventData)
{
    if (player == null || mode != Mode.BUTTON) {
        return;
    } 
    GameObject pointerObj = eventData.pointerEnter;
    if (curPointerObj != null) {
        return;
    }
    curPointerObj = pointerObj;
}

抬起

public void OnPointerUp(PointerEventData eventData)
{
    if (player == null || mode != Mode.BUTTON) {
        return;
    } 
    GameObject pointerObj = eventData.pointerEnter;
    if (curPointerObj == null || curPointerObj != pointerObj) {
        return;
    }
    curPointerObj = null;
}

3.2 摇杆模式实现

基本逻辑

监听拖拽事件,拖拽中(IEndDragHandler)为开始/移动中,拖拽结束(IDragHandler)为结束移动,实现拖拽并松开的移动过程。

脚本

// 摇杆内部可拖拽部分
private RectTransform rockerInnerTransform;
// 摇杆外部不可拖拽部分-边界
private RectTransform rockerOuterTransform;
// 当前摇杆方向
private Vector2 rockerDir = Vector2.zero;

拖拽中

public void OnDrag(PointerEventData eventData)
{
    if (player == null || mode != Mode.ROCKER) return;
    Vector2 pos = Camera.main.ScreenToWorldPoint(eventData.position);
    
    Vector2 rockerOriginPosition = rockerOuterTransform.position;
    // 拖拽方向
    rockerDir = (pos - rockerOriginPosition).normalized;
    
    float distance = Vector2.Distance(pos, rockerOriginPosition);
    if (distance <= 1.5f) // 1.5f刚好是摇杆外部边界和摇杆内部可拖拽部分中心重合时的距离
    {
        rockerInnerTransform.position = pos;
    }
    else
    {
        Vector2 dir = pos - rockerOriginPosition;
        // 拖拽超过摇杆外部边界时,摇杆内部可拖拽的位置为:外部中心 + 当前拖拽方向指定的拖拽距离位置(此时设置为1.5f,到达边界)。
        rockerInnerTransform.position = rockerOriginPosition + dir.normalized * 1.5f;
    }
}

拖拽结束

public void OnEndDrag(PointerEventData eventData)
{
    if (player == null || mode != Mode.ROCKER) return;
    // 恢复方向和位置
    rockerDir = Vector2.zero;
    rockerInnerTransform.position = rockerOuterTransform.position;
}
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号