H5C3J 学习笔记 part9 Javascript inherits spriteSheet

这几天一直在一个小东西上改来改去,今天终于成了一点形,得马上记录一下,不然就堆积得太多了。

首先是编写好一个Bird类,或者说,Vehicle,又或者说,Atomic类,总之是一个具备了2D向量行为的类型,下面我很自然的顺着原来的思路,想要编写一个该类的子类,然后第一次发现JavaScript是木有继承概念的……啊,我孤陋寡闻了。

我翻看了一些所谓的完美继承方案,大部分都看得很累,这些人写文章并非为了解决你的继承问题,而是炫耀他从过程中获得的点点优越感(我也是,但是没那么严重)。

然后我找到了这里,我认为这个老外用很少的代码,实现了基本完整的继承机制,原文在此

代码如下:

 Function.prototype.method = function (name, func) {  
   this.prototype[name] = func;  
   return this;  
 };  
 Function.method('inherits', function (parent) {  
   this.prototype = new parent();  
   var d = {},  
     p = this.prototype;  
   this.prototype.constructor = parent;  
   this.method('uber', function uber(name) {  
     if (!(name in d)) {  
       d[name] = 0;  
     }  
     var f, r, t = d[name], v = parent.prototype;  
     if (t) {  
       while (t) {  
         v = v.constructor.prototype;  
         t -= 1;  
       }  
       f = v[name];  
     } else {  
       f = p[name];  
       if (f == this[name]) {  
         f = v[name];  
       }  
     }  
     d[name] += 1;  
     r = f.apply(this, Array.prototype.slice.apply(arguments, [1]));  
     d[name] -= 1;  
     return r;  
   });  
   return this;  
 });  
 Function.method('swiss', function (parent) {  
   for (var i = 1; i < arguments.length; i += 1) {  
     var name = arguments[i];  
     this.prototype[name] = parent.prototype[name];  
   }  
   return this;  
 });  
`</pre>
要定义类型时,先声明一个空白的构造函数,然后声明一个init函数,在里面定义要使用的类变量。
<pre>` var Bird = function ()  
 {  
 }  
 Bird.method("init",function(px,py,vx,vy){  
   this.edgeBehavior = Bird.BOUNCE;  
   this.mass = 1.0;  
   this.maxSpeed = 30;  
 });  
`</pre>
想定义子类时,显式的调用<span>inherits函数,即可实现继承,例如:</span>
<pre>` var Tank = function()  
 {  
 }  
 Tank.inherits(Bird);  
 Tank.method("init",function(px,py,vx,vy){  
   //Some code for Tank Class,override parent function init  
 });  
`</pre>
第二个值得注意的地方是,this关键字的引用歧义陷阱,如下代码开始的时候让我完全没有注意到错误的来源:
<pre>` this.reachGoal = false;  
 setTimeout(function(){this.reachGoal = true},1000);  
`</pre>
JavaScript没有类概念,它的所谓类,就是一个函数而已,所以当我使用匿名函数做定时器调用时,这里的this,指代的已经不是我想操作的this,而是指代那个匿名函数了。解决的办法是(我暂且这样解决的)起个别名变量。
<pre>` this.reachGoal = false;  
 var main = this;  
 setTimeout(function(){main.reachGoal = true},1000);  

下面遇到的就是,如何展现一个爆炸动画,当然可以用粒子系统达成,但个人认为效率低,效果没有那么好,所以还是利用一个老技术,SpriteSheet来达成,可以很容易的找到一些资源,比如下面这种。

[![](http://tiger-a-s-s.tobybai.cn/explosion2.png)](http://tiger-a-s-s.tobybai.cn/explosion2.png)
Collie引擎中对SpriteSheet有很好的支持,当我把这玩意当个新鲜事儿和小白分享时,小白说他早就知道这个东西了,其解决的最大问题,就是可以减少发起http请求的次数,我当时满脑子惊异,在我看来,这东西是为了解决:“如何能象Flash一样利用单个文件描述一个连续动画”的问题,然后我猛然发现,我以Flash为中心的思路是多么狭隘,我考虑这问题时,完全忽略了这项技术可能先于Flash诞生的事实,而且Flash中很可能借鉴了这样的手段,只是它封闭起来,我没看见而已。
我从日本人对美国的态度上,学习到的是,知道人家比你强,就马上认输,俯首学习。
关于转向行为的部分代码,在看的书里目前都有,所以不再赘述。

下面是这几天的一个小小的结果展示。

[![](http://tiger-a-s-s.tobybai.cn/%2525E5%2525B1%25258F%2525E5%2525B9%252595%2525E5%2525BF%2525AB%2525E7%252585%2525A7%2525202013-10-14%252520%2525E4%2525B8%25258B%2525E5%25258D%25258811.12.14.png)](http://tiger-a-s-s.tobybai.cn/%2525E5%2525B1%25258F%2525E5%2525B9%252595%2525E5%2525BF%2525AB%2525E7%252585%2525A7%2525202013-10-14%252520%2525E4%2525B8%25258B%2525E5%25258D%25258811.12.14.png)
[demo](http://hector.ziki.me/tank/tank/Tank.html)
很郁闷的是,发现它在Safari下又不能正常工作了……,检查一下发现,用于实现帧动画的requestAnimationFrame函数在Mac版本的Safari下不能正常运行,在iOS6的Safari下也不能正常运行,在iOS7的Safari上可以运行,所以,我只好再改成利用Timer触发的版本了。
这个水真不是一般的深啊,我发现原来用AS实现的部分,例如层次关系坐标换算,用AS实现时很容易,做js开发果然要痛苦一些。