我有一种“弹跳球”项目,我在画布上绘制150个粒子,在每次重绘时,它都会重新计算粒子的位置,并验证是否有任何粒子在角落,以反转其迭代器。
但事实是,这个项目有一个并非所有“弹跳球”项目都有的因素。球需要在地图的范围内反弹。
因此,当我创建画布时,我还使用SVG迭代像素并创建x轴中左右各个边界的数组,这样我的粒子就能准确知道它们需要反弹的位置。 / p>
很好,很好,它工作得很好,但我的画布是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;
所以,问题是,有没有任何实用的建议来改进这个代码本身?
答案 0 :(得分:1)
你有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]条件,你将得到no好处,可能会略微降低性能。同样适用于循环中的项目数,如果循环迭代许多项目,您将看到改进,如果循环只有1或2项,您将看不到任何好处,对于一个项目,您将看到性能下降
注意,我不小心重构,上面的代码中可能有一些拼写错误,只是一个例子。
你说你用SVG迭代???
经验法则#2。 DOM很慢,SVG是DOM的一部分,在我的书中,SVG实际上是VSG(非常慢的图形),我想说减速的主要部分在于你使用SVG做的任何事情。我还使用SVG迭代像素
答案 1 :(得分:0)
建议:
这个函数做得太多了,考虑将其分解为这样的表达式
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/
随着代码的分解,很容易看出脚本的哪个部分遇到了性能问题,此时您可以看到如何修复,而无需进行预先成熟的优化。
答案 2 :(得分:0)
据我所知(但我不太了解)你的情况并没有给我们太多的manovre空间,因为你需要&#34;看到&#34;总是在屏幕上弹出所有物体。在更准确的点碰撞检测之前,绑定系统似乎对我检查边界很有用。 你要渲染多少个fps?我想也许可以调整一些东西。 再见