Скачиваний:
0
Добавлен:
12.02.2026
Размер:
643.13 Кб
Скачать

Список литературы

1. Стаи и толпы в играх: как программируют реалистичное стайное поведения // Skillbox Media. URL: https://skillbox.ru/media/gamedev/stai-i-tolpy-v- igrakh-kak-programmiruyut-realistichnoe-staynoe-povedenie/

(дата обращения: 07.12.2025).

2.Reynolds C.W. Flocks, herds, and schools: a distributed behavioral model / C.W. Reynolds // Computer Graphics, 1987. Вып. 21 (4, Июль). C. 25-34.

3.Boids – простой алгоритм перемещения групп юнитов // Habr. URL: https://habr.com/ru/articles/212721/ (дата обращения: 07.12.2025).

4.Boid'ы, птички и Unity3D // Habr. URL: https://habr.com/ru/articles/182382/

(дата обращения: 07.12.2025).

5. Bird–oid

objects,

поведение

стаи

//

igonin.ru.

URL:

https://igonin.ru/help/algorithms/bird–oid–objects/ (дата обращения: 07.12.2025).

21

Приложение Листинг программы

%% Инициализация параметров clear; clc; close all;

% Параметры алгоритма

numBoids = 20; % Количество боидов cohesionWeight = 1.0; % Вес сцепления

cohesionDist = 2.0; % Расстояние сцепления separationWeight = 1.5; % Вес разделения separationDist = 1.0; % Расстояние разделения alignmentWeight = 1.0; % Вес выравнивания alignmentDist = 1.5; % Расстояние выравнивания

minSpeed = 0.5; % Минимальная скорость maxSpeed = 20; % Максимальная скорость

% Параметры симуляции

numIterations = 200; % Количество итераций

fieldSize = 50;

% Размер поля

dt = 0.1;

% Шаг времени

% Цвета для разных боидов colors = lines(numBoids);

%% Инициализация боидов

% Начальные позиции (случайные в пределах поля) positions = (rand(numBoids, 2) – 0.5) * fieldSize;

% Начальные скорости (случайные направления с фиксированной скоростью) initialSpeed = (minSpeed + maxSpeed) / 2;

angles = 2 * pi * rand(numBoids, 1);

velocities = initialSpeed * [cos(angles), sin(angles)];

% Массивы для хранения траекторий

trajectories = cell(numBoids, 1);

22

for i = 1:numBoids trajectories{i} = positions(i, :);

end

%% Создание графического окна figure('Position', [100, 100, 1200, 500]);

% Подграфик 1: Анимация движения subplot(1, 2, 1);

hAx1 = gca; hold on; axis equal;

xlim([–fieldSize, fieldSize]); ylim([–fieldSize, fieldSize]); grid on;

xlabel('X');

ylabel('Y');

title('Анимация движения боидов');

% Создание графических объектов для боидов boidPlots = gobjects(numBoids, 1); trajectoryPlots = gobjects(numBoids, 1); velocityQuivers = gobjects(numBoids, 1);

for i = 1:numBoids % Траектории

trajectoryPlots(i) = plot(NaN, NaN, '–', 'Color', colors(i, :), ...

'LineWidth', 0.5, 'DisplayName', sprintf('Боид %d', i)); % Векторы скорости

velocityQuivers(i) = quiver(positions(i,1), positions(i,2), ...

velocities(i,1), velocities(i,2), 'Color', colors(i, :), ...

'LineWidth', 2, 'MaxHeadSize', 2, 'AutoScale', 'off'); % Маркеры боидов

23

boidPlots(i) = plot(positions(i,1), positions(i,2), 'o', ...

'MarkerSize', 10, 'MarkerFaceColor', colors(i, :), ...

'MarkerEdgeColor', 'k', 'LineWidth', 1);

end

legend(trajectoryPlots, 'Location', 'bestoutside'); hold off;

% Подграфик 2: Визуализация влияния правил subplot(1, 2, 2);

hAx2 = gca; hold on; axis equal;

xlim([–fieldSize, fieldSize]); ylim([–fieldSize, fieldSize]); grid on;

xlabel('X');

ylabel('Y');

title('Визуализация влияния правил'); hold off;

%% Главный цикл симуляции for iteration = 1:numIterations

% Буферы для новых скоростей и позиций newVelocities = zeros(size(velocities));

for i = 1:numBoids

% Поиск соседей в пределах максимального радиуса взаимодействия maxInteractionDist = max([cohesionDist, separationDist, alignmentDist]); dists = sqrt(sum((positions – positions(i, :)).^2, 2));

neighbors = find(dists > 0 & dists < maxInteractionDist);

% Инициализация векторов правил separationVec = [0, 0];

24

cohesionVec = [0, 0]; alignmentVec = [0, 0]; numNeighbors = length(neighbors); if numNeighbors > 0

% Вычисление разделения (отталкивание от близких соседей) closeNeighbors = neighbors(dists(neighbors) < separationDist);

if ~isempty(closeNeighbors)

for j = 1:length(closeNeighbors) neighborIdx = closeNeighbors(j);

diff = positions(i, :) – positions(neighborIdx, :); dist = dists(neighborIdx);

if dist > 0

separationVec = separationVec + (diff / dist^2); end

end

separationVec = separationVec / length(closeNeighbors); end

%Вычисление сцепления (движение к центру масс соседей) cohesionNeighbors = neighbors(dists(neighbors) < cohesionDist); if ~isempty(cohesionNeighbors)

centerOfMass = mean(positions(cohesionNeighbors, :), 1); cohesionVec = (centerOfMass – positions(i, :)); distToCenter = norm(cohesionVec);

if distToCenter > 0

cohesionVec = cohesionVec / distToCenter; end

end

%Вычисление выравнивания (совпадение со средней скоростью соседей)

alignmentNeighbors = neighbors(dists(neighbors) < alignmentDist);

25

if ~isempty(alignmentNeighbors)

avgVelocity = mean(velocities(alignmentNeighbors, :), 1); alignmentVec = avgVelocity – velocities(i, :);

alignMag = norm(alignmentVec); if alignMag > 0

alignmentVec = alignmentVec / alignMag; end

end end

% Применение весов к правилам

separationVec = separationWeight * separationVec; cohesionVec = cohesionWeight * cohesionVec; alignmentVec = alignmentWeight * alignmentVec; % Вычисление новой скорости

acceleration = separationVec + cohesionVec + alignmentVec; % Нормализация ускорения

accelMag = norm(acceleration); if accelMag > 0

acceleration = acceleration / accelMag; end

% Обновление скорости

newVelocities(i, :) = velocities(i, :) + acceleration * dt; % Ограничение скорости

speed = norm(newVelocities(i, :)); if speed > maxSpeed

newVelocities(i, :) = (newVelocities(i, :) / speed) * maxSpeed; elseif speed < minSpeed

newVelocities(i, :) = (newVelocities(i, :) / max(speed, 0.001)) * minSpeed; end

26

% Обновление траектории

trajectories{i} = [trajectories{i}; positions(i, :)]; end

% Обновление позиций velocities = newVelocities;

positions = positions + velocities * dt;

% Обработка границ поля (отражение от стен) for i = 1:numBoids

if abs(positions(i, 1)) > fieldSize velocities(i, 1) = –velocities(i, 1);

positions(i, 1) = sign(positions(i, 1)) * fieldSize * 0.99; end

if abs(positions(i, 2)) > fieldSize velocities(i, 2) = –velocities(i, 2);

positions(i, 2) = sign(positions(i, 2)) * fieldSize * 0.99; end

end

%% Обновление графики

% Обновление анимации subplot(1, 2, 1);

for i = 1:numBoids

% Обновление маркера боида

set(boidPlots(i), 'XData', positions(i, 1), 'YData', positions(i, 2)); % Обновление траектории

set(trajectoryPlots(i), 'XData', trajectories{i}(:,1), ...

'YData', trajectories{i}(:,2));

% Обновление вектора скорости

set(velocityQuivers(i), 'XData', positions(i, 1), ...

'YData', positions(i, 2), ...

27

'UData', velocities(i, 1), 'VData', velocities(i, 2));

end

% Обновление визуализации влияния правил subplot(1, 2, 2);

cla; hold on;

axis equal;

xlim([–fieldSize, fieldSize]); ylim([–fieldSize, fieldSize]); grid on;

title(sprintf('Визуализация влияния правил (Итерация: %d)', iteration)); % Отображение зон влияния для первого боида

i = 1; % Анализируем первого боида

% Рисуем круги зон влияния theta = linspace(0, 2*pi, 100);

% Зона разделения (красная)

xSep = separationDist * cos(theta) + positions(i, 1); ySep = separationDist * sin(theta) + positions(i, 2); fill(xSep, ySep, [1, 0.8, 0.8], 'EdgeColor', [1, 0.5, 0.5], ...

'LineWidth', 1, 'FaceAlpha', 0.3);

text(positions(i,1), positions(i,2)+separationDist*1.1, ...

'Разделение', 'Color', [1, 0, 0], 'HorizontalAlignment', 'center'); % Зона выравнивания (синяя)

xAlign = alignmentDist * cos(theta) + positions(i, 1); yAlign = alignmentDist * sin(theta) + positions(i, 2); plot(xAlign, yAlign, 'b––', 'LineWidth', 1); text(positions(i,1), positions(i,2)+alignmentDist*1.1, ...

'Выравнивание', 'Color', [0, 0, 1], 'HorizontalAlignment', 'center'); % Зона сцепления (зелёная)

28

xCoh = cohesionDist * cos(theta) + positions(i, 1); yCoh = cohesionDist * sin(theta) + positions(i, 2); plot(xCoh, yCoh, 'g––', 'LineWidth', 1); text(positions(i,1), positions(i,2)+cohesionDist*1.1, ...

'Сцепление', 'Color', [0, 0.7, 0], 'HorizontalAlignment', 'center'); % Поиск соседей в разных зонах

dists = sqrt(sum((positions – positions(i, :)).^2, 2)); separationNeighbors = find(dists > 0 & dists < separationDist); alignmentNeighbors = find(dists > 0 & dists < alignmentDist); cohesionNeighbors = find(dists > 0 & dists < cohesionDist); % Отображение боидов

for b = 1:numBoids color = colors(b, :); markerSize = 8;

if b == i

color = 'k'; % Выделяем анализируемого боида markerSize = 12;

elseif ismember(b, separationNeighbors)

color = [1, 0, 0]; % Красный для соседей в зоне разделения elseif ismember(b, alignmentNeighbors)

color = [0, 0, 1]; % Синий для соседей в зоне выравнивания elseif ismember(b, cohesionNeighbors)

color = [0, 0.7, 0]; % Зелёный для соседей в зоне сцепления end

plot(positions(b, 1), positions(b, 2), 'o', ...

'MarkerSize', markerSize, 'MarkerFaceColor', color, ...

'MarkerEdgeColor', 'k', 'LineWidth', 1); % Векторы скорости quiver(positions(b,1), positions(b,2), ...

29

velocities(b,1), velocities(b,2), 0.5, ...

'Color', colors(b, :), 'LineWidth', 1.5, 'MaxHeadSize', 1);

end

% Отображение центра масс для зоны сцепления if ~isempty(cohesionNeighbors)

centerOfMass = mean(positions(cohesionNeighbors, :), 1);

plot(centerOfMass(1), centerOfMass(2), 'gx', ...

'MarkerSize', 15, 'LineWidth', 2);

plot([positions(i,1), centerOfMass(1)], ...

[positions(i,2), centerOfMass(2)], 'g–', 'LineWidth', 2);

end hold off;

% Пауза для анимации pause(0.05);

% Обновление заголовка первого графика subplot(1, 2, 1);

title(sprintf('Движение боидов (Итерация: %d/%d)', iteration, numIterations)); end

%% Отображение итоговой статистики

fprintf('=== СТАТИСТИКА СИМУЛЯЦИИ ===\n'); fprintf('Количество боидов: %d\n', numBoids); fprintf('Количество итераций: %d\n', numIterations); fprintf('Параметры алгоритма:\n');

fprintf(' Вес сцепления: %.2f\n', cohesionWeight); fprintf(' Вес разделения: %.2f\n', separationWeight); fprintf(' Вес выравнивания: %.2f\n', alignmentWeight);

fprintf(' Скорости: min=%.2f, max=%.2f\n', minSpeed, maxSpeed); % Вычисление средней скорости

avgSpeed = mean(sqrt(sum(velocities.^2, 2))); 30

Соседние файлы в папке Движение стай (Boids)