人工智能(Artificial Intelligence) ,英文缩写为AI。它是研究、开发用于模拟、延伸和扩展智能的理论、方法、技术及应用系统的一门新的技术科学。本篇从严格意义上说属于人工智能的范畴,但也是基础中的基础。本篇的目的是要赋予小球解散和集合两项基本指令(智商),本篇内容子弹追踪等塔防类游戏当中。
基础类
二维向量(2D vector)可谓2D游戏或是动画里最常用型别了。这里三维向量用Vector2类实现,用(x, y)表示。 Vector2亦用来表示空间中的点(point),而不另建类。先看代码:
(function(window) {
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));
使用该类需要特别注意和区分的地方是:
它什么时候代表点、什么时候代表向量。
当其代表向量的时候,它的几何意义是什么?
不能把其当成一个黑盒来调用,需要知其然并知其所以然。
在下面的使用的过程当中,我会特别标注其代表点还是向量;代表向量时,其几何意义是什么?
给小球赋予智商,顾名思义需要小球类:
(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三个类之后,终于可以开始实现一点东西出来!
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);
if (imageData.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);
//像素点和小球转换
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();
}
//解散:生成随机速度
for (var i in balls) {
balls[i].disband();
}
}
其中分三个步骤:收集所有像素、 像素点和小球转换、生成随机速度。整个demo我们需要一个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) < 2) {
balls[i].velocity.y = 0;
balls[i].velocity.x = 0;
}
}
if (time === 3000) {
collectionCMD = true;
for (var i in balls) {
balls[i].collection(230);
}
}
if (time === 7500) {
time = 0;
collectionCMD = false;
for (var i in balls) {
balls[i].disband();
}
}
for (var 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();
balls[i].position.y += balls[i].velocity.y * cyc / 1000;
balls[i].position.x += balls[i].velocity.x * cyc / 1000;
}
},
cyc);
这里使用time整体控制,使其无限loop。ps:这里还有一点不够OO的地方就是应当为ball提供一个draw方法。
其中的balls[i].position.distanceTo(balls[i].collectionPosition) 代表了点与点之间的距离,这里判断小球是否到了集合点或家。这里其几何意义就不再向量了。
在线演示
本文版权归【当耐特砖家】和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
随笔分类 -HTML5
HTML5人工智能基础及OO实践
2012-03-29 08:42 by 【当耐特砖家】, 370 visits, 网摘, 收藏, 编辑HTML5 Canvas【所见===所得】编程工具正式发布
2012-03-28 08:28 by 【当耐特砖家】, 3322 visits, 网摘, 收藏, 编辑HTML5 Canvas开发者和读者的福音
2012-03-27 12:25 by 【当耐特砖家】, 1936 visits, 网摘, 收藏, 编辑HTML5 【IE9割绳子】制作教程来袭····
2012-03-26 08:04 by 【当耐特砖家】, 2426 visits, 网摘, 收藏, 编辑HTML5动感菜单来了
2012-03-22 08:59 by 【当耐特砖家】, 4256 visits, 网摘, 收藏, 编辑HTML5对联来了
2012-03-20 07:51 by 【当耐特砖家】, 3771 visits, 网摘, 收藏, 编辑HTML5错误的绳子算法
2012-03-12 14:31 by 【当耐特砖家】, 712 visits, 网摘, 收藏, 编辑HTML5热门游戏制作---没有99美元的Impact也行
2012-03-06 08:38 by 【当耐特砖家】, 2543 visits, 网摘, 收藏, 编辑HTML5实验室【四十二】—javascript挑战流体实验
2011-12-12 07:33 by 【当耐特砖家】, 8674 visits, 网摘, 收藏, 编辑HTML5游戏制作完全指南
2011-12-08 18:28 by 【当耐特砖家】, 4080 visits, 网摘, 收藏, 编辑HTML5实验室【四十一】--怎么把CanvasLoading插件嵌入你的游戏
2011-12-07 17:01 by 【当耐特砖家】, 1716 visits, 网摘, 收藏, 编辑HTML5书籍【下载】
2011-12-06 07:10 by 【当耐特砖家】, 8859 visits, 网摘, 收藏, 编辑HTML5实验室【四十】—Jscex版Loading插件V11.12.05发布
2011-12-05 17:22 by 【当耐特砖家】, 1994 visits, 网摘, 收藏, 编辑HTML5实验室【三十九】—Jscex版Loading插件预览版本抢先看
2011-12-04 17:30 by 【当耐特砖家】, 1920 visits, 网摘, 收藏, 编辑HTML5实验室【三十八】--玩转像素系列【二】
2011-12-03 14:11 by 【当耐特砖家】, 1886 visits, 网摘, 收藏, 编辑HTML5实验室【三十七】--玩转像素系列【一】
2011-12-02 18:36 by 【当耐特砖家】, 2045 visits, 网摘, 收藏, 编辑HTML5实验室【三十六】--借来的创意
2011-12-01 08:54 by 【当耐特砖家】, 2568 visits, 网摘, 收藏, 编辑HTML5实验室【三十五】--你必须知道的10个提高Canvas性能技巧
2011-11-29 17:07 by 【当耐特砖家】, 3443 visits, 网摘, 收藏, 编辑HTML5实验室【三十】—Text Particle Systems
2011-11-25 08:41 by 【当耐特砖家】, 2034 visits, 网摘, 收藏, 编辑HTML5实验室【二十九】—我的HTML5游戏大赛参赛作品(下载试玩)
2011-11-22 07:29 by 【当耐特砖家】, 3501 visits, 网摘, 收藏, 编辑HTML5实验室【二十八】—Canvas+Video打造酷炫播放体验
2011-11-21 08:32 by 【当耐特砖家】, 3810 visits, 网摘, 收藏, 编辑HTML5实验室【二十七】—WebSocket
2011-11-20 08:01 by 【当耐特砖家】, 2799 visits, 网摘, 收藏, 编辑HTML5实验室【二十六】--本地存储及应用
2011-11-18 21:10 by 【当耐特砖家】, 1961 visits, 网摘, 收藏, 编辑HTML5实验室【二十四】--令人震撼的表白,你hold住吗?
2011-11-15 09:02 by 【当耐特砖家】, 7286 visits, 网摘, 收藏, 编辑HTML5实验室系列【十七】—爱♥曲线,单身程序猿福音
2011-11-07 08:41 by 【当耐特砖家】, 5593 visits, 网摘, 收藏, 编辑HTML5实验室【目录】(持续更新···)
2011-11-06 10:05 by 【当耐特砖家】, 14648 visits, 网摘, 收藏, 编辑HTML5实验室【十五】----艺术!不是吗?
2011-11-02 08:48 by 【当耐特砖家】, 7316 visits, 网摘, 收藏, 编辑HTML5版3D实验室系列【七】----锥
2011-11-01 13:57 by 【当耐特砖家】, 2667 visits, 网摘, 收藏, 编辑HTML5版3D实验室系列【六】----WAVE
2011-10-31 10:53 by 【当耐特砖家】, 2689 visits, 网摘, 收藏, 编辑HTML5版3D实验室系列【三】----JavaScript玩转3D粒子系统
2011-10-19 12:41 by 【当耐特砖家】, 5872 visits, 网摘, 收藏, 编辑世界上最短的时钟代码!更短的,有木有?
2011-10-16 09:15 by 【当耐特砖家】, 9744 visits, 网摘, 收藏, 编辑javascript异步编程系列【十一】----HTML5 canvas编程入门游戏发布
2011-10-08 07:41 by 【当耐特砖家】, 3538 visits, 网摘, 收藏, 编辑CnBlogs博文demo演示技巧比较:jsfiddle完胜
2011-10-07 20:46 by 【当耐特砖家】, 5344 visits, 网摘, 收藏, 编辑HTML5实验室系列【四】----摄像机、投影、3D旋转、缩放
2011-09-23 08:18 by 【当耐特砖家】, 10710 visits, 网摘, 收藏, 编辑javascript异步编程系列【目录】
2011-09-20 08:31 by 【当耐特砖家】, 1643 visits, 网摘, 收藏, 编辑人工智能(Artificial Intelligence) ,英文缩写为AI。它是研究、开发用于模拟、延伸和扩展智能的理论、方法、技术及应用系统的一门新的技术科学。本篇从严格意义上说属于人工智能的范畴,但也是基础中的基础。本篇的目的是要赋予小球解散和集合两项基本指令(智商),本篇内容子弹追踪等塔防类游戏当中。
基础类
二维向量(2D vector)可谓2D游戏或是动画里最常用型别了。这里三维向量用Vector2类实现,用(x, y)表示。 Vector2亦用来表示空间中的点(point),而不另建类。先看代码:
(function(window) {
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));
使用该类需要特别注意和区分的地方是:
它什么时候代表点、什么时候代表向量。
当其代表向量的时候,它的几何意义是什么?
不能把其当成一个黑盒来调用,需要知其然并知其所以然。
在下面的使用的过程当中,我会特别标注其代表点还是向量;代表向量时,其几何意义是什么?
给小球赋予智商,顾名思义需要小球类:
(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三个类之后,终于可以开始实现一点东西出来!
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);
if (imageData.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);
//像素点和小球转换
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();
}
//解散:生成随机速度
for (var i in balls) {
balls[i].disband();
}
}
其中分三个步骤:收集所有像素、 像素点和小球转换、生成随机速度。整个demo我们需要一个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) < 2) {
balls[i].velocity.y = 0;
balls[i].velocity.x = 0;
}
}
if (time === 3000) {
collectionCMD = true;
for (var i in balls) {
balls[i].collection(230);
}
}
if (time === 7500) {
time = 0;
collectionCMD = false;
for (var i in balls) {
balls[i].disband();
}
}
for (var 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();
balls[i].position.y += balls[i].velocity.y * cyc / 1000;
balls[i].position.x += balls[i].velocity.x * cyc / 1000;
}
},
cyc);
这里使用time整体控制,使其无限loop。ps:这里还有一点不够OO的地方就是应当为ball提供一个draw方法。
其中的balls[i].position.distanceTo(balls[i].collectionPosition) 代表了点与点之间的距离,这里判断小球是否到了集合点或家。这里其几何意义就不再向量了。