gohud

HUD

← ウィジェット

出来を決めるのは小さなところだ

大きなパネルをいくら磨いても、目に留まるのはいつも小さなものだ — 途中で切れた単語、欠けた発光、 窮屈なスロット。2026-09-13 にそうした4つが指摘され、デモ画面ではなくウィジェットとテーマの側で直した。 だから、どの画面でも同じ結果になる。

何が起きたか原因直し方
コーチマークの DoneDon/e になった 折り返しを有効にしたボタンは文字幅を最小幅から差し引く — 狭められると単語の途中で割れる GoStyle.fit_words(): 1単語なら決して折り返さず、複数語なら折り返すがいちばん長い単語は必ず収まる。判定は翻訳キーではなく実際に表示される文字で行い、言語が変わればフォームが付け直す
全幅ボタンの発光が、左側だけ縦に切れた スクロールコンテナは例外なく自分の端で切り取る。右だけはレールの余白のおかげで残っていた GoScroll が親の余白を借りて端を 12dp 外へ押し出し、内側で返す — 中身の位置は動かない
スロットの中で、時間・アイコン・個数が縦に積み上がった 48dp の中に3行あった アイコンは中央に大きく、ショートカットは左上、個数は右下のバッジ、残り時間はアイコンに重ねたバッジへ — バッジのパネルはスキンの badge_box() から来る
ドロップダウンが平坦で、どれを選んでいるか見えない 項目のホバーにボタンのパネルを使い、ラジオの印はエンジンの薄い既定のままだった 専用のホバーパネル(淡いアクセント)、チェックボックスと同じラジオの絵、タッチに合わせた項目の高さ
開いたドロップダウン — 淡いアクセントのホバーパネルと、選択中の項目のラジオ印
ドロップダウン — ホバーパネルとラジオ印
4つのクイックスロット — 左上にショートカット、右下に個数バッジ、先頭には残り時間のバッジ
スロット — 隅のバッジと残り時間(SF)

アイコンだけのボタンには GoStyle.icon_button(icon, action, -1, tooltip_key) で説明を与える — マウス利用者へのツールチップも、スクリーンリーダー向けのアクセシビリティ名も、この1つの値から取る。 ツールチップは gohud が自分で描く。エンジンの既定は、幅の計算が狂うと文字を1文字ずつ改行してしまう (幅 1dp と実測された)。

コーチマークのカードは固定物を避ける

横持ちでは、カードが画面のいちばん上か下の端へ送られていた — ヘッダーや HUD がちょうど居座る場所だ。 デモではヘッダーの → × の上に重なっていた。いまは対象と同じ高さにとどまり、場所を確保している GoHudAnchor を回り込み、そのほか避けたいものは keep_clear で受け取る。 対象を覆わずに障害物から外れる最短の距離だけ動き、画面が狭くてすべてを避けきれないときはその場にとどまる — 重なるほうが、消えるよりましだ。ページより上にあると読めるだけの立体感は、スキンのダイヤルから来る (float_shadow_sizefloat_shadow_liftfloat_shadow_alpha。面取り系のスキンは float_glow_size)。

tour.keep_clear = [header_bar, toolbar]   # アンカーではない固定物

マウスとキーボードのある画面

指にはホバー状態がない。 モバイルだけを見て作ると、デスクトップにしかない2つの状態が未確認のまま残る — そして実際、片方は壊れていた。gohud のフォーカスリングが主ボタンの上で見えなかったのだ。パネルが アクセント色で、リングも同じ色。1.00:1、同じ色を同じ色の上に描いていた。キーボードで移動すると、 自分がどこにいるのか分からなかった。

同じボタンの列を3つの状態で — 通常、マウスホバー、キーボードフォーカス
上から 通常 · ホバー · フォーカス。塗りつぶしのボタンには、自分のパネルと対比するリングが付く。

塗りつぶしのボタン(GoPrimaryButtonGoDangerSolidButton)は 自分のパネルと対比するリングを使う — ダークテーマでは暗く、ライトテーマでは白く、SF では暗い照準 ブラケットになる。コントラスト検査はフォーカスリングを、それが載っているパネルに対して測るので、 パレットを変えてもこの規則は生き残る(WCAG 2.4.11 はフォーカス表示に 3:1 を求めている)。

HUD ウィジェット

GoHudAnchor — 9か所

セーフエリアと画面端の余白を尊重する。landscape_spot を与えれば横持ちで移動する — 縦持ちで下中央にあるコントロールを、横持ちでは右下へ回せる。

なぜ必要か。 HUD ごとに手で書いたアンカーとオフセットは必ずずれていく。ノッチのある端末では体力バーが カメラの切り欠きの下に入り、横持ちでは操作ボタンがジェスチャーバーの上に載る。その算術を1か所に集めてある。

本文を HUD の下に潜り込ませない

スクロールする画面が HUD と同じ表示面を分け合うと、本文はその下へ滑り込み、2組の文字が重なって どちらも読めなくなる。このアドオンでも2度起きた。入力欄のプレースホルダーがクイックスロットの間から はみ出し、設定のトグルのつまみが体力バーの上に載った。

form.avoid_hud = true                  # 表示中の GoHudAnchor をすべて避ける
joystick_anchor.reserve_space = false  # …指が触れたときだけ現れるものは除く

それぞれの矩形は失う面積がいちばん小さい方向へ避ける。右上のバーは、縦持ちのスマートフォンでは下へ 回り込み(高さの 13%)、横持ちでは横へ回り込む(幅の 21%) — 横持ちで縦に避ければ画面の 27% を失う。 すでに明け渡した領域は、次の矩形を測る前に差し引かれる。

HUD どうしもぶつかる

9か所は画面を分割するだけで、部品どうしがぶつからないことまでは保証しない。上中央の幅広い スナックバーが、右上の体力バーの真上に着地して値を隠した — 残り体力が読めなかったのだ。

notice_anchor.avoid_peers = true      # 固定 HUD の下へ落ち着く
notice_anchor.reserve_space = false   # 出ている間にページを押しのけたりはしない

よけるのは縦方向だけだ — 横にも動かすと、中央揃えのトーストが出るたびに違う場所に現れてしまう。 しかも、避けるのは自分からはよけない部品に対してだけだ。両方が譲ると、2つは永遠に場所を入れ替え続ける。

GoBar — 体力・マナ・経験値

var hp := GoBar.new()
hp.label_text = "HP"
hp.ink = GoUi.color(GoTheme.DANGER_FILL)   # 塗り専用のトークン
hp.set_values(320, 500)                     # "320 / 500"

変化は 0.18 秒かけてなめらかに動く — 跳ねる体力バーは、どれだけ強く殴られたのかを伝えない。 reduce_motion にすれば即座に反映する。大きな数は 12.3k のように略記するので、 桁が増減してもバーの幅が揺れない。

GoSlot — クイックスロット1つ

アイコン、個数、クールダウン、ショートカットを1つの面に収める。小さな円にバッジをぶら下げると、 スロットごとに幅が変わって列が揺れてしまう。

見える大きさと押せる大きさは違う。 詰めて並べたスロットは 48dp のタッチ領域が重なる。重なった分は 中心が近いほうのスロットが取る — touch_peers で互いの存在を教えておく。

keyboard_focus は既定で無効だ。8個並んだスロットが、キーボード利用者と設定項目すべての間に Tab 順で割り込まないようにするためである。キーボードやゲームパッドが唯一の入力手段なら有効にする。

GoJoystick — バーチャルスティック

モードふるまい
FIXED常に同じ場所 — 見なくても指が届く
FOLLOW親指を置いた場所に現れる
RELATIVE現れたあとも親指を追い続ける — 長く動かすときに楽だ

moved が渡す Vector2 は長さ 0〜1 なので、そのまま速度に掛けられる。 画面サイズや DPI で変わることもない。

GoIconButton — 小さく見えて大きく押せる

安全なのは、隣が入力を受け取らないときだけだ。 広げた領域が隣のボタンに重なると、そのボタンは 反応しなくなる。並べて置くアイコンボタンには touch_peers が要る。