アズールレーン風ボタン
Siv3D Discord サーバー「UI 研究ゲームジャム」に投稿したもの。
https://scrapbox.io/files/668fc01e1de53a001cce5811.mp4
code:siv_uijam_azurui_button.cpp
# include <Siv3D.hpp> // Siv3D v0.6.15
namespace AzurUI
{
namespace
{
constexpr double DefaultFontSize = 32;
constexpr SizeF Padding{ 24, 12 };
constexpr double BevelSize = 12.0;
constexpr double WhiteTriangleSize = 8.0;
constexpr double WhiteDotSize = 3.0;
constexpr Vec2 ShadowOffset{ 0, 3 };
constexpr ColorF ShadowColor{ 0, 0.2 };
constexpr ColorF DarkAreaOverlayColorTop{ 0, 0.24 };
constexpr ColorF DarkAreaOverlayColorBottom{ 0, 0.02 };
constexpr ColorF MouseoverOverlayColor{ 0, 0.05 };
constexpr ColorF PressOverlayColor{ 0, 0.08 };
constexpr double OutsideHighlightWidth = 1.0;
constexpr double BottomHighlightWidth = 3.0;
constexpr ColorF HighlightColor = ColorF{ 1.0, 0.5 };
constexpr ColorF HighlightColorWeak = ColorF{ 1.0, 0.0 };
}
void Init()
{
FontAsset::Register(U"AzurUI.Button", FontMethod::MSDF, DefaultFontSize, Typeface::Medium, FontStyle::Default);
}
enum class ButtonStyle : uint32
{
Default = 0,
Cancel,
};
bool ButtonAt(ButtonStyle style, StringView label, const Vec2& center, const Optional<SizeF> size)
{
const ColorF BaseColor = [](ButtonStyle style)
{
constexpr ColorF BaseColor_Default{ U"#66a1e8" };
constexpr ColorF BaseColor_Cancel{ Palette::Silver };
switch (style)
{
case ButtonStyle::Default: return BaseColor_Default;
case ButtonStyle::Cancel: return BaseColor_Cancel;
}
return BaseColor_Default;
}(style);
const auto font = FontAsset(U"AzurUI.Button");
double fontsize = DefaultFontSize;
RectF textRegion = font(label).regionAt(DefaultFontSize, center);
// ボタンの矩形領域
// マウスオーバー/クリック判定もこれで
RectF buttonRegion = textRegion.stretched(Padding.x, Padding.y);
if (size)
{
buttonRegion.set(Arg::center = buttonRegion.center(), *size);
fontsize = buttonRegion.h - Padding.y * 2;
}
// ボタン本体
// 左下に切り欠きがある
const Polygon buttonPolygon{
buttonRegion.tl(),
buttonRegion.tr(),
buttonRegion.br(),
buttonRegion.bl().movedBy(BevelSize, 0),
buttonRegion.bl().movedBy(0, -BevelSize),
};
buttonPolygon.draw(ShadowOffset, ShadowColor);
buttonPolygon.draw(BaseColor);
// ボタン左側を暗くする
const Quad darkAreaQuad{
buttonRegion.tl(),
buttonRegion.tl().movedBy(buttonRegion.w * 0.20, 0),
buttonRegion.bl().movedBy(buttonRegion.w * 0.92, 0),
buttonRegion.bl().movedBy(0, -BevelSize)
};
darkAreaQuad.draw(
DarkAreaOverlayColorTop,
DarkAreaOverlayColorTop,
DarkAreaOverlayColorBottom,
DarkAreaOverlayColorBottom);
// ボタン下部ハイライト
const RectF bottomHighlightHalfRect{
buttonRegion.bl().movedBy(BevelSize, -BottomHighlightWidth),
SizeF{ (buttonRegion.w - BevelSize) / 2, BottomHighlightWidth }
};
bottomHighlightHalfRect
.draw(Arg::left = HighlightColorWeak, Arg::right = HighlightColor);
bottomHighlightHalfRect.movedBy(bottomHighlightHalfRect.w, 0)
.draw(Arg::left = HighlightColor, Arg::right = HighlightColorWeak);
// ボタン外周ハイライト
RectF{ buttonRegion.tl(), SizeF{ buttonRegion.w, OutsideHighlightWidth } }
.draw(HighlightColor);
RectF{ buttonRegion.tl(), SizeF{ OutsideHighlightWidth, buttonRegion.h - BevelSize } }
.draw(Arg::top = HighlightColor, Arg::bottom = HighlightColorWeak);
RectF{ Arg::topRight = buttonRegion.tr(), SizeF{ OutsideHighlightWidth, buttonRegion.h } }
.draw(Arg::top = HighlightColor, Arg::bottom = HighlightColorWeak);
// マウス
if (buttonRegion.leftPressed())
{
buttonPolygon.draw(PressOverlayColor);
}
else if (buttonRegion.mouseOver())
{
buttonPolygon.draw(MouseoverOverlayColor);
}
// 左下
const auto tri = Triangle{
buttonRegion.bl(),
buttonRegion.bl().movedBy(WhiteTriangleSize, 0),
buttonRegion.bl().movedBy(0, -WhiteTriangleSize) };
tri.movedBy(ShadowOffset).draw(ShadowColor);
tri.draw();
// 左上・右側隅
RectF{ Arg::topLeft = buttonRegion.tl(), WhiteDotSize }.draw();
RectF{ Arg::topRight = buttonRegion.tr(), WhiteDotSize }.draw();
RectF{ Arg::bottomRight = buttonRegion.br(), WhiteDotSize }.draw();
font(label).drawAt(fontsize, center, ColorF{ 1.0 });
return buttonRegion.leftClicked();
}
}
void Main()
{
Scene::SetBackground(ColorF{ U"#52596b" });
AzurUI::Init();
bool useDefaultSize = true;
double width = 240;
double height = 64;
size_t selectedThemeIndex = 0;
while (System::Update())
{
RectF{ Arg::center = Scene::CenterF(), 800, 240 }.draw(ColorF{ U"#979eb0" });
SimpleGUI::CheckBox(useDefaultSize, U"Use default size"_sv, Vec2{ 4, 4 });
SimpleGUI::Slider(U"Width"_sv, width, 100, 700, Vec2{ 4, 4 + 36 * 1 }, 80.0, 120.0, not useDefaultSize);
SimpleGUI::Slider(U"Height"_sv, height, 24, 120, Vec2{ 4, 4 + 36 * 2 }, 80.0, 120.0, not useDefaultSize);
SimpleGUI::RadioButtons(selectedThemeIndex, { U"Default", U"Cancel" }, Vec2{ 4, 4 + 36 * 3 });
AzurUI::ButtonAt(
ToEnum<AzurUI::ButtonStyle>(selectedThemeIndex),
U"出撃開始"_sv,
Scene::CenterF(),
useDefaultSize ? none : Optional<SizeF>({width, height}));
}
}
https://gyazo.com/46008fd4f91ddbb75cd145af2d143cce