笨木头  2014-09-25 21:46     Cocos Code IDE     阅读(24906)     评论(12)
转载请注明,原文地址: http://www.benmutou.com/archives/1844
文章来源:笨木头与游戏开发
 

这次要来说一个吹水的话题,关于性能方面,最近在用Cocos2d-x + Lua写一个小游戏,因为实在太简单,就完全没想过会有什么掉帧的情况。

结果一到手机上运行,在关卡场景里的帧率立刻降低了,大概只有16到30帧,这个帧率对这个游戏来说,实在是有点可怕。

 

找了一下原因,凶手是某个update函数,因为每帧都要调用,遍历200到400个对象,主要是做碰撞检测,就在这里帧率下降了一半。

优化也很简单,把当前不在屏幕范围的对象都忽略碰撞就好了。

可奇怪的是,帧数还是不够高,于是,我发现了一个小问题...

 
来自未来的PS:

  今天收到偶尔e网事发来的贺电,才知道这不是lua binding的性能缺陷,而是Cocos Code IDE的bug~!

我想了这么个奇葩的解决方案、还花了这么多时间写这篇文章,原来都是假的!只是一个Bug而已。

  没关系,我已经醉了。

  这个Bug会引起debug模式下效率问题,下个版本的Cocos Code IDE会解决。

  以下的文章正文内容,大家就随意看看吧,关于lua binding的观点是错误的,就当娱乐吧~

By 木头 2014.09.29 10:53
 

 

1.那些Lua-binding

我们都知道,Cocos2d-x的API大部分都绑定到lua里了,可以直接使用。

而我的问题就出在这里了,通过lua去调用c++,这之间的损耗我没有去研究过。

但有一点,这之间的损耗比直接调用lua里的table大多了。

 

我们来看看这样一个测试吧:
[cce_lua]
    -- 随便创建500个Node
    local nodes = {};
    for i = 1, 500 do
        nodes[i] = cc.Node:create();
        layerMenu:addChild(nodes[i]);
    end

  -- 注册update函数   self:scheduleUpdateWithPriorityLua(function(dt)   local pos = nil;   local size = nil;     -- 遍历所有节点,仅仅是进行了获取坐标和大小的操作   for index, node in pairs(nodes) do   pos = node:getPosition();   size = node:getContentSize();   end   end, 0); [/cce_lua]
这段代码是在一个Layer里的,模拟的就是我游戏里的情况(当然,这里简化了很多)。

创建了500个Node节点,然后在update函数里遍历这些节点,取出它们的坐标和大小,就这么简单的操作。

 

然而,如果在电脑上用调试模式(这样才更接近手机环境)运行游戏,帧数是这样的:

 

cocos2dxluabinding1

虽然电脑的数据不能说明什么,但是,我移植到手机上的情况也是不容乐观的,帧数也很低。

经过测试,造成帧数低的凶手就是getPosition和getContentSize函数,是的,我完全没有想过竟然是它们T_T,我是如此的信任...

 

2.简单的处理,让帧数飞回来

当然,我这代码每帧都要执行,所以才这么损耗帧数,但从另一个角度来说,我无法接受凶手竟然是两个不起眼的函数。

所以,我要解决它。

 

看如下代码:
[cce_lua]
    -- 随便创建500个Node
    local nodes = {};
    for i = 1, 500 do
        nodes[i] = cc.Node:create();
        nodes[i].pos = cc.p(100, 200 * i);
        nodes[i].size = nodes[i]:getContentSize();
        layerMenu:addChild(nodes[i]);
    end

  -- 注册update函数   self:scheduleUpdateWithPriorityLua(function(dt)   local pos = nil;   local size = nil;     -- 遍历所有节点,仅仅是进行了获取坐标和大小的操作   for index, node in pairs(nodes) do   pos = node.pos;   size = node.size;   end   end, 0); [/cce_lua]
注意,我只是改动了一点点,在创建Node节点的时候,我使用pos和size字段将节点的坐标和大小预先保存起来了。

接着,在遍历节点坐标和大小时,就仅仅是从table中取值了。

结果,帧数的情况如下:

cocos2dxluabinding2

怎么样,这变化实在是太大了。

 

3.一些小麻烦

不管怎么说,我这次的优化算是建立在一个奇怪的基础上?

又或许是我这个游戏实在是太简单了(逻辑上),仅仅只有碰撞检测和一些简单的碰撞处理。

我也想过,不要每帧都这么遍历一次,可以间隔一小段时间进行遍历。

但又觉得,还是每一帧都遍历比较好,避免造成其他的bug。

 

由于我这游戏里参与碰撞检测的对象基本上是不会动的,也基本不会改变大小,所以把坐标和大小这么特殊处理,也不会造成管理上的麻烦。

并且,只是针对特定的对象才进行这些处理。

 

另外,经过这么处理之后,我这游戏即使在跑分8000的安卓机器上,也能基本维持58帧/s了。

 

当然,缺点呢?这么处理的话,就要自己另外处理对象的坐标和大小属性了,不能使用原来的getPosition、setPosition之类的。

关于这些的细节处理,我就不多说了,如果你也希望这么处理的话,可以给我留言~我再简单说说实现的思路,其实很简单的。

 

总而言之,我的目的只是,想表达一下我的惊讶——竟然是getPosition成为了我这游戏的性能障碍。

 

4.结束

今天的文章可能写得比较死板、难懂,这是因为我最近有点累,也好多天没写文章了。

嗯,就这样吧。

 

 

 
12 条评论
  • 哈六    2019-09-05 11:24:47

    我也就试试能不能评论
    回复
  • 余再延    2015-12-07 10:19:46

    scheduleUpdateWithPriorityLua如何暂停
    回复
    • 糟糕_树叶的mut    2015-12-07 12:20:09

      暂时我都用bool变量的,自己加if判断,暂停就是直接return。
      回复
  • 爆笑内涵囧图    2015-10-24 02:29:31

    路过看一下!
    回复
  • Super_捞bi_    2015-09-17 10:55:22

    已被坑
    回复
  • lxl    2015-05-25 17:33:46

    不用Cocos Code IDE 跑游戏,还是会有性能问题啊?
    回复
    • 糟糕_树叶的mut    2015-05-25 21:23:57

      性能问题到哪都有,也不能全靠引擎
      回复
  • 魔蝎少    2014-11-02 21:15:53

  • 偶尔e网事    2014-09-29 10:28:29

    木头,你用的是Cocos Code IDE?
    回复
    • 糟糕_树叶的mut    2014-09-29 11:00:08

      还有多少坑,尽管来。。。我都给你踩了~
      回复
      • 偶尔e网事    2014-09-29 11:48:24

        世上本没有坑,趟的人多了,也便成了坑
        回复
        • 糟糕_树叶的mut    2014-09-29 12:24:07

发表评论
粤ICP备16043700号

本博客基于 BlazorAnt Design Blazor 开发