Живой пример
Имейте в виду, это использует Рафаэль для рендеринга и подчеркивание для семантического сахара.
Я написал очень маленькую программу, которая соответствует вашим требованиям. (Это было весело).
1 Создается популяция, каждая из которых изначально обладает одними и теми же фенотипическими признаками, но различается по своим навыкам (для этого скорость).
var Critter = function() {
// default the speed to something random.
this.speed = SPEED + Math.random()*SPEED;
// logic module
var logic = function() { ... }
}
...
// initialize an array of critters.
critters: _.map(_.range(0,COUNT), function() {
return new Critter;
})
Создайте функцию конструктора для вашего члена группы, а затем заполните массив этих парней. Я сопоставил массив длины с массивом тварей. (Дерзкий за петлей).
Каждый созданный вами криттер будет похож, но у него будут разные навыки (на основе Math.random()
), но они будут содержать одну и ту же логическую единицу.
2 Генерируется один источник пищи (каждый раз один и тот же)
// trivial Food object.
var Food = function() {
// rectangle with random x, random y, and SIZE as width / height
this.el = paper.rect(Math.random()*WIDTH, Math.random()*HEIGHT, SIZE, SIZE);
};
Конструктор объекта питания просто размещает квадрат на экране случайным образом
3 Примерно через 5 секунд после настройки среды (шаги 1 и 2) популяция организмов должна найти способ добраться до источника пищи на конкурентной основе
Настройка среды:
_.invoke(this.critters, "start", this.food.el.getBBox(), out_of_bounds);
Для каждого твари вы вызываете метод старта.
this.start = function(food) {
// create a player (circle);
this.el = paper.circle(Math.random()*WIDTH, Math.random()*HEIGHT, SIZE / 2);
// set an interval to run the logic over and over.
loop = setInterval(_.bind(logic, this, food), 25);
};
Каждый зверь просто размещает себя на экране случайным образом, а затем снова и снова вызывает свою собственную логику в цикле.
4 Только один организм может достичь предмета питания. При достижении этого условия сбрасываются, за исключением того, что организм, обнаруживший продукт питания в предыдущий раз, теперь получает выгоду, и его уровень скорости может увеличиваться, в то время как другие, совершившие особенно ужасные действия, могут становиться еще медленнее или прекращаться
var logic = function(food) {
// if you hit food you win
if (this.el.collision(food)) {
this.win();
}
}
// you won
this.win = function() {
console.log("win");
// increase speed
this.speed += Math.random()*5;
// end round
Game.end();
};
Твари обнаружат, есть ли у них еда в логической петле. Получив еду, он вызывает свой собственный метод победы. Это завершает текущий раунд игры.
Когда зверь побеждает, он получает повышение скорости.
Игра перезапустится при вызове .end
(после удаления всех текущих тварей)
end: function () {
// tell all critters to end their round
_.invoke(this.critters, "remove");
// remove the food
this.food.el.remove();
// start again !
this.start();
},
5 Процесс повторяется; пользователь может наблюдать особенности населения и видеть, какие из них преуспевают эволюционно и т. д.
Смотрите живой пример:)
6 Что дальше:
- Настройка глобальных номеров и других жестко закодированных номеров
- Реализация ИИ в функции
logic
.
- Пройдите все jsfiddles от / 1 до / 180 и посмотрите, как это было сделано.
- Пожаловаться, что комментарии недостаточно подробны
- Выбросьте мой код и начните с нуля, теперь, когда вы видели пример.
- Код рождения просто создает «базового» Криттера. Это не размножается из двух существующих
твари и не имеет повышенных навыков. Это означает отсутствие эволюции.
Бонус:
Путешествие к еде
Предупреждение: Приведенная выше ссылка действительно движется к еде, но она делает что-то не так, я думаю, там есть хитрая ошибка. Я не думаю, что смогу исправить это.
Я объясню логику путешествия к еде
// angle between critter and food
var angle = Raphael.angle(
this.el.getBBox().x,
this.el.getBBox().y,
food.x,
food.y) - 135; // the 135 is the default direction (bottom right)
// get a random speed
var rand = Math.random()*this.speed;
// travel towards the food box by rotating your vector by the angle
var points = this.rotateVector([rand, rand], angle);
// move towards the box
this.el.translate(points[0], points[1]);
Сначала rand
создает случайный вектор, который выглядит следующим образом:
Math.random()
определяет, насколько далеко / быстро движется твари. Это указывает на нижний правый угол.
Поскольку он указывает на правый нижний угол, мы должны удалить 135
градусов от угла для этого вектора
Затем мы должны вычислить угол между твари и пищей. Мы делаем это, передавая в двух точках Raphael.angle
, и он вычисляет угол для нас.
Теперь у нас есть угол, и мы хотим повернуть наш вектор движения на этот угол. Вектор движения в данный момент направлен вверх (черный цвет), и мы хотим повернуть его на угол до новой позиции (красный цвет). В коде это this.rotateVector
Теперь указывали в правильном направлении! Мы можем просто позвонить this.el.translate(points[0], points[1])