上期链接:Unity2D游戏制作入门 | 07-CSDN博客
上期我们聊到如何让人物能够进行跳跃,主要是使用注册函数的方法让按键按下的那一刻执行了人物的跳跃,不像Fixupdate那样调用Move函数,跳跃不是时时检测的,只有当按下空格键才会触发跳跃事件。**细节方面就是施加的力和重力规模的适当选择(为了舒适的操作手感),然后问题也有,如无限跳跃和粘墙上的问题,**本期内容我们来聊聊如何进行GameObject的物理环境检测及Gizmos测绘,以及解决上期遗留的问题。本期完整代码先放在下面方便查看:
//#physicsCheck.cs
[Header("检测参数")]
public Vector2 bottomOffset;//底部位移差值
public float checkPaduis;//检测半径
public LayerMask groundLayer;
[Header("状态")]
public bool isGround;//布尔值变量,它只会取true或flase
private void Update()
{
Check();
}
public void Check()
{
//检测地面。检测到isGround即为true。加入位移偏差bottomOffset希望精测位置更精确
isGround = Physics2D.OverlapCircle((Vector2)transform.position+bottomOffset,checkPaduis,groundLayer);//第一参数:检测位置(这里是以脚底中心点),第二参数:检测范围,第三参数:筛选碰撞的层
}
private void OnDrawGizmosSelected()//当物体被选中时,在窗口Scene当中进行绘制。代码如果没有启用也会绘制出来,只要你选择物体。
{
//画虚线的球。
Gizmos.DrawWireSphere((Vector2)transform.position + bottomOffset, checkPaduis);//第一个参数中心点位置,第二个为半径大小。
//直接复制上面即可,然后这个没有检测功能,
//只是绘制在窗口让我们有直观的印象
}
//提醒,还要在playerControl代码中调用物理检测的布尔值变量isGround加入到Jump函数中去判断人物是否在地面上。
正文:
我们需要规定只有人物站在地上时,才能进行跳跃操作。这回我们需要再单独写一份代码,因为除了人物需要检测周围的物理环境,敌人也需要(如敌人撞墙了,或是走到悬崖边需要回头等等)。我们要将这份代码写成通用的功能,让它可以被大多数GameObject当成一个通用的组件即Component来进行使用。
新代码创建再Player下, 并挂载到人物身上。然后打开代码。
我们创建一个公共的函数Check,然后要持续不断地进行检测,所以放到Update函数中去执行。然后检测地面是一种状态,如果它在地面则允许执行跳跃操作。创建变量来表示人物或其他物体的状态,即isGround是否在地面。但是难点是,我们需要使用什么方法来检测人物是否在地面呢?
public bool isGround;//布尔值变量,它只会取true或flase
private void Update()
{
Check();
}
public void Check()
{
//检测地面
}
PS:碰墙和碰地面需要区分开来,因为人物可能会需要爬墙滑动和蹬墙跳的功能,分别检测这些方向比如左边右边和下边。这是我是第一次刷视频时没有弄明白的,所以这是我们要考虑进去的东西。
我们需要先学习一个函数的写法,我们去到代码手册,用API搜索2D的物理检测,进入第一个搜到的结果。我们可以看到2D物理全局检测的方法(下方第二张图),怎说呢,我还是举例吧:要互相检测,物体都要加入collider的组件,然后如果使用BoxCast即方形的检测方法,就会在人物上用代码写出一个隐身的方形线框,如果敌人身上挂载关于Collider的组件,那么当敌人的Collider进入玩家的检测框内,我们就可用报告发现敌人或是做一些其他的事情。不过在下面的内容中我们使用OverlapCircle的检测方法,因为它有一个变量layMask,它是一个筛选器,可以筛选指定的碰撞层。用layMask的好处是,如果我们踩到脚下的花,敌人等这需要持续判断,我们用OverlapCircle就可以避免这种情况,因为我们只想检测人物是否在地面上,就要用到这个参数作为筛选器。
如下图,先给地面挂上Ground这层,没有该选项的话先添加新的再选择进去,添加的位置任意填写(可以从第六个位置往后写,第三个位置是预留先不写)。再给人物的GroundLayer选择Ground即可(它是可编辑的下拉菜单)。
设置脚底检测的圆圈范围不要太大,设置为0.2,然后运行游戏试玩,你就会看到isGround自动勾选,如果按空格跳跃它又会被取消勾选。然后我们可以通过isGround是否被勾选,以此来修改和限制我们之前的无限跳跃,只允许在地上才能跳跃 。所以需要在Player_control代码访问一下PhysicsCheck里面的isGround这个状态是否为true。
每一份挂载到人物身上的代码,你都可以看成一个组件。那么代码如果变成了组件,我们可以用老方法去获得它的使用权(去到Player_control代码中,在关键位置添加即可):
private physicsCheck physicsCheck;//创建物理检测变量
private void Awake()
{
physicsCheck = GetComponent<physicsCheck>();
}
......
private void Jump(InputAction.CallbackContext obj)
{
if(physicsCheck.isGround)
rb.AddForce(jumpForce*transform.up,ForceMode2D.Impulse);//第一个参数表示给哪个方向施加力,第二个参数施加的力的模式
}
PS:需要说一下,如果我们在Player_control的代码中调用PhysicsCheck代码里面的内容,比如它的布尔值变量isGround,如果isGround在最初没有定义成公开的变量,我们也是无法获取到的。
现在保存代码再去运行游戏,发现只有在地上才能跳跃 。刚才对应地面的检测,单纯是靠对于函数方法的想象,就我们给人物脚底中心位置挂了一个半径为0.2的圆圈去检测我们的地方,这样不够直观,我们把这个检测地面层圈给显性出来。
//#physicsCheck.cs(写这行是表示我当前操作的代码文件是哪份)
public Vector2 bottomOffset;//底部位移差值
.....
public void Check()
{
//检测地面。检测到isGround即为true。加入位移偏差bottomOffset希望精测位置更精确
isGround = Physics2D.OverlapCircle((Vector2)transform.position+bottomOffset,checkPaduis,groundLayer);//第一参数:检测位置(这里是以脚底中心点),第二参数:检测范围,第三参数:筛选碰撞的层
}
private void OnDrawGizmosSelected()//当物体被选中时,在窗口Scene当中进行绘制。
{
//画虚线的球。
Gizmos.DrawWireSpheree((Vector2)transform.position + bottomOffset, checkPaduis);//第一个参数中心点位置,第二个为半径大小。
//直接复制上面Check()函数即可,然后这个没有检测功能,
//只是绘制在窗口让我们有直观的印象
}
然后在Scene窗口中我们可以看到我们检测的圆圈范围了。(不过为什么代码没有启用即没勾选它还能显示出来,估计是和Gizmos.DrawWireSphere这个方法有关系。)然后我们新加的为Vector类型变量的bottomOffset也可以进行检测的微调,这样**绘制的位置和检测的位置也会跟着一起移动。**这圈的范围可以设定为0.8,因为人物贴近时才会触发检测地面,这符合我们的直觉。最后这样我们就能实现我们的单次跳跃了。
之前提到我们的人物贴墙上会粘着不动,这是因为人物有质量的(Mass),因为质量导致有真实的物理材质,比如人物表面粗糙会有摩檫力,用力撞在一个物体上的话我们不会下滑。注意下图:rigidbody里面也有这个材质(材料),collider碰撞体也有。
我们在setting下创建新的2D的物理材质(创建时要进入2D找到物理材质,而不是在表面找因为那是3D物体的物理材质)。创建好点击smooth你会看到Friction变量,这是摩檫力系数,调成0,然后挂载到人物碰撞体的物理材质上。
下方图二,如果你发现游戏运行时人物被地图遮挡,是因为在精灵渲染层它们都是同一个层的,所以把Order in Layer的显示优先级调大一些即可(这个地方比地图的数字大就可以,比如5)
总结:
我们先创建了一个新的检测物理环境的c#脚本,然后使用Unity引擎自带的Physics2D.OverlapCircle方法来判断人物是否在地面上,最后在PlayerControl中调用physicscheck中的isGround变量,来判断我们的人物是否能够调用跳跃这个功能(仅限站在地面上时)。我们还绘制了直观的检测范围和位置,这很好的帮忙我们知道我们检测的具体情况,最后我们解决人物材质问题,让它跳上墙时不会粘在墙上。
补充:
1、在测试期间,如果发现一些问题,比如人物没有跳起来,有可能你在你调试时没有把能跳跃的代码进行启用,注意检查BUG哦!
未尽事宜以后可能会补充。
----------------------------------结束线