查看原文
其他

CreatorPrimer|物理小游戏(碰撞监听)

张晓衡 Creator星球游戏开发社区 2021-08-09


继续物理小游戏,我们先回顾一下CreatorPrimer仓库中提供的五个组件脚本:


通用物理组件

使用这5个组件脚本,可以构建非常有趣的物理小游戏,下面我们对这5个自定义组件做一个简单介绍:

  1. PhysicsManager: 物理引擎管理器,使用它无需编程即可开启\关闭物理引擎,并提供刚体的着色调试开关。


    物理引擎管理器

  2. PhysicsVelocity: 物理速度控制组件,提供了一个force函数方便使用cc.Button在编辑器中调用,为刚体施加外力。

  3. PhysicsColliderNotification: 物理碰撞通知组件,使用它可以让非物理组件或脚本能收到物理碰撞事件。

  4. ScoreNotificationHandle:得分通知处理组件,该组件监听PhysicsColliderNotification发出的事件通知,更新Label文本。

  5. ScoreVerifyNotificationHandle:带验证功能的得分通知处理组件。


我们今天的重点是PhysicsColliderNotification组件的实现。

1. 开启刚体碰撞监听


开启碰撞接触监听

PhysicsColliderNotification组件功能是监听刚体的碰撞事件,因此它需要依赖刚体组件(RigidBody),同时在运行时自动开启刚体的enabledContactListener属性。

cc.Class({    //依赖刚体组件    editor: CC_EDITOR && {        
           requireComponent: cc.RigidBody,    },    
   extends: cc.Component,    ...    start () {        
       //获取刚体组件        let rigidBody = this.getComponent(cc.RigidBody);        
       //开启碰撞接触监听        rigidBody.enabledContactListener = true;    },    ... });

最初,有网友在使用Shawn提供的脚本发现时有不灵,发现是因为未开启刚体碰撞监听开关的原故,因此重构时增加了RigidBody的依赖,同时在组件start生命周期函数中开启刚体的enabledContactListener属性,增强使用体验,减少意外发生。

2. 碰撞事件监听

在篮框节点上开启了刚体的碰撞监听,就可以此节点的任意组件代码上编写碰撞监听处理函数了,我们看一下PhysicsColliderNotification碰撞处理函数的实现细节:

/** * 物理碰撞通知组件,要以让非物理组件或脚本能收到物理碰撞事件 */cc.Class({    ...    extends: cc.Component,    
   properties: {      
       notificationName:'',      
       _p0: null,      
       _p1: null,    },    
   /**     * 只在两个碰撞体开始接触时被调用一次     */    onBeginContact(contact, selfCollider, otherCollider) {        cc.log(otherCollider.node.name);        
       this._p0 = otherCollider.node.position;    },    
   /**     * 只在两个碰撞体结束接触时被调用一次     */    onEndContact: function (contact, selfCollider, otherCollider) {        
       this._p1 = otherCollider.node.position;        
       if (this.notificationName) {            cc.director.emit(this.notificationName, contact, this._p0, this._p1);        }    }, });

不知道大家是否还记得,在篮框的碰撞组件中需要设置Sensor属性,它可以使用节点不产生物理碰撞效果,让其它动态刚体可以穿透它,但能监听物理碰撞事件,请看下图:


开启Sensor属性

开启了Sensor属性,通过引擎提供的onBeginContact、onEndContact两个事件监听函数获取篮球刚体的坐标点,识别篮球是从上向下投进的,还是从下向上进框的,从而实现正确记分。

组件中的_p0、_p1变量就是刚体碰撞时的开始点和结束点,在onEndContact事件中通过cc.director.emit将自定义事件、碰撞开始\结束坐标点广播出去。

3. 自定义事件

为什么不直接在刚体节点上直接处理得分呢?要使用cc.director.emit中转一下呢?因为刚体碰撞事件,只能在刚体节点上才以监听到,得分的表现使用的是一个Label组件,如果将代码写在一些,那这个PhysicsColliderNotification组件做的事情就不只一件,而且太过去具体,而且设计多个对象,导致通用性会大大降低。

使用cc.director.emit('xxx')将广播一个事件出去,在任意脚本中使用cc.director.on('xxx')接收事件,不论是更新得分,还是处理游戏的流程、特效等等,会更加的灵活可变,可以让策划或设计师发挥出更多的创作空间。

cc.Director是继承成自cc.EventTarget,cc.director是一个全局变量,因此使用cc.director.emit、cc.director.on实现事件的订阅、发布非常简单,是实现组件间的通信的一种非常方便的方案。

很多人都使用过cc.Node.emit、cc.Node.on来发送和监听事件,唯一不方便的就是你需要先获取发送事件的节点对象。相信还有人怀念Cocos2d-x中的CCNotificationCenter,完全可以使用cc.EventTarget实例化一个全局的EventTarget对象来模拟,实现相同的效果。

通过事件可以方便解耦对象之间的依赖,用一个通俗点的说法就是:“你不要打电话给我,我会打电话给你!”。打电话首先需要话号码就是事件名称,说这句话的人就是EventTarget对象,听话的人就是递交电话号码(事件名)、接听电话的程序同学。

4. 小结

本篇介绍了PhysicsColliderNotification组件的实现,全是代码和逻辑,不能照顾到非程序员同学,还请包涵。

监听物理碰撞一定要开启刚体的enabledContactListener属性,在onBeginContact、onEndContact事件中获取刚体的位置以识别刚体的运行方向。同时使用cc.director.emit将事件、坐标点广播出去,在关心的地方做对应的逻辑处理。

目前源码已经合并到CreatorPrimer仓库主干,欢迎把玩,提出你的建议!
源码地址:https://github.com/ShawnZhang2015/CreatorPrimer


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存