zoukankan      html  css  js  c++  java
  • 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,未完待续......

  • 相关阅读:
    CSS中一个冒号和两个冒号有什么区别
    伪类元素实现可伸缩时间轴
    Gulp实现css、js、图片的压缩以及css、js文件的MD5命名
    for 循环进化史
    细谈sass和less中的变量及其作用域
    Vue2.0源码阅读笔记--双向绑定实现原理
    你所不知道的setTimeout
    前端COOKIE与SESSION的区别
    js移动端向左滑动出现删除按钮
    推荐几款屏幕录制工具(可录制GIF)
  • 原文地址:https://www.cnblogs.com/iamzhanglei/p/2422618.html
Copyright © 2011-2022 走看看