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

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

通用物理组件

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

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

物理引擎管理器.png
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


如果觉得公众号上的文章对您或您身边的朋友有帮助,请分享给他,愿我们一起成长!

奎特尔星球

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章