HTML5人工智能基礎(chǔ)及實(shí)踐
簡(jiǎn) 介
人工智能(Artificial Intelligence) ,英文縮寫(xiě)為AI。它是研究、開(kāi)發(fā)用于模擬、延伸和擴(kuò)展智能的理論、方法、技術(shù)及應(yīng)用系統(tǒng)的一門(mén)新的技術(shù)科學(xué)。本篇從嚴(yán)格意義上說(shuō)屬于人工智能的范疇,但也是基礎(chǔ)中的基礎(chǔ)。本篇的目的是要賦予小球解散和集合兩項(xiàng)基本指令(智商),本篇內(nèi)容中相關(guān)算法適用于子彈追蹤等塔防類游戲當(dāng)中。
基礎(chǔ)類
二維向量(2D vector)可謂2D游戲或是動(dòng)畫(huà)里最常用型別了。這里二維向量用Vector2類實(shí)現(xiàn),用(x, y)表示。 Vector2亦用來(lái)表示空間中的點(diǎn)(point),而不另建類。先看代碼:
- var Vector2 = function(x, y) {
- this.x = x || 0;
- this.y = y || 0;
- };
- Vector2.prototype = {
- set: function(x, y) {
- this.x = x;
- this.y = y;
- return this;
- },
- sub: function(v) {
- return new Vector2(this.x - v.x, this.y - v.y);
- },
- multiplyScalar: function(s) {
- this.x *= s;
- this.y *= s;
- return this;
- },
- divideScalar: function(s) {
- if (s) {
- this.x /= s;
- this.y /= s;
- } else {
- this.set(0, 0);
- }
- return this;
- },
- length: function() {
- return Math.sqrt(this.lengthSq());
- },
- normalize: function() {
- return this.divideScalar(this.length());
- },
- lengthSq: function() {
- return this.x * this.x + this.y * this.y;
- },
- distanceToSquared: function(v) {
- var dx = this.x - v.x,
- dy = this.y - v.y;
- return dx * dx + dy * dy;
- },
- distanceTo: function(v) {
- return Math.sqrt(this.distanceToSquared(v));
- },
- setLength: function(l) {
- return this.normalize().multiplyScalar(l);
- }
- };
- window.Vector2 = Vector2;
- } (window));
使用該類需要特別注意和區(qū)分的地方是:
它什么時(shí)候代表點(diǎn)、什么時(shí)候代表向量。 當(dāng)其代表向量的時(shí)候,它的幾何意義是什么? 不能把其當(dāng)成一個(gè)黑盒來(lái)調(diào)用,需要知其然并知其所以然。 |
在下面的使用的過(guò)程當(dāng)中,我會(huì)特別標(biāo)注其代表點(diǎn)還是向量;代表向量時(shí),其幾何意義是什么?
給小球賦予智商,顧名思義需要小球類:
- (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) {
- thisthis.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個(gè)屬性,分別是:radius半徑、velocity速度(Vector2)、position位置(Vector2)、collectionPosition集合點(diǎn)/小球的家(Vector2)。
小球擁有2個(gè)方法,分別是:collection集合、disband解散。
小球的集合方法所傳遞的參數(shù)為集合的速度,因?yàn)樾∏蚨加幸粋€(gè)集合點(diǎn)的屬性,所以這里不用再傳入集合點(diǎn)/家給小球。
這里詳細(xì)分析一下collection方法,這也是整個(gè)demo的關(guān)鍵代碼。
- collection: function (v) {
- thisthis.velocity =this.collectionPosition.sub(this.position).setLength(v);
- },
因?yàn)閟etLength設(shè)置向量的長(zhǎng)度:
- setLength: function (l) {
- return this.normalize().multiplyScalar(l);
- }
所以collection可以改成:
- thisthis.velocity = this.collectionPosition.sub(this.position).normalize().multiplyScalar(v);
normalize是獲取單位向量,也可以改成:
- this.collectionPosition.sub(this.position).divideScalar(this.length()).multiplyScalar(v);
整個(gè)Vector2黑盒就全部展現(xiàn)出來(lái),其整個(gè)過(guò)程都是向量的運(yùn)算,代表含義如下所示:
this.collectionPosition
.sub(this.position) 獲取小球所在位置指向小球集合位置的向量;
.divideScalar(this.length()) 得到該向量的單位向量;
.multiplyScalar(v); 改變?cè)撓蛄康拈L(zhǎng)度。
最后把所得到的向量賦給小球的速度。
上面我們還是用到了解散方法,其過(guò)程是幫小球生成一個(gè)隨機(jī)速度,用到了MathHelp類的一個(gè)靜態(tài)方法:
- (function (window) {
- var MathHelp = {};
- MathHelp.getRandomNumber = function (min, max) {
- return (min + Math.floor(Math.random() * (max - min + 1)));
- }
- window.MathHelp = MathHelp;
- } (window));
粒子生成
寫(xiě)了Vector2、Ball、MathHeper三個(gè)類之后,終于可以開(kāi)始實(shí)現(xiàn)一點(diǎn)東西出來(lái)!
- var ps = [],
- balls = [];
- function init(tex) {
- balls.length = 0;
- ps.length = 0;
- cxt.clearRect(0, 0, canvas.width, canvas.height);
- cxt.fillStyle = "rgba(0,0,0,1)";
- cxt.fillRect(0, 0, canvas.width, canvas.height);
- cxt.fillStyle = "rgba(255,255,255,1)";
- cxt.font = "bolder 160px 宋體";
- cxt.textBaseline = 'top';
- cxt.fillText(tex, 20, 20);
- //收集所有像素
- for (y = 1; y < canvas.height; y += 7) {
- for (x = 1; x < canvas.width; x += 7) {
- imageData = cxt.getImageData(20 + x, 20 + y, 1, 1);
- mageData.data[0] > 170) {
- ps.push({
- px: 20 + x,
- py: 20 + y
- })
- }
- }
- };
- cxt.fillStyle = "rgba(0,0,0,1)";
- cxt.fillRect(20, 20, canvas.width, canvas.height);
- //像素點(diǎn)和小球轉(zhuǎn)換
- for (var i in ps) {
- 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));
- balls.push(ball);
- };
- cxt.fillStyle = "#fff";
- for (i in balls) {
- cxt.beginPath();
- cxt.arc(balls[i].position.x, balls[i].position.y, balls[i].radius, 0, Math.PI * 2, true);
- cxt.closePath();
- cxt.fill();
- }
- //解散:生成隨機(jī)速度
- for (var i in balls) {
- balls[i].disband();
其中分三個(gè)步驟:收集所有像素、 像素點(diǎn)和小球轉(zhuǎn)換、生成隨機(jī)速度。整個(gè)demo我們需要一個(gè)loop:
- var time = 0;
- var cyc = 15;
- var a = 80;
- var collectionCMD = false;
- setInterval(function() {
- cxt.fillStyle = "rgba(0, 0, 0, .3)";
- cxt.fillRect(0, 0, canvas.width, canvas.height);
- cxt.fillStyle = "#fff";
- time += cyc;
- for (var i in balls) {
- if (collectionCMD === true && balls[i].position.distanceTo(balls[i].collectionPosition) <
- {
- balls[i].velocity.y = 0;
- balls[i].velocity.x = 0;
- CMD = true;
- for (var i in balls) {
- balls[i].collection(230);
- }
- }
- if (time === 7500) {
- time = 0;
- collectionCMD = false;
- or (var i in balls) {
- balls[i].velocity.y * cyc / 1000;
- balls[i].position.x += balls[i].velocity.x * cyc / 1000;
- }
- },
- cyc);
這里使用time整體控制,使其無(wú)限loop。ps:這里還有一點(diǎn)不夠OO的地方就是應(yīng)當(dāng)為ball提供一個(gè)draw方法。
其中的balls[i].position.distanceTo(balls[i].collectionPosition) 代表了點(diǎn)與點(diǎn)之間的距離,這里判斷小球是否到了集合點(diǎn)或家。這里其幾何意義就不再向量了。
在線演示
請(qǐng)移步原文
原文鏈接:http://www.cnblogs.com/iamzhanglei/archive/2012/03/29/2422618.html
【編輯推薦】