unity 多种角色控制方式介绍 以及 CharacterController角色控制器详解_unity 角色控制器可以有多个?-程序员宅基地

技术标签: unity  character  controller  角色控制  # unity3D 使用、技巧笔记  unity控制  

简介

操作人物移动,我们一般有以下几种办法:

  1. 直接操作坐标
  2. 使用物理引擎操控
  3. 使用动作 Root Motion
  4. 使用角色控制器
关于坐标操作

坐标操作,就是通过设置transoform.position坐标 或是Vector.transform 等方法使物体移动到指定坐标。
该方式的优点,当然是简单暴力。坏处么,各种无互动无反馈,效果太楞。只适合简单的变化操作或是2d游戏。如果需要复杂点的效果,比如曲线过度,重力下降都要自己去实现。需要自己实现呀,兄弟们我们使用引擎的目的是什么,当然是使用提供的工具提升工作效率。不能什么都自己搞呀。所以这个方式只推荐应用在npc或是机关变化。

关于物理引擎操作

物理引擎操作的好处是可以使用诸多物理特性。当游戏有大量碰撞或移动特性时,使用这个比较好。比如赛车游戏。你可能需要设置赛车的重量来决定过弯的表现和撞车时力反馈的计算,又或是爆炸时被波及的力度。
使用物理引擎操作的主要方式就是添加力。由此可知,向前移动就是添加向前的作用力,跳跃就是添加向上的作用力,物理效果会让人物跳跃后自动下降。

关于Root Motion

这个方式是我认为最合理,过度最平滑,效果最好的方式。只可惜成本太高实现太难。
他所需要的技术包括:角色骨骼绑定 + Animation动作库 + Animator动画控制器 + Root Motion根坐标移动
这就需要我们不仅拥有质量高且数量庞大的动作库,以及各种对动画的精确控制才能实现。我们使用市面上已有的动作库可以实现基本的移动等操作。但总的来说,性能还是不如下面那个,而且开发成本还是比较高的,调试周期特别长,在遇到一些自适应需求的时候开发难度也会增加。
我相信,不久的将来它会成为游戏引擎中的操控最高级形态,并且在技术的推动下变得更加易用。

使用角色控制器(CharacterController)操作

这是个unity的组件。一般情况下控制人物的不二选择。那么为什么首选角色控制器呢,有以下几个理由:

  1. 首先他简化了刚体组件,去掉了很多不必要的计算。在人物比较多的场景中,这节省了大量的物理计算。例如物理引擎中的翻转、重力等效果,你肯定不希望你在移动过程中,会因为碰撞到物体而自动变换方向吧,一般做法就是用freezon来限制,其实这些都是没有必要的性能浪费。如果场景中人物较多时,这种优化就等于性能的巨幅提升。
  2. 其次,他内置了爬坡、登阶阈值设置。可以比较简单的处理多路况的移动问题。
  3. 第三,这个控制器,非常适合与nevmesh agent连用。即unity自带的巡路系统。当我们使用寻路系统时,如果人物身上有物理刚体,那么不仅会被沿途障碍物所影响,还会出现各种意想不到的情况比如惯性等性质。 如果使用角色控制器。则不必担心出现这种情况。一切都那么顺滑,防侧漏,夜夜安心。
  4. 不必担心被坐标被动作库写死。更不必担心由于动作库的坐标移动而出现意外的坐标干扰。
  5. 这可能是最重要的理由了:如果是网络游戏类型,最好使用坐标或Character Controller的控制实现。这是因为当网络数据传输-帧同步时,我们必须要保证多个客户端的场景数据的一致性。所以不应该使用其他的比较容易出现意外的实现方式。 关于网络游戏数据传输和帧同步,这里有清晰的介绍

角色控制器(CharacterController)组件参数介绍

在目标物体的inspector窗口中 点击add components ,添加character controller 即可完成组件添加。
在这里插入图片描述
【Slope Limit:】:斜坡角度。允许角色在指定的坡度上行动。
比如在手游和平精英中,你可能会发现某些房顶的斜坡就能走上去,某些房顶斜坡就走不上去。这都是这个参数所致。虽然和平精英用的是ue4引擎,但使用了和unity原理相似的控制组件。他们都有这个斜坡设置。
【Step Offset】:台阶高度。允许角色自动越过多高的障碍物。 这个设置就是诸如楼梯,台阶,马路牙子之类的障碍,你总不能遇到个小东西就卡住吧,有了这个就可以越过去。有人说,我没有用character controller,用刚体也能越过比较低矮的障碍物啊,怎么回事呢? 那是因为你的碰撞盒下方并不平整,比如胶囊或圆形碰撞盒,由于下方是曲线过度的,所以会在接触物体时通过物理计算的推动下摩擦过去。这种方式不容易控制并且会可能发生意外情况。
【Skin Width】:皮肤宽度。这个就相当于第二层碰撞盒。这个值不能大于下方的碰撞盒的Radius值。否则会卡在某个地方。一般情况这个值应该在Radius的5%左右会比较好
【Min Move Distance】:最小移动范围。当你在代码中使用Move方法移动时,小于这个值的移动将被忽略。这个值可以帮你减少角色因操作产生的抖动。
【Center】:角色碰撞盒偏移。设置物理空间的位置,你需要通过调整这个来使碰撞盒与角色模型重合。
【Radius】:碰撞盒半径。角色控制器的自带碰撞盒是胶囊,这个值用来设置胶囊半径。这个设置还有另一个影响,这个半径值将影响脚本中的isGrounded属性的作用范围。这对我们实现控制角色y坐标位置,比如跳跃等功能极其重要。
【Height】:碰撞盒高度。同上,胶囊高度。

角色控制器(CharacterController)使用

在添加了CharacterController的物体上新建一个脚本。

//获取 CharacterController对象
CharacterController _characterController = gameObject.GetComponent<CharacterController> ();
移动的实现

以下是两种移动方式。分别是世界坐标和本地坐标

//移动方向
private Vector3 moveDirection = Vector3.zero;
//移动速度
float movespeed  = 2f;
void FixedUpdate(){
    
	//世界坐标移动  适用于2d游戏,有固定的方向
	_characterController.Move(Vector3.up * movespeed * Time.deltaTime);

	//角色坐标移动实现   基于当前角色视角的方向移动,适用于3d游戏
	//根据输入的x y值获得移动方向
	float vertical = Input.GetAxis ("Vertical");
    float horizontal = Input.GetAxis ("Horizontal");
    moveDirection = new Vector3(horizontal, 0f, vertical);
    // 计算 基于当前物体坐标,要移动的方向
    moveDirection = transform.TransformDirection(moveDirection) * movespeed;
    // 移动
    _characterController.Move(Vector3.up * movespeed * Time.deltaTime);
}
跳跃的实现
public float jumpPower = 3f;
public float speed = 10f;
public float gravity = 10f;
private Vector3 moveDirection = Vector3.zero;
void FixedUpdate() {
    
   //isGrounded属性 用于 检测当前角色下方是否接触到地面。这个属性表现并不稳定,至少在我的unity2020中他不够稳定,经常闪烁。所以需要我们再用一个射线检测的方法来辅助。
    if(_characterController.isGrounded || IsGrounded(0.2f)) {
    
       moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0f, 				Input.GetAxis("Vertical"));
       moveDirection = transform.TransformDirection(moveDirection);
       moveDirection *= speed;
       if (Input.GetButton("Jump"))
           moveDirection.y = jumpPower ;
       }
       // 角色在世界中自动下降,模拟重力
       moveDirection.y -= gravity * Time.deltaTime;
       controller.Move(moveDirection * Time.deltaTime);
}
// 射线检测,抛砖引玉 我这里使用五个射线。实际上不需要这么多
 public bool IsGrounded(float distance){
    
 		//pointOffset: 点的偏移位置, distance:检测物体与地面的距离
        float pointOffset= 0.12f;
        bool b = Physics.Raycast(new Vector3(transform.position.x, transform.position.y, transform.position.z), -Vector3.up, distance);
        bool b1 = Physics.Raycast(new Vector3(transform.position.x - pointOffset, transform.position.y, transform.position.z), -Vector3.up, distance);
        bool b2 = Physics.Raycast(new Vector3(transform.position.x + pointOffset, transform.position.y, transform.position.z), -Vector3.up, distance);
        bool b3 = Physics.Raycast(new Vector3(transform.position.x, transform.position.y, transform.position.z + pointOffset), -Vector3.up, distance);
        bool b4 = Physics.Raycast(new Vector3(transform.position.x, transform.position.y, transform.position.z - pointOffset), -Vector3.up, distance);
        return b || b1 || b2 || b3 || b4;
    }

这里只是简单的实现,在实际的需求中,你可能要捕捉人物的跳跃状态,为人物跳跃指定起跳、浮空、落地等动作,还要设置原地起跳高度,移动跳跃距离等设定等。

注意事项
  1. 如果主人公身上有animator 需要看情况去掉root motion选项。该选项有可能导致坐标冲突
  2. CharacterController.isGrounded 这个会闪烁。所以会导致很多意外情况。可选的解决方案是:
    一、碰撞盒替代。是比较理想的方案。
    二、CharacterController.isGrounded + 射线辅助的方式。性能会好一些。不可以单独只使用射线。这样会存在盲点。
完成的效果

在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/lengyoumo/article/details/107015378

智能推荐

GBT28181国标流媒体服务,对接摄像机NVR视频流网关等下级设备_gb28181 和nvr 是什么关系-程序员宅基地

文章浏览阅读133次。各地视频大规模建设后,省级、国家级集中调阅,对重特大事件通过视频掌握现场并进行指挥调度的需求逐步涌现,然而不同平台间缺乏统一的互通协议。liveweb流媒体平台能够通过简单的网络摄像机通道配置,将传统监控行业里面的高清网络摄像机IP Camera、NVR等GB28181国标协议输出的设备、平台接入到liveweb流媒体平台,能够将这些视频源的音视频数据进行拉取,转换为RTMP/HLS/FLV/RTSP,进行全平台web直播,并且能够将视频源的直播数据对接到第三方CDN网络,实现互联网级别的直播分发;_gb28181 和nvr 是什么关系

【P45】JMeter 开关控制器(Switch Controller)_jmeter switch控制器-程序员宅基地

文章浏览阅读1.3k次,点赞2次,收藏3次。开关控制器(Switch Controller)参数及使用说明详解_jmeter switch控制器

SpringBoot注入service为null_service注入为null-程序员宅基地

文章浏览阅读6.7k次,点赞10次,收藏15次。使用@Autowired注入service时报错空指针异常,应该如何解决?_service注入为null

用c语言编写一个汇编编译器,【提问】最早的汇编语言编译器如何诞生?-程序员宅基地

文章浏览阅读780次。该楼层疑似违规已被系统折叠隐藏此楼查看此楼查了资料,如下汇编。这真的是最早最早的。准确的来说,这和编译器的开发有关,不用说太细,很麻烦怕你不懂。你现在假设第一个编译器是用会变写出来的,它的功能很简单,就是解释简单一种类似于C语言的高级语言,但是这种所谓的高级语言还没有完全拥有C语言的所有特性。只有比较简单核心功能,比如能把文本文件的高级语言转换成机器代码并且执行。有了这个原型之后,就可以用这个编..._汇编语言的编译器怎么写的

前后端分离架构中的接口安全(上篇)_前后端分离 安全设计-程序员宅基地

文章浏览阅读3w次,点赞8次,收藏98次。互联网发展至今,已由传统的前后端统一架构演变为如今的前后端分离架构,最初的前端网页大多由JSP、ASP、PHP等动态网页技术生成,前后端十分耦合,也不利于扩展。现在的前端分支很多,如:Web前端、Android端、IOS端,甚至还有物联网等。前后端分离的好处就是后端只需要实现一套界面,所有前端即可通用。 前后端的传输通过HTTP进行传输,也带来了一些安全问题,如果抓包、模拟请求、洪水攻击、参数劫..._前后端分离 安全设计

浅探Activity,Window,DecorView关系_activity decorview window-程序员宅基地

文章浏览阅读216次。Activity,Window,DecorView简介关系图ActivityWindowDecorViewViewRoot关联过程简析Activity->setContentView简单分析Activity获取window的流程前提摘要:仅个人笔记整理,参考文章https://lrh1993.gitbooks.io/android_interview_guide/content/android/basis/decorview.htmlActivity,Windo.._activity decorview window

随便推点

可持久化专题(一)——浅谈主席树:可持久化线段树-程序员宅基地

文章浏览阅读6.1k次,点赞17次,收藏26次。前言不得不说,可持久化数据结构真是太难了! 由于数据结构这东西真的太玄学了,学这个主席树我真的学了很久。简介主席树为什么叫主席树?据说因为它是一个名字缩写为HJTHJTHJT的神犇发明的,与当时主席的名字缩写一样…… 主席树实质上就是一棵可持久化线段树,它的具体实现可以看下面。让我们从值域线段树开始说起要学主席树,我们就要先学值域线段树。 值域线段树的区间存的并不..._可持久化线段树

Crash工具介绍和常见命令使用_crash工具使用-程序员宅基地

文章浏览阅读3.4k次,点赞4次,收藏15次。本文主要介绍crash工具的使用以及常用的命令。crash工具,常用来分析内核的coredump以及应用的coredump,功能非常强大。_crash工具使用

【sketchup 2021】草图大师的辅助建模工具2【模型交错、照片匹配(重要)】-程序员宅基地

文章浏览阅读1.8k次。文章目录量角器与文字、尺寸标注与三维字、实体工具模型交错鼠标右键编辑菜单示例照片匹配基本用法说明建模一个床头柜示例量角器与文字、尺寸标注与三维字、实体工具一篇文字2w字左右,多了看着费劲加载也慢所以这些去看这篇博客:【sketchup 2021】草图大师的辅助建模工具1【量角器与文字、尺寸标注与三维字、实体工具】模型交错模型交错命令主要是帮助我们在遇到两个及两个以上相交的模型时,可以通过生成的相交线,然后擦除不要的一部分,进而得到一个特殊的形体。这个和实体工具类似,只是这_模型交错

情人节程序员用HTML网页表白【粉色生日祝福网页】TML5七夕情人节表白网页源码 HTML+CSS+JavaScript-程序员宅基地

文章浏览阅读816次,点赞20次,收藏18次。1 网页简介:基于HTML+CSS+JavaScript 制作七夕情人节表白网页、生日祝福、七夕告白、 求婚、浪漫爱情3D相册、炫酷代码,快来制作一款高端的表白网页送(他/她)浪漫的告白,制作修改简单,可自行更换背景音乐,文字和图片即可使用等任意html编辑软件进行运行及修改编辑等操作)。

uni-app字符串数字转换_uniapp 字符串转数字-程序员宅基地

文章浏览阅读1.1w次,点赞2次,收藏5次。uni-app字符串数字转换_uniapp 字符串转数字

MLE极大似然估计和EM最大期望算法_em算法与mle-程序员宅基地

文章浏览阅读4k次,点赞3次,收藏10次。机器学习十大算法之一:EM算法。能评得上十大之一,让人听起来觉得挺NB的。什么是NB啊,我们一般说某个人很NB,是因为他能解决一些别人解决不了的问题。神为什么是神,因为神能做很多人做不了的事。那么EM算法能解决什么问题呢?或者说EM算法是因为什么而来到这个世界上,还吸引了那么多世人的目光。 我希望自己能通俗地把它理解或者说明白,但是,EM这个问题感觉真的不太好用通俗的语言去说明_em算法与mle