Vejis 开发笔记 2010.8.17

Version: 0.0.0.4

昨天做的东西比较多, 有大致有cookie的操作, 简单的get和post, json.

cookie的操作目前有1个集合, 5种方法共8次重载. (vejis的重载是我的大爱啊!) 简单操作的例子.

vejis.use(vejis, true); //使用vejis命名空间.

cookies.set(‘name’, ‘Vilic’); //添加名称为name的cookie, 值为’Vilic’.
cookies.set([‘age’, ‘sex’], [’17’, ‘male’]); //批量添加.

alert(cookies[‘name’]);

cookies.del(‘name’); //删除名称为name的cookie.

alert(cookies[‘name’]);

然后是xmlhttp, 做得比较简单, 够我用就好了:

vejis.use(vejis, true);

var data = new xmlhttp.Data();
data.title = ‘This is a test!’;
data.content = ‘Hello, I\’m Vilic!’;

var callback = _(Boolean, String, Number, function (done, text, status) {
    alert(‘Done:\n’ + done + ‘\nText:\n’ + text + ‘\nStatus:\n’ + status);
});

var xhr = xmlhttp.post(‘sample.ashx’, data, callback);

最后是json, 这个我只做了post带callback的, 因为一般不会用get来传递json.

vejis.use(vejis, true);

var callback = _(Boolean, Object, Number, function (done, value, status) {
    alert(JSON.stringify(value));
});

var obj = { name: ‘Vilic’, age: 18, hobbies: [‘Physics’, ‘JavaScript’, ‘Drawing’] };

json.post(‘sample.ashx’, ‘json’, obj, callback);

现在文件已经有500多行了, 虽然与一些专业的框架还相距甚远. 呵呵, 比不得. 顺便昨天七夕, 我跟代码从早到晚都在一起…

Vejis 开发笔记 2010.8.16

Version: 0.0.0.3

再次改进了重载算法. 然后开始各种杂项的开发, 比如string, array命名空间. 其中部分有enhance方法, 用于加强相应的原型.

之前创建可重载的函数时, 是通过函数内部创建之后return的. 但是一直想使用类似new的方法. 今天也算巩固了下之前很久听说过的一个知识:

function Test() {
    return fn;
    function fn() {
        alert(‘Test OK!’);
    }
}

var test = new Test();
test();

你认为上面的代码能弹出 “Test OK!” 吗? 答案是可以的. 但是这个时候, test instanceof Text == false. 也就是说, test此时并非Test的实例, 而是一个function(){}.

在vejis里, 虽然我最终用类似的方法实现了new Method的操作, 但得到的方法也并非Method的实例:

vejis.use(vejis, true); //使用vejis命名空间, 并且覆盖已有的方法和属性.

var test = new Method(); //创建一个可重载的方法.
test.overload(function(){ //添加一个无参数的重载.
    alert(‘Test’);
});

test(); //执行test方法.
alert(test instanceof Method); //结果是false;

另外还有包含了JSON2.js文件, 准备起床之后实现简单的AJAX函数, 我看着JQuery的, 头晕啊. 太有跳跃性了. 没打算做得它那么全, 满足我日常使用即可.

Vejis 开发笔记 2010.8.15

Version: 0.0.0.2

更改了函数重载的实现, 将原来的字符串变成了类, 扩展性更强. 见下面的MyClass.

vejis.use(vejis, true);

var test = _();

test._(Integer, function (n) {
    alert(‘Integer: ‘ + n);
});

test._(MyClass, function (obj) {
    obj.alert();
});

var obj = new MyClass();
test(18);
test(obj);

function MyClass() {
    this.alert = function () {
        alert(‘It\’s a new Class!’);
    };
}

Vejis 开发笔记 2010.8.14

Version: 0.0.0.1

选择的是BSD协议. 现在有接近200行了. 主要功能是createFunction. 下面来一段演示的代码:

vejis.use(vejis, true);

var test = createFunction();

test._(‘string’, function (name) {
    alert(‘name: ‘ + name);
});

test._(‘int’, function (age) {
   alert(‘age: ‘ + age);
});

呵呵, 看出来了吧, 函数重载. 不过在这个简单的例子上, 你可能觉得有点多余, 看看这个, 这个是vejis里的一个函数, 有4个重载:

var argsCountError = this.argsCountError = createFunction();

argsCountError._(‘integer’, function (count) {
   if (arguments.callee._caller.arguments.length != count)
      error(‘The method needs ‘ + count + ‘ argument’ + (count > 1 ? ‘s.’ : ‘.’));
});

argsCountError._(‘integer, integer’, function (least, most) {
   if (least >= most) error(‘”least” must be smaller than “most”‘);
   var count = arguments.callee._caller.arguments.length;
   if (count < least) error(‘The method needs at least ‘ + least + ‘ argument’ + (least > 1 ? ‘s.’ : ‘.’));
   if (count > most) error(‘The method needs at most ‘ + most + ‘ argument’ + (most > 1 ? ‘s.’ : ‘.’));
});

argsCountError._(‘null, integer’, function (least, most) {
   arguments = arguments.callee._caller.arguments;
   least = 0;
   argsCountError(least, most);
});

argsCountError._(‘integer, null’, function (least, most) {
   arguments = arguments.callee._caller.arguments;
   most = 25;
   argsCountError(least, most);
});

目前为止, 变量类型支持string, number, number:integer, boolean, object, object:array, object:null, function, 考虑到不同人的习惯, integer和boolean分别可以简写作int和bool. 个人觉得在函数重载很多, 而调用次数不多(其实只要不是大数量的枚举, 遍历什么的, 都不算多)时, 这个功能是非常实用的.

另外vejis.use(namespace, overwrite)也是个比较实用的东西, 虽然目前功能还非常简单, 但以后会慢慢增强.

其他的很弱, 也没什么特色了. 慢慢来.

圆形碰撞算法 封装类

昨天群里有朋友问到, 顺便发下. FTP连不上, 我直接贴代码得了.

FTP弄好了, Demo地址 http://www.vilic.info/demo/collide/

沙发同学Lin.x爆料地下的代码部分半角被替换成了全角, 会报错. 如果需要代码的话, 打开Demo自己另存为吧.

groinup.js

/*
圆形碰撞算法
www.vilic.info
by Vilic Vane
©2010 Groinup
*/
var groinup = new function () {

    var array = this.array = new function () {
        this.clear = function (aimArray) {
            aimArray.length = 0;
        };

        this.remove = function (item, arr) {
            var i;
            for (i in arr)
                if (arr[i] == item)
                    arr.splice(i, 1);
        };

        this.addUnique = function (item, arr) {
            var found = false;
            var i;
            for (i in arr)
                if (arr[i] == item) {
                    found = true;
                    break;
                }
            if (!found) arr.push(item);
        };
    };

    var object = this.object = new function () {
        this.copy = function (obj) {
            var newObj = {};
            var i;
            for (i in obj)
                newObj[i] = obj[i];
            return newObj;
        };
    } ();

    var math = this.math = new function () {
        var sqr = this.sqr = function (n) { return n * n; };
        var sqrt = this.sqrt = function (n) { return Math.sqrt(n); };

        var modulus = this.modulus = function (a1, a2) {
            var x1 = a1.x;
            var y1 = a1.y;
            var x2 = a2.x;
            var y2 = a2.y;

            return (x1 * x2 + y1 * y2) / sqrt((sqr(x1) + sqr(y1)) * (sqr(x2) + sqr(y2)));
        };

        var point = this.point = new function () {
            var getDistance = this.getDistance = function (pos1, pos2) {
                return sqrt(sqr(pos1.x – pos2.x) + sqr(pos1.y – pos2.y));
            };
        } ();

        var circle = this.circle = new function () {
            this.getDistance = function (pos1, pos2, r1, r2) { return point.getDistance(pos1, pos2) – r1 – r2; };
        };

        var Position = this.Position = function (x, y) {
            this.x = x;
            this.y = y;
        };

    } ();

    var physics = this.physics = new function () {
        var sqr = math.sqr;
        var sqrt = math.sqrt;

        var getMovingDistance = this.getMovingDistance = function (v0, a, t) {
            return v0 * t + 0.5 * a * math.sqr(t);
        };

        var Velocity = this.Velocity = function (vx, vy) {
            this.x = vx;
            this.y = vy;
        };

        var Acceleration = this.Acceleration = function (ax, ay) {
            this.x = ax;
            this.y = ay;
        };
    } ();

    var collide = this.collide = new function () {

        //函数引用
        var sqr = math.sqr;
        var sqrt = math.sqrt;
        var modulus = math.modulus;

        var Circle = this.Circle = function (m, r, p, v, a, goFunc) {
            var _this = this;
            this.m = m;
            this.r = r;
            this.p = p;
            this.v = v;

            this.a = a || new physics.Acceleration(0, 0);
            a = this.a;

            var acTime = 0;
            this.resetAcTime = function () { acTime = 0; };
            this.onCollide = function () { };

            this.collideCallBack = function (p, c) {
                _this.onCollide(p, c);
            };

            this.onVelocityReverse = function () { };

            this.onSpeedUp = function () { };

            this._isOnSurface = false;

            if (goFunc)
                this.go = function (t) {
                    acTime += t;
                    if (goFunc(acTime) == false) go(t);
                };
            else
                this.go = go;

            function go(t) {
                var vx = v.x + a.x * t;
                var vy = v.y + a.y * t;

                var sqrVxy0 = sqr(v.x) + sqr(v.y);
                var sqrVxy = sqr(vx) + sqr(vy);

                p.x += (vx + v.x) / 2 * t;
                p.y += (vy + v.y) / 2 * t;

                v.x = vx;
                v.y = vy;

                if (sqrVxy >= sqrVxy0) _this.onSpeedUp();
            }
        };

        var Surface = this.Surface = function () {
            var kmax = sqrt(Number.MAX_VALUE) – 1;
            var circles = [];
            var isSearching = false;

            this.add = function (circle) {
                circle._isOnSurface = true;
                circles.push(circle);
            };

            this.remove = function (circle) {
                circle._isOnSurface = false;
                if (!isSearching) array.remove(circle, circles);
            };

            this.go = function (time, step) {
                collideSearch(time, step);
            };

            function collideSearch(time, step) {
                isSearching = true;

                var sAmt = Math.floor(time / step);
                for (var i = 0; i < sAmt; i++)
                    search();

                isSearching = false;

                function search() {
                    var i;

                    var removeList = [];

                    for (i in circles)
                        circles[i].go(step);

                    var getDis = math.circle.getDistance;
                    var len = circles.length;
                    for (var j = 0; j < len; j++) {
                        var c1 = circles[j];

                        //判断元素是否已经移除
                        if (!c1._isOnSurface) {
                            removeList.push(c1);
                            continue;
                        }
                        for (var k = j + 1; k < len; k++) {
                            var c2 = circles[k];

                            //判断元素是否已经移除
                            if (!c1._isOnSurface) {
                                removeList.push(c1);
                                break;
                            }
                            else
                                if (!c2._isOnSurface) {
                                    array.addUnique(c2, removeList);
                                    continue;
                                }

                            var d = getDis(c1.p, c2.p, c1.r, c2.r);
                            if (getDis(c1.p, c2.p, c1.r, c2.r) <= 0)
                                dealCollide(c1, c2);
                        }
                    }

                    //移除在搜索过程中被搁置的需要移除的项
                    for (i in removeList)
                        array.remove(removeList[i], circles);
                }

                function dealCollide(c1, c2) {
                    //获取相关数据
                    var p1 = c1.p, p2 = c2.p;
                    var v1 = c1.v, v2 = c2.v;
                    var m1 = c1.m, m2 = c2.m;
                    var x1 = p1.x, x2 = p2.x, y1 = p1.y, y2 = p2.y;
                    var vx1 = v1.x, vx2 = v2.x, vy1 = v1.y, vy2 = v2.y;

                    var a11 = { x: vx1, y: vy1 };
                    var a12 = { x: x2 – x1, y: y2 – y1 };
                    var a21 = { x: vx2, y: vy2 };
                    var a22 = { x: x1 – x2, y: y1 – y2 };

                    //计算两个圆圆心连线的斜率
                    var k;
                    var dx = x1 – x2;

                    //判断斜率是否存在
                    if (dx) k = (y1 – y2) / dx;
                    //如果不存在,则去尽可能大的值
                    else k = kmax;

                    //**速度分解

                    //*第一个圆
                    //圆心连线方向的分速度
                    var vox1 = apart(vx1, vy1);
                    var voy1 = vox1 * k;

                    //与连线方向垂直的分速度
                    var vpx1 = vx1 – vox1;
                    var vpy1 = vy1 – voy1;

                    //*第二个圆
                    //圆心连线方向的分速度
                    var vox2 = apart(vx2, vy2);
                    var voy2 = vox2 * k;

                    //与连线方向垂直的分速度
                    var vpx2 = vx2 – vox2;
                    var vpy2 = vy2 – voy2;

                    //碰撞后与连线方向垂直的分速度不变,连线方向的分速度变化
                    var vox1a = calculateV(m1, m2, vox1, vox2);
                    var vox2a = calculateV(m2, m1, vox2, vox1);

                    var voy1a = calculateV(m1, m2, voy1, voy2);
                    var voy2a = calculateV(m2, m1, voy2, voy1);

                    //重新复合速度
                    v1.x = vox1a + vpx1;
                    v1.y = voy1a + vpy1;
                    v2.x = vox2a + vpx2;
                    v2.y = voy2a + vpy2;

                    //告知动量变化量
                    var dp1 = sqrt(sqr(vox1a – vox1) + sqr(voy1a – voy1)) * m1;
                    var dp2 = sqrt(sqr(vox2a – vox2) + sqr(voy2a – voy2)) * m2;

                    c1.collideCallBack(dp1, c2);
                    c2.collideCallBack(dp2, c1);

                    //分解出与圆心连线方向的分速度的x方向速度
                    function apart(vx, vy) {
                        return (k * vy + vx) / (sqr(k) + 1);
                    }

                    //根据动量和能量守恒计算速度变化
                    function calculateV(m1, m2, v1, v2) {
                        return ((m1 – m2) * v1 + 2 * m2 * v2) / (m1 + m2);
                    }
                }
            }
        };
    } ();
}

index.html

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd“>

<html xmlns=”http://www.w3.org/1999/xhtml“>
<head>
    <title>碰撞类</title>
    <style type=”text/css”>
        #c1 { position: absolute; margin: -10px; width: 20px; height: 20px; background-color: Red; -webkit-border-radius: 10px; -moz-border-radius: 10px; -o-border-radius: 10px; }
        #c2 { position: absolute; margin: -15px; width: 30px; height: 30px; background-color: Blue; -webkit-border-radius: 15px; -moz-border-radius: 15px; -o-border-radius: 15px; }
        #c3 { position: absolute; margin: -6px; width: 12px; height: 12px; background-color: Green; -webkit-border-radius: 6px; -moz-border-radius: 6px; -o-border-radius: 6px; }
    </style>
    <script src=”groinup.js” type=”text/javascript”></script>
</head>
<body>
    <div id=”c1″></div>
    <div id=”c2″></div>
    <div id=”c3″></div>
</body>
<script type=”text/javascript”>
    //使用举例

    //获取元素
    var c1 = document.getElementById(‘c1’);
    var c2 = document.getElementById(‘c2’);
    var c3 = document.getElementById(‘c3’);

    //容器
    var surface = new groinup.collide.Surface();

    //定义碰撞的圆形, 参数依次为 质量, 半径, 位置, 速度, 加速度, 搜索过程中的回调函数
    var ci1 = new groinup.collide.Circle(10, 10, new groinup.math.Position(210, 200), new groinup.physics.Velocity(40, 10), 0, null);
    var ci2 = new groinup.collide.Circle(5, 15, new groinup.math.Position(400, 220), new groinup.physics.Velocity(-50, -10), 0, null);
    var ci3 = new groinup.collide.Circle(2, 6, new groinup.math.Position(100, 320), new groinup.physics.Velocity(60, -10), 0, null);

    //向容器中添加圆形
    surface.add(ci1);
    surface.add(ci2);
    surface.add(ci3);

    //控制运动
    var i = 0;
    var interval = setInterval(setPos, 30);

    function setPos() {
        if (i++ > 100) clearInterval(interval);

        //移动, 参数分别为移动的时间和单次搜索的时间(单次搜索的时间越短, 运动越精确)
        surface.go(0.05, 0.005);

        //设置位置
        sP(c1, ci1.p.x, ci1.p.y);
        sP(c2, ci2.p.x, ci2.p.y);
        sP(c3, ci3.p.x, ci3.p.y);

        function sP(o, x, y) {
            o.style.left = x + ‘px’;
            o.style.top = y + ‘px’;
        }
    }

</script>
</html>

通过重载原有函数实现取消所有Interval和Timeout的功能

今天凌晨写东西的时候遇到的问题, 因为用到setInterval和setTimeout的地方比较多, 懒得改, 便想到了通过重载来实现. 之前只用考虑Safari, 移植到IE之后还有些不一样.

测试了IE8和FF, 都正常. 其他的浏览器应该也没什么问题.

/*
通过重载原有函数实现取消所有Interval和Timeout的功能
请将这段代码放到脚本中靠前的位置, 并确保它在所有setInterval和setTimeout函数被使用之前被解释运行
Vilic Vane (www.vilic.info)
©2010 Groinup
*/
new function () {
    //备份原有函数
    var _setInterval = window.setInterval;
    var _setTimeout = window.setTimeout;
    var _clearInterval = window.clearInterval;
    var _clearTimeout = window.clearTimeout;

    //私有计时器列表
    var intervalList = [];
    var timeoutList = [];

    //重载setInterval
    window.setInterval = function (code, delay) {
        var id = _setInterval(code, delay);
        intervalList.push(id);
        return id;
    };

    //重载setTimeout
    window.setTimeout = function (code, delay) {
        var id = _setTimeout(code, delay);
        timeoutList.push(id);
        return id;
    };

    //重载clearInterval
    window.clearInterval = function (intervalID) {
        _clearInterval(intervalID);
        remove(intervalID, intervalList);
    };

    //重载setTimeout
    window.clearTimeout = function (timeoutID) {
        _clearTimeout(timeoutID);
        remove(timeoutID, timeoutList);
    };

    //添加clearAllInterval, 用于取消所有Interval
    window.clearAllInterval = function () {
        for (var i = 0; i < intervalList.length; i++)
            _clearInterval(intervalList[i]);
        intervalList.length = 0;
    };

    //添加clearAllTimeout, 用于取消所有Timeout
    window.clearAllTimeout = function () {
        for (var i = 0; i < timeoutList.length; i++)
            _clearTimeout(timeoutList[i]);
        timeoutList.length = 0;
    };

    //私有数组操作函数
    function remove(item, from) {
        for (var i = 0; i < from.length; i++)
            if (from[i] == item) {
                from.splice(i, 1);
                break;
            }
    }
} ();

JS混淆软件推荐

这次做的这个游戏,需要将代码混淆,到网上搜了一些混淆工具,有在线的,也有桌面的,不过多数都会害死我的JS,可能是因为我喜欢用一些特殊(其实也比较常见)的写法,而这些工具都还不够完善。

后来找到了JSA。JSA是jar应用,所以需要JAVA的环境。使用非常简单,将脚本复制到JSA的文本框,在顶部菜单栏选择“操作”>“压缩”,在弹出的窗口中设置好,确定即可。

下载地址:http://sourceforge.net/projects/jsintegration/files/

注意下载的时候选择All Files下方tools中的JSA而不是上面的JSI。

JS圆形碰撞算法的探讨及实现

也是做同一个东西,碰撞是又一个关键,受限于JS的执行速度,我们必须考虑CPU的承受能力。因为有这个想法,我一开始的思路是通过数学计算得到一个式子,用于求碰撞的位置,但是,当我假设运动是匀速直线时,得出来的是一个以时间t为未知数的一元四次方程,能解,但是很长很悲壮。更不要说匀加速运动了。

现在连续的数学方法走不通,就只有搜索,因为最终会表现到网页上物体位置的变化,而这个过程会消耗大量的资源,如果让搜索密度较大,并且每次搜索都向页面反馈的话,恐怕CPU承受不了,如果降低搜索密度,又会降低搜索的精确程度,最终影响碰撞的效果。于是,将其折中,搜索一定次数后,向页面反馈一次,这样一方面提高了精确程度,一方面也减小了CPU资源消耗。

这样一来,在哪里碰撞就变得很容易得到了,接下来的问题就是碰撞后物体的方向,和速度的大小。高中物理经常遇到两个物体对撞的问题,其实这里也大同小异,不过首先要做的,是将速度分解为沿两圆圆心连线方向和与该连线方向垂直的分速度,根据两分速度(矢量)相加等于合速度,还有到角公式tanα = (k1 – k2) / (1 + k1k2),可以算得分速度。

这时候,需要进行处理的就是圆心连线方向的分速度了,根据物理的动量守恒和能量守恒,可以算得碰撞之后的相应速度,最后,和与圆心连线垂直的分速度相加,即可得到碰撞后的速度(矢量)了。

上JS,这个是我用来计算碰撞后的速度的,里面有些东西没有上下代码,所以不能运行,仅供参考。

//获取相关数据
var p1 = c1.p, p2 = c2.p; //获取位置(坐标)
var v1 = c1.v, v2 = c2.v; //获取速度(矢量)
var m1 = c1.m, m2 = c2.m; //获取质量
var x1 = p1.x, x2 = p2.x, y1 = p1.y, y2 = p2.y; //位置坐标
var vx1 = v1.x, vx2 = v2.x, vy1 = v1.y, vy2 = v2.y; //速度

//计算两个圆圆心连线的斜率
var k;
var dx = x1 – x2;

//判断斜率是否存在
if (dx) k = (y1 – y2) / dx;
//如果不存在,则去尽可能大的值
else k = kmax;

//**速度分解

//*第一个圆
//圆心连线方向的分速度
var vox1 = apart(vx1, vy1);
var voy1 = vox1 * k;

//与连线方向垂直的分速度
var vpx1 = vx1 – vox1;
var vpy1 = vy1 – voy1;

//*第二个圆
//圆心连线方向的分速度
var vox2 = apart(vx2, vy2);
var voy2 = vox2 * k;

//与连线方向垂直的分速度
var vpx2 = vx2 – vox2;
var vpy2 = vy2 – voy2;

//碰撞后与连线方向垂直的分速度不变,连线方向的分速度变化
var vox1a = calculateV(m1, m2, vox1, vox2);
var vox2a = calculateV(m2, m1, vox2, vox1);

var voy1a = calculateV(m1, m2, voy1, voy2);
var voy2a = calculateV(m2, m1, voy2, voy1);

//重新复合速度
v1.x = vox1a + vpx1;
v1.y = voy1a + vpy1;
v2.x = vox2a + vpx2;
v2.y = voy2a + vpy2;

//告知动量变化量
var dp1 = sqrt(sqr(vox1a – vox1) + sqr(voy1a – voy1)) * m1;
var dp2 = sqrt(sqr(vox2a – vox2) + sqr(voy2a – voy2)) * m2;

c1.collideCallBack(dp1, c2);
c2.collideCallBack(dp2, c1);

//分解出与圆心连线方向的分速度的x方向速度
function apart(vx, vy) {
return (k * vy + vx) / (sqr(k) + 1);
}

//根据动量和能量守恒计算速度变化
function calculateV(m1, m2, v1, v2) {
return ((m1 – m2) * v1 + 2 * m2 * v2) / (m1 + m2);
}

弹跳曲线算法

这个是做某JS游戏时遇到的第一个问题,如何生成一个相对符合物理规律的弹跳曲线呢?

现在假定我们有一个物体的初始位置和速度信息等,首先需要做的,就是计算出相应的抛物线。高三课本中讲到的导数在这里就得用上了。


y = ax2 + bx + c

则有
y’ = 2ax + b

设物体的初始位置为(0, h),初始速度水平和竖直方向分别为vx、vy,那么,当x = 0时,我们列出以下方程
h = c
y’ = b = vy / vx

然后在物理上,有
s = at2 / 2
s = vt

在本例中(当物体还没有着地时),即有
y = h + vyt- gt2 / 2
x = vxt

带入之前的方程,有
h + vyt – gt2 / 2 = a(vxt)2 + bvxt + h

解得
a = – g / 2(vx)2
b = vy / vx
c = h

那到此最关键的部分就完成了,然后通过
x2 = (b – √(b2 – 4ab)) / 2a
可计算得落点的位置,通过累加x,可以将这三个解扩充。

下面附我写的JS类
//速度类
function Speed(x, y) {
this.x = x;
this.y = y || 0;
}

/******** 通用函数 ********/

//剩余速度比例
function Remain(x, y) {
this.x = x;
this.y = y;
}

//平面路径
function Route(speed, height, gravity, remain) {
var v = copyObject(speed);

var a = [], b = [], c = [];
var vX = [];

var lastX = 0, lastT = 0;
var lastH = height;

var xAreas = [], tAreas = [0];

var xByT = [];

for (var i = 0; ; i++) {
var aI = a[i] = -0.5 * gravity / sqr(v.x);
var bI = b[i] = v.y / v.x – 2 * aI * lastX;
var cI = c[i] = lastH – aI * sqr(lastX) – bI * lastX;

nowX = (-bI – sqrt(sqr(bI) – 4 * aI * cI)) / (2 * aI);

xAreas.push(nowX);

lastT += (nowX – lastX) / v.x;
tAreas.push(lastT);
vX.push(v.x);
xByT.push(lastX);

if (nowX – lastX < 1) break;

lastX = nowX;

v.x *= remain.x;
v.y = -(2 * aI * lastX + bI) * v.x * remain.y;
lastH = 0;
}

var xAreaI = 0, tAreaI = 0; //为了减小比较数量,此值会在必要时累加.

//通过x坐标获取高度(y)
this.getHeightByX = function (x) {
while (x > xAreas[xAreaI]) xAreaI++;
return a[xAreaI] * sqr(x) + b[xAreaI] * x + c[xAreaI];
};

//通过时间获取坐标
this.getPositionByT = function (t) {
while (t > tAreas[tAreaI + 1]) tAreaI++;

var x = xByT[tAreaI] + vX[tAreaI] * (t – tAreas[tAreaI]);
var y = this.getHeightByX(x);

if ((x !== 0) && !x || (y !== 0) && !y)
return null;
else
return { x: x, y: y };
};

this.reset = function () {
xAreaI = tAreaI = 0;
};
}

function copyObject(obj) {
var newObj = {};
for (child in obj)
newObj[child] = obj[child];
return newObj;
}

function sqr(n) {
return n * n;
}

function sqrt(n) {
return Math.sqrt(n);
}

几款基于AJAX的网页操作系统(WebOS)对比

现在的网页操作系统(WebOS)不是一二般的多。当然,技术上也参差不齐。到了2010年还在谈这个话题是有点过时了,但也无伤大雅。这篇文章将 对总共六款基于AJAX技术的网页操作系统进行对比,它们分别是国产的千脑、Prever Start和进口的EyeOS1.0/2.0、OOS、StartForce、Live Desktop。

第一环节:界面

千脑在界面上不是逊色了一点两点, 不管是整体美工还是细节处理,在这点上赶了当之无愧的鸭子。

Prever Start的界面虽然整体来说略显单调,不饱满,但在细节的处理上却是很不错的。比如桌面的图标,调整窗口大小后便会发现图标间距会些许改变,以保证下方 不会出现较大的空白。同时,日历也会始终相对窗口右边静止。

EyeOS 1.0的界面十分清爽,美工比较到位,简约而不简单。但可惜细节上还有比较严重的问题,比如最大化EyeOS应用的窗口后调整浏览器窗口大小,最大化的窗 口不能自己适应。还有桌面上的一个小工具盒也不会随窗口调整而移动。

EyeOS 2.0的桌面抛弃了1.0版本的模式,采用分栏显示,使桌面内容更加丰富。美工上继承了1.0简约的特点,感觉不错。很重要的是细节上有了较大的改进。

OOS给人一种复古的感觉,图标是 最小的,风格是最老的。但细节处理比较到位,整体感觉还不错。

StartForce感觉比较前 卫,细节处理也很到位,大图标,有一种耳目一新的感觉。

Live Desktop的界面风格类似Windows Vista/7,做得相当到位,觉得美中不足的一点就是地下的任务栏比较丑。

第二环节:功能

不管界面如何,最终还得回归到功 能上。而功能的数量多少,质量高低,对于一个OS,即使是WebOS来说,也直接关乎到其内核的设计。一个难以扩展的“WebOS”实际上是不能称作 WebOS的。从这点来讲,Live Desktop似乎并不是WebOS,当然我想微软一开始也没打算叫它WebOS,而是把它定位为一种以文件管理为目的的网页应用程序。

那就抛开Live Desktop,比较下其他几个吧!

1.应用程序。在这些WebOS里,应用程序质量高且丰富的有EyeOS、OOS,接着是StartForce,最弱的是Prever Start和千脑。其实千脑的“应用程序”还是挺多的,只不过多是一个iframe就完事了……关于这点我就不多评价了。StartForce可以使用 Office2007,但不足的是需要Java支持。

2.开放性。EyeOS、OOS和Prever Start有一定优势,其中EyeOS提供了可视化的开发环境,OOS也提供了开发工具,而Prever Start可以运行“绿色软件”,将程序文件放到Prever Start上的任意位置即可运行。

3.储存空间。除了Prever Start是一个因为停止开发只剩Demo的WebOS,其他几个都提供了足够使用的储存空间。

4.速度。Prever Start因为只是一个Demo,所以拿开不说。综合起来速度最快的是StartForce,然后是千脑,然后才是EyeOS和OOS。但因为跟功能的复 杂程度有关,EyeOS和OOS在这里吃亏不少。

所以从功能上将,赶鸭子的是Prever Start。

好啦,就到这里,以下给出各个 WebOS的链接:

千 脑 http://www.qiannao.com/
Prever Start http://prever.vilic.info/
EyeOS http://www.eyeos.com/
OOS http://www.oos.cc/
StartForce http://www.startforce.com/