主要内容:碰撞理论以及正确使用 KinematicBody2D 节点
阅读时间: 15 分钟
永久链接: http://liuqingwen.me/blog/2018/12/30/introduction-of-godot-3-part-12-talk-about-collision-and-move-and-collide-vs-move-and-slide-in-kinematicbody2d/
系列主页: http://liuqingwen.me/blog/introduction-of-godot-series/
二、正文
本篇目标
- 四个节点回顾: KinematicBody2D/RigidBody2D/StaticBody2D/Area2D
- 碰撞图层和碰撞图层掩码: Collision Layers/Collision Masks
- 两个重要方法的区别和联系: move_and_collide/move_and_slide
三个物理节点
在 Godot 中有三个常用的 2D 节点,它们具有碰撞检测与反馈的功能,这三个节点的基础区别在我之前的文章中已经讨论过:Godot3游戏引擎入门之五:上下左右移动动画(下),搬用之前的表格,他们之间的关系和应用场景大致如下:
节点名 | StaticBody2D | RigidBody2D | KinematicBody2D |
---|---|---|---|
节点名称 | 静态碰撞节点( 2D ) | 刚体节点( 2D ) | 运动学节点( 2D ) |
基本特性 | 自动碰撞检测,位置固定不变 | 自动碰撞检测,产生碰撞响应:有线速度、角速度等 | 参与碰撞检测,无自动响应,完全由代码控制移动 |
使用场景 | 一般用于固定的墙壁、地面等 | 一般用于受外界影响而产生运动的物体,比如球体、陨石等 | 主要用于由代码控制的带物理属性的玩家 |
- StaticBody2D 能应用于所有游戏,作为墙壁、地面、障碍物等固定物
- RigidBody2D 比如像愤怒的小鸟、割绳子、太空飞船游戏的主角等
- KinematicBody2D 几乎所有的前后左右移动、跳跃的平台游戏玩家或者敌人
- Area2D 常见于游戏中的可收集元素或者标记,比如金币、楼梯、关口或者特殊区域等
这几个节点我们在前面的文章中都遇见过,也有不少例子,它们的使用方法大家应该都会了。这里,关于刚体 RigidBody2D 我暂时不会介绍很多,大家可以参考这篇文章: Godot 3.0: Rigid Bodies ,介绍的内容比较全面。
重要说明: Godot 3.1 版本中对于 StaticBody2D 以及 RigidBody2D 的摩擦力属性( )和弹性属性( )的设置没有出现在属性面板中,而需要在新增的 Physic Material Override 属性下新建一个 PhysicMaterial 间接进行设置即可,实质上区别影响并不大。
碰撞形状和图层
这里重点要提到的概念是碰撞图层以及碰撞图层掩码。在使用碰撞图层之前,你必须在 Godot 项目设置中对你所需要的图层进行添加并合理命名:
游戏物体 | 碰撞图层 | 图层掩码 |
---|---|---|
玩家 | 1 | 2, 3 |
敌人 | 2 | 1 (or 0) |
金币 | 3 | 1 (or 0) |
在这种场景设置下,很显然,玩家掩码为 2(enemy) 和 3(coin) ,那么玩家会检测与敌人或者金币之间的碰撞,敌人和金币的掩码设置都是 1(player) ,所以它们分别也会检测与玩家之间发生的碰撞,但是敌人与金币、敌人与敌人、金币与金币、玩家与玩家之间则都不会互相发生任何碰撞检测!
重点说明:图层和掩码都可以不勾选,也就是完全删除,如果这里敌人或者金币删除全部的掩码,即设置图层掩码为 0 ,那么是不是敌人就不能检测到与玩家之间的碰撞了呢并不是!他们依然能互相检测到与对方的碰撞,这是因为玩家的掩码中包含了敌人,只要双方有一个设置了与对方可以发生碰撞检测的掩码,那么双方即可相互检测到与对方之间发生的碰撞!
既然如此,那么假设有这种需求:“游戏中的玩家只检测敌人或者金币,而金币或者敌人不需要去检测玩家”,那能否实现呢在 PhysicsBody2D 的三个节点中还真没办法,但是这里我们可以不考虑使用 KinematicBody2D 等节点,转而使用 Area2D 节点就可以实现了,需要注意该节点的两个属性:
- Monitoring 是否能主动检测其他碰撞体
- Monitorable 是否能被其他碰撞体检测到
OK ,明白了图层和掩码对游戏的开发帮助非常大,你完全可以自己写一个 Demo 尝试一下,或者下载我的源码一探究竟吧,偷偷告诉你:这很重要!哈哈! p>
两个重要的方法
接下来我们的重点是 KinematicBody2D 节点的两个常用方法,因为涉及到物理碰撞的大部分游戏中,玩家都是使用 KinematicBody2D 节点制作的,而它又有两个非常重要的碰撞处理方法,所以我们必须重点“针对”它们!
首先,在正常的游戏场景中,对于 KinematicBody2D 几何学碰撞体节点的移动实现,我们主要有以下三种方式:
- 属性设置,即控制位置,完全手动检测碰撞
- 方法调用,移动并自动检测碰撞
- 方法调用,移动并自动检测碰撞,支持滑动
对于第一种方式,直接操作 位置属性,一般在有碰撞体的游戏中很少这么“武断”地使用,即使你的游戏是没有任何碰撞体,你这个时候你也没必要选择 KinematicBody2D 节点,直接使用 Area2D 节点就好。那么,接下来我们主要讨论另外两种方式,包括它们的定义,区别与联系以及应用场合等。
1. 相关联系
第一个:很显然,他们必须都在 方法中调用,因为该方法的内部会对物理引擎进行相关处理,前面我们已经讨论过,最好不要在 中使用这两个方法,避免出现异常情况,这也是新手容易犯的错误之一。
第二个:这两个方法在某场景中是完全可以互相取代的,只需要对碰撞行为作出对应的处理即可。举个例子,下面两个代码段的效果表现会完全相同:
效果图如下:
解决这个问题的方法很简单,把方法替换为 即可。该方法不仅能正确处理碰撞反馈,还能告诉你在发生碰撞后物体的实际运行速度,即方法的返回值,在本 Demo 中你可以通过打开 use real velocity 这个开关查看碰撞后物体运动的实时速度。
那么,是不是所有的 KinematicBody2D 节点的移动都应该直接使用 方法呢不是!一起来看第二个示例。
2. 碰撞反弹效果
考虑下这个场景,我们有一个用刚体(不反弹)做成的弹力球,这个球在碰撞到墙壁后能弹回去,但是墙壁是静态物体也没有弹性,这个时候如果使用 方法那么弹球遇到墙壁就会停止或者直接沿着墙壁下滑啦,如何处理呢然,我们需要一点代码!
这就是 方法的用武之地了,我们可以利用这个方法的返回值进行相关处理,返回值是一个 类型的碰撞结果,其中包含我们所需要的数据,比如碰撞体的表面方向,即碰撞体的法线方向(垂直方向),把弹力球的速度按法线方向将其反射,那么球就能顺利反弹了!
代码可以参考上文,图效果可以看下:
三、总结
Just do it, man!
- 三种 2D 物理节点以及 Area2D 节点的回顾
- 碰撞层和碰撞掩码理论知识
- KinematicBody2D 两个方法详述
- 简单的应用场景分析
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!