OpenSiv3DのSimpleGUIを使ってみる-1-
OpenSiv3Dを久しぶりに使うあるみにの話。
今回はOpenSiv3DのSimpleGUIを使って
表示したRectの大きさや回転角、回転速度などをいじれるGUIを作りたいと思います。
環境
- VisualSudio2017
- OpenSiv3D v.0.3.1
要求
今回実現したいスライダーの要件は、
- 値をハイライトする
- 取り得る値に範囲がある
- ボタンを使用して特定の単位ごとに値を変更できる
- 「0」ボタンで値を0に初期化できる
みたいな感じで。
イメージ図はこんな。
旧Siv3Dではこんな感じでした。
「0ボタン」はこの時はないですね、だからこそ、これを機に作るんですけど
ライブラリ確認
今回はOpenSiv3Dにある「SimpleGUI」というのを使っていきたいと思います。
F12で実装を軽く見てみる。
知りたいのはスライダーなので…
bool Slider(double& value, const Vec2& pos, double sliderWidth = 120.0, bool enabled = true); bool Slider(double& value, double min, double max, const Vec2& pos, double sliderWidth = 120.0, bool enabled = true); bool Slider(const String& label, double& value, const Vec2& pos, double labelWidth = 80.0, double sliderWidth = 120.0, bool enabled = true); bool Slider(const String& label, double& value, double min, double max, const Vec2& pos, double labelWidth = 80.0, double sliderWidth = 120.0, bool enabled = true);
今回見るべきなのはこの辺かな、訳すと、
Slider(値,座標,スライダーの横幅,有効状態):
Slider(値,最小値,最大値,座標,スライダー横幅,有効状態):
Slider(ラベル,値,座標,ラベルの横幅,スライダーの横幅,有効状態):
Slider(ラベル,値,最小値,最大値,座標,ラベルの横幅,スライダーの横幅,有効状態):
といったところですね。
fontと「2」の実装を組み合わせればいいかな。
できた
というわけでできたのがこんな。
やっつけですがGUIに合わせて図形が動くようにしてあります
詰まったところ
ToRadians
回転をさせる処理は
rotated(ラジアン角)
な訳ですが、GUIのハイライトでラジアン角を表記するのは分かりにくいです。
そこでGUIの値は-360~360の度数で扱い、処理の段階でラジアン角に変換することにしました。
というわけでRectの回転を、
RectF(100,100,block_w,block_h).rotated(Radians(block_r)).draw(Palette::White);
としていたら、Radiansで怒られました。
OpenSiv3DではToRadiansを使うみたいですね。
エラーコード見れば一目瞭然なんですが、焦っていたみたいで気が付かずウンウン言ってました()
値の表記
先ほどの話の続きになりますが、
GUIのスライダーによって値を変更するとき、値がdouble型なだけあって、かなり中途半端な値を取り得ります。
例えば127,345…………みたいな事です。
2つ問題があります。
こんな風に、ただ表示してると値が表示され過ぎる
表示され過ぎてUIとびぬけてる。
0と1の間に差が生じる
↑明らかに0じゃない0だ。この値は、有効範囲が-10~10と狭い。スライダーは長いのでこういった表示だけ誤魔化しても中途半端な状態が生まれる。
こっちの方が重いです。表示だけ直したとしても表記上0で0でない値はあまり良くない。
特に角速度、x移動速度、y移動速度は0であるのと0出ないのとでは大きく異なるため、厳密にする必要がある。
値をint型にしてしまいたいところですが、スライダーで扱う値はdouble型でなければならないので、intにキャストしてから代入しなおしてます。
なお、この場合値を変更している最中はSliderの処理中だからなのか気持ち悪い表示のままです。
こんな感じで、カーソルを離した瞬間は補正がきくものの、変更中は補正されてないのでそのまま表示されてしまう。
加えてスライダー処理中の値の変化についてはいじり方が分からなかったので手が出せません。
そこで、たまたま知ったのですが、
U"{:.1f}"_fmt(変数)
とする事で、表示する変数の桁数を定めることができるみたいです。(この場合小数点以下1桁まで)
というわけで使いました。まあつまり、基本的に補正はかけているので、結局見た目も誤魔化しちゃおうということです。
今回、小数点以下を全部なくしてるだけなので、表記する値をintにキャストするだけで良かったのでは…………?
レイアウト
GUIのレイアウトは1つのウィンドウ用のRect(=BlockGUIBox)の座標を基準に、特定のVec2を加算して相対的に決めています。
if (SimpleGUI::Button(U"-", BlockGUIBox.pos + Vec2(65, 40), 20)) { block_w--; }
基準にしているBlockGUIBoxが動けば一緒についてくるので、持ち運ぶ挙動ができました。
バーの部分だけ持てるようにしてあります。あとバーは画面外に出ません。
前のGUIのウィンドウみたいになった気がする。
今後
とりあえずここまでで一度公開してしまって、クラス化?みたいなのをざっくりやってもう一度上げたいな
元々自作クラスで実装したものを引っ張り出してMainに直書きしたのであんまり見やすくないかもしれない。
とはいえクラスで見せるのもアレなので………
というか公にするにはコードがガバガバ過ぎるよう……
いい感じに汎用クラスみたいにできたらいいんだけどなあ、定石がわからんなあ
処理と描画を分けようとして失敗(?)した話とかしよう
まとめ
OpemSiv3Dに久しぶりに触れ、新しい仕様のSImpleGUIを触りました。
前よりはレイアウトや動かし方に若干自由度が増えた?前よりは扱い方がわかりやすくなったような気がします。
他の図形なんかと扱い方が近くなった?からかな
SimpleGUIが値の変更とGUIの描画そのものを同時に担っているので、処理部と描画部は分けられなさそうだなーと思いました。
ちょっと機能使ってないと忘れそうなので、備忘録的に使っていけたらいいな
今回はGitでコードの公開もしてみたけど、Gistの方がよかったかもしれん
あと「何やこれひどいな!こうしたほうがいい!!」という人がいましたらマサカリ投げてください(震)