HTML5 OO實踐


簡介

人工智能(Artificial Intelligence) ,英文縮寫為AI。它是研究、開發用於模擬、延伸和擴展智能的理論、方法、技術及應用系統的一門新的技術科學。本篇從嚴格意義上說屬於人工智能的范疇,但也是基礎中的基礎。本篇的目的是要賦予小球解散和集合兩項基本指令(智商),本篇內容中相關算法適用於子彈追蹤等塔防類游戲當中。

基礎類

二維向量(2D vector)可謂2D游戲或是動畫里最常用型別了。這里二維向量用Vector2類實現,用(x, y)表示。 Vector2亦用來表示空間中的點(point),而不另建類。先看代碼:

 1  (function(window) {

 2      var Vector2 =  function(x, y) {
 3          this.x = x || 0;
 4          this.y = y || 0;
 5     };
 6     Vector2.prototype = {
 7         set:  function(x, y) {
 8              this.x = x;
 9              this.y = y;
10              return  this;
11         },
12         sub:  function(v) {
13              return  new Vector2( this.x - v.x,  this.y - v.y);
14         },
15         multiplyScalar:  function(s) {
16              this.x *= s;
17              this.y *= s;
18              return  this;
19         },
20         divideScalar:  function(s) {
21              if (s) {
22                  this.x /= s;
23                  this.y /= s;
24             }  else {
25                  this.set(0, 0);
26             }
27              return  this;
28         },
29         length:  function() {
30              return Math.sqrt( this.lengthSq());
31         },
32         normalize:  function() {
33              return  this.divideScalar( this.length());
34         },
35         lengthSq:  function() {
36              return  this.x *  this.x +  this.y *  this.y;
37         },
38         distanceToSquared:  function(v) {
39              var dx =  this.x - v.x,
40             dy =  this.y - v.y;
41              return dx * dx + dy * dy;
42         },
43         distanceTo:  function(v) {
44              return Math.sqrt( this.distanceToSquared(v));
45         },
46         setLength:  function(l) {
47              return  this.normalize().multiplyScalar(l);
48         }
49     };
50     window.Vector2 = Vector2;
51 } (window));

使用該類需要特別注意和區分的地方是:

它什么時候代表點、什么時候代表向量。

當其代表向量的時候,它的幾何意義是什么?

不能把其當成一個黑盒來調用,需要知其然並知其所以然。

在下面的使用的過程當中,我會特別標注其代表點還是向量;代表向量時,其幾何意義是什么?

給小球賦予智商,顧名思義需要小球類:

( function(window) {
     var Ball =  function(r, v, p, cp) {
         this.radius = r;
         this.velocity = v;
         this.position = p;
         this.collectionPosition = cp
    }
    Ball.prototype = {
        collection:  function(v) {
             this.velocity =  this.collectionPosition.sub( this.position).setLength(v)
        },
        disband:  function() {
             this.velocity =  new Vector2(MathHelp.getRandomNumber( - 230, 230), MathHelp.getRandomNumber( - 230, 230))
        }
    }
    window.Ball = Ball
} (window)); 

其中

小球擁有4個屬性,分別是:radius半徑、velocity速度(Vector2)、position位置(Vector2)、collectionPosition集合點/小球的家(Vector2)。

小球擁有2個方法,分別是:collection集合、disband解散。

小球的集合方法所傳遞的參數為集合的速度,因為小球都有一個集合點的屬性,所以這里不用再傳入集合點/家給小球。

這里詳細分析一下collection方法,這也是整個demo的關鍵代碼。

collection:  function (v) {
  this.velocity = this.collectionPosition.sub( this.position).setLength(v);
}, 

因為setLength設置向量的長度:

setLength:  function (l) {
  return  this.normalize().multiplyScalar(l);

 } 

所以collection可以改成:

   this.velocity =  this.collectionPosition.sub( this.position).normalize().multiplyScalar(v);

normalize是獲取單位向量,也可以改成:

this.collectionPosition.sub( this.position).divideScalar( this.length()).multiplyScalar(v);   

整個Vector2黑盒就全部展現出來,其整個過程都是向量的運算,代表含義如下所示:

this.collectionPosition

                          .sub(this.position)                獲取小球所在位置指向小球集合位置的向量;

                          .divideScalar(this.length()) 得到該向量的單位向量;
                           .multiplyScalar(v);               改變該向量的長度。

最后把所得到的向量賦給小球的速度。
上面我們還是用到了解散方法,其過程是幫小球生成一個隨機速度,用到了MathHelp類的一個靜態方法:

( function (window) {
  var MathHelp = {};
 MathHelp.getRandomNumber =  function (min, max) {
  return (min + Math.floor(Math.random() * (max - min + 1)));
 }
 window.MathHelp = MathHelp;

} (window)); 

粒子生成

寫了Vector2、Ball、MathHeper三個類之后,終於可以開始實現一點東西出來!

 1  var ps = [],
 2 balls = [];
 3  function init(tex) {
 4     balls.length = 0;
 5     ps.length = 0;
 6     cxt.clearRect(0, 0, canvas.width, canvas.height);
 7     cxt.fillStyle = "rgba(0,0,0,1)";
 8     cxt.fillRect(0, 0, canvas.width, canvas.height);
 9     cxt.fillStyle = "rgba(255,255,255,1)";
10     cxt.font = "bolder 160px 宋體";
11     cxt.textBaseline = 'top';
12     cxt.fillText(tex, 20, 20);
13 
14      // 收集所有像素
15       for (y = 1; y < canvas.height; y += 7) {
16          for (x = 1; x < canvas.width; x += 7) {
17             imageData = cxt.getImageData(20 + x, 20 + y, 1, 1);
18              if (imageData.data[0] > 170) {
19                 ps.push({
20                     px: 20 + x,
21                     py: 20 + y
22                 })
23             }
24         }
25     };
26     cxt.fillStyle = "rgba(0,0,0,1)";
27     cxt.fillRect(20, 20, canvas.width, canvas.height);
28 
29      // 像素點和小球轉換
30       for ( var i  in ps) {
31          var ball =  new Ball(2,  new Vector2(0, 0),  new Vector2(ps[i].px, ps[i].py),  new Vector2(ps[i].px, ps[i].py));
32         balls.push(ball);
33     };
34 
35     cxt.fillStyle = "#fff";
36      for (i  in balls) {
37         cxt.beginPath();
38         cxt.arc(balls[i].position.x, balls[i].position.y, balls[i].radius, 0, Math.PI * 2,  true);
39         cxt.closePath();
40         cxt.fill();
41     }
42 
43      // 解散:生成隨機速度
44       for ( var i  in balls) {
45         balls[i].disband();
46     }

47 } 

其中分三個步驟:收集所有像素、 像素點和小球轉換、生成隨機速度。整個demo我們需要一個loop:

 1  var time = 0;
 2  var cyc = 15;
 3  var a = 80;
 4  var collectionCMD =  false;
 5 setInterval( function() {
 6     cxt.fillStyle = "rgba(0, 0, 0, .3)";
 7     cxt.fillRect(0, 0, canvas.width, canvas.height);
 8     cxt.fillStyle = "#fff";
 9     time += cyc;
10      for ( var i  in balls) {
11          if (collectionCMD ===  true && balls[i].position.distanceTo(balls[i].collectionPosition) < 2) {
12             balls[i].velocity.y = 0;
13             balls[i].velocity.x = 0;
14         }
15     }
16 
17      if (time === 3000) {
18         collectionCMD =  true;
19          for ( var i  in balls) {
20             balls[i].collection(230);
21         }
22     }
23      if (time === 7500) {
24         time = 0;
25         collectionCMD =  false;
26          for ( var i  in balls) {
27             balls[i].disband();
28         }
29     }
30 
31      for ( var i  in balls) {
32         cxt.beginPath();
33         cxt.arc(balls[i].position.x, balls[i].position.y, balls[i].radius, 0, Math.PI * 2,  true);
34         cxt.closePath();
35         cxt.fill();
36         balls[i].position.y += balls[i].velocity.y * cyc / 1000;
37         balls[i].position.x += balls[i].velocity.x * cyc / 1000;
38     }
39 },

40 cyc);  

這里使用time整體控制,使其無限loop。ps:這里還有一點不夠OO的地方就是應當為ball提供一個draw方法。

其中的balls[i].position.distanceTo(balls[i].collectionPosition) 代表了點與點之間的距離,這里判斷小球是否到了集合點或家。這里其幾何意義就不再向量了。

在線演示

這你也敢叫人工智能?ok,未完待續......


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM