Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
//based on https://siv3d.github.io/ja-jp/reference/2d-particle/
# include <Siv3D.hpp>
const String siv3d_kun_path = U"example/siv3d-kun.png";
Polygon CreateSiv3D_kunPolygon()
{
return Image(siv3d_kun_path)
.alphaToPolygonCentered().simplified(1);
}
auto CreateParticleTexture()
{
Image image{ 128,128 };
Shape2D::NStar(5, 64, 32, image.size() / 2).asPolygon().overwrite(image, Palette::White);
return Texture{ image };
};
void Main()
{
Window::Resize(1280, 720);
bool debugMode = false;
bool whiteBackground = false;
const std::array<BlendState, 4> blends = {
BlendState::Default, BlendState::Additive, BlendState::Opaque, BlendState::Subtractive
};
size_t blendIndex = 0;
CircleEmitter2D circleEmitter;
ArcEmitter2D arcEmitter;
RectEmitter2D rectEmitter;
PolygonEmitter2D polygonEmitter(CreateSiv3D_kunPolygon());
enum EmitterType : size_t {
Circle, Arc, Rect, Polygon,
};
size_t emitterIndex = EmitterType::Arc;
Vec2 position{ 300, 340 };
Vec2 force{ 0.0, 0.0 };
ParticleSystem2D particleSystem(position, force);
particleSystem.setEmitter(arcEmitter);
particleSystem.setTexture(CreateParticleTexture());
particleSystem.prewarm();
ParticleSystem2DParameters parameters;
HSV startColor{ ColorF(1.0) };
const Texture texture = Texture(siv3d_kun_path);
bool drawTexture = false;
while (System::Update())
{
SimpleGUI::CheckBox(debugMode, U"Debug", Vec2(40, 660), 120);
SimpleGUI::CheckBox(whiteBackground, U"White", Vec2(160, 660), 120);
SimpleGUI::CheckBox(drawTexture, U"Texture", Vec2(280, 660), 140, (emitterIndex == EmitterType::Polygon));
Scene::SetBackground(whiteBackground ? Color(250, 252, 255) : Palette::DefaultBackground);
{//particleSystem,parametersの設定
const int32 x = 560, labelw = 120, sliderw = 200;
SimpleGUI::Slider(U"Rate", parameters.rate, 1.0, 500.0, { x, 20 }, labelw, sliderw);
SimpleGUI::Slider(U"Max", parameters.maxParticles, 50.0, 2500.0, Vec2(x, 60), labelw, sliderw);
SimpleGUI::Slider(U"LifeTime", parameters.startLifeTime, 0.0, 5.0, Vec2(x, 100), labelw, sliderw);
SimpleGUI::Slider(U"Speed", parameters.startSpeed, 0.0, 320.0, Vec2(x, 140), labelw, sliderw);
SimpleGUI::ColorPicker(startColor, Vec2(x, 180));
SimpleGUI::Slider(U"Size", parameters.startSize, 0.0, 150.0, Vec2(x, 300), labelw, sliderw);
SimpleGUI::Slider(U"Rotation", parameters.startRotationDeg, -180, 180, Vec2(x, 340), labelw, sliderw);
SimpleGUI::Slider(U"AngularVel", parameters.startAngularVelocityDeg, -720, 720, Vec2(x, 380), labelw, sliderw);
SimpleGUI::Slider(U"Force X", force.x, -320.0, 320.0, Vec2(x, 420), labelw, sliderw);
SimpleGUI::Slider(U"Force Y", force.y, -320, 320.0, Vec2(x, 460), labelw, sliderw);
SimpleGUI::RadioButtons(blendIndex, { U"Default", U"Additive", U"Opaque", U"Subtractive" }, Vec2(x, 500), 320);
SimpleGUI::CheckBox(parameters.randomStartRotation, U"randomRotation", Vec2(x, 660), 220);
SimpleGUI::CheckBox(parameters.randomAngularVelocity, U"randomAngularVelocity", Vec2(x + 200, 660), 280);
parameters.blendState = blends[blendIndex];
parameters.startColor = startColor;
particleSystem.setParameters(parameters);
particleSystem.setForce(force);
if (MouseR.pressed())
particleSystem.setPosition(position = Cursor::Pos());
}
{//emitterの設定
const int32 x = 900, labelw = 120, sliderw = 200;
bool emitterChanged = false;
emitterChanged = SimpleGUI::RadioButtons(emitterIndex, { U"Circle", U"Arc", U"Rect", U"Polygon" }, Vec2(x, 20), 360);
switch (emitterIndex)
{
case EmitterType::Circle:
emitterChanged |= SimpleGUI::Slider(U"Source Radius", circleEmitter.sourceRadius, 0.0, 40.0, Vec2(x, 180), 160, 200);
emitterChanged |= SimpleGUI::Slider(U"R", circleEmitter.r, 0.0, 320.0, Vec2(x, 220), 160, 200);
emitterChanged |= SimpleGUI::CheckBox(circleEmitter.randomDirection, U"Random Direction", Vec2(x, 260), 360);
emitterChanged |= SimpleGUI::CheckBox(circleEmitter.fromShell, U"From Shell", Vec2(x, 300), 300);
if (emitterChanged) // setEmitter は重い処理なので、変更があった時だけ
particleSystem.setEmitter(circleEmitter);
break;
case EmitterType::Arc:
emitterChanged |= SimpleGUI::Slider(U"Source Radius", arcEmitter.sourceRadius, 0.0, 40.0, Vec2(x, 180), 160, 200);
emitterChanged |= SimpleGUI::Slider(U"R", arcEmitter.r, 0.0, 320.0, Vec2(x, 220), 160, 200);
emitterChanged |= SimpleGUI::Slider(U"Direction", arcEmitter.direction, -180, 180, Vec2(x, 260), 160, 200);
emitterChanged |= SimpleGUI::Slider(U"Angle", arcEmitter.angle, 0.0, 360, Vec2(x, 300), 160, 200);
emitterChanged |= SimpleGUI::CheckBox(arcEmitter.randomDirection, U"Random Direction", Vec2(x, 340), 360);
emitterChanged |= SimpleGUI::CheckBox(arcEmitter.fromShell, U"From Shell", Vec2(x, 380), 360);
if (emitterChanged) // setEmitter は重い処理なので、変更があった時だけ
particleSystem.setEmitter(arcEmitter);
break;
case EmitterType::Rect:
emitterChanged |= SimpleGUI::Slider(U"Source Radius", rectEmitter.sourceRadius, 0.0, 40.0, Vec2(x, 180), 160, 200);
emitterChanged |= SimpleGUI::Slider(U"Width", rectEmitter.width, 0, 720, Vec2(x, 220), 160, 200);
emitterChanged |= SimpleGUI::Slider(U"Height", rectEmitter.height, 0, 720, Vec2(x, 260), 160, 200);
emitterChanged |= SimpleGUI::CheckBox(rectEmitter.randomDirection, U"Random Direction", Vec2(x, 300), 360);
emitterChanged |= SimpleGUI::CheckBox(rectEmitter.fromShell, U"From Shell", Vec2(x, 340), 360);
if (emitterChanged) // setEmitter は重い処理なので、変更があった時だけ
particleSystem.setEmitter(rectEmitter);
break;
case EmitterType::Polygon:
if (emitterChanged) // setEmitter は重い処理なので、変更があった時だけ
particleSystem.setEmitter(polygonEmitter);
break;
}
}
particleSystem.update();
if (debugMode)
particleSystem.drawDebug();
else
particleSystem.draw();
if (emitterIndex == EmitterType::Polygon && drawTexture)
texture.drawAt(position);
ClearPrint();
Print << U"{} particles"_fmt(particleSystem.num_particles());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment