• 【unity实战】Unity实现2D人物双击疾跑


    最终效果

    在这里插入图片描述

    前言

    我们要实现的功能是双击疾跑,当玩家快速地按下同一个移动键两次时能进入跑步状态

    我假设快速按下的定义为0.2秒内,按下同一按键两次

    简单的分析一下需求,实现它的关键在于获得按键按下的时间,我们需要知道第一次按下按键的时间,然后判断规定时间内有没有按下按键

    有两种实现方法
    第一种
    启动一个计时器,判断在计时器结束之前有没有再次按下这个键
    在这里插入图片描述
    第二种
    是分别记录下两次按键的时间,然后用第二次按下的时间减去第一次按下的时间,判断是否小于0.2
    在这里插入图片描述
    这里我采用第二种方法,为了获取按下的时间,我们需要使用到Unity给我们提供的Time类,里面的Time.time会提供游戏启动到现在运行了多少秒,这个需求还需要我们检测到按键是否被按下,我打算使用Input Manager来实现

    public static float GetAxis (string axisName);
    public static float GetAxisRaw(string axisName);
    
    • 1
    • 2

    GetAxisRaw会在检测到按键后,马上返回1或-1,松开按键后马上变成0
    而GetAxis会在检测到按键的时候,从0过渡到1或-1,松开按键后再过渡到0

    为了方便,我使用GetAxisRaw来获得输入的时间,当按键按下时意味着GetAxisRaw的返回值为1的绝对值,我们在符合条件的时候使用Time.time来获得当前的时间即可

    但显然,我们不希望玩家按下a后马上按下d,还能让人物进入到疾跑状态,所以两个按键的输入时间要分开存储,还有一个需要注意的地方是,当玩家开始走路或疾跑时,a键或d键是按住不放的,所以当玩家在移动的时候,我们要使个bool变量为真,当这个变量为真时,就不再刷新输入的时间

    我们设想一下,玩家进入游戏以后,马上按下了一次移动键,如果他电脑开游戏开的特别的快,他第一次按下移动键的时间,离打开游戏不到0.2秒,如果我们存储按键时间的变量,没有初始化,那么会默认赋值为0,当他第一次按下移动时,就会进入到疾跑状态,这很明显是我们不想要看到的bug

    所以最后一个要点是给存储按键时间的变量进行初始化,但初始化的只要赋值为多少也是一个值得考虑的问题,如果赋值为一个极大的正数,就算赋值为1万,万一玩家一开始在挂机刚好在10,000.01秒,按一下移动按键,还是会错误地进入到疾跑状态,所以可以给他赋值为,负的最大等待输入时间,如果实在不放心,可以赋值为2倍,这样第一次输入就不会出现bug

    经过了这么多的分析,相信你此时此刻已经完全明白了,接下来我们进入到代码实战环节

    开始

    配置动画,walk为true进入走路动画,run为true进入跑步动画
    在这里插入图片描述
    新增人物控制脚本

    public class PlayerController : MonoBehaviour
    {
        private Rigidbody2D rb;  // 刚体组件
        private Animator animator;  // 动画控制器
        public float maxAwaitTime;  // 最大等待时间
        private float leftPressTime, rightPressTime;  // 左键按下时间,右键按下时间
        private bool moving, canRun;  // 是否在移动,是否可以奔跑
        public int walkSpeed, runSpeed;  // 步行速度,奔跑速度
        private int currentSpeed;  // 当前速度
        private float h;  // 水平输入
    
        private void Awake()
        {
            rb = GetComponent<Rigidbody2D>();  // 获取刚体组件
            animator = GetComponent<Animator>();  // 获取动画控制器
            leftPressTime = rightPressTime = -maxAwaitTime;  // 初始化左右按下时间
        }
    
        private void Update()
        {
            h = Input.GetAxisRaw("Horizontal");  // 获取水平输入
            ChangeFaceDirection();  // 更改角色朝向
            CheckRun();  // 检查奔跑状态
        }
    
        private void ChangeFaceDirection()
        {
            if (h == 1)
            {
                transform.localScale = new Vector3(1, 1, 1);  // 面向右侧
            }
            else if (h == -1)
            {
                transform.localScale = new Vector3(-1, 1, 1);  // 面向左侧
            }
        }
    
        private void CheckRun()
        {
            if (h == 1 && !moving)
            {
                if (Time.time - rightPressTime <= maxAwaitTime)
                {
                    canRun = true;
                }
                rightPressTime = Time.time;
            }
            
            if (h == -1 && !moving)
            {
                if (Time.time - leftPressTime <= maxAwaitTime)
                {
                    canRun = true;
                }
                leftPressTime = Time.time;
            }
    
    		// 取 h 的绝对值
            if (Mathf.Abs(h) == 1)
            {
                moving = true;
                if (canRun)
                {
                    currentSpeed = runSpeed;
                    animator.SetBool("run", true);  // 设置奔跑动画
                }
                else
                {
                    currentSpeed = walkSpeed;
                    animator.SetBool("walk", true);  // 设置行走动画
                }
            }
            else
            {
                animator.SetBool("run", false);  // 关闭奔跑动画
                animator.SetBool("walk", false);  // 关闭行走动画
                moving = false;
                canRun = false;
            }
        }
    
        private void FixedUpdate()
        {
            rb.velocity = new Vector2(h * currentSpeed * Time.deltaTime, rb.velocity.y);  // 更新刚体速度
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87

    效果
    在这里插入图片描述

    参考

    如果觉得本文实现的效果不错的话,非常推荐大家去支持一下原作者

    【视频】https://www.bilibili.com/video/BV1YN4113771/

    完结

    赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

    好了,我是向宇https://xiangyu.blog.csdn.net

    一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
    在这里插入图片描述

  • 相关阅读:
    制造企业为什么要部署数字化工厂系统
    【算法】算法学习七:动态规划 | 背包问题 | 最长公共子串(含源代码)
    金仓数据库 KingbaseGIS 使用手册(8.4. 栅格存取函数)
    JAVA环境配置(基础教学版:WIN11为例)
    矩阵分析与应用+张贤达
    Mac 重启后 nvm -v 报错 zsh: command not found: nvm
    消息队列缓存,以蓝牙消息服务为例
    Vue+el-image-viewer显示tiff图片,并能够切换图片中的帧
    【设计模式】适配器模式
    企业数字化转型的好处?_光点科技
  • 原文地址:https://blog.csdn.net/qq_36303853/article/details/134234091