реклама
разместить

Простая система частиц на SFML C++

Простая система частиц на SFML C++

Простая система частиц на SFML C++

Приветствую всех, кто интересуется графикой и программированием! Сегодня мы погрузимся в увлекательный мир создания систем частиц с помощью библиотеки SFML на C++. Эта тема открывает широкие возможности для визуализации различных эффектов, от простых искр и дыма до сложных взрывов и магических заклинаний в играх и других приложениях.

Системы частиц — это мощный инструмент для генерации динамических визуальных эффектов. Они основаны на идее создания множества мелких объектов (частиц), каждый из которых обладает собственными параметрами, такими как положение, скорость, цвет, размер и время жизни. Управляя этими параметрами, можно добиться самых разнообразных результатов.

Создадим отдельный класс для управления системой частиц.

Назовём его ParticleSystem. Ниже реализация кода данного класса.

#pragma once #include <SFML/Graphics.hpp> #include <vector> struct Particle { sf::Vector2f velocity; sf::Vector2f position; sf::Color color; }; class ParticleSystem : public sf::Drawable, public sf::Transformable { public: ParticleSystem(); void addParticle(sf::Vector2f position, sf::Vector2f velocity, sf::Color color); void update(sf::Time elapsed, sf::RenderWindow& window); private: std::vector<Particle> particles; sf::VertexArray vertices; virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const; };

Опишем свойства и методы класса ParticleSystem.

Класс наследуется от классов библиотеки SFML:

Drawable - позволяет объектам класса ParticleSystem быть нарисованными с помощью метода window.draw, переопределяя метод draw;

Transformable - позволяет использовать трансформации, в нашем случае перемещение для всей системы частиц.

Публичные поля.

Конструктор класса - инициализирует систему частиц.

Метод addParticle добавляет новую частицу в систему.

Параметры данного метода:

position - начальная позиция частицы;

velocity - вектор скорости;

color - цвет частицы.

Метод update - обновляет состояние всех частиц.

Параметры метода:

elapsed - время, прошедшее с момента последнего обновления, используется для корректного перемещения частиц;

window - cсылка на графическое окно, для проверки, находятся ли частицы внутри границ окна.

Приватные поля.

Контейнер вектор particles для хранения всех частиц. Каждая частица представляет собой объект структуры Particle.

Массив вершин vertices, представляющий графическое отображение всех частиц. Связывает частицы с их визуальными атрибутами это позиция и цвет.

Виртуальный метод draw. Это переопределённый метод от класса Drawable, отвечающий за отрисовку частиц.

Далее реализовываем методы данного класса.

#include "ParticleSystem.h" // Конструктор ParticleSystem::ParticleSystem() { vertices.setPrimitiveType(sf::PrimitiveType::Points); } void ParticleSystem::addParticle(sf::Vector2f position, sf::Vector2f velocity, sf::Color color) { Particle particle; particle.position = position; particle.velocity = velocity; particle.color = color; particles.push_back(particle); sf::Vertex vertex; vertex.position = position; vertex.color = color; vertices.append(vertex); } void ParticleSystem::update(sf::Time elapsed, sf::RenderWindow& window) { std::vector<Particle> updatedParticles; sf::VertexArray updatedVertices(sf::PrimitiveType::Points); for (std::size_t i = 0; i < particles.size(); ++i) { Particle& particle = particles[i]; particle.position += particle.velocity * elapsed.asSeconds(); if (particle.position.x >= 0 && particle.position.x <= window.getSize().x && particle.position.y >= 0 && particle.position.y <= window.getSize().y) { updatedParticles.push_back(particle); sf::Vertex vertex; vertex.position = particle.position; vertex.color = particle.color; updatedVertices.append(vertex); } } particles = std::move(updatedParticles); vertices = std::move(updatedVertices); } void ParticleSystem::draw(sf::RenderTarget& target, sf::RenderStates states) const { states.transform *= getTransform(); target.draw(vertices, states); }

Конструктор ParticleSystem устанавливает тип графического примитива массива вершин как "точки". Это значит, что каждая вершина будет отрисовываться как отдельная точка на экране.

Метод добавления частицы addParticle. Добавляет новую частицу в систему. Создаёт объект Particle, в который записываются: позиция, скорость, цвет. Этот объект добавляется в массив particles т.е. вектор всех частиц. Создаётся вершина vertex, которая определяет: позицию частицы и цвет частицы. Эта вершина добавляется в массив vertices, чтобы позже её можно было отобразить.

Метод обновления частиц update. Обновляет позиции частиц и удаляет те частицы, которые вышли за границы окна. Создаются временные контейнеры:

updatedParticles - для хранения обновлённых частиц;

updatedVertices - для хранения новых вершин, соответствующих обновлённым частицам.

Цикл перебирает каждую частицу из вектора particles. Вычисляется новое положение частицы. Если новая позиция частицы находится в пределах границ окна: Частица добавляется в updatedParticles. Создаётся соответствующая вершина, которая добавляется в updatedVertices. После завершения цикла, cтарые массивы particles и vertices заменяются на новые с использованием move для оптимального переноса данных.

Метод отрисовки draw отвечает за отрисовку системы частиц на экране. Метод является переопределением функции draw из класса Drawable. Конструкция states.transform *= getTransform() применяет текущую трансформацию, например позицию к нашей точке, перед отрисовкой. Далее target.draw(vertices, states) отрисовывает массив вершин vertices на целевом объекте target т.е. RenderWindow.

В следующем коде используем данный класс для реализации эффекта фейерверка т.е. распыления частиц в разные стороны, пока будет зажата левая кнопка мыши.

#include "ParticleSystem.h" #include <random> std::random_device rd; std::mt19937 gen(rd()); float randomFloat(float min, float max) { std::uniform_real_distribution<float> dist(min, max); return dist(gen); } int randomInt(int min, int max) { std::uniform_int_distribution<int> dist(min, max); return dist(gen); } int main() { sf::RenderWindow window(sf::VideoMode(1280, 720), "Particle System with Modules"); ParticleSystem particles; sf::Clock clock; sf::Clock mousePressTimer; bool isMousePressed = false; sf::Vector2f emitterPosition; while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) window.close(); if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) { isMousePressed = true; mousePressTimer.restart(); emitterPosition = sf::Vector2f(sf::Mouse::getPosition(window)); } if (event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left) { isMousePressed = false; } } sf::Time elapsed = clock.restart(); if (isMousePressed) { if (mousePressTimer.getElapsedTime().asMilliseconds() >= 1.0f) { mousePressTimer.restart(); float angle = randomFloat(0.f, 360.f) * 3.14f / 180.f; float speed = randomFloat(50.f, 200.f); sf::Vector2f velocity(std::cos(angle) * speed, std::sin(angle) * speed); sf::Color color = sf::Color(randomInt(0, 255), randomInt(0, 255), randomInt(0, 255)); particles.addParticle(emitterPosition, velocity, color); } } particles.update(elapsed, window); window.clear(); window.draw(particles); window.display(); } return 0; }

Устанавливаем глобальные переменные для генерации случайных чисел.

std::random_device rd;

std::mt19937 gen(rd());

Функция randomFloat возвращает случайное число с плавающей точкой в диапазоне от min до max.

Функция randomInt возвращает целое случайное число в заданном диапазоне.

sf::RenderWindow window(sf::VideoMode(1280, 720), "Particle System with Modules");

Данный код создаёт графическое окно размером 1280 x 720 пикселей с заголовком «Particle System with Modules».

Объекты и переменные:

particles - экземпляр системы частиц, где хранятся и обновляются данные о частицах;

clock - таймер для измерения времени между кадрами т.е. управление скоростью обновления;

mousePressTimer - таймер для определения длительности удержания левой кнопки мыши;

isMousePressed - флаг, указывающий, зажата ли левая кнопка мыши; emitterPosition - позиция эмиттера т.е. координаты точки появления частиц.

Блок обработки событий:

event - объект для обработки событий;

if (event.type == sf::Event::Closed) window.close();

Конструкция обработки события закрытия окна. Если пользователь нажал кнопку "Закрыть", окно закрывается.

Блок обработки события - нажатие и удержание левой кнопки мыши.

if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) {

isMousePressed = true;

mousePressTimer.restart();

emitterPosition = sf::Vector2f(sf::Mouse::getPosition(window));

}

if (event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left) {

isMousePressed = false;

}

При нажатии кнопки мыши, устанавливается флаг isMousePressed в положение true. Сбрасывается таймер mousePressTimer т.е. запускается отсчёт времени. Записывается текущая позиция мыши в emitterPosition.

При отпускании кнопки: флаг isMousePressed сбрасывается.

Также не забываем создать глобальный цикл графического окна while (window.isOpen()) и цикл обработки событий while (window.pollEvent(event)).

Блок обновление частиц:

elapsed - время, прошедшее с последнего кадра, используется для обновления движения частиц.

if (mousePressTimer.getElapsedTime().asMilliseconds() >= 1.0f)

Если мышь зажата, каждую одну миллисекунду создаётся новая частица.

float angle = randomFloat(0.f, 360.f) * 3.14f / 180.f;

Вычисляется случайный угол и скорость частицы.

float speed = randomFloat(50.f, 200.f);

Вычисляется начальная скорость и цвет.

Новая частица добавляется в систему через метод addParticle.

Метод particlesupdate обновляет все частицы.

Далее очищаем графическое окно window.clear(), отрисовываем частицы через метод draw системы частиц window.draw(particles).

window.display()

Отображаем новый кадр.

Более подробную инструкцию вы можете получить, посмотрев видео «Простая система частиц SFML C++»

22
реклама
разместить
Начать дискуссию
Как писать шейдеры по уму. Шейдер дождливой погоды [Shader Graph]

В этой статье мы разберем как сделать простой шейдер дождя и намокания поверхностей, который будет управляться внешним скриптом-контроллером. В этом простом примере мы учтем весь производственный цикл и рассмотрим как сделать все этапы правильно 🥸

3131
44
🎮💾 Оптимизация памяти в Unity: как избежать лагов и повысить FPS в играх
🎮💾 Оптимизация памяти в Unity: как избежать лагов и повысить FPS в играх

Бывало ли такое, что вы вложили всю душу в создание потрясающей игры на Unity, а потом видите, как ее мучают проблемы с производительностью? Лаги и вылеты могут отпугнуть игроков. Но не пугайтесь, при правильном подходе к оптимизации памяти вы сможете добиться высокой производительности даже в самых крупных проектах.

99
Как написать сложный пользовательский шейдер для Unreal Engine

Не привлекая внимания санитаров.

Как написать сложный пользовательский шейдер для Unreal Engine
3333
99
11
после прочтения поняла только что ты очень умный, а я очень тупая
Ищем программиста на Юнити в команду рпг про ведьмочку. Так же есть вакансия для дизайнера интерфейсов и аниматора.

Проект начал кодится по итогу на юнити.ДИСКЛЕЙМЕР: Платить зп у меня возможности нет в настоящий момент. Даже если вы замечательный специалист - но готовы работать только за деньги в руки - ничем не могу помочь.Теперь для оставшихся.

44
11
Как грамотно вывести "Hello World" на C++ что бы вас зауважали. Глава 2/финал.

Ну что погнали, тема сегодняшней главы такова:

Как грамотно вывести "Hello World" на C++ что бы вас зауважали. Глава 2/финал.
99
11
11
Как грамотно вывести "Hello World" на C++ что бы вас зауважали. Глава 1.

В данной статье, я:

Жмахаем кнопку создать проект.
44
44
11
11
Вторая часть исследования Nau Engine

Во второй части нашей трилогии об игровом движке Nau Engine мы обсудим важные аспекты оптимизации и повышения производительности. Наша цель — выявить проблемы, которые могут повлиять на эффективность и стабильность игр, созданных с использованием Nau Engine.

Вторая часть исследования Nau Engine
55
За что отвечают графические настройки в играх. Рассказываю простым языком с примерами
За что отвечают графические настройки в играх. Рассказываю простым языком с примерами

Привет! Рад написать новую статью, в которой я постараюсь для обычного рядового геймера по пальцам объяснить, за что отвечают графические настройки в играх, потому что многие геймеры до сих пор не понимают, что такое антиалиасинг, вертикальная синхронизация и так далее. А эти штуки напрямую влияют на игровой процесс (вертикальная синхронизация так…

529529
3333
2424
99
66
33
33
22
11
11
Хахах, при вертикальной синхронизации большая нагрузка на производительность? Что?
Гайд на шикарные анимешные деревья в Unreal Engine 5
Гайд на шикарные анимешные деревья в Unreal Engine 5
88
11
реклама
разместить
ChatGPT вместо программиста

Поиски заинтересованного кодера пока идут безрезультатно. Поэтому делаю несложные скрипты при помощи чатаЖПТ. Пока получается. Сделал базовую смену дня и ночи с автоматическим включением и выключением ночных фонарей и сменой цвета глобального освещения, сделал покачивание предметов, как при левитации, сделал вращение кое-где и тд.

На сколько реально вообще запрограммировать механики прототипа при помощи нейросетей при условии, что я буду подробно ему давать описание каждого параметра и как это должно работать человеческим языком?

11
Какие хитрые трюки и методы используются в разработке игр
Какие хитрые трюки и методы используются в разработке игр

Решил коротко рассказать про некоторые хитрые штуковины, которые используются при разработке игр. Штуки эти общеупотребимы, поэтому используются почти во всех играх. И если вы далеки от разработки игр, то некоторые штуки, думаю, вам будет интересно узнать.

201201
1414
22
22
11
Набор костылей и велосипедов которые на самом деле уродуют сцену и на которые разработчики вынуждены идти что бы фпс был больше 0. Лично я все эти "хитрые трюки и методы" видел и не недолюбливал всю игровую жизнь(30+лет), т.к. каждый раз когда вижу это дерьмо выпадаю из погружения. Лучше уж обмазаться лучами и длссами в низком разрешении, чем в 4К кристально четко видеть что сцена - фанерный фуфел. Но на самом деле лучи это пол беды, а вот физика и коллизии гораздо более серьезная проблема, для решения которой нет даже намека на технологии...
Fallout на WPF

На днях вспомнил про свой пет-проект семилетней давности и подумал, что будет интересно поделиться тем, как я почти "сделал" Fallout на WPF с 20 fps-геймингом.

1515
22
11
11