Unity超级角色控制器研究(四)——地形检测
一个地形检测反例
因此我们想知道什么在角色脚底下呢?首先是距离脚下有多远。我们会想知道角色的脚是否贴着地面还是在半空中。我们还会想知道脚下地面具体位置坐标,这对于上一章强调过的钳住地面是很重要的。第三个就是会想知道脚下地形的法线是多少。而最后很有必要知道脚下的GameObject是谁,这使得我们可以为地形添加组件(在超级角色控制器当中,会有SuperCollisionType可以添加到地形当中来描述地形)。
看看之前研究Unity物理API的文章,找到最合适的解决方案是Physics.Raycast。我们可以通过向下打射线找到地面。虽然RaycastHit结构体可以让我们得到碰撞点,打击距离,打击法线以及发生碰撞的对象。第一眼看上去就完全满足了我们的需求,但是仔细想想还是会有一些问题。
我们的角色控制器是用一系列的球体来表示的,这意味着当直接站在平面上的时候,平面上的最近点就恰好距离底部球体球心一个半径距离。但是如果角色站在斜坡上就会出问题。如果我们现在还是像之前一样直接向下打射线,所得的点就不再是底部球体的最近点了。这对于钳住地面来讲会出错的(具体后面会谈到)。
射线直接从底部球心直接向下打出。在角色站在斜坡的情况下,下面的点是不正确的。而当角色钳住地面的时候,那个点会让角色稍稍与斜坡交叉。对于陡峭的坡体来说,这个问题就更加明显了。
幸运的是,我们有救兵Physics.SphereCast。与其投射一条细微的射线出去,我们可以投射一个球体。这样就能解决上面提到的问题,从而确保角色总是完全在地表之上。
在使用SphereCast能够顺利工作的同时,也带来了一些问题。首先是SphereCast碰到碰撞体边缘的时候,hit.normal返回的是两个相邻面的插值。这与Vector3.Lerp函数来类似。
动画演示了SphereCast返回的hit.normal的插值情况。
我发现很有必要知道所站的表面法线的真实值,而不是插值。为了解决SphereCast带来的插值问题。我用单独的射线分别跟踪SphereCast所得到邻近的两个面,这样就能够得到正确的法线(在超级角色控制器的ProbeGround方法中,这个称为nearHit与farHit,分别表示距离控制器中心的最近的面与最远的面)。
SphereCast的下一个问题是我们用了它来做地形检测,但还是会有准确性的问题。我们已经默认了SphereCast打中的所有碰撞体都是地形,我们的角色可以站上去(或者在有的游戏中是滑上去)。但实际上这不是总能行得通的。我们可以有理有据地认为游戏世界的物理表面(角色与之碰撞的对象)可以划分为地形与墙体,而只有地形表面才应该被地形检测所检测出来。最简单的划分方法就是将表面法线与某个向量(比如世界空间的Vector3.up)的夹角来划分。小于90度的是地面,大于90度的是墙面。这样我们就可以确保不会将墙体也当做地面来处理。我们的地形检测里这个问题很天然的解决了:我们总是向下投射球体,这就是说这不可能打中90度的墙体。但是,游戏中的墙体法线会接近90度,甚至处于85到90之间。我们想把这些85度的表面看做是墙体,也就是说它们应该忽略SphereCast。
我们的角色控制器是上不去85度墙的。对于这个墙来说我们的SphereCast的碰撞点是黄色标记,而不是脚下方的平面。这会使得我们的角色会认为自己站在陡坡上,而不是平地上。
最常见的办法是用Physics.SphereCastAll。它会理想地同时打中墙体与地面,然后我们可以遍历所有碰撞点,从而找到合适的立足点。不幸的是,SphereCastAll只能每个对象拣选一个碰撞点,也就是说如果墙体与地面是同一个对象,那么这个方案会出错。
对于上面的问题,我们可以通过减小SphereCast的半径来解决。这样确实能解决一些问题,但不是全部。我们还是要想一种可靠的方法来来处理贴着陡坡这个问题。
「PS: 在SuperCharacterController中,陡坡的定义是SuperCollisionType组件的StandAngle值定义的,可以放在所有与角色碰撞的碰撞体上。」
为了解决这个问题,可以想象一下我们脚底下某种地形,如果没有被陡坡影响,我们是能够通过SphereCast检测出来的。卖手机靓号为了找到这个地面,我们可以在SphereCast打中的地方用Raycast。这是主要用于检验是否存在这块地面,而且可以获取它的法线。
最初SphereCast的碰撞点在黄色标记位置。因为我们与陡坡有碰撞,我们可以Raycast(红色)来检测陡坡之下是否有一块地面在我们之下(紫色)。
这让我们知道下面有什么,但是由于用了Raycast,而不是SphereCast,我们会又一次遇到之前的问题,碰撞点会让地形与球体重合。给定我们有的信息(脚下地形的法线),我们可以将其转换为近似于SphereCast的数据吗?答案是Yes。
每当你从控制器底部向下SphereCast,然后碰到了一个表面,就会就在碰撞表面法线与碰撞点之间存在一种联系。在我们从斜坡碰撞点向下打射线得到正确地面的法线之后,我们的任务就是找到控制器底部向下SphereCast与地面的交点。下面我们看看二维的情况,然后再回来解决三维问题。
动画演示了SphereCast的碰撞点与碰撞平面法线的关系。SphereCast的原点在黄色球那里,碰撞在红色球那里,碰撞点标记为蓝色。注意到随着斜坡越来越斜,红色圆形就越往上。
由于我们想找一个二维空间的点,而这两个值分别是x和y。如果计算正确,x和y会将我们圆形的往下与地面碰撞的点。对应上面的图来看,我们要用给定的地面法线,找到上图中蓝色交点的位置。
幸运的是,这其实并不困难。复习一下中学的数学知识,通过法线作为角度传入,我们可以使用三角函数来计算x和y的位置。
- x = Mathf.Sin(groundAngle);
- y = Mathf.Cos(groundAngle);
复制代码
要注意的是,Unity的Sine和Cosine需要以弧度的方式传入夹角,需要转换一下。
通过sine与cosine计算碰撞点的位置
现在我么可以用这些值来调整控制器的位置(乘上半径)。
「PS: 在SuperCharacterController中,近似计算SphereCast值的方法叫SimulateSphereCast。」
以上就是超级角色控制器中用到所有地形检测技术。不像之前的文章,这里地形检测话题是很开放的–上面只是其中的一种,但我法线它在实际中运行的很好。
Unity超级角色控制器研究(四)——地形检测相关推荐
- Unity自定义角色控制器(一):碰撞检测
我实在很喜欢用Unity.它在处理很多底层问题的同时有给了开发者很多自由.而且它还有着非常活跃的社区,起到了很大的帮助. 不幸的是,之前也说了,Unity也带着世界上最糟糕的角色控制器.在与Unity ...
- Unity 2D角色控制器(横板滚轴)
unity自带的2D刚体在坡上会往下滑.而且也是会有可能穿墙,或碰撞到其他物体时鬼畜抖动. 设计思路 1.利用射线进行判断碰撞防止穿墙: 原理传送门 2.在地面时往地面发射两条射线,获得的两个点,两个 ...
- Unity:角色控制器(CharacterController)
角色控制器是unity中专门用来控制角色的组件(主要是运动相关),区别于直接用Transform或者RigidBody,CharacterController有着更好的效果,它拥有RigidBody的 ...
- unity 使用角色控制器CharacterController移动对象造成模型动画的抖动
使用角色控制器控制对象的移动,主要用到Move和simplemove函数: function Move (motion : Vector3) //montion表示将控制器移动到这个坐标点,注意它 ...
- 详解Unity中的角色控制器
前言 如何让玩家所操纵的角色动起来,这在Unity中很容易实现,但是如何确保玩家所操作的角色不会产生一些非常违反物理常识的情况?而这就需要进行大量的检测,已确保玩家所操纵的角色正常.所幸Unity为我 ...
- 【Unity游戏开发教程】零基础带你从小白到超神16——四种方法控制人物移动之角色控制器
角色控制器 控制人物移动的四种方式 直接修改组件位置 去资源商城下载角色控制系统成品 unity提供的角色控制器组件 Character Controller API 通过物理系统自己做 拓展 常用的 ...
- Unity手游之路lt;七gt;角色控制器
我们要控制角色的移动,能够所有细节都由自己来实现.控制角色模型的移动,同一时候移动摄影机,改变视角.当然Unity也提供了一些组件,能够让我们做更少的工作,实现我们所期望的功能.今天我们就一起系统来学 ...
- unity3d人物跳_Unity3D研究院之角色控制器组件研究(二十二)
Unity3D封装了一个非常好用的组件来实现第一人称视角与第三人称视角游戏开发,我们称他为角色控制器组件,几乎不用写一行代码就可以完成一切的操作,神奇吧.使用它的方法如下,首先打开Unity游戏引擎编 ...
- 【Unity】多种方法实现第一人称角色移动(一)角色控制器
前言 在Unity中要实现第一人称视角移动的方法有很多,每种方法各有优劣,本次要介绍的就是使用角色控制器CharacterController来实现的方法. 在阅览下面的步骤之前,你首先需要一 ...
最新文章
- mysql 5.7 Stage Tracking DDL进度跟踪
- 总结JavaScript常用数组操作方法,包含ES6方法
- Mysql和mono,.net – Mac OS X Mono和MySql连接器问题
- 2009 .NET技术大会图文分享
- HTML在日期单元格添加小图片,如何给图片添加上文字、日期和自己名字的小水印呢?...
- 涨疯了!国产鞋被爆炒,原价1499元卖48889元,有人几天赚一辆车
- rap2检测哪些接口在使用_使用四合一气体检测仪应注意哪些方面?-逸云天
- linux磁盘及文件系统管理
- copy的过去式_copy什么意思_copy是什么意思中文翻译
- 如何在桌面上显示我的计算机,Win10如何将我的电脑(此电脑)显示到桌面上?
- 批量查询域名是否注册
- Wordpress 网站添加打赏插件
- uniapp 微信小程序 保存图片到本地
- 中国成为论文发表数量第一的国家
- 2021-1-26-java生成二维码
- 什么是CPU?什么是计算机?
- su鉴定故障和su拒绝权限
- Oracle sql创建序列sequence
- 某程序员感叹:4年开发,年包才40多万
- 应届毕业生身份有什么用?应注意事项?
热门文章
- 0x84bb0001 sqlserver_sqlserver 2000 远程连接 服务器的解决方案
- 全选文字的快捷键_高效办公必备Excel快捷键之Ctrl+26个字母!掌握它们,告别加班...
- python用format保留三位小数_关于Python 保留小数使用format、%、round()、Decimal函数及format和%只能保留到六位问题...
- 深度学习-Tensorflow2.2-深度学习基础和tf.keras{1}-逻辑回归与交叉熵概述-05
- oracle让查出来的数据排序,Oracle数据库的查询排序
- 算法优化:最大m个子段和,问题规模从1个子段和扩展到m个,动态规划
- Java 从业一年的心得体会
- tomcat日志格式中的含义
- 面试题25: 合并两个排序的链表
- docker overview