堕天使の煉獄

Gallery
Comic
Story
Production
Work
Link

2014-08

16

08:38:17

いろいろ失敗

PGつづき。

実際に組み始めるといろいろと失敗していたことに気づくw


失敗その1「形から入りすぎた」

unityを真似て、シーンクラス内では

updateとdrawメソッドとは別に
guiUpdateとguiDrawというのを
それぞれの前後に実行するのを基本動作としているのだけども。

順番的には

guiUpdate()
update()
draw()
guiDraw()

となっている。
最初にGUIの処理(たとえば選択肢選択とか)を行い、
最後にGUIを描画(必ずシーンの描画内容の上(最前面)に描画される)
というのが目的です。

んで、参考にしたunityの場合、GUI描画用のメソッドでは
GUI専用の描画命令しか使えません。

おそらくGUI関係のクラスのメンバとして継承されたメソッドなのでしょう。

が、DxLibでは、当然ながらそんな物ないので
drawとguiDrawのどっちにも全描画命令が書けるわけで。

はっきり言って、分けた理由は、シーン描画が終わった後に
その前面に描画されるという、描画順を分けるためだけにある様な物です。
(それはそれで意義はあるけど)

が、しかし、unityのイメージにとらわれてしまった所為か
なんか勝手にGUI用の物と、通常の物とを別けなきゃいけない、
と言うような思い込みを持ってしまったようで。

前回の日記の中の
DxLabel
というクラスは、tstringとpos(位置)とフォントハンドルと色(とエッジの色とか)
をまとめた、文字描画用のクラスなのですが。

じつはすでにDxStringという、全く同じ機能を持つクラスをすでに作っていたりします。
両者の違いは、GuiObjectから継承しているかどうかの違いぐらいです。

んで、先に述べたように、guiDrawの中では
別にGuiObjectしか描画出来ない訳ではなく、
普通にguiDrawの中ではDxStringも、それこそ普通にDrawGraphとかも
使えるわけです。

……分ける意味あったのかこれ?



失敗その2「節子、それ逆やっ」

今度はQTの真似をした部分。
半分は前述の、形から入っちゃって失敗した部分と重なるのですが、

たとえば画像一枚で画像サイズのサブウィンドウを表示するGUIの場合。

DxGuiObject→DxWindow→DxGraphWindow

と多重継承で実現する設計だったのですが。

実際に使う場合には、たとえばダイアログボックスなんか作るときは
DxGraphWindow内にDxLayoutを持っているので
そこにDxGuiObjectであるDxButtonを登録して……
「はい」「いいえ」の二つのDxButtonGroupを使うべきですね。
DxButtonGroupを登録して。
するとDxLayoutによってDxGraphWindow内のドキュメント領域に
指定のLayout方法でボタンが配置されると。

みたいの考えてたのですが。

よくよく考えてみると、
ゲームのGUIって、表示位置てだいたい固定なんですよね。
一度設定したら、位置が変わることなんてほとんど無い。

QTなどの場合は、ウィンドウサイズも可変なので
ウィンドウ内に配置したオブジェクトの位置も
相対的に変化することが前提な訳です。

特殊な状況の場合でもなければ、
(例:RPGなんかでキャラの位置のそばに出る会話ウィンドウとか?)
動的にオブジェクトの位置やサイズを調整する必要なんて無いわけです。

さらに、やはり、多重継承のコストも気になるところ。
基本的に仮想関数の実行は高コストです。
メンバ関数も呼び出しコストがかかりますが、
仮想関数はおおよそ、その4倍程度のコストがかかるという計測結果もあります。

ゲームPGでは、
1フレーム内、60fpsなら約16ミリ秒内で処理を終了しなくてはなりません。

速度が最優先であるわけで、このコストは塵も積もれば……ということで
無視出来る物ではないです。

そして設計的に失敗だったのは
継承でなくて、コンポジットするべきだったなと。

オブジェクト指向な設計では割と良くあることなのですが
依存関係を逆にする方が良い、と気づくことが後からあったりするんですよね。

さらには、継承よりもコンポジットで実現した方が
実行コストも軽減されるとか。

上のDxGraphWindowを例にとると

DxGuiObjectには、

オブジェクトの位置とサイズ情報(rect)
それから有効かどうかのenableフラグ
update、drawなどの基本メソッドなど(virtual)
guiオブジェクトに共通するメンバを持っている。


DxWindowには
ウィンドウ関係のオブジェクトに共通する基本部分。
ウィンドウの内側の、クライアント領域のrectもしくはそのマージン設定
ウィンドウ内に登録されるGuiObjectを格納するコンテナ。

DxGraphWindowは、表示に使う画像だけ持つ。

と、DxGraphWindowは共通部分をそれぞれ継承しているわけです。

しかし、オブジェクトの位置とサイズ情報というのは
DxGuiObjectのメンバとして、DxRectというrect関係を扱うクラスを持っています。

位置やサイズの変更はsetRect()ではなく
rect().setRectで行われるわけです。

(↑DxGuiObjectにsetRect()メソッドを持たずに
DxRect& rect(){retuen m_rect;}
というメソッドをもっていて、変更の処理自体はDxRectオブジェクトに委託)

……DxGraphWindowにDxRectをコンポジットしたらええんとちゃうのんか?

ということになりますよね。

もっと言えば。

ダイアログボックスを作ると考えたとき

DxGraphWindowでウィンドウを描画
DxStringで文字を描画
(たとえば「ゲームを終了します。よろしいですか?」みたいなの)
DxButtonGroupでボタンを描画

という処理が必要になりますが
DxGraphWindowの中に
DxStringとDxButtonGroupを登録する方法って
スマートなのだろうか? と。

普通に
DxGraphWindow.draw();
DxString.draw();
DxButtonGrou.draw();

とシーンクラスのguiDraw()メソッド内に書いちゃったほうが
表示順もわかりやすいし。
あとは
str.relativePos(window.pos());
とかやると、相対座標座標になるとかいうのあれば便利かな。

もしくはDialogクラスとか作って
メンバに
DxGraphWindow
DxString
DxButtonGrou

を持つとか。

つまるところ、トップダウンで設計したのが裏目に出た感じに。
ボトムアップ的な手法で
一番最少なGUI部品を作り

それらを部品としてコンポジットした
GUIオブジェクトを構築する……という方のが良かったようです。

最初からQTとかのお手本があったために
トップダウンでも問題ないと思ったのですけども、ドツボでしたw

そこで最初の話に戻るのですが
シーンクラス内のguiDraw()メソッドでは
単にシーンのdraw()の後に呼ばれる
というだけの物です。

たとえばguiDraw()内に

DxGraphWindow.draw();
DxString.draw();
DxButtonGrou.draw();

と描いた場合、guiDraw()メソッド自体が
ダイアログボックスとして機能しているといえます。

べつにGUIアプリ作ってるわけでもないので
この位のシンプルさの方がよいのでは……という結論に。

あとはGUI部品の組み合わせで複雑な物も作ろうと思えば作れる訳ですし。
何より、継承による仮想関数のコストも掛からない。

やはり最初の方針は失敗だったなぁと。

ぎゃふん~。



失敗その3「やっぱ速くないとね」

最後は、ちょっとしたポカ。

GUIオブジェクトにDxBlendという
描画モードを扱うクラスを追加していたのですが。

コンストラクタは
DxBlend(Mode::Alpha, 128);
という感じで、描画モードとパラメータを設定する感じで。
各GUIオブジェクトのdrawメソッドの最初と最後に設定して

blend.setBlendMode();
str.draw();
blend.restoreBlendMode();

みたいな感じで、GUIオブジェクト毎にブレンドモードを設定出来るみたいな。

そこで。

……SetDrawBlendMode使うと、unityで言うところの
ドローコールが増えるというデメリットがあるの忘れてた……。

描画命令は一度に実行した方が速いのです。
DxLibも内部的に、タイミングや条件をもとに
draw命令をいくつか貯めておき、一括して描画することで高速化を図っています。

しかしSetDrawBlendModeは、
その貯めているのをそこで打ち切ってしまう効果があるのです。

なので
SetDrawBlendMode(DX_BLENDMODE_ALPHA, 128);
DrawRect(0,0,200,200,-1);
SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0);
SetDrawBlendMode(DX_BLENDMODE_ALPHA, 128);
DrawRect(0,0,200,200,-1);
SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0);
と書くよりも

SetDrawBlendMode(DX_BLENDMODE_ALPHA, 128);
DrawRect(0,0,200,200,-1);
DrawRect(0,0,200,200,-1);
SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0);

こう書いた方が速いというわけです。

なにげにunityでもGUIの描画命令は
1ドローコール消費するコストが掛かるので低速。
と言うのがあるのですが、その理由はたぶんこの理由と同じ?

GUIオブジェクト毎に描画モード変更できるのは便利だけども
その分低速なのじゃなぁ……

さらに恐ろしいことに
DxLibの標準の描画系のラッパーで
ブレンド指定版とか作ってたりして(汗

全部無駄やんw

いや、使えないってことはないけど
あんまし濫用できる様なものではないし。

そもそもブレンドモードを変更する時
元に戻すのもあわせてSetDrawBlendModeで挟むのがなんかやだなぁ
と言うところがあったりするのですけども。

なにげにラムダ式でdrawメソッドを登録して~
みたいなのも作ったこともあったのですが……

汎用するにはラムダ式の書式はちょっと邪魔くさい……

毎度描画するたびに

blend([&](){ DrawRect(0,0,200,200,-1);}, DxBlend(Mode::Alpha, 128));

とか書くのもなぁ……と。
内部はテンプレート(とインライン?)で実装されるので
いっぱい使いまくった場合、ビルド時間伸びそうだしw

そんなこんなで、blend関係は
ここぞというところでしか使わない。
使うときはなるべくまとめて使う。

それなら普通に手書きでSetDrawBlendModeでええんでないの?

ということに。


んでもそういう観点からも
シーンクラスのguiDraw()メソッド内で

GUIパーツ毎に描画するというのは
たとえば半透明ウィンドウなダイアログボックスを考えたとき

void guiDraw(){
SetDrawBlendMode(DX_BLENDMODE_ALPHA, 128);
DxGraphWindow.draw();
SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0);

DxString.draw();
DxButtonGrou.draw();
}

と書ける方が
ある意味便利。

画面上に複数のサブウィンドウがあるときは
SetDrawBlendMode囲まれた部分にサブウィンドウのdraw()をまとめる
という事が出来るし。

これがダイアログボックスクラスとしてまとめられて
その中でblend設定を内包していると
そういうことが出来なくなってしまう。

GUIパーツはあんまし
ひとまとめにクラスでまとめるより
部品毎にguiDraw()に直接書いた方がよい。

というのが速度的にもベターな感じっぽい。

もしくは

dialog.drawWindow(DxBlend(Mode::Alpha, 128));
dialog.drawString();
dialog.drawButton();

とかいう感じで描画メソッドを細かく分けるとか?



といった感じで、描画速度のコストも考えると
いろいろとまた設計の見直しが必要っぽい。
普通のGUIアプリと違って
フレーム単位で処理を終了させなければならない
ゲームPGとの差異の部分でいろいろと見誤ってた部分がいぱーい。

んでもまあ、最少単位の部品から作っていくというのは
今のところ既定路線になったので、とりあえずそっちを進めていこうかと。

これ、今月中に終わるかなぁ……。
Sun
Mon
Tue
Wed
Thu
Fri
Sat
01
02
03
ちゃんと作ろうと思うと……
04
05
06
07
でんぐりがえり
08
09
10
やっぱいいなぁ
11
12
シンプルイズベストなんだよな
13
昨日の続き
14
15
16
いろいろ失敗
17
18
19
20
21
22
23
24
25
26
27
28
29
30
ぐにょぐにょ
31
total:2076291 t:199 y:119
■記事タイトル■

■年度別リスト■
2024年 2024年12月(0)
2024年11月(0)
2024年10月(1)
2024年09月(2)
2024年08月(1)
2024年07月(1)
2024年06月(5)
2024年05月(2)
2024年04月(1)
2024年03月(6)
2024年02月(4)
2024年01月(3)
2023年 2023年12月(3)
2023年11月(1)
2023年10月(2)
2023年09月(3)
2023年08月(3)
2023年07月(3)
2023年06月(7)
2023年05月(8)
2023年04月(2)
2023年03月(1)
2023年02月(2)
2023年01月(3)
2022年 2022年12月(4)
2022年11月(3)
2022年10月(1)
2022年09月(3)
2022年08月(3)
2022年07月(2)
2022年06月(1)
2022年05月(3)
2022年04月(2)
2022年03月(2)
2022年02月(1)
2022年01月(6)
2021年 2021年12月(8)
2021年11月(3)
2021年10月(4)
2021年09月(6)
2021年08月(2)
2021年07月(1)
2021年06月(3)
2021年05月(2)
2021年04月(2)
2021年03月(3)
2021年02月(1)
2021年01月(4)
2020年 2020年12月(3)
2020年11月(7)
2020年10月(2)
2020年09月(3)
2020年08月(1)
2020年07月(3)
2020年06月(7)
2020年05月(5)
2020年04月(8)
2020年03月(4)
2020年02月(2)
2020年01月(4)
2019年 2019年12月(1)
2019年11月(1)
2019年10月(2)
2019年09月(1)
2019年08月(3)
2019年07月(2)
2019年06月(2)
2019年05月(2)
2019年04月(4)
2019年03月(1)
2019年02月(7)
2019年01月(1)
2018年 2018年12月(1)
2018年11月(1)
2018年10月(5)
2018年09月(1)
2018年08月(5)
2018年07月(1)
2018年06月(1)
2018年05月(1)
2018年04月(2)
2018年03月(2)
2018年02月(1)
2018年01月(1)
2017年 2017年12月(2)
2017年11月(1)
2017年10月(2)
2017年09月(5)
2017年08月(8)
2017年07月(2)
2017年06月(1)
2017年05月(1)
2017年04月(3)
2017年03月(5)
2017年02月(7)
2017年01月(8)
2016年 2016年12月(7)
2016年11月(2)
2016年10月(3)
2016年09月(7)
2016年08月(8)
2016年07月(10)
2016年06月(17)
2016年05月(6)
2016年04月(8)
2016年03月(10)
2016年02月(5)
2016年01月(10)
2015年 2015年12月(7)
2015年11月(7)
2015年10月(13)
2015年09月(7)
2015年08月(7)
2015年07月(5)
2015年06月(4)
2015年05月(5)
2015年04月(2)
2015年03月(4)
2015年02月(1)
2015年01月(7)
2014年 2014年12月(12)
2014年11月(8)
2014年10月(4)
2014年09月(6)
2014年08月(7)
2014年07月(4)
2014年06月(2)
2014年05月(5)
2014年04月(4)
2014年03月(8)
2014年02月(4)
2014年01月(8)
2013年 2013年12月(15)
2013年11月(8)
2013年10月(3)
2013年09月(3)
2013年08月(8)
2013年07月(0)
2013年06月(0)
2013年05月(0)
2013年04月(0)
2013年03月(0)
2013年02月(0)
2013年01月(0)

■レス履歴■

2023-09-26 14:59:38 - 久慈光樹

2023-09-26 14:29:10 - 織田霧さくら

2023-09-26 13:10:45 - 久慈光樹

2023-03-20 05:30:16 - 織田霧さくら

2023-03-15 20:42:58 - まうる

2022-12-26 19:14:57 - 織田霧さくら

2022-12-25 02:28:36 - まうる@まるるん

2022-09-30 04:29:01 - 織田霧さくら

2022-09-23 19:01:29 - まるるん

2022-06-16 21:06:34 - 山本


■ファイル抽出■

■ワード検索■

堕天使の煉獄

https://rengoku.sakura.ne.jp
管理人

織田霧さくら(oda-x)

E-mail (■を@に)

oda-x■rengoku.sakura.ne.jp

堕天使の煉獄バナー 堕天使の煉獄バナー