该游戏模拟了自治智能体的群体运动和物体间的引力。玩家可通过鼠标操控小球群运动,鼠标移动越快,球体之间的距离越大,反之粒子会趋向于聚集到一起。游戏过程中会随机出现大小位置不同的吸引子,对群体粒子产生引力,小球一旦被吸引子吸入则消失。游戏通过操控群体粒子到达目标点来计分,所有粒子被吸引子吸入则游戏结束。
小球会跟着鼠标的移动转换运动方向,当小球离鼠标距离很近时,小球受到鼠标位置的影响会变小。小球下一帧速度的方向是由小球当前速度方向的向量与小球位置与鼠标位置之间的向量相减产生的,为了防止小球移动的速度过大,设定了一个maxspeed,限制了小球运动的最大速度,另外minspeed规定了小球与鼠标距离很近时的速度大小。
代码如下:
this.move=function()//移动位置计算
{
this.targetchange();
op=this.valocity.sub(target);
op=op.normalize();
if(target.mag()<50)
op=op.mult(this.minspeed);
else
op=op.mult(this.maxspeed);
this.pos=this.pos.add(op);
}
targetchange()是为了让小球运动的更像一个生命体,每帧小球运动的目的地并不是完全指向鼠标的,而是在以鼠标为圆心的一定半径的圆内随机选择一个点。
//半径选择大一些的情况
当粒子数量从一变成几十时,如果只是简单的直接增加粒子数,而不增加别的力,粒子的运动会趋向于一条直线。
//一坨粒子的移动
这显然不是我们想要的效果,在现实生活中真的生物体的群体运动是会在一定程度上避免相互之间的碰撞的。
代码如下:
this.separate=function()//防止粒子间过于靠近
{ sum=createVector(0,0);
for(item in particles){
d=particles[item].pos.dist(this.pos);
other=createVector(particles[item].pos.x,particles[item].pos.y);
self=createVector(this.pos.x,this.pos.y);
maxd=map(this.force*this.force,25,400,0,0);
if(d<maxd&&d>0){
diff=self.sub(other);
diff=diff.normalize();
diff.div(d);
sum=sum.add(diff);
}
}
return sum.normalize();
}
将粒子间的斥力和粒子向目的地运动的驱动力加权相加就可以接近我们想要的效果了:
op=op.mult(0.6).add(sum.mult(0.4));
在游戏过程中,canvas上会随机出现大小不一的空心圆,粒子靠近它时会被其产生的引力影响,引力大小与半径有关,一旦玩家操控的所有的粒子都被吸引子吸入则游戏结束。
引力的大小与距离的平方成反比,代码如下:
this.addforce=function(newc)//增加引力
{ dir=createVector(newc.pos.x,newc.pos.y);
self=createVector(this.pos.x,this.pos.y);
dir=dir.sub(self);
lens=dir.mag();
dir=dir.normalize();
m=(k*this.weight)/(lens*lens);
f=dir.mult(m).div(this.weight);
this.pos=this.pos.add(f);
}
另外在吸引子消失的时候增加了另一种粒子,粒子从里到外半径逐渐变小,制造消散的效果。
再为吸引子增加出现和旋转的动效
在index.html页面增添网页上方说明文字和开始按钮响应,增添游戏开始前的倒计时提示和失败后的提示。
《代码本色》ch1、ch2、ch4、ch6