Программа, которую мы рассмотрим далее, основана на некоторых исходных кодах Ларри О'Брайена и вдохновлена программой "Boids", созданной Крейгом Рейнольдсом в 1986 году. Эта программа была предназначена для демонстрации специального аспекта теории сложности, известного как "эмерджентность" (emergence).
Целью здесь является создание реалистичного представления группового поведения животных путём установления нескольких простых правил для каждого животного. Каждое животное может видеть всю окружающую среду вместе с другими животными, но взаимодействует только со своими ближайшими "групповыми партнерами". Движение животных основано на трёх простых поведенческих принципах:
(1) Разделение: избегание чрезмерной компактности среди ближайших групповых партнеров.
(2) Направление: следование общему направлению движения ближайших групповых партнеров.
(3) Агрегация: движение к центру группы ближайших групповых партнеров.Более сложные модели могут также учитывать препятствия, позволяя животным прогнозировать и избегать столкновений с ними, что позволяет им свободно перемещаться вокруг постоянных объектов в окружающей среде. Кроме того, животные могут иметь свои собственные особые цели, что может привести к тому, что группа будет двигаться по определенному пути. Для упрощения обсуждения факторы избегания препятствий и поиска целей не были включены в модель, представленную здесь.Несмотря на то, что компьютеры сами по себе довольно примитивны, и правила, используемые в этой модели, тоже достаточно просты, результат выглядит вполне реалистично. То есть, очень реалистичное поведение "выходит" из этого простого моделирования.
Программа предоставляется в виде объединенного приложения/программного модуля:
//: FieldOfBeasts.java
// Демонстрация теории сложности; моделирует
// групповое поведение животных. Вдохновлен
// программой Ларри О'Брайена lobrien@msn.com
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.util.*;
``````java
class Beast {
int
x, y, // Координаты экрана
currentSpeed; // Пикселей в секунду
float currentDirection; // Углы в радианах
Color color; // Цвет заливки
FieldOBeasts field; // Область передвижения Beast
static final int GSIZE = 10; // Размер графики
}
```markdown
public Beast(FieldOBeasts f, int x, int y,
float cD, int cS, Color c) {
this.field = f;
this.x = x;
this.y = y;
this.currentDirection = cD;
this.currentSpeed = cS;
this.color = c;
}
public void step() {
// Вы перемещаетесь в зависимости от того, что видите:
Vector visible = this.field.beastListInSector(this);
// Если вы не впереди
if (visible.size() > 0) {
// Собираете данные о том, что видите
int totalSpeed = 0;
float totalDirection = 0.0f;
float distanceToNearest = 100000.0f;
Beast nearestBeast =
(Beast)visible.elementAt(0);
Enumeration e = visible.elements();
while (e.hasMoreElements()) {
Beast aBeast = (Beast)e.nextElement();
totalSpeed += aBeast.currentSpeed;
float direction =
aBeast.bearingFromPointAlongAxis(
x, y, currentDirection);
totalDirection += direction;
float distanceToBeast =
aBeast.distanceFromPoint(x, y);
if (distanceToBeast < distanceToNearest) {
nearestBeast = aBeast;
distanceToNearest = distanceToBeast;
}
}
// Правило 1: Соответствие средней скорости списка:
currentSpeed = totalSpeed / visible.size();
// Правило 2: Движение в сторону воспринятого центра масс стада:
currentDirection =
общее_направление / видимый.size();
// Правило 3: Поддержание минимального расстояния от окружающих:
если (расстояние_до_ближайшего <=
поле.minimumDistance) {
текущее_направление =
ближайший_beast.currentDirection;
текущая_скорость = ближайший_beast.currentSpeed;
если (текущая_скорость > поле.maxSpeed) {
текущая_скорость = поле.maxSpeed;
}
}
}
иначе { // Вы впереди, поэтому замедляетесь
текущая_скорость =
(int)(текущая_скорость * поле.decayRate);
}
// Делаем зверя двигаться:
x += (int)(Math.cos(текущее_направление)
* текущая_скорость);
y += (int)(Math.sin(текущее_направление)
* текущая_скорость);
x %= поле.xExtent;
y %= поле.yExtent;
если (x < 0)
x += поле.xExtent;
если (y < 0)
y += поле.yExtent;
}
публичный float bearingFromPointAlongAxis (
int originX, int originY, float axis) {
// Возвращает угол направления текущего зверя
// в системе координат мира
попробуй {
double направление_в_радианах =
Math.atan(
(this.y - originY) /
(this.x - originX)
);
// Обратный тангенс имеет два решения, поэтому вам
// нужно скорректировать за другие четверти:
если (x < originX) {
если (y < originY) {
направление_в_радианах += -(float)Math.PI;
} иначе {
направление_в_радианах = (float)Math.PI - направление_в_радианах;
}
}
}
}
// Просто вычти ось (в радианах):
return (float)(axis - bearingInRadians);
} catch (ArithmeticException ae) {
// Возможна ошибка деления на ноль
if (x > originX) {
return 0;
} else {
return (float) Math.PI;
}
}
}Код предоставлен не требует перевода, поскольку он представляет собой программный код на языке программирования Java. Ниже представлен сам код без изменений:
public float distanceFromPoint(int x1, int y1) {
return (float) Math.sqrt(
Math.pow(x1 - x, 2) +
Math.pow(y1 - y, 2)
);
}
public Point position() {
return new Point(x, y);
}
Если требуется перевод документации или комментариев к данному коду, пожалуйста, предоставьте соответствующий текст для перевода.```java public class ПолеЖивотных extends Applet implements Runnable { private Vector животные; static float полеДействия = (float)(Math.PI / 4), // В радианах // Декремент % в секунду: коэффициентУменьшения = 1.0f, минимальноеРасстояние = 10f; // В пикселях static int половинаПолаДействия = (int)((полеДействия * 360) / (2 * Math.PI)), xОбласть = 0, yОбласть = 0, количествоЖивотных = 50, максимальнаяСкорость = 20; // Пикселей/секунду boolean уникальныеЧерты = true; Thread этотПоток; int задержка = 25;
public void init() { if (xОбласть == 0 && yОбласть == 0) { xОбласть = Integer.parseInt(getParameter("xExtent")); yОбласть = Integer.parseInt(getParameter("yExtent")); } животные = сделатьМассивЖивотных(количествоЖивотных, уникальныеЧерты); // Теперь запустим животных: этотПоток = new Thread(this); этотПоток.start(); }
public void run() { while (true) { for (int i = 0; i < животные.size(); i++) { Животное b = (Животное) животные.elementAt(i); b.step(); } try { этотПоток.sleep(задержка); } catch (InterruptedException ex) {} repaint(); // Иначе он не будет обновляться } }
Vector сделатьМассивЖивотных(int количество, boolean уникальныеЧерты) { Vector новыеЖивотные = new Vector(); Random генератор = new Random(); }
// Используется только если уникальные_черты включены:
double корень_куба_из_количество_животных =
Math.pow((double)количество_животных, 1.0 / 3.0);
float шаг_куба_цвета =
(float)(1.0 / корень_куба_из_количество_животных);
float r = 0.0f;
float g = 0.0f;
float b = 0.0f;
for(int i = 0; i < количество; i++) {
int x =
(int)(генератор.nextFloat() * x_область);
if(x > x_область - Животное.GSIZE)
x -= Животное.GSIZE;
int y =
(int)(генератор.nextFloat() * y_область);
if(y > y_область - Животное.GSIZE)
y -= Животное.GSIZE;
float направление = (float)(
генератор.nextFloat() * 2 * Math.PI);
int скорость = (int)(
генератор.nextFloat() * (float)максимальная_скорость);
if(уникальные_черты) {
r += шаг_куба_цвета;
if(r > 1.0) {
r -= 1.0f;
g += шаг_куба_цвета;
if(g > 1.0) {
g -= 1.0f;
b += шаг_куба_цвета;
if(b > 1.0)
b -= 1.0f;
}
}
}
новые_животные.addElement(
новый Животное(this, x, y, направление, скорость,
новый Цвет(r, g, b))));
}
return новые_животные;
}
общая Вектор животновладелец_список_в_секторе(Животное наблюдатель) {
Вектор выход = новый Вектор();
Перечисление e = животновладелец.элементы();
Животное одноживотное = (Животное)животновладелец.элементПоИндексу(0);
целое число счетчик = 0;
while(e.естьДальшеЭлементы()) {
одноживотное = (Животное)e.следующийЭлемент();
if(одноживотное != наблюдатель) {
Точка p = одноживотное.положение();
Точка v = наблюдатель.положение();
```
```markdown
с плавающей запятой bearing =
одноживотное. направлениеОтТочкиПоАксису(
v.x, v.y, наблюдатель.текущенаправление);
если(Math.абсолютноезначение(bearing) < полеЗрения / 2)
выход.добавитьЭлемент(одноживотное);
}
}
возвращаемый выход;
}
общий void отрисовать(Графика g) {
Перечисление e = животновладелец.элементы();
пока(e.естьДальшеЭлементы()) {
(((Животное)e.следующийЭлемент())).отрисовать(g);
}
}
общий статический void основной(Строк[] аргументы) {
ПолеЖивотных поле = новый ПолеЖивотных();
поле.xОбласть = 640;
поле.yОбласть = 480;
Окно окно = новый Окно("Поле 'О Животных'");
// По желанию использовать командную строку аргумент
// для времени сна:
если(аргументы.length >= 1)
поле.delay = Целое.parseInt(аргументы[0]);
окно.addWindowListener(
новый WindowAdapter() {
общего void windowClosing(WindowEvent e) {
Система.exit(0);
}
});
);
окно.add(поле, BorderLayout.CENTER);
окно.setSize(640,480);
поле.init();
поле.start();
окно.setVisible(истинный);
}
} ///:~
```
```Примечание: В данном переводе были использованы названия классов и методов, которые могут отличаться от реальных названий в Java. Например, `Color`, `Graphics`, `Frame` и другие ключевые слова остаются без изменения согласно правилам перевода. Также были адаптированы названия классов и методов для лучшего понимания на русском языке. Хорошим примером такого поведения является работа Craig Reynold'a "Boids". Она демонстрирует уникальные и привлекательные особенности. Изменение значений позволяет полностью настраивать систему. Для получения более подробной информации о групповом поведении можно посетить страницу Craig Reynold'a — там также доступна публичная версия Yö 3D-симуляции Boids:
http://www.hmt.com/cwr/boids.html
Чтобы запустить этот скрипт как апплет, установите следующие параметры в вашем HTML-файле:
```html
<applet
code=FieldOBeasts
width=640
height=480>
<param name=xExtent value="640">
<param name=yExtent value="480">
</applet>
```
Фиксировано:
"Yö 3D-симуляции Boids" -> "3D-симуляции Boids"
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )