【3】Siv3Dで画面のスクロール・拡大縮小機能を実装する
こんばんは。
前回の記事に引き続き、Siv3Dを用いたUIを紹介します。
題目通りなのですが、たまたま先ほどQiitaにて
Siv3D での 2D カメラ操作をサポートする Camera2D - Qiita
という記事を発見してしまいました。
なんと今回僕が作ったコードとほぼほぼ同じUIに関する記事です。それどころがこっちの方がラップされてて扱いやすい上に高機能なんだよなぁ…
…はい。まぁこちらの方が拡張しやすいという長所があるし、せっかく実装もしたので紹介します。
コード
# include <Siv3D.hpp> void Main() { Vec2 pos = Vec2(0, 0); double expansion = 1.0; Vec2 RectfPlace = Window::Center() / 2; Vec2 CirclePlace = Window::Center(); bool RectfisPressed = false; bool CircleisPressed = false; int bl_width = 100; int bl_height = 100; int radius = 40; while (System::Update()) { const RectF rectf(pos + RectfPlace*expansion, bl_width * expansion, bl_height * expansion); if (rectf.leftClicked) { RectfisPressed = true; } if (Input::MouseL.released) { RectfisPressed = false; } if (RectfisPressed) { RectfPlace += Mouse::Delta() / expansion; } const Circle circle(pos + CirclePlace*expansion, radius*expansion); if (circle.leftClicked) { CircleisPressed = true; } if (Input::MouseL.released) { CircleisPressed = false; } if (CircleisPressed) { CirclePlace += Mouse::Delta() / expansion; } rectf.draw(Palette::Yellow); circle.draw(Palette::Aqua); //枠の描写 Rect rect(pos.x + 20 * expansion, pos.y + 20 * expansion, 600 * expansion, 440 * expansion); rect.drawFrame(0, 3 * expansion, Palette::Red); //座標変換 if (Input::MouseR.pressed) { const Point delta = Mouse::Delta(); pos += delta; } // ホイール回転量 const int wheel = Mouse::Wheel(); if (wheel == 1) { if (expansion >= 0.25) { expansion = expansion / 2; pos = (pos + Window::Center()) / 2; } } else if (wheel == -1) { if (expansion <= 8) { expansion = expansion * 2; pos = pos * 2 - Window::Center(); } } PutText(L" ×{}"_fmt, expansion); } }
仕様
・右クリック&ドラッグで、画面のスクロールができる(タッチ操作や、UEのブループリントみたいなのを想像してくれるといいかも)
・マウスホイールを回転すると、拡大倍率を0.125倍から16倍まで可変できる
・図形を左クリック&ドラッグすると、図形を動かせる(参考:前回の記事)
konkea.hatenablog.com
スクリーンショット
↓初期画面↓
↓マウスホイールで極限まで縮小したもの↓
↓マウスホイールで4倍まで拡大したもの↓
↓右クリックによる画面のスクロール↓
↓左クリックによる図形オブジェクトの移動↓
↓いろいろいじった後の画面↓
反省とか
拡張していけばデスクトップなんかが実装できそうなUIができました。今回のプログラムでは拡大率を倍々のスケールで処理していますが、プログラム中ホイール回転量のパラメータをいじってやれば、上限やスケール等々いじれます。
今回のプログラムの肝となるのがパラメータposとexpansionで、それぞれ「現在画面のどこを表示しているか」と「画面の拡大率はいくつか」を格納しています。2つのパラメータを描写の際に乗じてやることで、このような処理が実装できるわけですね。
さてこのようなプログラムになってくると、新しく図形を描写するのにいちいち
const Circle circle(pos + CirclePlace*expansion, radius*expansion); if (circle.leftClicked) { CircleisPressed = true; } if (Input::MouseL.released) { CircleisPressed = false; } if (CircleisPressed) { CirclePlace += Mouse::Delta() / expansion; } circle.draw(Palette::Aqua);
このような記述を付け足していかなくてはいけなくなります。そうなると記述量増えすぎるし、拡張しづらいし不便ですよね。ってことで、次回は複数のオブジェクトを取り扱うための手法を紹介しようと思います。