0

几个月前制作了这个 2D 水演示(http://nauful.com/Qasim/Pani.html),它有一个名为 waveHandler 的核心渲染函数,它经常被调用(ENTER_FRAME)。

这里有一堆图像处理置换贴图/卷积的东西,但这并不重要。我想修改这个 waveHandler 函数中发生的事情,但我不想在这里有一个不断运行的 IF 语句。例如,这种虚假的后期处理绽放/反射率的东西往往会在旧机器上陷入困境(按〜显示FPS计数器),我希望有一个启用/禁用它的选项,而无需IF 语句不断检查一些布尔变量的值。

在我的脑海中,一种非常不优雅和冗长的方法是让 waveHandler 的多个版本处理这些选项的排列,然后删除一个版本的侦听器并启用另一个版本。但是我该如何正确地做到这一点?

另外,是否可以让变量“指向”函数?因此,如果 var asdf:Function 一次指向一个函数,然后将 asdf 的值更改为指向另一个函数,则主函数可以调用 asdf 指向的任何函数,而无需不断检查条件语句。

谢谢!

4

2 回答 2

0

后者当然是可能的,但您不能将该变量放入 addEventListener 调用中。但是,你可以这样做:

function onEnterFrame(e:Event):void {
    if (asdf) asdf();
}

并将您的 asdf 变量设置为指向正确的函数。但是请注意,您不应该对参数集中不统一的函数使用这种方法,比如一个函数有一个 int 参数,另一个有零个参数 - 这会引发异常。

但是鉴于您的条件,我会使用布尔 if 语句,因为检查一次布尔值甚至比通过变量调用函数更便宜。

于 2012-10-14T04:58:05.057 回答
0

最快的将是您建议的那个:对于每个选项排列都有一个 waveHandler 。启用选项时最快,禁用选项时最快。

您自己建议的另一种方法:引用函数并更改引用以启用或禁用选项。我们可以通过将引用更改为指向一个空函数来“禁用”。像这样的东西:

package {
    import flash.display.Sprite;
    import flash.utils.getTimer;

    public class Main extends Sprite {
        private var call1: Function;
        private var call2: Function;
        private var call3: Function;

        public function Main() : void {
            var doOption1 : Boolean = true;
            var doOption2 : Boolean = false;
            var doOption3 : Boolean = true;

            call1 = doOption1 ? option1 : empty;
            call2 = doOption2 ? option2 : empty;
            call3 = doOption3 ? option3 : empty;

            onEnterFrame();
        }

        private function onEnterFrame():void {
            call1();
            call2();
            call3();
        }

        private function option1():void {
            trace("option1");
        }

        private function option2():void {
            trace("option2");
        }

        private function option3():void {
            trace("option3");
        }

        private function empty():void {
        }
    }
}

启用选项时,这不会给您带来任何性能损失,但是与第一个解决方案相比,禁用选项时您会受到惩罚,因为您正在调用一个空函数,因此您得到的开销很小。

我知道整个问题可能更像是一种学术类型,而且您已经知道它不会真正对性能产生任何明显的影响。

但是,从性能的角度来看,您似乎认为 if 情况比实际情况更糟。我会坚持使用它们(因为它们会产生非常可读的代码)并专注于优化代码的某些部分,以便产生衡量的影响。

我只是做了一个简单的测试,让您了解一些布尔检查是多么微不足道。我有两个不同的 onEnterFrame 函数。两者都调用了一个空函数十次。第一个是“普通的”(只有十个连续的电话)。另一个在每次调用该方法之前检查标志是否为真。

在我相当标准的笔记本电脑上,第一个结果是这样的:

普通:3133 毫秒
使用 if 检查:3167 毫秒
1000000 次 onEnterFrame 调用的
差异:34 毫秒每次 onEnterFrame 调用的差异:0.000034 毫秒

差异是如此之小,以至于即使您进行一百万次调用也很难衡量(在第一次运行后的某些测试运行中,带有if 检查的版本实际上更快)。

这只是一种冗长的说法,当涉及到优化时,你真的应该采取更科学的方法,否则你最终会花费大量时间尝试进行优化,而最终只会让代码更难阅读和维护速度几乎没有提高。在这里做过:-)

最后,如果您想自己运行它,这里是测试:

package {
    import flash.display.Sprite;
    import flash.utils.getTimer;

    public class Main extends Sprite {
        private var m_flag: Boolean = true;

        public function Main() : void {
            var callCount : int = 1000000, time1 : int, time2 : int, i : int;

            i = callCount;
            time1 = getTimer();
            while (i-- > 0) {
                onEnterFrame1();
            }
            time1 = (getTimer() - time1);

            i = callCount;
            time2 = getTimer();
            while (i-- > 0) {
                onEnterFrame2();
            }
            time2 = (getTimer() - time2);

            trace("Plain: " + time1 + " ms");
            trace("With if checks: " + time2 + " ms");
            trace("Difference for " + callCount + " onEnterFrame calls: " + (time2 - time1) + " ms");
            trace("Difference per onEnterFrame call:  " + ((time2 - time1) / callCount) + " ms");
        }

        private function onEnterFrame1():void {
            emptyMethod();
            emptyMethod();
            emptyMethod();
            emptyMethod();
            emptyMethod();
            emptyMethod();
            emptyMethod();
            emptyMethod();
            emptyMethod();
            emptyMethod();
        }

        private function onEnterFrame2():void {
            if (m_flag) emptyMethod();
            if (m_flag) emptyMethod();
            if (m_flag) emptyMethod();
            if (m_flag) emptyMethod();
            if (m_flag) emptyMethod();
            if (m_flag) emptyMethod();
            if (m_flag) emptyMethod();
            if (m_flag) emptyMethod();
            if (m_flag) emptyMethod();
            if (m_flag) emptyMethod();
        }

        private function emptyMethod():void {
        }
    }
}
于 2012-10-14T10:02:09.010 回答