某アークな音ゲー風クリックエフェクト
https://gyazo.com/2bcc37bb3519048f410842fcd8455b8b
説明
アークな音ゲーのエフェクトです。
Textureには、デフォルトで入っているexample/particle.pngを使用しています。
コード
code:Main.cpp
# include <Siv3D.hpp> // OpenSiv3D v0.6.10
//ライトブルームクラス
class LightBloom {
public:
const RenderTexture gaussianA1, gaussianB1;
const RenderTexture gaussianA4, gaussianB4;
const RenderTexture gaussianA8, gaussianB8;
const Size area;
const ColorF colorA1, colorA4, colorA8;
LightBloom(const Size& size, const ColorF& colorA1 = ColorF(0.1), const ColorF& colorA4 = ColorF(0.4), const ColorF& colorA8 = ColorF(0.8))
:area{ size },
gaussianA1{ size }, gaussianB1{ size },
gaussianA4{ size / 4 }, gaussianB4{ size / 4 },
gaussianA8{ size / 8 }, gaussianB8{ size / 8 },
colorA1{ colorA1 },
colorA4{ colorA4 },
colorA8{ colorA8 } {}
void draw()
{
Shader::GaussianBlur(gaussianA1, gaussianB1, gaussianA1);
Shader::Downsample(gaussianA1, gaussianA4);
Shader::GaussianBlur(gaussianA4, gaussianB4, gaussianA4);
Shader::Downsample(gaussianA4, gaussianA8);
Shader::GaussianBlur(gaussianA8, gaussianB8, gaussianA8);
const ScopedRenderStates2D blend{ BlendState::Additive };
gaussianA1.resized(area).draw(colorA1);
gaussianA4.resized(area).draw(colorA4);
gaussianA8.resized(area).draw(colorA8);
}
};
struct ArcaeaEffect : IEffect
{
struct Broke
{
double theta; //極座標の角度
double target; //どれだけ動かすか
bool sheardX; //true:sheardX false:sheardY
double sheard; //スライドさせる強さ
double angle; //回転させる角度
double Hue; //色相
double Sat; //彩度
double Bri; //明度
double size; //大きさ
};
private:
Vec2 m_pos;
Texture m_texture;
LightBloom light{ Scene::Size(), ColorF{1}, ColorF{1}, ColorF{1} };
Array<Broke> brokes;
public:
ArcaeaEffect(const Vec2& pos, const Texture& texture)
:m_pos{ pos },
m_texture{ texture }
{
for (auto i : step(30))
{
Broke broke
{
.theta = Random(0_deg, 360_deg),
.target = Random(40.0, 120.0),
.sheardX = RandomBool(),
.sheard = Random(-10.0, 10.0),
.angle = Random(-15_deg, 15_deg),
.Hue = 300 + Random(-30.0, 30.0),
.Sat = Random(0.2, 0.4),
.Bri = Random(0.1, 0.7),
.size = Random(6.0, 11.0),
};
brokes << broke;
}
}
//飛び散る破片を描く関数
void drawBroke(double t)
{
const double e = EaseOutExpo(t);
const double a = EaseInOutQuart(t);
for (auto& broke : brokes)
{
if (broke.sheardX) RectF{ Arg::center(OffsetCircular{m_pos, e * broke.target, broke.theta}), broke.size }.shearedX(broke.sheard).rotatedAt(OffsetCircular{ m_pos, e * broke.target, broke.theta }, broke.angle).draw(HSV(broke.Hue, broke.Sat, broke.Bri, 1 - a));
else RectF{ Arg::center(OffsetCircular{m_pos, e * broke.target, broke.theta}), broke.size }.shearedY(broke.sheard).rotatedAt(OffsetCircular{ m_pos, e * broke.target, broke.theta }, broke.angle).draw(HSV(broke.Hue, broke.Sat, broke.Bri, 1 - a));
}
}
//円の線を描く関数
void drawCircleFrame(double t)
{
const double e = EaseOutExpo(t);
const double a = EaseInOutQuart(t);
Circle{ m_pos, e * 60 }.drawFrame(2 - a * 2, HSV(300, 0.1, 1, 1 - a));
}
//真ん中の光ってるやつを描く関数
void drawFlare(double t)
{
const double e = EaseOutExpo(t);
const double a = EaseInOutQuart(t);
{
const ScopedRenderTarget2D target{ light.gaussianA1.clear(ColorF{ 0.0 }) };
const ScopedRenderStates2D blend{ BlendState::Additive };
m_texture.scaled(2.0 - a * 2.0).drawAt(m_pos, HSV(300, 1, 0.8, 1.2 - a));
m_texture.scaled(2.0 - a * 2.0).drawAt(m_pos, HSV(300, 0.3, 1, 1.2 - a));
m_texture.scaled(Vec2(e * 10.0, 4 * (1 - e))).drawAt(m_pos, HSV(300, 0.5, 0.8, 1 - a));
}
light.draw();
}
bool update(double t) override
{
t *= 2;
drawBroke(t);
drawCircleFrame(t);
drawFlare(t);
return t < 1.0;
}
};
void Main()
{
Effect effect;
const Texture texture{ U"example/particle.png", TextureDesc::Mipped };
while (System::Update())
{
if (MouseL.down())
{
effect.add<ArcaeaEffect>(Cursor::PosF(), texture);
}
effect.update();
}
}
作者
たのれん