实时示例
请注意,此代码使用 Raphael 进行渲染,并使用 underscore 进行语义糖。
我编写了一个非常小的程序,基本符合您的要求(这很有趣)。
1 生成一组个体,初始时每个个体看起来具有相同的表型属性,但在技能方面却不同(例如速度)。
var Critter = function() {
this.speed = SPEED + Math.random()*SPEED;
var logic = function() { ... }
}
...
critters: _.map(_.range(0,COUNT), function() {
return new Critter;
})
创建一个人口成员的构造函数,然后用这些人口成员填充一个数组。我已经将长度为count的数组映射到了一个生物数组中。(使用了一个调皮的for循环)
每个你创建的生物都会相似,但具有不同的技能(基于Math.random()),但它们将包含相同的逻辑单元。
2 生成一个单一的食物源(每次相同)
var Food = function() {
this.el = paper.rect(Math.random()*WIDTH, Math.random()*HEIGHT, SIZE, SIZE);
};
食物对象构造函数只是随机地将一个正方形放置在屏幕上。
3 在设置环境(步骤1和2)约5秒钟后,生物种群需要竞争地找到一种方法到达食物来源
设置环境:
_.invoke(this.critters, "start", this.food.el.getBBox(), out_of_bounds);
对于每个生物,调用其启动方法。
this.start = function(food) {
this.el = paper.circle(Math.random()*WIDTH, Math.random()*HEIGHT, SIZE / 2);
loop = setInterval(_.bind(logic, this, food), 25);
};
每个生物只是在屏幕上随机放置自己,然后在循环中反复调用自己的逻辑。
4 只有一个生物可以到达食物。达到目标后,环境将被重置,除了找到食物的生物上一次获益外,其速度级别可能会增加,而那些表现特别糟糕的生物可能会变得更慢或被终止。
var logic = function(food) {
if (this.el.collision(food)) {
this.win();
}
}
this.win = function() {
console.log("win");
this.speed += Math.random()*5;
Game.end();
};
这个生物将在逻辑循环中检测是否有食物。一旦它获得了食物,就会调用自己的胜利方法。这会结束当前游戏回合。
当生物获胜时,它将获得速度提升。
当你调用.end
时(在移除所有当前生物后),游戏将重新启动。
end: function () {
_.invoke(this.critters, "remove");
this.food.el.remove();
this.start();
},
5 这个过程会被重复执行;用户可以观察种群的特征,看哪些特征在进化中成功等。
查看实时示例 :)
6 下一步:
- 微调全局数字和其他硬编码数字
- 在
logic
函数中实现一些人工智能。
- 从 /1 到 /180 遍历所有 jsfiddles,看看它是如何构建的。
- 抱怨评论不够详细
- 在您看到一个示例之后扔掉我的代码并重新开始。
- 出生代码只创建一个 "基本的" Critter。它不会从两个现有的 Critters 繁殖,也没有增加技能。这意味着没有进化。
奖励:
向食物移动
警告:上面的链接确实会朝着食物前进,但其中有一个错误,我认为有一个虚假的 bug。我想我不会去修复它。
我将解释朝着食物前进的逻辑。
var angle = Raphael.angle(
this.el.getBBox().x,
this.el.getBBox().y,
food.x,
food.y) - 135;
var rand = Math.random()*this.speed;
var points = this.rotateVector([rand, rand], angle);
this.el.translate(points[0], points[1]);
rand
首先创建一个看起来像这样的随机向量:
Math.random()
确定了生物移动的距离/速度。这个向量指向右下角。
因为它指向右下角,所以我们必须从该向量的角度中减去135
度。
然后,我们需要计算生物和食物之间的夹角。我们通过将两个点传递到Raphael.angle
中来完成这个操作,并由它为我们计算出该角度。
现在我们有了角度,我们希望将我们的运动向量旋转该角度。运动向量当前指向上方(黑色),我们希望将其旋转到新位置(红色)。在代码中,这是通过this.rotateVector
实现的。
现在我们指向了正确的方向!我们只需调用this.el.translate(points[0], points[1])
即可。