[CocosCreator]记一次H5项目的物理优化

前言

项目是一款2D横版酷跑项目。用到了CocosCreator自带的2D物理组件。涉及到射线检测,碰撞检测。

游戏的逻辑是启动后会初始化一定数量小物件,放到缓冲池中。需要的时候根据配置表来组装成场景。
比如:路面(表面带Collider,用于和玩家检测碰撞,防止玩家持续下落)。房子(房顶有Collider,玩家可以射出一个钩子,勾中房顶,玩家会有荡秋千的效果)等等。

问题描述

在PC浏览器上运行一切OK,发布到手机浏览器上就开始卡了。微信上就更卡了。

问题原因

在文章:[CocosCreator]性能优化中,笔者提到了CC的物理系统比较坑的问题。特别是jit原因导致在ios微信小游戏上比较卡。
但是本项目,笔者在分析源码后,从代码层找到一个严重影响性能的原因。

前文中提到了游戏的大概逻辑,所以就涉及到大量对物体设置显示、隐藏的操作。本身在CC中对物体执行这种操作据官方说就相对耗。
这都不是重点。看下文:
cocos2d-js.js大概11422行,代码如下

      onDisable: function() {
        cc.director.getCollisionManager().removeCollider(this);
      },
      onEnable: function() {
        cc.director.getCollisionManager().addCollider(this);
      }

解读:每个附着物理组件的物体,在onEnable会被添加到系统的碰撞管理器中,在onDisable时会被移除。
再看addCollider和removeCollider的实现(大概cocos2d-js.js的11614行):

      addCollider: function(collider) {
        var colliders = this._colliders;
        var index = colliders.indexOf(collider);
        if (-1 === index) {
          for (var i = 0, l = colliders.length; i < l; i++) {
            var other = colliders[i];
            if (this.shouldCollide(collider, other)) {
              var contact = new Contact(collider, other);
              this._contacts.push(contact);
            }
          }
          colliders.push(collider);
          this.initCollider(collider);
        }
        collider.node.on(NodeEvent.GROUP_CHANGED, this.onNodeGroupChanged, this);
      },
      removeCollider: function(collider) {
        var colliders = this._colliders;
        var index = colliders.indexOf(collider);
        if (index >= 0) {
          colliders.splice(index, 1);
          var contacts = this._contacts;
          for (var i = contacts.length - 1; i >= 0; i--) {
            var contact = contacts[i];
            if (contact.collider1 === collider || contact.collider2 === collider) {
              contact.touching && this._doCollide(CollisionType.CollisionExit, contact);
              contacts.splice(i, 1);
            }
          }
          collider.node.off(NodeEvent.GROUP_CHANGED, this.onNodeGroupChanged, this);
        } else cc.errorID(6600);
      }

这就显而易见了。物体在显示的时候会往碰撞管理器添加碰撞信息,物体隐藏的时候会把碰撞信息移除。我们的游戏有大量的显示、隐藏操作。导致这部分代码(addCollider、removeCollider代码本身就有大量循环、比较)被大量执行。性能不低才怪。

解决方案

改造cocos2d-js.js文件
1,改造onDisable函数

        onDisable: function() {
            if (this.name.search("coin") != -1 || this.name.search("road") != -1 || this.name.search("tower") != -1) {
                return;
            }            
            cc.director.getCollisionManager().removeCollider(this);
        }

对于特定类型的物体,在onDisable的时候不再移除Collider。

2,改造onEnable函数

        onEnable: function() {            
            var colliders = cc.director.getCollisionManager()._colliders;
            var isExist = false;
            for (i = 0, l = colliders.length; i < l; i++) {
                if (colliders[i].name == this.name) {
                    isExist = true;
                    break;
                }
            }
            if (isExist == false) {             
                cc.director.getCollisionManager().addCollider(this);
            }
        }

已经存在于碰撞管理器中的物体,不再添加。
3,增加一个清空碰撞的函数
大概在11470行CollisionManager的构造函数下面加一个函数

        RemoveAllColliders: function() {
            this._colliders = [];
            this._contacts = [];
        }

游戏在合适的时候调用cc.director.getCollisionManager().RemoveAllColliders();

4,改造在CollisionManager update
大概11472行的update方法第一行时候加上一句
if(this._colliders.length==0) return;

经过以上改造,可以大大缓解我们游戏中的性能开销。

发布了198 篇原创文章 · 获赞 23 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/iningwei/article/details/100279109