13
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

actionbarでリッチなUIを作ろう!

Last updated at Posted at 2025-12-16

この記事は、Minecraft Command Advent Calendar 2025 16日目の記事です。:santa:

はじめに

私は約5年前に思い立って以来、マイクラRPG(未だ完成していない!!)のUIを試行錯誤しながら延々と手を加えてきた者なのですが、時を経て知見がまとまってきたので、この機会に解説してみます。RPGに限らず何事もUIがリッチだと完成度が高く見えるもので、幅広い場面で活用できる知見をざっと紹介していきます。

また1.21.5より、テキストの記述方法が「JSONテキスト」から「SNBT」というフォーマットに変わったため、アップデート作業がてら自身の日記としてここに記しておきます。

Minecraft Java版 ver 1.21.11 時点の情報となります。

actionbar UIとは?


それぞれの要素が独自に動きまくる、バニラライクなRPG風UI

早い話、こういったものです。画面下部の「actionbar」に/titleコマンドでテキストやカスタムフォントを表示し、これをピクセル単位で位置調整することで、動画のような賑やかなUIを作ることができます。


スコアの桁が変わっても位置がズレない、ミニゲームの得点表示

とこのように、マイクラに既存のHPや空腹度表示・経験値バーといったUIの上に、更に画面上に情報を増やしたい時に大いに活用ができます。

プレイヤースコアの表示 ───────

基本的には以下のような/titleコマンドを用いてUIを作っていきます。
まずはプレイヤーのスコアを表示させるところから。

プレイヤーのHPやHPの最大値を表示
title @s actionbar ["",{"text":"\uE100","shadow_color":0},"\uF822",{"score":{"name":"@s","objective":"HP"}},"/",{"score":{"name":"@s","objective":"MaxHP"}}]


\uE100(♡アイコン)、2px分の空白、HP、"/"、最大HPの順番で表示される

ここで大切な概念としては先頭の""(空白テキスト)。テキストのリストにおいて「先頭の要素に設定された書式は、各要素で上書きされない限り継承される」ため、先頭でフラットな書式を設定することで、2要素目のshadow_colorなどが以降に影響しないようにしています。

参照: https://ja.minecraft.wiki/w/テキストコンポーネント#データ型


カスタムフォントの設定
{
    "providers": [
        {
            "type": "space",
            "advances": {
                "\uE820": 0,
                "\uE821": 1,
                "\uE822": 2,
                
                # ---------- 中略 ---------- #
                
                "\uF82F": 32768
            }
        },
        {
            "type": "bitmap",
            "file": "resource:font/heart.png",
            "ascent": 0,
            "height": 9,
            "chars": [
                "\uE100"
            ]
        }
    }
}

♡アイコンはカスタムフォント1で定義しており、ascent, heightを上手く設定することで上下の位置や大きさを設定できます。ascentもとい上下の位置調整については後で詳しく!


テクスチャアトラスから♡のスプライトを参照して表示
title @s actionbar {"type":"object","atlas":"gui","sprite":"hud/heart/full"}

また、1.21.9で追加されたobjectを用いてテクスチャアトラスの参照ができる件については、ハートの大きさや上下の位置調整が困難だったことから断念しました。残念。

ストレージを用いたテキスト表示

続いて今後の為にテキストをストレージに格納し、/titleコマンドをスリムにしていきます。

プレイヤーのHP表示(ストレージを使用)
# ストレージの準備
+   data modify storage player:temp hp set value ["",{"text":"\uE100","shadow_color":0},"\uF822",{"score":{"name":"@s","objective":"HP"}},"/",{"score":{"name":"@s","objective":"MaxHP"}}]

# UIの表示
-   title @s actionbar ["",{"text":"\uE100","shadow_color":0},"\uF822",{"score":{"name":"@s","objective":"HP"}},"/",{"score":{"name":"@s","objective":"MaxHP"}}]
+   title @s actionbar ["",{"nbt":"hp","storage":"player:temp","interpret":true}]

# リセット
+   data remove storage player:temp hp

一見意味のない作業のように見えますが、UIパーツに名前を付けて管理できる点や、繰り返し同じパーツを使いたい時(後述: テキストの左揃え・右揃え)等で使い勝手が良くなります。

テキストの左揃え・右揃え

続いてテキストを左右に揃えていきます。actionbarに表示されるテキストは中央揃えなので、例えばスコアMaxHPの値が増えた場合、現状だと以下のような挙動になります。


増えた幅が左右に均等に伸びていく「中央揃え」

これではスコア以外で画面に固定したいUIがある場合は大変都合が悪く、値に応じて全てのUIの位置をずらす等といった処理を行う必要が出てきてしまいます。そこで、左右揃え

プレイヤーのHP表示(右揃え)
# ストレージの準備
    data modify storage player:temp hp set value ["",{"text":"\uE100","shadow_color":0},"\uF822",{"score":{"name":"@s","objective":"HP"}},"/",{"score":{"name":"@s","objective":"MaxHP"}}]

# UIの表示
-   title @s actionbar ["",{"nbt":"hp","storage":"player:temp","interpret":true}
+   title @s actionbar ["","\uF82F",{"nbt":"hp","storage":"player:temp","interpret":true},"\uF82F",{"nbt":"hp","storage":"player:temp","interpret":true}]

# リセット
    data remove storage player:temp hp

ひと手間加えるだけで、あら不思議。右揃えのHPスコアが完成します。


増えた幅が左方向にのみ伸びていく「右揃え」

...そのひと手間とは、具体的に「画面外右側にもHPスコアを表示する」です。
「画面内のテキスト幅がに伸びる分」と「画面外右側のテキスト幅がに伸びる分」が相殺することで、画面内のスコアは左だけに伸びているように見えます。


画面外に追いやっているテキスト(黄色で表示)を画面内に戻してみるとこんな感じ。


同様の手法で、レベルや所持ゴールド表示(左揃え)も実装。
HPは右揃え、レベル/経験値/所持ゴールドは左揃え
# ストレージの準備
    data modify storage player:temp hp set value ["",{"text":"\uE100","shadow_color":0},"\uF822",{"score":{"name":"@s","objective":"HP"}},"/",{"score":{"name":"@s","objective":"MaxHP"}}]
+   data modify storage player:temp lvl set value [{"text":"","color":"#E0E0E0"},"Lv.\uF822",{"score":{"name":"@s","objective":"LVL"},"color":"white","bold":true},"\uF822(",{"score":{"name":"@s","objective":"EXP"},"color":"#9EE082"},"/",{"score":{"name":"@s","objective":"NextEXP"}},") "]
+   data modify storage player:temp gold set value ["",{"score":{"name":"@s","objective":"Gold"}},{"text":"G","color":"#FFEE59"},"\uF822",{"text":"\uE101","shadow_color":0}]

# UIの表示(2~3行目:左画面外、5~7行目画面内、9行目右画面外)
   title @s actionbar ["",\
+  {"nbt":"lvl","storage":"player:temp","interpret":true},\
+  {"nbt":"gold","storage":"player:temp","interpret":true},\
   "\uF82F",\
   {"nbt":"hp","storage":"player:temp","interpret":true},\
+  {"nbt":"lvl","storage":"player:temp","interpret":true},\
+  {"nbt":"gold","storage":"player:temp","interpret":true},\
   "\uF82F",\
   {"nbt":"hp","storage":"player:temp","interpret":true}]

# リセット
    data remove storage player:temp hp
+   data remove storage player:temp lvl
+   data remove storage player:temp gold

ちなみに当然HPの左側や所持ゴールドの右側(アイコンが配置されている表示部分)は動いてしまうので、固定したいUIは今後ストレージhplvlの間に追加していきます。

スコアに応じたアイコンの表示 ────

ここまで来れば、以降の発想は結構シンプルです。スコアに応じてストレージにカスタムフォントを格納し、それを/titleコマンドに追加していくだけ!まぁそれが大変なのですが!

最大HPに応じたHPバーの表示
# ---------- 前略 ---------- #

+ # HPバー
+    # HPの割合計算
+       scoreboard players operation $MaxHP Temporary = @s MaxHP
+       scoreboard players operation $MaxHP Temporary /= #5 Constant
+       execute store result storage macro:temp hp_bar.value int 1 run scoreboard players add $MaxHP Temporary 10
+   # 適用
+       function player:actionbar/hp_bar with storage macro:temp hp_bar
        
# UIの表示
   title @s actionbar ["",\
   {"nbt":"lvl","storage":"player:temp","interpret":true},\
   {"nbt":"gold","storage":"player:temp","interpret":true},\
   "\uF82F",\
   {"nbt":"hp","storage":"player:temp","interpret":true},\
+  {"nbt":"hp_bar","storage":"player:temp","interpret":true},\
   {"nbt":"lvl","storage":"player:temp","interpret":true},\
   {"nbt":"gold","storage":"player:temp","interpret":true},\
   "\uF82F",\
   {"nbt":"hp","storage":"player:temp","interpret":true}]

# ---------- 後略 ---------- #
(function) player:actionbar/hp_barの中身
# マクロも活用してhp_barに適切なフォントを格納
    execute if score $MaxHP Temporary matches ..9 run data modify storage player:temp hp_bar set value {"text":"\uE211","shadow_color":0}
    $data modify storage player:temp hp_bar set value {"text":"\uE2$(value)","shadow_color":0}
    execute if score $MaxHP Temporary matches 50.. run data modify storage player:temp hp_bar set value {"text":"\uE250","shadow_color":0}


最終的にはHPバーの位置を揃えて、60/100をアイコンで表現するイメージ


カスタムフォントの設定 resource:font/hp_bars.png
\uE211~\uE250にHPバーのアイコンを設定
{
    "providers": [
        # ---------- 中略 ---------- #
        {
            "type": "bitmap",
            "file": "resource:font/hp_bars.png",
            "ascent": 0,
            "height": 20,
            "chars": [
                "\uE211\uE212\uE213\uE214\uE215",
                "\uE216\uE217\uE218\uE219\uE220",
                "\uE221\uE222\uE223\uE224\uE225",
                "\uE226\uE227\uE228\uE229\uE230",
                "\uE231\uE232\uE233\uE234\uE235",
                "\uE236\uE237\uE238\uE239\uE240",
                "\uE241\uE242\uE243\uE244\uE245",
                "\uE246\uE247\uE248\uE249\uE250"
            ]
        }
    }
}

結構なゴリ押しであることは実装からも読み取れると思いますが、マクロを活用することでいくらかスマートに実装できていると思います。また、テクスチャ側で全アイコンが同じ幅を持つよう、空白箇所にも透明度1%やらの何らかのピクセルを描いておく必要があります。

あえて描かずに、空白のまま残して自動的に左詰めさせる仕様2を使うときもありますが。


同様の手法で、職業スキル用のアイコンも実装。
最大残弾数/弾数に応じた矢のアイコン表示
# ---------- 前略 ---------- #

+ # 職業スキルアイコン
+   execute store result storage macro:temp skill_icon.max_arrow int 1 run scoreboard players get @s MaxHArrow
+   execute store result storage macro:temp skill_icon.arrow int 1 run scoreboard players get @s HArrow
+   function player:actionbar/hunter/arrow with storage macro:temp skill_icon

# UIの表示
   title @s actionbar ["",\
   {"nbt":"lvl","storage":"player:temp","interpret":true},\
   {"nbt":"gold","storage":"player:temp","interpret":true},\
   "\uF82F",\
   {"nbt":"hp","storage":"player:temp","interpret":true},\
   {"nbt":"hp_bar","storage":"player:temp","interpret":true},\
+  {"nbt":"skill_icon","storage":"player:temp","interpret":true},\
   {"nbt":"lvl","storage":"player:temp","interpret":true},\
   {"nbt":"gold","storage":"player:temp","interpret":true},\
   "\uF82F",\
   {"nbt":"hp","storage":"player:temp","interpret":true}]

# ---------- 後略 ---------- #
(function) player:actionbar/hunter/arrowの中身
$data modify storage player:temp skill_icon set value {"text":"\uE5$(max_arrow)$(arrow)","shadow_color":[0,0,0,0.5]}
resource:font/arrow_icons.png
\uE510~\uE533に矢のアイコンを設定
{
    "providers": [
        # ---------- 中略 ---------- #
        {
            "type": "bitmap",
            "file": "resource:font/arrow_icons.png",
            "ascent": 0,
            "height": 9,
            "chars": [
                "\uE510\uE511\uE520",
                "\uE521\uE522\uE530",
                "\uE531\uE532\uE533"
            ]
        }
    }
}

アニメーションアイコン

続いてアニメーションを持つUIの表示。とはいえ名前ほど大層なことはしていなくて、やっていることとしてはタイマースコアに応じたアイコンの表示。手順も先程とほぼ同じです。

スキルクールタイムに応じたスキルバーの表示
# ---------- 前略 ---------- #

+ # スキルバー
+   # スキルクールダウンの割合計算
+       scoreboard players operation $SkillTimer Temporary = @s SkillTimer
+       scoreboard players operation $SkillTimer Temporary /= #20 Constant
+       scoreboard players add $SkillTimer Temporary 10
+       execute if entity @s run scoreboard players add $SkillTimer Temporary 40
+       execute store result storage macro:temp skill_bar.value int 1 run scoreboard players get $SkillTimer Temporary
+   # 適用
+       function player:actionbar/skill_bar with storage macro:temp skill_bar
        
# UIの表示
   title @s actionbar ["",\
   {"nbt":"lvl","storage":"player:temp","interpret":true},\
   {"nbt":"gold","storage":"player:temp","interpret":true},\
   "\uF82F",\
   {"nbt":"hp","storage":"player:temp","interpret":true},\
   {"nbt":"hp_bar","storage":"player:temp","interpret":true},\
   {"nbt":"skill_icon","storage":"player:temp","interpret":true},\
+  {"nbt":"skill_bar","storage":"player:temp","interpret":true},\
   {"nbt":"lvl","storage":"player:temp","interpret":true},\
   {"nbt":"gold","storage":"player:temp","interpret":true},\
   "\uF82F",\
   {"nbt":"hp","storage":"player:temp","interpret":true}]

# ---------- 後略 ---------- #
(function) player:actionbar/skill_barの中身
# マクロを用いてskill_barに適切なフォントを格納
    $data modify storage player:temp skill_bar set value {"text":"\uE3$(value)","shadow_color":0}


スコアの更新に基づいて連続的にフォントが切り替わる


カスタムフォントの設定 resource:font/skill_bars.png
\uE310~\uE381にスキルバーのアイコンを設定
{
    "providers": [
        # ---------- 中略 ---------- #
        {
            "type": "bitmap",
            "file": "resource:font/skill_bars.png",
            "ascent": 0,
            "height": 5,
            "chars": [
                "\uE310\uE311\uE312\uE313",
                "\uE314\uE315\uE316\uE317",
                "\uE318\uE319\uE320\uE321",
                "\uE322\uE323\uE324\uE325",
                "\uE326\uE327\uE328\uE329",
                "\uE330\uE331\uE332\uE333",
                "\uE334\uE335\uE336\uE337",
                "\uE338\uE339\uE340\uE341",
                "\uE350\uE351\uE352\uE353",
                "\uE354\uE355\uE356\uE357",
                "\uE358\uE359\uE360\uE361",
                "\uE362\uE363\uE364\uE365",
                "\uE366\uE367\uE368\uE369",
                "\uE370\uE371\uE372\uE373",
                "\uE374\uE375\uE376\uE377",
                "\uE378\uE379\uE380\uE381"
            ]
        }
    }
}

先程のHPバーでも同じような定義をしていましたが、フォントの割り当てを\uE310から始めることで、下2桁をマクロで設定することを可能にして不用意なエラー3を避けています。


同様の手法で、酸素ゲージ表示も実装。
水中にいる時の残り酸素を表示
# ---------- 前略 ---------- #

+ # 酸素ゲージ
+   data modify storage player:temp oxygen set value {"text":"\uE60A"}
+   # 酸素ゲージの割合を計算
+       scoreboard players operation $OxygenRatio Temporary = @s Oxygen
+       scoreboard players operation $OxygenRatio Temporary *= #100 Constant
+       scoreboard players operation $OxygenRatio Temporary /= @s MaxOxygen
+   # 気泡が破裂するアイコン
+       execute if entity @s[tag=Underwater] if score $OxygenRatio Temporary matches 1 run data modify storage player:temp oxygen set value {"text":"\uE60B","shadow_color":0}
+       execute if entity @s[tag=Underwater] if score $OxygenRatio Temporary matches 21 run data modify storage player:temp oxygen set value {"text":"\uE60C","shadow_color":0}
+       execute if entity @s[tag=Underwater] if score $OxygenRatio Temporary matches 41 run data modify storage player:temp oxygen set value {"text":"\uE60D","shadow_color":0}
+       execute if entity @s[tag=Underwater] if score $OxygenRatio Temporary matches 61 run data modify storage player:temp oxygen set value {"text":"\uE60E","shadow_color":0}
+       execute if entity @s[tag=Underwater] if score $OxygenRatio Temporary matches 81 run data modify storage player:temp oxygen set value {"text":"\uE60F","shadow_color":0}
+   # 割合に応じて気泡アイコンを表示
+       scoreboard players add $OxygenRatio Temporary 19
+       scoreboard players operation $OxygenRatio Temporary /= #20 Constant
+       execute store result storage macro:temp oxygen.value int 1 run scoreboard players get $OxygenRatio Temporary
+   # 酸素ゲージが満タンの時は非表示
+       execute unless score @s Oxygen = @s MaxOxygen run function player:actionbar/oxygen with storage macro:temp oxygen

# UIの表示
   title @s actionbar ["",\
   {"nbt":"lvl","storage":"player:temp","interpret":true},\
   {"nbt":"gold","storage":"player:temp","interpret":true},\
   "\uF82F",\
   {"nbt":"hp","storage":"player:temp","interpret":true},\
   {"nbt":"hp_bar","storage":"player:temp","interpret":true},\
   {"nbt":"skill_icon","storage":"player:temp","interpret":true},\
   {"nbt":"skill_bar","storage":"player:temp","interpret":true},\
+  {"nbt":"oxygen","storage":"player:temp","interpret":true},\
   {"nbt":"lvl","storage":"player:temp","interpret":true},\
   {"nbt":"gold","storage":"player:temp","interpret":true},\
   "\uF82F",\
   {"nbt":"hp","storage":"player:temp","interpret":true}]

# ---------- 後略 ---------- #
(function) player:actionbar/oxygenの中身
$execute unless data storage player:temp oxygen.shadow_color run data modify storage player:temp oxygen set value {"text":"\uE60$(value)","shadow_color":0}
resource:font/oxygen.png
\uE510~\uE533に矢のアイコンを設定
{
    "providers": [
        # ---------- 中略 ---------- #
        {
            "type": "bitmap",
            "file": "resource:font/oxygen.png",
            "ascent": 0,
            "height": 9,
            "chars": [
                "\uE600\uE60A",
                "\uE601\uE60B",
                "\uE602\uE60C",
                "\uE603\uE60D",
                "\uE604\uE60E",
                "\uE605\uE60F"
            ]
        }
    }
}

またここで、minecraft/textures/gui/sprites/hudの中の酸素ゲージや防具アイコン、経験値バー等を編集して非表示にしたり、自分好みに表示させています。

ステータスバフアイコン

画面中央に広くスペースを確保し、受けているバフに応じてアイコンを表示させています。アイコンはそれぞれ効果時間を表し、それがバフかデバフか一目でわかるように工夫されています。様々な状況に応じてアイコンを操る、集大成のようなUI。


左右のpxを上手に調整して、これは中央揃えに。よくやったものだ。

...基本的なアイデアはそんな感じですが、解説するのはちょっと骨が折れそうだ!
ということでまたいつか、番外編の動画やらで解説することにします。

経験値バー操作 ───────────

ホットバーの上に位置する経験値表示用の既存のUI。これを自在に操作することで、独自のUIを作っていきます。今回はMPを表示するものとして。...出来上がったものがこちら!!


目的の割合になるまで滑らかに増減する。


実装の詳細
常時実行でMPの割合を計算し、それに基づいて経験値バーを操作
# MPバー操作
    # MPの割合計算
        scoreboard players operation @s MPRatio = @s MP
        scoreboard players operation @s MPRatio *= #835 Constant
        scoreboard players operation @s MPRatio /= @s MaxMP
    # MPバーを適用
        execute unless score @s PrevMPRatio = @s MPRatio run function player:status/mp/bar/_
(function) player:status/mp/bar/_の中身
# 操作前のレベルを一旦保存
    execute store result score $XPBarLevels Temporary run scoreboard players get @s MP

# レベル129はポイントが 0~1002 なので割合を調べるのに最適
    xp set @s 129 levels
    execute store result score $XPBarPoints Temporary run xp query @s points

# MPの割合(0~100%)との違いを調べる
    scoreboard players operation $XPBarDif Temporary = @s MPRatio
    scoreboard players operation $XPBarDif Temporary -= $XPBarPoints Temporary
    scoreboard players operation $XPBarDif Temporary /= #8 Constant

# 経験値ポイント加算
    xp set @s 0 points
    scoreboard players operation $XPBarPoints Temporary += $XPBarDif Temporary
    execute store result storage macro:temp xp_bar.point int 1 run scoreboard players get $XPBarPoints Temporary
    function player:status/mp/bar/set_point with storage macro:temp xp_bar

# レベル数値加算
    xp set @s 0 levels
    execute store result storage macro:temp xp_bar.level int 1 run scoreboard players get $XPBarLevels Temporary
    function player:status/mp/bar/set_level with storage macro:temp xp_bar

# MPに変化がある時だけfunctionを常時実行
    scoreboard players set @s PrevMPRatio -1
    execute if score $XPBarDif Temporary matches 0 run scoreboard players operation @s PrevMPRatio = @s MPRatio

# リセット
    data remove storage macro:temp xp_bar
    scoreboard players reset $XPBarDif Temporary
    scoreboard players reset $XPBarLevels Temporary
    scoreboard players reset $XPBarPoints Temporary
(function) player:status/mp/bar/set_pointの中身
$xp set @s $(point) points
(function) player:status/mp/bar/set_levelの中身
$xp set @s $(level) levels

経験値操作については過去に動画4で一度解説したことがあるので、未見の方はそちらを見ていただくとより掴めるかと思います。マクロの登場によって動画投稿時点より最終的なpoint, levelの設定が簡単になったので、実装を見比べてみるのもまた一興。

テキスト・アイコンの上下位置調整 ──

さて、仕上げとして、ようやくこれらをいい感じに並べて、いい感じにしていきましょう。まずはアイコンから。フォントの定義において、ascentの値をいじることで上下可能です。


ベストな位置をpx単位で、納得いくまで調節する!

この時、ascentの値がheightを上回ると読み込みエラーが起きてしまうため注意。

参照(ソース): https://ja.minecraft.wiki/w/フォントのカスタマイズ より


続いてテキストの位置調整。以前、動画では自作のフォントを作る必要がある!と自信満々に言ってしまっていましたが、もう少し簡単な手法を見つけたのでそちらを紹介します。

テキストをアイコンで上書きしたフォントを定義する」手法。default.jsonの入っているフォルダにて新しく適当なjsonファイルを作成し、中身をこのように定義します。重要な部分は2要素目のui_text.pngを割り当てしている部分。

y-22px.jsonの中身
{
    "providers": [
        {
            "type": "space",
            "advances": {
                " ": 4,
                "\uF822": 2
            }
        },
        {
            "type": "bitmap",
            "file": "resource:font/ui_text.png",
            "ascent": -22,
            "height": 7,
            "chars": [
                "0123456789Lv.(/)G"
            ]
        },
        {
            "type": "bitmap",
            "file": "resource:font/heart.png",
            "ascent": -21,
            "height": 9,
            "chars": [
                "\uE100"
            ]
        }
    ]
}


0123456789Lv.(/)Gのテキストにそれぞれ画像を割り当てしていく

こうすることで「\uE100→♡」となるように「1→1の画像」となるわけです。画像(bitmap)はascentタグを用いることで簡単に上下させることが可能なので、アイコンと同様の操作を行ってテキストも上下していきます。

先頭にフォントを定義し、以降の要素(テキスト)に継承
# ストレージの準備
-   data modify storage player:temp hp set value ["",{"text":"\uE100","shadow_color":0},"\uF822",{"score":{"name":"@s","objective":"HP"}},"/",{"score":{"name":"@s","objective":"MaxHP"}}]
-   data modify storage player:temp lvl set value [{"text":"","color":"#E0E0E0"},"Lv.\uF822",{"score":{"name":"@s","objective":"LVL"},"color":"white","bold":true},"\uF822(",{"score":{"name":"@s","objective":"EXP"},"color":"#9EE082"},"/",{"score":{"name":"@s","objective":"NextEXP"}},") "]
-   data modify storage player:temp gold set value ["",{"score":{"name":"@s","objective":"Gold"}},{"text":"G","color":"#FFEE59"},"\uF822",{"text":"\uE101","shadow_color":0}]
+   data modify storage player:temp hp set value [{"text":"","font":"y-22px"},{"text":"\uE100","shadow_color":0},"\uF822",{"score":{"name":"@s","objective":"HP"}},"/",{"score":{"name":"@s","objective":"MaxHP"}}]
+   data modify storage player:temp lvl set value [{"text":"","color":"#E0E0E0","font":"y-16px"},"Lv.\uF822",{"score":{"name":"@s","objective":"LVL"},"color":"white","bold":true},"\uF822(",{"score":{"name":"@s","objective":"EXP"},"color":"#9EE082"},"/",{"score":{"name":"@s","objective":"NextEXP"}},") "]
+   data modify storage player:temp gold set value [{"text":"","font":"y-16px"},{"score":{"name":"@s","objective":"Gold"}},{"text":"G","color":"#FFEE59"},"\uF822",{"text":"\uE101","shadow_color":0}]

# ---------- 後略 ---------- #


いい感じになってきました。あと1歩!!

テキスト・アイコンの左右位置調整 ──

ラスボス、左右位置調整です。なぜこれを最後にやるかというと、一つを目的の位置に動かそうとするたび、全てが連動して動いてしまうためです。一気にやったほうがお得。また、左右の位置調整にはspaceを使っていきます。...と出来上がっていく様子がこちら!!


編集しては/reload、編集しては/reload ...

ポジティブ/ネガティブスペースを入れて左右の位置調整
# ---------- 前略 ---------- #

# UIの表示
   title @s actionbar ["",\
   {"nbt":"lvl","storage":"player:temp","interpret":true},\
   {"nbt":"gold","storage":"player:temp","interpret":true},\
+  "\uF82F",{"translate":"space.-79"},\
+  {"nbt":"hp","storage":"player:temp","interpret":true},{"translate":"space.6"},\
   {"nbt":"hp_bar","storage":"player:temp","interpret":true},\
+  {"nbt":"skill_icon","storage":"player:temp","interpret":true},{"translate":"space.53"},\
+  {"nbt":"skill_bar","storage":"player:temp","interpret":true},{"translate":"space.2"},\
+  {"nbt":"oxygen","storage":"player:temp","interpret":true},{"translate":"space.-126"},\
   {"nbt":"lvl","storage":"player:temp","interpret":true},\
   {"nbt":"gold","storage":"player:temp","interpret":true},\
+  {"translate":"space.8"},"\uF82F",\
   {"nbt":"hp","storage":"player:temp","interpret":true}]

# ---------- 後略 ---------- #

カスタムフォントの設定
{
    "providers": [
        {
            "type": "space",
            "advances": {
                "\uF800": 0,
                "\uF801": -1,
                "\uF802": -2,
                "\uF803": -3,
                "\uF804": -4,
                "\uF805": -5,
                "\uF806": -6,
                "\uF807": -7,
                "\uF808": -8,
                "\uF809": -16,
                "\uF80A": -32,
                "\uF80B": -64,
                "\uF80C": -128,
                "\uF80D": -256,
                "\uF80E": -512,
                "\uF80F": -32768,
                "\uF820": 0,
                "\uF821": 1,
                "\uF822": 2,
                "\uF823": 3,
                "\uF824": 4,
                "\uF825": 5,
                "\uF826": 6,
                "\uF827": 7,
                "\uF828": 8,
                "\uF829": 16,
                "\uF82A": 32,
                "\uF82B": 64,
                "\uF82C": 128,
                "\uF82D": 256,
                "\uF82E": 512,
                "\uF82F": 32768
            }
        },

        # ---------- 後略 ---------- #
    ]
}
lang/en_us.jsonファイルで幅を定義(可読性UPのため)
{
    "space.-126": "\uF80B\uF80A\uF809\uF808\uF806",
    "space.-79": "\uF80B\uF808\uF807",
    "space.2": "\uF822",
    "space.6": "\uF826",
    "space.8": "\uF828",
    "space.53": "\uF82A\uF829\uF825"
}

以前はAmberWatさんの制作したNegativeSpaceFontを導入する必要がありましたが、今やdefault.json内でspaceを定義するだけでOK。とてもシンプルになりました。

さいごに

実際にストレージに適切なアイコンを格納する部分や、諸々actionbar以外の細かな処理でかなり解説を端折った部分があったと思います!!申し訳ないです...!全てgithubで公開しているので、奥で動いている処理に興味のある方はそこまで覗いてもらえると嬉しいです。

長いことUI周りの知見を外に出していなかった自覚があるので、この機会に放出できてよかったです。カスタムフォントの定義であったり、細かなコマンド周りで知見を汲み取ってもらえると...!!あとは... 程々に元気です。制作頑張ります。

  1. リソースパックを用いて任意の文字にアイコンを割り当てすることができる技術。私作のこちらの渾身の動画を参考にしてください。https://youtu.be/w0Zraz-o8yE?si=51rLwk7WKMKl3iUI

  2. 表示するアイコンの中に描画するピクセルが存在しない場合、右側の空白に限り自動的に左に詰められます。この仕様を用いることで、縦横サイズの統一をしていないアイコンを一つの画像で割り当てできるので、何かと活用することがあります(後述のui_text.pngにて活用しています)。

  3. \uE301~\uE380などと割り当てをした場合、マクロで下2桁を設定する際に01~80を入力する必要性が出てくるため、純粋に数値を入力するだけでは\uE31などといった存在しないテキストを出力しようとしてしまい、特定の場合でエラーが起きてしまう。

  4. こちらの動画。渾身です。https://youtu.be/Dtn_FQcDF8E?si=aIPJHBbUf9UmJg4a

13
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?