当前位置: 首页 > article >正文

二.Unity中使用虚拟摇杆来控制角色移动

上一篇中我们完成了不借助第三方插件实现手游的虚拟摇杆,现在借助这个虚拟摇杆来实现控制角色的移动。

虚拟摇杆实际上就给角色输出方向,类似于键盘的WSAD,也是一个二维坐标,也就是(-1,1)的范围,将摇杆的方向进行归一化传递给角色即可,创建一个名为PlayerManager的脚本,通过Character组件来控制角色的移动。这里在上一篇文章在一. Unity实现虚拟摇杆及屏幕自适应功能,讲述过了,这里拖拽的时候将位移的向量归一化后传递给角色,松手的时候归0.

 mUIEvtListener.OnPointerUpEvent += (eventData =>
            {
                mPointImg.transform.localPosition = mDefaultPos;
                mPointImg.SetActiveState(false);
                mDirImg.transform.localPosition = mDefaultPos;
                PlayerManager.Instance.SetPlayerDir(Vector2.zero);
            });
            mUIEvtListener.OnDragFunc += (eventData =>
            {
                Vector2 dir = eventData.position - mStartPos;
                float length = dir.magnitude;
                PlayerManager.Instance.SetPlayerDir(dir.normalized);
                if (length > mTouchMaxDir)
                {
                    Vector2 clampDir = Vector2.ClampMagnitude(dir, mTouchMaxDir);
                    mPointImg.transform.position = mStartPos + clampDir;
                }
                else
                {
                    mPointImg.transform.position = eventData.position;
                }
            });

在PlayerManager中就是一些常规操作,设置方向,这里用了一个Vector2.SignedAngle的API,其作用就是返回传入向量和目标向量之间的角度,我们设定的目标向量是(0,1)也就是二维向量的正前方,下面画了一张图,应该会很清楚。其中为什么要+mCamTrans.eulerAngles.y,是因为相机是倾斜的照着角色,摄像机于角色之间有一个相对角度,是为了能够确保玩家的移动方向与摄像机视角一致,不论摄像机朝哪个方向,玩家的输入都能按照当前摄像机的视角调整角色的朝向。

在这里插入图片描述

 public class PlayerManager : Component<PlayerManager>
    {
        private const float TouchSpeed = 5;
        private CharacterController mCC;
        private Animator mAnim;
        private Vector2 mDir;
        private Transform mCamTrans;
        private Vector3 mOffset;
        private float mCurAnimSpeed;
        private float mTargerAnimSpeed;
        private const float AccelerSpeed = 5;
        public override void IStart()
        {
            base.IStart();
            mCC = GetComponent<CharacterController>();
            mAnim = GetComponentInChildren<Animator>();
            mCamTrans = Camera.main.transform;
            mOffset = transform.position - mCamTrans.transform.position;
        }

        public override void IUpdate()
        {
            base.IUpdate();
            if (mDir != Vector2.zero)
            {
                SetDir();
                SetMove();
                SetCamera();
            }
        
        }
        /// <summary>
        /// 通过摇杆控制玩家方向
        /// </summary>
        /// <param name="dir"></param>
        public void SetPlayerDir(Vector2 dir)
        {
            if (dir != Vector2.zero)
            {
                mDir = dir;
                SetAnimSpeed(1);
            }
            else
            {
                mDir = Vector2.zero;
                SetAnimSpeed(0);
            }
        }

        private void SetDir()
        {
            float angle = Vector2.SignedAngle(mDir, new Vector2(0, 1)) + mCamTrans.eulerAngles.y;
            transform.eulerAngles = new Vector3(0, angle, 0);
        }

        private void SetMove()
        {
            mCC.Move(transform.forward * Time.deltaTime * TouchSpeed);
        }

        private void SetCamera()
        {
            mCamTrans.transform.position = transform.position - mOffset;
        }
  
    }
}

在这里插入图片描述
最后简单设置一下角色的动画,将Idle和Run进行一个简单的混合,通过插值的形式,让当前的Speed以平缓的过渡到目标值。

   public class PlayerManager : Component<PlayerManager>
    {
        private float mCurAnimSpeed;
        private float mTargerAnimSpeed;
        private const float AccelerSpeed = 5;
       
        public override void IUpdate()
        {
            base.IUpdate();
            if (mDir != Vector2.zero)
            {
                SetDir();
                SetMove();
                SetCamera();
            }
            if (mCurAnimSpeed != mTargerAnimSpeed)
            {
                UpdateAnimFixed();
            }
        }
        private void SetAnimSpeed(float speed)
        {
            mTargerAnimSpeed = speed;
        }

        private void UpdateAnimFixed()
        {
            if (Mathf.Abs(mCurAnimSpeed - mTargerAnimSpeed) > AccelerSpeed)
            {
                mCurAnimSpeed = AccelerSpeed;
            }
            else if(mCurAnimSpeed > mTargerAnimSpeed)
            {
                mCurAnimSpeed -= Time.deltaTime * AccelerSpeed;
            }
            else if(mCurAnimSpeed< mTargerAnimSpeed)
            {
                mCurAnimSpeed += Time.deltaTime * AccelerSpeed;
            }
            mAnim.SetFloat("Speed",mCurAnimSpeed);
        }
     }

测试运行结果如下:
在这里插入图片描述


http://www.kler.cn/a/308451.html

相关文章:

  • redis7.x源码分析:(1) sds动态字符串
  • C++初阶:类和对象(上)
  • 【Golang】Channel的ring buffer实现
  • 《TCP/IP网络编程》学习笔记 | Chapter 8:域名及网络地址
  • UVC 输出视频格式修改和windows下数据分析
  • 如何从头开始构建神经网络?(附教程)
  • 解码 OpenAI 的 o1 系列大型语言模型
  • flash_attention简要笔记
  • QT程序的安装包制作教程
  • 第二十三章 加密安全标头元素
  • go-zero的快速实战(完整)
  • udp的广播,多播,单播 demo
  • 沉浸式利用自然语言无代码开发工具生成式AI产品应用(下)
  • leetcode 42 接雨水
  • 【SQL】百题计划:SQL内置函数“LENGTH“的使用
  • c++ 线程库
  • 汽车英文单词缩写汇总
  • C++学习笔记(27)
  • Rust: Warp RESTful API 如何得到客户端IP?
  • Notepad++中提升编码效率的关键快捷键
  • C++:opencv计算轮廓周长--cv::arcLength
  • 如何快速入门 Vue 3
  • MySQL基础篇(黑马程序员2022-01-18)
  • xilinx hbm ip运用
  • 自定义类型:联合和枚举
  • Java零基础-Java对象详解