CSS3+PNG解决GIF动画无半透明的问题

No comments July 29th, 2010

因为GIF不支持半透明, 在使用时, 如果背景固定还好说, 如果背景是变化的, 那么透明的GIF图片边缘会有很明显的粗糙锯齿.

最近做JS游戏, 因为只针对设备开发的, iPhone和iPod里的Mobile Safari支持部分CSS3, 所以就想出了这个解决办法. 虽然比较小众, 但是对于我来说, 还是有价值的.

当然, 因为PNG图一般都偏大, 所以这个方案不适用于帧数很多的动画.

思路是很简单的, 通过改变背景的位置(背景定位)来实现.

首先我们需要把动画中出现的每一帧连成一个长条, 就像电影一样, 然后通过CSS3, 使它们逐帧显示出来. 例子如下(以Webkit为例).

@-webkit-keyframes ‘somename’ {
    0% { background-position: 0px; }
    49.9999% { background-position: 0px; }
    50% { background-position: -100px; }
    100% { background-position: -100px; }
}

#someid {
    background-image: url(somepic.png);
    -webkit-animation-name: somename;
    -webkit-animation-duration: 0.2s;
    -webkit-animation-iteration-count: infinite;
}

属性的意思我就不解释了, 英文, 很明了的. 因为CSS3动画本身貌似不是为逐帧的动画而生, 所以, 请注意49.9999%和50%这个百分比, 因为相隔很近, 可以让背景一次性从一个位置, 跳动到另一个位置, 这样以来, 就模拟了帧的变化.

如果想了解更多的CSS3动画技术, 请Google之. 其实我也不是很懂. 所以说不定会有更加直接的办法呢?

Original link of this archive: http://www.vilic.info/blog/archives/458
本文的原始链接: http://www.vilic.info/blog/archives/458

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

No comments July 29th, 2010

今天凌晨写东西的时候遇到的问题, 因为用到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;
            }
    }
} ();

Original link of this archive: http://www.vilic.info/blog/archives/454
本文的原始链接: http://www.vilic.info/blog/archives/454

为什么花80万也有人愿意移民?

1 comment July 21st, 2010

转自 Ruby’s Louvre, 原文链接 http://www.cnblogs.com/rubylouvre/archive/2010/07/04/1770834.html

最近拜访一位美国著名媒体的专栏作家,她1985年就来到中国,中文很好。

因为她的作家身份,提问似乎变成了双向。她问:“你能告诉我,为什么最近我总是收到很多让我移民的短信?”

短信道:“移民澳大利亚40万人民币,移民美国80万人民币。”她逐条给我看短信,可移民国度还包括加拿大、新西兰甚至新加坡。

她问:“中国不是越来越富强吗?个人不是越来越有钱吗?为什么这么多中国人有钱了还要移民外国?”

她说,那天在大街上看到一条广告,上书几个大字:“房子这么贵?还不如移民呢!”

我终于忍不住大笑,这条不够狠,我看到一条间接广告,锵锵泰斗“窦文涛”说的:“中国有风险,投胎需谨慎”。

即使是中国通,她小心记下“DOU文涛”三个字以后,却被“投胎”这两个字难倒了。她问,什么叫“投胎”?我想了很久,回答她说:”中国人,或者说佛家相信轮回。因此乐观的中国人相信,你死后会再投入人世,变成小孩,再出生。这里是更乐观的人相信,你不但会再生,而且还可以选择自己投胎的国度。”

那么上句话的意思可以是:如果你可以替孩子选择出生地的话,中国不是一个好选择。这算是给她的答案,为什么中国人会这么热衷于移民。

当然,作为一个未必真正生活在中国人群里的“中国通”,她依然不知道为什么移民要那么贵。我说,我正好有一个朋友在移民公司工作,一次我拿到了一在她那里看到一份移民美国的“收益”清单,如果按这份清单的话,那么80万的费用似乎是不贵的(他们公司好像只收20万费用)。

以下是清单部分内容:

*孩子出生。在美出生的孩子就是美国公民。注意你在北京超生一个孩子要罚款24万人民币,而在美国你可以多生几个,不用付罚款。(在加拿大每个孩子每个月政府还支付还有牛奶金呢)

*中小学学费。18岁大学前美国全部中小学都是义务教育。目前北京、上海、广州三地机构办理中小学生赴美的学费每年都在3万美元以上(接近21万人民币)。3万×3年=9万 约等于超过60万人民币。

*大学学费。上大学本地学生的学费每年约3千多美金,而外籍学生要交2万多美金。每年节省1.7万×4年=6.8万 约等于50万人民币

*学生贷款。18岁以上的绿卡持有者可以在拿到绿卡当年申请各种类型的学生贷款,找到工作以后可以分年还清,通常只要拿工资的10%-20%还款。美国和加拿大的学生贷款系统非常方便简单,很多学生都靠自己贷款和打工读完大学。

*政府帮助找工作。美国政府在各地设有专门机构免费为国人找工作,绿卡持有者只要到这些部门登记技能、专长,这些部门就会为登记这免费找工作及提供工作的各种政府资讯。同时,这些部门每年还有各项基金帮助培训待业者,比如电脑、英文。

*周游世界。绿卡持有者在绝大多数国家有免签的优势。当然去朝鲜和古巴两国除外。

*回国投资。美国绿卡持有者被视为华侨,回国投资被视为外资或合资,并享受很多优惠政策。

*退休福利。绿卡持有人在一生累积十年交税记录后(底线为每月50美元的税金)可在退休后(通常为65岁)终生领取美国政府的退休金(每月700-1200美元)。

*失业救济。在有正常收入并交税不少于6个月以后失业,到美国相关部门报失业并办理相关手续就可以按月领取政府救济金(每月600-1200美金不等)。

*事故时的人道待遇。在美国发生事故(车祸,怪病)一切以救人为第一准则。即使你表明没有钱支付手术费,医院也会不懈余力地抢救……

我不是帮移民公司做广告,因为大家每天都在手机收到小广告。以上的信息确实是移民公司所列,而且事实情况大致如此,至少我知道在加拿大的社会福利比美国还要好。比如医疗保险,在有的阿尔伯塔省是全部免费,在卑诗省对穷人医保还有特别的优惠。

我只是想列出来,有一些对社会安定起决定因素的社会福利待遇,西方国家有,而我们没有,这样移民公司和移民生意才有市场。

老实说,假如移民美国费用是80万,你多生一个小孩,让他读3年美国高中,4年美国大学基本省出的钱已经超过80万人民币了—条件是假如你不想让孩子和很多学生一起高考,并且大学毕业以后打破头的找工作的话。

这些费用还只是算到了孩子大学毕业,步入社会的社会的医疗保险、失业保险、退休金等等还没有计算。

如果有能力在美国大城市买一幢房子,基本上今天你省的就更多了,就拿通州2万的房价来说吧,你在美国波士顿的郊区绝对可以买到每平方尺单价更好更便宜的房子。

除了这些可以计算的显性数字,干净的空气、清澈的蓝天、纯净的饮用水,孩子们可以活动的大片绿地。更好的市政措施、更好的交通管理等等,还有人们相对平静的心态这些都是数字和金钱无法计算的。

如果你你要问我为什么国人选择移民,我首先会回答因为他们不想自己将来的小孩喝三鹿奶粉,吃食物中的苏丹红、地沟油和各种肉类中的超标激素……好不容易挤进大学校门,毕业了以后却要排着队在富士康门口找工作。还有越来越大的基尼系数和贫富分化带来的社会不稳定性……这些也是金钱无法计算的。

“中国有风险,投胎需谨慎”这样的口号,当然只能是对自己国家最有深切体验的中国人才能总结出来的。等每个北京老外每天都收到移民加拿大、美国、澳大利亚的小广告的时候,我想这也算是黑色幽默了。

我记得当年在新东方学习英语的时候,老师曾经说过,俞敏洪为美国一飞机一飞机的输送了GRE考了高分的最好的中国学生。这是多么大的壮举啊。

如果移民公司再一飞机一飞机的输送中国掏得起移民费用的社会精英或者贪污的官员,这何尝不是壮举。

当然,如此诋毁祖国母亲的移民广告,肯定会有许多爱国者愤愤不平,但我还是觉得,作为一个爱国者,对这种广告,最好的办法就是广泛地传播它,因为,如此一来,最后留在这个国家的人,都会是纯粹的爱国者了。

Original link of this archive: http://www.vilic.info/blog/archives/451
本文的原始链接: http://www.vilic.info/blog/archives/451

离线Web应用-HTML5 Cache Manifest试验

4 comments July 11th, 2010

原文地址 http://www.bennadel.com/blog/1944-Experimenting-With-HTML5-s-Cache-Manifest-For-Offline-Web-Applications.htm
译者 Vilic Vane (www.vilic.info)

 (译者注:第一次翻译东西,限于英文水平,不足之处请见谅.另外,原文作者使用的是ColdFusion,代码中有些内容并非浏览器最终获得的内容,请注意区别.然后空了会争取翻一下文件内的注释.)

 之前我试过通过Safari的SQLite支持来创建客户端的数据库,觉得还应该试试通过HTML5的”Cache Manifest(缓存清单)”来创建离线的Web应用程序.Cache Manifest是一个列出了应用程序所需的所有需要被缓存的资源的文本文件,以便在离线的时候程序一样可以使用.在Cache Manifest中列出的文件会被储存在”Application Cache(应用程序缓存)”里.Application Cache就像浏览器普通缓存,但是却更加强大.只要资源被储存在了Application Cache里,除非相应缓存被清除或者Cache Manifest作废,浏览器永远不会再次从网络请求这个资源.

当我刚开始使用Cache Manifest的时候,我对”离线”方面的兴趣比不上对beasty(译者注:抱歉…没查到这个单词)缓存机制方面的兴趣.只要浏览器发现了Cache Manifest文件,并且得到了你对于它创建离线缓存的许可,浏览器接下来便会在后台开始下载所有需要缓存的资源.如此一来,你只需要点击主页(只是举个例子,不必真的这么做)就可以最终让整个应用程序被缓存下来.并且,一旦应用程序的资源被缓存,对于这个程序的操作,更多的便成了本地的操作,而不是远程的.

为了进行这个HTML5的Cache Manifest试验,我创建了一个非常简单的照片列表页面,并在其中列出了一些链接,以便于查看一些较高分辨率的图片.每一个”查看”页面都是会通过照片的ID动态加载相应图片的ColdFusion页面.列表页面的HTML内容非常简单:

<!—
 Use an HTML5 doc-type. This is required for some browsers to
 work properly with the offline-cache.
—>
<!DOCTYPE HTML>
 
<!—
 Add a file to the cache manifest. NOTE: Any file that calls
 a cache manifest file will be automatically cached, even if
 it is in the WHITELIST portion of the cache manifest.
—>
<html manifest=”./cache_manifest.cfm”>
<head>
 <title>Cache Manifest For Offline Pages</title>
 
 <!—
  These are the two graphics (logo and startup screen) use
  for “app mode” on the iPhone (when the web page is put on
  the main screen as its own logo).
 
  NOTE: This part has nothing to do with the cache manifest
  stuff – this is strictly related to runnin a website in
  ”App Mode” on an iPhone. Feel free to remove this entirely
  from the example.
 —>
 <link rel=”apple-touch-icon” href=”icon.png”/>
 <link rel=”apple-touch-startup-image” href=”home.png” />
</head>
<body>
 
 <h1>
  Cache Manifest For Offline Pages
 </h1>
 
 <h3>
  Pictures of Alisha Morrow
 </h3>
 
 <ul>
  <cfoutput>
 
   <!—
    Notice that we are dynamically generating this
    page. It will only be generated on the first
    request. After that, this page will be coming out
    of the cache.
   —>
   <cfloop
    index=”pictureIndex”
    from=”1″
    to=”5″
    step=”1″>
 
    <li>
     <a href=”view.cfm?id=#pictureIndex#”
      >View Image #pictureIndex#</a>
    </li>
 
   </cfloop>
 
  </cfoutput>
 </ul>
 
 <p>
  Now:
  <cfoutput>
   #timeFormat( now() , “hh:mm:ss TT” )#
  </cfoutput>
 </p>
 
</body>
</html>

当我们使用Cache Manifest的时候,有两个地方非常重要,首先,因为Cache Manifest是HTML5的一部分,我们需要使用HTML5 doctype:

<!DOCTYPE HTML>

虽然不是所有浏览器都要求这样做(我猜想的话),但为了跨浏览器的兼容性,这样做更好.然后,或许更加重要的东西是我们需要添加一个链接来指向Cache Manifest文件.这条链接是定义在HTML标签里的:

<html manifest=”./cache_manifest.cfm”>

cache_manifest.cfm文件就是列出了应用程序中所有需要缓存的资源的文件:

Cache Manifest (cache_manifest.cfm)

<!—
 Define the Cache Manifest content. I’m doing it this way since
 the “CACHE MANIFEST” line needs to be the first line in the file
 and storing it in a buffer allows us to TRIM later without having
 ugly line breaks.
—>
<cfsavecontent variable=”cacheManifest”>
 
<!—
 NOTE: Cache Manifest must be the very first thing in this
 manifest file.
—>
CACHE MANIFEST
 
<!—
 When a cache manifest is reviewed by the browser, it uses a
 complete byte-wise comparison. As such, we can use COMMENTS
 to defunk a previously used cache manifest. In this way, we
 can use a version-comment to indicate change even when the
 file list has not changed.
 
 NOTE: If ANY part of this file is different from the previous
 cache manifest, ALL of the files are re-downloaded.
—>
# Cache Manifest Version: 1.3
 
<!—
 Let’s list the file that get cached. The URLs to these files
 are relative to the cache manifest file (or absolute).
—>
# Core files.
./index.cfm
 
# iPhone App files.
./icon.png
./home.png
 
# View Pages. Notice that these can be dynamic pages as long
# as they are valid URLs.
./view.cfm?id=1
./view.cfm?id=2
./view.cfm?id=3
./view.cfm?id=4
./view.cfm?id=5
 
# Images that get viewed.
./images/1.jpg
./images/2.jpg
./images/3.jpg
./images/4.jpg
./images/5.jpg
 
</cfsavecontent>
 
 
<!— —————————————————– —>
<!— —————————————————– —>
 
 
<!—
 Let’s reset the output and set the appropriate content type.
 It is critical that the manifest file be served up as a type
 ”text/cache-manifest” mime-type.
 
 NOTE: We need to be careful about the whitespace here since
 the very first line of the file must contain the phrase,
 ”CACHE MANIFEST”. As such, we must TRIM() the content.
—>
<cfcontent
 type=”text/cache-manifest”
 variable=”#toBinary( toBase64( trim( cacheManifest ) ) )#”
 />

在使用Cache Manifest的时候,有一些要点需要明白.第一,”CACHE MANIFEST”这行文字,必须出现在Cache Manifest文件的开头.第二,文件的类型必须被定义为MIME类型,”text/cache-manifest”.第三,整个Cache Manifest文件是通过每个字节来区分版本的.这第三点的意思就是说,Cache Manifest文件中任何位置的变动,包括注释内容(#),都会使原来的Cache Manifest作废.此时,整个列表中需要被缓存的资源都会被重新下载.

就像在CSS文件中一样,Cache Manifest中列出的资源路径既可以是完整的,也可以是相对这个Cache Manifest文件的.因为我们缓存的是动态页面,这些动态页面按说应该独立地列在Cache Manifest文件里(译者注:可能意思是,举个例子,有时动态页面需要更新缓存,而图片不变,这是如果动态页面的Cache Manifest文件和图片的是一个文件,便会使整个列表,也即包括图片被重新下载).还有其他的一些办法来做到这点,但是仅对于我的试验来说,这是最简单的做法.

列表中的”查看”页面除了动态显示与获得的ID相应的图片以外,什么也没做.

view.cfm

<!— Param the image ID that we are going to view. —>
<cfparam name=”url.id” type=”numeric” />
 
 
<!—
 Use an HTML5 doc-type. This is required for some browsers to
 work properly with the offline-cache.
—>
<!DOCTYPE HTML>
 
<!—
 Add a file to the cache manifest. NOTE: Any file that calls
 a cache manifest file will be automatically cached, even if
 it is in the WHITELIST portion of the cache manifest.
—>
<html manifest=”./cache_manifest.cfm”>
<head>
 <title>View Image</title>
</head>
<body>
 
 <h1>
  View Image
 </h1>
 
 <p>
  &laquo; <a href=”./index.cfm”>Back to List</a>
 </p>
 
 <p>
  <cfoutput>
   <img src=”./images/#url.id#.jpg” width=”300″ />
  </cfoutput>
 </p>
 
</body>
</html>

我在查看页面中也加入了Cache Manifest的链接;虽然我相信它并没有被浏览器请求.只要用户首先打开的是列表页面,Cache Manifest文件便会被下载,并且查看页面应该被自动缓存了.我在这里也加上这个,只是单纯地为了保险(译者注:原文为for good measure,不知道能不能我这样翻译).

在列表页面中,你可能已经注意到了一些奇怪的LINK标签,这些LINK标签是为苹果的iPhone设计的Web应用在”App Mode(应用程序模式)”用来定义其图标和启动界面图形的.”App Mode”是当页面URL被添加到了iPhone的Home Screen(主页面)时实现的全屏的模式.这些Link标签与Cache Manifest没有关系;但是,它们能说明我进行HTML5在这一块的探索的原因-为iPhone创建可以在本地运行(译者注:原文为native-esque,没查到)的Web应用程序.

Cache Manifest似乎是HTML5的一个非常酷特征,这些例子能够在Firefox,Safari和我的iPhone上运行(没有尝试过其他浏览器).我并没有在桌面Safari的研究上下很多的功夫,但是或许它能在Firefox的离线模式和iPhone的飞行模式下使用已经非常惊人了.就像我之前所说的,我最终想要进行这个研究,是为了让我的Dig Deep Fitness web application在iPhone上像本地应用程序那样运行.

注意:当我刚开始尝试使用Cache Manifest时,为了让离线缓存被识别,费了很大的力气.两天的时间我一直在检查我的拼写和无效链接.后来我重新启动了Firefox,终于得到了一点安慰(译者注:原文blam,没查到,Google了下,貌似有类似的意思)-它开始工作了.所以,如果第一次没有作用,你或许需要重新启动一下浏览器.

Original link of this archive: http://www.vilic.info/blog/archives/448
本文的原始链接: http://www.vilic.info/blog/archives/448

整理了下AIVOS的源码,有兴趣的拿走

7 comments July 7th, 2010

http://www.vilic.info/blog/aivos

AIVOS因为初步完成了权限系统(一年前的事了),所以可以用作文件管理器.今天翻老电脑里的东西,翻出来的.

Original link of this archive: http://www.vilic.info/blog/archives/443
本文的原始链接: http://www.vilic.info/blog/archives/443

QQ表情包(*.eip)导入指南

1 comment July 5th, 2010

普通访客请无视此文,特殊访客请无视此句.

其实貌似可以直接双击导入,但是刚刚我导入失败,如果你也失败的话,可以试试这样的方法.

首先打开一个聊天窗口,依次点击”选择表情”>”表情管理”.

接着选择”导入和导出”>”导入表情”,之后再弹出的文件选择窗口中选中表情文件即可.

导入完成后,即可在表情列表/选项卡中看到导入的表情了.

Original link of this archive: http://www.vilic.info/blog/archives/432
本文的原始链接: http://www.vilic.info/blog/archives/432

JS混淆软件推荐

6 comments June 29th, 2010

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

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

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

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

Original link of this archive: http://www.vilic.info/blog/archives/426
本文的原始链接: http://www.vilic.info/blog/archives/426

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

2 comments June 29th, 2010

也是做同一个东西,碰撞是又一个关键,受限于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);
}

Original link of this archive: http://www.vilic.info/blog/archives/423
本文的原始链接: http://www.vilic.info/blog/archives/423

弹跳曲线算法

6 comments June 29th, 2010

这个是做某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);
}

Original link of this archive: http://www.vilic.info/blog/archives/419
本文的原始链接: http://www.vilic.info/blog/archives/419

Prever Start 开发笔记整理(7、8、9、10月)

1 comment June 15th, 2010

2009年07月01日 23:50

今天遇到一个很棘手的问题,开始做“Prever菜单”,类似于“开始菜单”,当然,根据规划,它也是一个程序,不过在关闭菜单的时候,如果后面有程序,会出现死循环,郁闷…而且不像一般的错误,一下就可以找到,这个还要逐句去分析…最那啥的是,因为上一次写那一段代码已经是很久以前了,都忘得差不多了…明天继续想!还有就是生成菜单的时候,会处理信息树,之前都忘了,突然发现按一定顺序点开菜单会出现不同的现象…才意识到是改动了信息树,于是写了个深度复制(类似于深搜),每次生成菜单前先弄一个副本出来,这样就避免了问题,但效率就…鱼和熊掌啊…

反思,大改…2009年07月02日 16:17

今天又一次看了下OOS,也是一个网页操作系统。见www.oos.cc。原来就听说它有个开发程序,今天看了下,程序本身到没什么,但它的默认的代码给了我不少启发,所以决定暂停Prever的开发,好好反思下,改善规划,大改一次!其实我猜也花不了多少时间,毕竟Prever还在前期,啊,幸好还在前期…

2009年07月15日 19:47

桌面功能已经恢复了,接下来要继续改普通窗口,这个比起桌面的窗口来要复杂多了,希望早点改完,然后就改ContextMenu类,然后就基本完成了?或许吧?改完了就专心开发接下来的东西,不过,先后顺序还没有想好…

2009年07月21日 16:37

这多天经过努力,终于让Prever的窗口重新出来了,这也意味着大改的窗口部分(这次大改的核心)终于要告一段落了,不过从外观上看起来,和以前是一模一样的…哎,忍了,我现在深刻地相信着,有了这次大改,以后会方便很多。不过那天把时间列了下,才发现暑假20来天可能根本不够,也就是以后的午觉又泡汤了…都是那些教育部的…让我高呼,还我暑假!还我暑假!还我暑假!

2009年07月24日 09:12

昨天更改了任务栏选项卡的一个东西,就是当选项卡较多时的处理,原来使用的是滚动显示,因为主观上觉得通过改变宽度(类似于Windows)实现可能比较复杂…但昨天下决心改了之后,才发现简单了不晓得多少…郁闷…不过发现了一点小问题,就是当上面的窗口关闭时,下面的窗口有时没有获得焦点,争取今天解决…然后窗口部分还要弄子窗口和父窗口抢焦点的功能,不过想来难度不大,加油!

2009年08月01日 16:34

把My.Element.Icon.Container的排序基本写好啦,真的可以说是功能惊艳!支持横纵优先,左右优先,上下优先,而这个功能的第一个试用者,就是Prever.FileManager控件。这个控件的第一个试用者呐,就是FileManager了。实际上我猜想,给网页操作系统里的程序加控件这个概念,还是第一次吧。加油,这两天有点颓废,感觉没有寒假状态那么好,得加快进度了!

2009年08月03日 00:32

昨天的状态不错,不久FileManager的浏览功能就可以实现了,加上Icon类及其辅助类Icon.Container强大的功能,更换显示模式就很简单啦。这个做完了就是它的文件操作功能与扩展,这些大多工作是在后台,AIVOS也写过了,所以进度应该会很快。今天起来继续加油!

2009年08月05日 01:00

昨天主要在做文件管理,进度还是不理想,中途牵涉到一个范围比较大的改动,耗时有点多,都怪自己一开始没有想周到…还有一点,因为核心是一个控件,所以在保证满足当前连带开发部分需求的同时,要为以后的不同需求的调用做准备,这点我想是最麻烦的了…而且因为这部分连带了三个地方,所以弄起来相当麻烦。完了…刚刚脑袋里又蹦出来一个念头…难道今天又要大改?天哪…希望不会花费太多时间。

2009年08月30日 09:54

这段时间在做文件选择器,之后是文件夹选择器,不过除开Prever,心里有了一个更加宏伟的计划,而且,设想中的Prever II的开发和这个计划有相当大的关联。不过还是有些遗憾,Start因为抢时间,在有些地方还规划得很不完善。虽然已经相当神奇。但话说回来,就像这个版本的代号一样,Start,只是一个开始,它的开发经验将会给II更多的积淀。而Prever II,作为第一个享受我下一个计划的项目,又会为我计划中的产物积累宝贵的经验,至于这个计划到底是什么,就暂时不透露了,呵呵。不过计划再好,也高三了,接下来近一年的时间肯定是没办法进行了的,打算到了大学组个团队一起做。但…大一JS有我这水平的我想也难找…郁闷。

2009年09月09日 17:42

经过一个又一个中午的战斗,终于把文件选择控件写好了。支持设置多种文件类型,和多选、单选模式。功能简单,但是比较实用。已经应用到了图片浏览器上,但是遇到了一点小问题,明天争取解决。其实今天中午效率多高的,一般我是12点40的样子到,14点走,今天把那个做了我看到都50多分了,就回了教室,结果发现一个人也没有,然后回过来看时间,才13点…郁闷…接下来按理说应该先做文件夹选择控件,但决定先放下。呵呵,做些实用的小东西。主要还是时间不够…哎…

2009年09月10日 17:56

问题解决了,还是细节。Window类里面初始化的时候没有给IsMinimized赋值为false…平时到是看不出问题的,因为undefined转换为boolean也是false,但我有个地方判断了是否等于null,然后就…接下来是做文本编辑器还是做桌面日历呐?

2009年09月17日 09:13

想到前段时间解决的一个问题。我的图标排列不同的图标边距不同,很长一段时间来看到我的FileManager里的图标本来应该有边距,却没边距了,有时又刚刚相反。但长时间以来以为是浏览器的BUG,也就放了一放。终于,当我下决心要解决的时候,才发现…是有关边距的一个变量我忘了声明,被当成了全局函数…哎,要更加细心啊!

2009年09月20日 09:26

前两天把日历的颜色由灰色改为了蓝色,生气了许多。然后偷了下懒,做了个文本浏览器,就暂时放放文本编辑器了。只有10天中午的时间了,考虑做下在线解压,必须把我的右键菜单利用起来,当时写了那么久…然后再写个简介和伪SDK,还有示例程序。我在想那些评委些看不看我的代码啊,还是就点几下鼠标?不过话说还有一件很巨大的事情,我的Prever菜单(类似“开始”)还有快捷菜单还是空的…右下角的状态栏也没动…算了,忍了,这10天抓紧,能做多少做多少…

2009年09月23日 09:41

昨天把文件解压做了,因为赶时间,做得比较简陋,没办法…但至少让我的带图标的多级菜单没有白写。只能解压ZIP的,不过也够用了。

2009年09月24日 23:02

今天搞定了桌面背景的设置,但加上图片后才发现原来黑色的图标字体很不清楚,于是要考虑加影子咯。IE我加了3个shadow的filter,就为了把文字包围起来,然后刚刚Wait提醒了我,是不是可以考虑用文字发光?呵呵,还是我太死了。不过text-shadow不知道怎么实现那种环绕的效果,明天查下。嗯嗯,明天可能是最后一天在学校做Prever,然后回家还可以奋战两三天,加油!

2009年09月29日 09:49

有个窗口小问题Franky貌似在暑假就提过了,不过一直没处理,直到昨天Wait再提,我才决定弄一下…结果又一次比想象中简单无数倍…发现自己总是喜欢把复杂问题想简单,把简单问题想复杂…哎。

2009年10月05日 23:00

从今天起,摸电脑的时间就很少了,不过还是决定把睡觉前的时间拿来把《JavaScript高级程序设计》看了,不能半途而废。觉得这本书讲的东西比DOM那本对我有用,呵呵,谁叫我学的不系统呢。嗯,继续看书咯,看一会儿睡觉去!

后记:在后来的时间中,断断续续有一些小改动,譬如添加了文本编辑器,Flash播放器,还有添加了又去掉了的音乐播放器,URL文件等等,很多都是在网吧里完成的。之前还有小机房可以供我使用,但随着小机房被清空,我的周末也便只能耗在网吧了。从开始到现在,已经一年多了,Prever Start让我收获了很多,而我也坚定地相信,正如它的名字,这只是一个起点!

Original link of this archive: http://www.vilic.info/blog/archives/407
本文的原始链接: http://www.vilic.info/blog/archives/407