繁体   English   中英

如何提高此功能的性能?

[英]How to improve performance in this function?

我有一个“弹跳球”项目,我在画布上绘制150个粒子,并且在每次重绘时,它都会重新计算粒子的位置,并验证是否有任何粒子在拐角处,以反转其迭代器。

但事实是,该项目具有并非所有“弹跳球”项目都具有的因素。 球需要在地图范围内反弹。

因此,当我创建画布时,我还使用SVG遍历像素并创建x轴左右两侧的每个边界的数组,因此我的粒子将确切知道它们需要重新反弹的位置。

很好,很好,它工作得很好,但是我的画布是500px高,因此它需要进行500次迭代,并带有很多防止怪异行为的条件,该条件乘以150个粒子,并且每次重绘。

它变得非常贪婪,我需要提高性能,所以这是我的碰撞系统代码

const colisionSystem = state => {
  for (var b=0, hs=state.bounds.length; b<hs; b++) {
    if(
      state.bounds[b][0]
      && state.x - state.radius < state.bounds[b][0].x
      && state.y + state.radius > state.bounds[b][0].y
      && state.y - state.radius < state.bounds[b][0].y
    ) {
      if (
        state.bounds[b][0].x > 0
        && state.bounds[b][0].x < (state.widgetSize.width * 0.33)
        && state.bounds[b][0].y > (state.widgetSize.height * 0.33)
        && state.bounds[b][0].y < (state.widgetSize.width * 0.45)
      ) {
        // middle left bottom corner at acre
        state.x = state.radius + state.bounds[b][0].x;
        state.vy *= -1;
      } else if (
        state.bounds[b][0].x > 0
        && state.bounds[b][0].x < (state.widgetSize.width * 0.098)
        && state.bounds[b][0].y > (state.widgetSize.height * 0.167)
        && state.bounds[b][0].y < (state.widgetSize.width * 0.206)
      ) {
        // middle left top corner at acre
        state.y = state.radius + state.bounds[b][0].y + 1;
        state.vx *= -1;
        state.vy *= -1;
      } else {
        state.x = state.radius + state.bounds[b][0].x;
        state.vx *= -1;
      }

      if(state.oldAxis === state.x) {
        state.y = state.y - 1;
      } else {
        state.oldAxis = state.x;
      }

      state.antiRebounce = false;
    }
    if(
      state.bounds[b][1]
      && state.x + state.radius > state.bounds[b][1].x
      && state.y + state.radius > state.bounds[b][1].y
      && state.y - state.radius < state.bounds[b][1].y
    ) {
      if (
        state.bounds[b][1].x > (state.widgetSize.width * 0.555)
        && state.bounds[b][1].x < (state.widgetSize.width * 0.983)
        && state.bounds[b][1].y > 0
        && state.bounds[b][1].y < (state.widgetSize.width * 0.2098)
      ) {
        // Top right corner
        if(state.antiRebounce) {
          state.vy *= -1;
          state.antiRebounce = false;
        } else {
          state.antiRebounce = true;
        }
        state.y = state.bounds[b][1].y + state.radius + 1;
        state.vy *= -1;
      }
      if (
        state.bounds[b][1].x > (state.widgetSize.width * 0.604)
        && state.bounds[b][1].x < (state.widgetSize.width * 0.827)
        && state.bounds[b][1].y > (state.widgetSize.width * 0.665)
        && state.bounds[b][1].y < (state.widgetSize.width * 0.778)
      ) {
        // bottom right corner
        state.vy *= -1;
      } else {
        state.vx *= -1;
        state.x = state.bounds[b][1].x - state.radius;
      }

      if(state.oldAxis === state.x) {
        state.y = state.y - 1;
      } else {
        state.oldAxis = state.x;
      }
    }
  }

  if (state.y + state.radius > state.widgetSize.height) {
    state.vy *= -1;
    state.y = state.widgetSize.height - state.radius;
  }
  if (state.y - state.radius < 0) {
    state.vy *= -1;
    state.y = state.radius;
  }

  return state;
}

export default colisionSystem;

因此,问题是,是否有任何实用建议来改进此代码本身?

您有500 * 150粒子(750000),这对于JS应用程序来说实在太多了,坦白说太多了。 (但是您说了150个粒子,所以我对您的工作感到困惑)

为了提高所提供功能的性能,您可以使用一些简单的经验法则。

数组查找比直接引用慢。

// a compound referance
state.bounds[b][1].x // find state, then bounds, then index b, then 1,then x
// if you have the common parts used frequently
var b1 = state.bounds[b][1]; // does all the lookups
b1.x; // but now only needs one lookup to get x

项目属性也是如此。 每个. 表示额外的查询。 通过创建临时变量来保存所有查找的结果,您可以获得很多额外的性能。

将其应用到您的代码中,您将获得

const colisionSystem = state => {
    var w = state.widgetSize.width;  // used many times in the loop
    var h = state.widgetSize.height;
    var x = state.x;
    var y = state.y;
    var r = state.radius;
    for (var b = 0, hs = state.bounds.length; b < hs; b++) {
        var bounds = state.bounds[b];        
        if (bounds[0]){
            var b0 = bounds[0];
            if( x - r < b0.x && y + r > b0.y && y - r < b0.y) {
                if ( b0.x > 0 && b0.x < (w * 0.33) && b0.y > (h * 0.33) && b0.y < (w * 0.45)) {                    
                    x = r + b0.x; // middle left bottom corner at acre
                    state.vy *= -1;
                } else if ( b0.x > 0 && b0.x < (w * 0.098) && b0.y > (h * 0.167) && b0.y < (w * 0.206)) {                   
                    y = r + b0.y + 1; // middle left top corner at acre
                    state.vx *= -1;
                    state.vy *= -1;
                } else {
                    x = r + b0.x;
                    state.vx *= -1;
                }
                if (state.oldAxis === x) {
                    y -= 1;
                } else {
                    state.oldAxis = x;
                }
                state.antiRebounce = false;
            }
        }
        if (bounds[1]){
            var b1 = bounds[1];
            if( x + r > b1.x && y + r > b1.y && y - r < b1.y) {
                if ( b1.x > (w * 0.555) && b1.x < (w * 0.983) && b1.y > 0 && b1.y < (w * 0.2098)) {                        
                    if (state.antiRebounce) { // Top right corner
                        state.vy *= -1;
                        state.antiRebounce = false;
                    } else {
                        state.antiRebounce = true;
                    }
                    y = b1.y + r + 1;
                    state.vy *= -1;
                }
                if (b1.x > (w * 0.604) && b1.x < (w * 0.827) && b1.y > (w * 0.665) && b1.y < (w * 0.778)) {                    
                    state.vy *= -1; // bottom right corner
                } else {
                    state.vx *= -1;
                    x = b1.x - r;
                }
                if (state.oldAxis === x) {
                    y = y - 1;
                } else {
                    state.oldAxis = x;
                }
            }
        }
    }
    if (y + r > h) {
        state.vy *= -1;
        y = h - r;
    } else if (y - r < 0) {  // added else. Cant both happen at the same time?????
        state.vy *= -1;
        y = r;
    }
    state.y = y; // set state x,y to reflect any changes.
    state.x = x; 

    return state;
}

通过用直接引用替换许多复合引用,您可以节省大量CPU时间,但这取决于数据。 如果上面的代码花了更多时间尽早拒绝条件语句,那么您将不会获得太多好处,并且如果仅对一次colisionSystem的调用传递了bounds [1],bounds [0]条件,您将不会获得任何好处,也许性能略有下降。 对于循环中的项目数也是如此,如果循环迭代许多项目,您将看到改善;如果循环仅1或2个项目,您将看不到任何好处;对于一项,您将看到性能下降。

注意,我不小心重构,上面的代码中可能有一些错别字,仅是示例。

您说您使用SVG进行迭代???

我还使用SVG遍历像素

经验法则#2。 DOM很慢,SVG是DOM的一部分,在我的书中SVG实际上是VSG(非常慢的图形),我想说,减速的主要部分在于您对SVG所做的一切。

建议:

  • 这个函数做的太多了,考虑将其分解,以便像这样的表达式

      state.bounds[b][1].x > (state.widgetSize.width * 0.604) && state.bounds[b][1].x < (state.widgetSize.width * 0.827) && state.bounds[b][1].y > (state.widgetSize.width * 0.665) && state.bounds[b][1].y < (state.widgetSize.width * 0.778) 

    是自己的功能

  • 考虑使用_.map而不是for循环,无论如何您都处于返回state ,因此_.map更具语义。

  • 考虑将if s与函数的嵌套分开。 每次使用代码注释时,请考虑使其成为函数。 例如

     // Top right corner if(state.antiRebounce) { state.vy *= -1; state.antiRebounce = false; } else { state.antiRebounce = true; } state.y = state.bounds[b][1].y + state.radius + 1; state.vy *= -1; 

    可能

     const topRightCorner = (state) => { if(state.antiRebounce) { state.vy *= -1; state.antiRebounce = false; } else { state.antiRebounce = true; } state.y = state.bounds[b][1].y + state.radius + 1; state.vy *= -1; return state; } 

一旦将这个巨大的功能分解为许多更易于理解的较小功能。 您可以使用chrome性能分析工具来查找性能瓶颈。

https://developers.google.com/web/tools/chrome-devtools/rendering-tools/

随着代码的分解,可以很容易地看到脚本的哪一部分受到性能问题的影响,此时,您可以了解如何解决问题,而无需进行过早的优化。

据我所知(但我所不知道的太多),您的情况并没有给我们太多的操作空间,因为您需要始终在屏幕上“看到”所有反弹的物体。 边界系统对我来说似乎更好,可以在更精确的点碰撞检测之前检查边界。 您要渲染多少fps? 我想也许可以调整一些东西。 再见

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM