Unity初学者实践与提高(四)---角色控制系统

效果

输入系统

上一章角色可以做不同的动作了,但是还是原地动作,现在我们让他真正的动起来。
控制角色移动需要输入设备,PC上一般是用键盘控制,手机用触摸屏(软摇杆),其它硬件也有不同的配套输入设备,我们要给每种设备都写一套事件响应逻辑吗?显然不是一个好主意,Unity为我们提供了封装。
以前的Unity版本中有Input,InputManager分别提供了读取设备输入值,以及通过虚拟轴映射游戏事件的作用,新版本提供了一套新的输入系统InputSystem.我们就介绍一下新输入系统的使用方法。
首先打开包管理器: Window->Package Manager,选择Input System进行安装:


安装

随后弹出的对话框中选Yes.


警告

Unity将重新启动并禁用旧版Input Api,启用新版Input System.即使这里没有选Yes,我们也可以手动去切换输入系统,方法是打开项目设置: Edit->Project Setting->Player->Active Input Handling,选择Input System Package(New):
设置

遇到问题

好了,输入系统切换完成,运行项目,发现UI不响应了,又发生了什么?
其实这是因为UI默认采用的是老版输入系统作为其输入,我们只需要一个简单的设置就可以解决它。


切换新输入系统

在Hierarchy面板选中EventSystem,点击Inspector面板的 Replace with InputSystemUIInputModule.然后再运行项目,UI又恢复响应了。

控制角色

新输入系统准备好了,现在要开始控制角色了.
控制角色有多种方式,可以用物理引擎控制,可以用Untiy提供的CharacterController来控制,我们为了学习,尝试自己实现一个简单的:
先给角色加一个Player Input组件:


PlayerInput组件

在红框位置有一个CreateActions的按钮,按一下,选择文件位置,会创建一个Input Action Assets,同时会打开左边的面板。这里面定义好了一些Action,以及对输入设备的映射。
写逻辑的时候,只要处理Action就好了,而不用管具体的是键盘输入的,还是手柄摇杆,达到了输入和逻辑相分离的目的。
逻辑代码和Action关联的方式有多种,可以通过Player Input组件的Behavior来控制,它表示当有动作触发时的响应方式:

  • Send Messages
  • Broadcast Messages
  • Unity Events
  • CSharp Events

这四种触发模式,从效率上看,Broadcast Messsages < Send Messages < Unity Events < Csharp Events。
前两种很好接入,只要在脚本中添加 On{ActionName}()函数就可以。
Unity Events 要在 Inspector 中分配各种回调函数,可视化操作,对新手友好,但在函数和动作逻辑较多时比较麻烦。
最后一个比较高效,但是所有的动作共享同一个回调事件 event Action<InputAction.CallbackContext> onActionTriggerd,需要在这个函数中自行区分具体的触发动作。

具体的接入方式可以参考Input System提供的Demo: 打开包管理器,选中Input System,在右边面板选中要查看的Demo,然后点击Import按钮(非必须):


查看Demo

现在我们来创建自己的角色控制逻辑,创建一个名为SimpleActorController的脚本,挂载到角色身上,代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class SimpleActorController : MonoBehaviour
{
    public float moveSpeed; //角色移动速度
    
    private InputAction m_MoveAction;
    private Animator animator;
    private Vector3 rotationVector;

    
    private Vector2 m_Move;

    // Start is called before the first frame update
    void Start()
    {
        animator = GetComponent<Animator>();

        if (m_MoveAction == null)
        {
            PlayerInput input = GetComponent<PlayerInput>();
            m_MoveAction = input.actions["move"];
        }
    }

    private void Update()
    {
        MoveActor();
    }

    //移动角色
    public void MoveActor()
    {
        bool isMoving = false;
        if (m_MoveAction != null && m_MoveAction.IsPressed())
        {
            m_Move = m_MoveAction.ReadValue<Vector2>();
            if(m_Move.sqrMagnitude > 0.1f)
            {
                Vector2 moveVector = m_Move * (moveSpeed * Time.deltaTime);
                //求前进的方向
                Vector3 dir = Camera.main.transform.localToWorldMatrix.MultiplyVector(new Vector3(moveVector.x, 0, moveVector.y));
                dir.y = 0f;
                dir = dir.normalized;
                //把角色转向前进方向
                transform.forward = Vector3.SmoothDamp(transform.forward, dir, ref rotationVector, 0.1f);
                transform.position = transform.position + dir * moveVector.magnitude;
                isMoving = true;
            }
        }
        
        animator.SetFloat("speed", isMoving ? moveSpeed : 0.0f);
    }
}

可以看到,我们用最简便快捷的方式,在Update函数中直接检测Action是否被按下,实际项目中不建议这么做。

然后在Inspector面板中设置移动速度为5左右,现在运行程序,并尝试按方向按钮或者ASDW键,可以看到角色动起来了。

再遇问题

角色是可以移动了,但是好像反应迟钝,先滑步好长距离,才开始跑步,停下的时候也原地踏步半天才停下,这是什么原因呢?
我们在实际项目中经常会遇到类似的状况,明明觉得该做的都做了,但总会出现一些意外。这就要考验大家知识掌握的是否扎实,或者经验是否老到。你可能会记起在学习Animator Controller的时候,有个Has Exit Time的选项,用来控制角色是否一定要播完上一个动作,再切换到下一个动作,目前这个现象很像是勾选了这个选项造成的,打开我们的RoleController,点击Idle状态,在Inspector面板中查看,果然是勾选状态,去掉勾选。


去掉Has Exit Time

我们还要能够举一反三,想想还有没有类似的问题,好像子状态机里面还有状态,好打开后进行同样的操作,保存再试.

"果然好了,不那么迟钝了。可是为什么摄像机不跟着角色走呀?"

因为我们还没有写摄像机控制的代码呀,游戏界有个名词叫 "3C" 就是 "Character Camera Control(角色、相机、控制)" 三个单词的缩写, 它的好坏直接影响到游戏体验,是游戏中十分重要的功能,我们的SimpleActorController是帮助大家入门,所以写的越简单越好,真正项目中要复杂的多,就等你去完善了。

说到摄像机控制,我们下章再来实现吧。

同样给出本章项目连接 角色控制系统


返回主目录
【转载请注明出处】

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容