カードの操作と時間経過の見せ方

概要

カードを動かす操作——端のタップ・ドラッグ&ドロップ・並べ替え——と、ワールドの変化をどう見せるか ——移動アニメーション・時間経過の再生——を決めるドキュメントです。カードと枠の見た目は CardView.md、レーンとエリアの配置は ScreenLayout.md、 子ウィンドウは Windows.md が扱います。

方針は次のとおりです。操作の可否は画面が決めず、カード 1 枚ずつエンジンへ訊きます (WorldObject.rejectionForMoveTo、1 節・2 節)。ワールドは操作した瞬間に変わり切っていて、 実時間をかけるのは見せ方だけです(Windows.md 5.2 節。7〜9 節がその見せ方)。

実装は src/game/ui/CardTable.ts(場に出ている札の実体と動き)・src/game/ui/DustPuff.ts(砂埃)と src/game/PlayScene.ts で、実装済みです。

1. カードの端によるレーン間の移動

隣り合う 2 つのレーンの間でアイテムを移す操作は、カードの端 1/6 に割り当てます。向きはレーンの 並び(設置物 → アイテム → 手持ち)そのままで、上端(▲)が 1 つ上のレーン、下端(▼)が 1 つ下の レーンを指します。押している間だけ、その操作エリアに半透明のオーバーレイと矢印を重ねて「今押して いるのはどちら向きの移動か」を示します。手持ちが 6 枠とも埋まっている場合など、移せなかったときは 何も起きません。

端が出るかどうかは、そのカードがそこへ移せるかで決まります。 画面はレーンごとに向きを決め打ち せず、カード 1 枚ずつエンジンへ訊きます(WorldObject.rejectionForMoveTo)。ヤシの木が端を持たない のは item タグを持たないから、編み籠が設置物レーンで ▼ を、アイテムレーンで ▲ を出すのは item と fixture を兼ねているからです。上下の押せる範囲は重ならないので、両方向へ送れるカードは端を 2 つ 持ちます。

2. カードのドラッグ&ドロップ

同じ 2 つのレーンの間は、カードを掴んで運ぶこともできます。ドロップ先の意味は次のとおりです。

カード同士の実際の隙間は 12u と狭く、移したいだけなのにドラッグ型の操作と判定されやすいため、 カードの左右 1/4 も隙間側として扱います。空いている枠には重ねる相手が居ないので、こちらは 枠の幅いっぱいが落とし先になります。

レーン自体も横ドラッグでスクロールするため、カードの上から始まったドラッグがどちらの操作なのかを 押し始めた位置で見分けます。カードの本体から始まればカードを掴んだ操作、上の左右 1/4——隙間側 として扱うのと同じ幅——から始まればレーンのスクロールです。向きは見ませんし、待つ必要もありません。 タップの指のぶれと見分けられるだけ動いた時点で、どちらかに決まります。

押している間は、カードの縁を太い黒線でなぞります。掴む操作になった時点(またはタップとして 成立した時点)で消えるので、この線が出ている間が「まだどちらの操作か決まっていない」時間です。

掴んでいる間は、掴んだ札そのものがポインタに追従します(束から分かれた実体で、着いた先で 合流します)。レーンの外へも出るため、レーンの中ではなく画面の最前面に描きます。運んでいる札も、 束が残っている元のカードも半透明にしません。札が透けるのはカードゲームらしくないためです。

薄くするのは、束を丸ごと持ち出して残りが 0 枚になった元のカードだけです(1 枚しか映していない カードを掴んだとき、または待って束が全部ついてきたとき)。そこに残っているのはもう札ではなく、 帰ってくる場所を示す姿だからです。数字のバッジも出ません。

掴んだ瞬間に、そのカードを受け入れられるカードすべてのふちを光らせます(明滅する琥珀色の縁取り)。 どこへ持っていけば何かが起きるのかを、重ねてみる前に見せるためです。落としたときに何かが起きる位置に いるときだけ、その行き先(重ねる相手のカード・入る隙間・入る空き枠)を緑の枠で示します。候補と現在の 落とし先で色相を分けているので、両者を取り違えません。何も言うことの無い位置では枠を出さず、離しても 何も起きません。断る理由を持つ相手だけは例外で、灰色の枠を出します(2.1 節)。3 色の意味は 「持っていけば起きる(琥珀)」「離せば起きる(緑)」「理由がある(灰)」で、何かが起きる 2 色は 色相で分け、何も起きない灰は色相を持ちません(無彩色。色相を 1 つも使わないので、他の色を圧迫しません)。

カードに重ねている間は、そのドラッグ型の操作の名前と説明を吹き出しで出します。 duration を持つ組み合わせでは、続けてかかる時間も出します。吹き出しが出ることは「離せば 実行される」を意味しません——理由を言うためだけの落とし先(2.1 節)では、時間の代わりに 断る理由が出ます。

入れるのに時間がかかる枠(put_in、GameElementDefinition.md 7.10 節。怪我へ治療具を当てる等)も同じ吹き出しを出します。カードへ重ねたときも、枠・隙間へ落とした ときもです——離す前に値段を見せるのが、簡単なジェスチャで時間が経つことへの答えだからです。 入れるだけで時間もかからない移動には、これまでどおり吹き出しを出しません。 置き場所は掴んでいるカードの真上です。指はカードの中心にあるので、上へ逃がせば隠れません(画面の上端に 近くて入り切らない場合だけ下へ回します)。文字は指で操作する前提でカード名より大きく取ります。

2.1 理由を言うためだけの落とし先

条件で成立しない組み合わせを候補から消すと、プレイヤーには「重ねても何も起きない」としか見えません。 reason を書いた要件は、落ちたときに理由が届くという約束(GameElementDefinition.md 14.6 節)なので、暗い中での石の打ち割りも薪の無い炉への着火も、なぜできないのかをその場で言います。

理由の宣言が無い要件で落ちている組み合わせは、これまでどおり候補になりません。黙って断ると決めた宣言に、 画面が言葉を足すことはしません。

3. 「その枠へ落とした」の行き先

空き枠へ落としたカードは、枠の位置が安定しているスロットならその枠そのものへ入ります (cell_count を持つスロット、SlotSystem.md 3 節)。前詰めのスロットに 空き枠は末尾の受け皿(CardView.md 12 節)しか無いので、そちらはその位置の隙間へ 落としたものとして扱い、並びの末尾へ入ります。画面は枠を指すだけで、それが位置の指定になるかどうかは ワールド側の宣言が決めます。

4. 並べ替えだけはスタックごと

レーンをまたぐ移動は掴んだぶん(1 個、または待ってついてきた数)だけですが、同じレーンの中での 並べ替えだけはスタックを丸ごと動かします。1 個だけ抜いて入れ直そうとすると、残った同種のスタックへの合流が位置指定より 優先されるため(SlotSystem.md 3 節)、必ず元の位置へ戻ってしまい、 スタックしているカードの並べ替えが原理的にできないからです。

ドラッグしているのはあくまでカード 1 枚で、落とした先が同じレーンだったときにスタックごと動く、という 組み立てにしています。並べ替えで詰める向きは、スタックが抜けた跡の側を先に試します(そちらには必ず 空きがあるので、遠くの枠を動かさずに済みます)。自分の両隣の隙間へ落とした場合は何も動きません。

5. 落とし先の上で待つと、2 枚目以降がついてくる

物をいくつも入れ物へ移すのに 1 個ずつ掴み直すのは手間なので、落とし先の上で指を止めたまま待つと、 同じスタックの 2 枚目・3 枚目が 1 枚ずつついてきます。離せば、ついてきたぶんが一度に入ります。 待ち時間と間隔はカードの端を押し続けたときと同じ(0.4 秒待ってから、間隔を 0.3 秒から 50 ミリ秒 まで詰める)です。どちらも「カードが 1 枚ずつ出てくる」速さなので、違うと別の操作に見えます。 待ち時間は指が止まってから数えます。動いている間まで数えると、空き枠は当たり判定が広いので、 落とすつもりで横切っただけの指に 2 枚目がついてきてしまいます。

運んでいる枚数は、運んでいる札の右上の数字で見せます。ついてくる札は元の枠から飛んできて 指の下の札に合流し、数字が 1 つ増えます(速さは 6 節のカードの移動アニメーションと同じ)。

運んでいるぶんは、元の束から減って見えます。 掴んだ 1 枚も含めて、手に在る札はもう束には 居ないからです。石 3 個の束から 1 枚掴めば、元の枠の数字は 2 になります。離した後も、その札が 手に在る間は減ったままです(6 節。時間のかかるドラッグ型の操作では経過を見せている間ずっと)。

落とし先が変わっても、そこがそのまま受け取れるなら運んでいる枚数は保ちます(ハンドレーンの隣の 空き枠へずらしただけで数え直しにはなりません)。受け取れる枚数のほうが少なければそこまで減らし、 あふれたぶんだけ返します。運んでいる枚数は「これだけ入る」という約束なので、守れなくなるぶんだけを 返せば足りるからです。

指の下から居なくなる札は、必ず元の枠へ飛んで返ります——あふれて減ったぶんも、落とさずに離した ぶんもです。着いた時点で元の束に合流します。

入りきらないぶんは、そもそもついてきません。 ついてきた枚数はそのまま「これだけ入る」という 約束なので、落とした後に一部だけ弾かれる、が起きないようにします。何個入るかは枠自身が答えます (accept・max・capacity と既に入っているぶんから決まる。Slot.acceptedCount)。時間のかかる枠 (put_in)では吹き出しの時間も入る個数ぶんになります——1 個ずつ入れるのと同じことをするからです。

ドラッグ型の操作にも、宣言が許していればついてきます(allow_multiple、 GameElementDefinition.md 12.4 節)。許していなければ 1 枚だけです。 条件は世界のどこでも参照でき、1 回実行するたびに世界が変わるので、2 回目が成立するかを実行前に 言えるのは、値域を持つプロパティのように単調に埋まる器へ入れる宣言だけ——炉へ薪をくべる操作が そうで、fuel の残りが何本ぶんかを数えられます(DesignNotes.md 「まとめて入れる」節)。

6. カードの移動アニメーション

ワールドが変わったときは画面を作り直さず、レーンの中身だけを差し替えます。カードは作り直さずに 残したまま新しい位置へ動かすので、位置の変化がそのままアニメーションになります。

カードの同定には、そのカードが映しているインスタンスの ID を使います。1 枚が複数のインスタンス (スタック)を表すことがあるため ID は集合で持ち、差し替えの前後で 1 つでも重なるカード同士を 同じカードとみなします。これだけで次のすべてを区別できます。

起きたこと ID 集合の関係 見せ方
移動・押し出し・詰め直し 重なる 新しい位置へ動く
スタックへの合流 消えた側が残ったカードに含まれる 合流先へ飛んで上に重なる(薄れさせない。カードゲームなので札が重なるように見せる)
出現 差し替え前のどの ID とも重ならない それを起こした側のカードから飛んでくる(探索なら現在地、ドラッグ型なら宣言している側の札、獣が生んだ怪我ならその獣)
破棄 差し替え後のどの ID とも重ならない その場で即座に消える(薄れさせない。掴んで離したカードが即座に消えるのと食い違って見えるため)

出どころは世界に起きた変化が個体ごとに答えます(HuntingSystem.md 6.2 節)。 一度に出どころの違う物が現れても、それぞれの出どころから飛びます。画面にしか出どころが無いのは、レシピ一覧から 作り始めた製作中オブジェクト(一覧で選んだ札の位置。一覧は閉じている)と、後述の指を離した位置だけです。 どちらでもない——世界も画面も出どころを知らない——ものは、その場で浮かび上がります。

一度に複数動いたぶんは、1 枚ずつ間を置いて飛ばします。 何個動いたのかを、飛ぶ枚数で数えられる ようにするためです。ヤシの実を 3 個まとめて採れば、手持ちでは 1 枚に束ねて見えていても3 枚が順に 飛んできます(飛んでいる札は右上の数字を持ちません)。出どころに積まれたまま、順に飛び立つ姿になります。 まとめて別のレーンへ入れた 3 個も同じ見え方で、3 枚とも指を離した場所から動き出します—— ついてきた札も、落とす時点では指の下に居たからです。

間隔は端を押し続けて送り続けるときの最短間隔と同じ 50 ミリ秒です。どちらも「カードが 1 枚ずつ 出てくる」速さなので、違うと別の出来事に見えます。

掴んで離したカードだけは、元の枠ではなく指を離した場所から動き出します。手に持っていたカードは そこに在るからです。重ねてもカード自身は動かないドラッグ型の操作(石を打ち割る等)も同じ扱いで、 差し替えの時点で指を離した場所から元の枠へ戻ります。同じレーンの中で並べ替えたときも同じで、指を 離した場所から新しい位置へ入ります。

時間のかかるドラッグ型の操作では、経過を見せている間ずっと、そのカードは指を離した場所に置いた ままです。相手の札の上に置いた道具はそこに在るからで、経過し切った時点で元の枠へ戻ります——道具は 使い終わってから手元へ戻る、という見え方になります。元の枠の見え方も、掴んで運んでいる間から 変わりません(2 節・5 節)——置いた 1 つはまだ手に在るので、スタックはその 1 つを引いた数字のまま、 1 つしか映していないカードは薄い姿のままです。帰り着いた時点で元へ戻り、使い切って帰らなければ そのまま消えます。

詰め直しとして滑るのは、掴んでいなかったカードだけです。

飛んでいくのは運んでいるインスタンスを載せた実体の札で、着いた枠の札に合流します(IDセットの 和になり、枚数はそこから導かれます)。飛んでいる間は画面最前面の層に置きます——レーンからはみ出した カードは隣接エリアの背景板に隠れる設計のため、レーンの中に置いたままでは境界を越えられないからです。 この層は子ウィンドウよりも手前に置き、ウィンドウを開いたまま探索したときに、見つけたものが覆いに 隠れないようにしています。

着く前に次の差し替えが来たら、飛んでいる札は新しい行き先へ向き直ります(上下へ移すボタンの 連打がこれにあたります)。行き先は差し替えのたびに引き直すので、カードの居なくなった枠へ着いて 別の場所のカードへ 1 枚足すことは起きません。運んでいたインスタンスが世界から出ていれば、 その場で消えます。

6.1 生まれた札・壊れた札は砂埃を立てる

オブジェクトが世界に生まれたとき・世界から出た(壊れた・使い切った)ときは、その札の中心から 外へ砂埃をぱふっと散らします。移動と違って、出入りは並びの前後を見比べても跡が残らないためです。

どちらなのかを知っているのは世界に起きた変化だけです(HuntingSystem.md 6.2 節と同じログ)。レーンから居なくなった札は壊れた札とレーンを移った札のどちらでもあり、現れた札は 生まれた札と移ってきた札のどちらでもあるので、画面の出入りでは代われません。

立つ場所と時機は、その札が並びに出入りする場所と時機に揃えます。壊れた札はその枠で即座に、 生まれた札は飛んで着いた枠で立ちます。突き当たられて壊れた札だけは、突進が着いてから (6.3 節)——片付けるのがそのときだからで、規則そのものは同じです。壊れた側は札 1 枚につき 1 回 です——3 個の束が丸ごと消えても、居なくなった札は 1 枚だからです。生まれた側は着くたびに 1 回なので、3 個が順に飛んでくれば 3 回立ちます。画面に出ていなかった物(閉じた入れ物の中で壊れた物)は枠を持たないので、何も立ちません。

粒の大きさも散る距離も札の幅から引きます。画面の寸法トークンを別に持つと、カードだけが縮む向きの 変更で埃だけが取り残されるためです。粒の絵(src/assets/ui/dust_puff.png)は 💭 の輪郭を借りて色を 塗り直したもので、吹き出しの付け根は落としてあります。

6.2 宙に在る札は、行き先の枠にまだ居ない

ワールドは操作した瞬間に変わり切っていますが、画面はこれから運びます。運んでいる間、その 1 枚は 行き先の枠にまだ居ません——枠が見せる枚数は、世界の枚数からその枠へ向かって宙に在る枚数を 引いた数です。1 枚着くごとに 1 つ増えます。宙に在るのは、飛んでいる札と、指を離した場所に置いた ままの札(6 節)と、突進している札(6.3 節)です。

石 2 個の束へ 1 個を移せば、飛んでいる間の束は 2 個に見え、着いた瞬間に 3 個になります。丸ごと 運ばれてくるカードで 0 枚になれば、そこに札は出ません——「着くまで伏せておく」も、この引き算の 結果でしかありません。

子ウィンドウが出している札は、宙にではなくそこに在ります(Windows.md 1.1 節)。 元の枠はその 1 枚を名乗らず、帰りを待つ印だけを残します。1 つのものを映す札が画面に 2 枚出ないのは、 それを名乗る枠が常に 1 つに決まっているからで、運びの途中かどうかとは関わりません。

0 枚の枠に印(2 節の薄い姿)が残るのは、元から居た札を持ち出された枠だけです。まだ 1 枚も 来ていない枠には出しません。そこに在ったことのない札の、帰ってくる場所は無いからです ——探索で見つかったものが、借りられているあいだレーンに枠を空けないのもこれです (Windows.md 5.1 節)。

6.3 手を出した札は、相手の枠まで突進する

獣が足元の物へ手を出したとき、その獣の札が相手の枠まで動いて、突き当たり、自分の枠へ帰ります。 レーンの上では「物が消えた」としか見えない回に、誰の仕業かを出すための動きです。

行きと帰りは、ほかの飛びと同じ速さ・同じ加速で進みます(6 節)。往復している間その個体はどの枠にも 居ないので、元の枠には帰ってくる場所の印(薄い姿)が残ります(6.2 節)。

相手の札を片付けるのは、突き当たってからです。 着く前に消すと、何も無い所へ飛びかかったように 見えます。壊された相手の砂埃(6.1 節)も、同じく突き当たった瞬間に立ちます——生まれた札の砂埃を 着いた先で立てるのと同じ理由です。束の一部だけを持ち去られた札はその場に残るので、片付けるものは ありません。同じ札へ2匹が手を出しても、片付けも砂埃も1回だけです(6.1 節の「札 1 枚につき 1 回」)。

突き当たる前に途切れたら、相手の消滅はその場で見せます。 突進している個体が帰る枠を失う (自分も世界から出た・別の土地へ移った)と往復は打ち切られますが、壊れた相手まで黙って消えては いけないためです。

どの変化が突進として読まれるのかは HuntingSystem.md 6.1 節が持ちます。

7. 時間経過のドーナツグラフ (Progress Ring)

duration を持つアクションの実行中、フィールドエリアの中央に重ねて出す輪です。duration 全体を 100% として、経過ぶんを真上から時計回りに塗ります。カードや子ウィンドウより手前に出し、下が透ける 濃さで描きます。

割合は一定の速さでは進めず、区切りごとに一拍置きます。区切りの前半で次の目盛りまで進み、後半は 止まります。ゲーム内の変化が起きるのは tick 境界だけなので、滑らかに増やすより実際の進み方に合います。

目盛りへ向かう間は、加速して動き出し減速して止まります。 一定の速さで動いて急に止まると、目盛り ごとに動きが切れて見えるためです。加速に使うのは進む側の実時間の 35% で、残りの 65% を減速に使います ——止まり方のほうが目に付くので、そちらへ時間を多く割きます。一拍置く作りそのものは変えていません。

1 回の経過にかける実時間には上限があります(3 秒=ゲーム内 90 分ぶん)。これを超える長さの行動 ——半日の睡眠(Characters.md 休息節)——は、上限に収まるよう早送りします。 等速で見せると十数秒待たされ、待つこと自体が休息の値段になってしまうためです。刻み方は変わらず、 目盛りの間隔だけが詰まります。上限は、1 回の行動に許される長さ(1 時間。 ../engine/ActionSystem.md 6.3 節)より外に置いてあるので、線の内側の 行動はどれも等速のまま見えます。

目盛りは「実際に tick が回る瞬間」に置きます。 すなわち絶対時刻が 1 tick(15 分)の 倍数になる瞬間で、WorldSession.advanceWorldTime が tick を回すタイミングそのものです。そのため 区切りの長さは一定とは限りません。

状況エリアの時計も同じ区切りで動きます。 塗りが目盛りへ届いた瞬間に、その時刻へ飛びます。 塗りと時計が食い違って見えないよう、どちらも同じ区切りから導いています。

7.1 経過時間の数字

輪の中心に、開始からの経過時間を +0:15・+1:00 の形で大きく出します。 輪が示すのは 「どれだけ進んだか(割合)」だけなので、それ単独では何分経ったのかが読めないためです。文字は輪の 外径より横へはみ出す大きさにし、輪は文字の後ろへ回します——読ませたいのは数字のほうで、輪は残りの 見当を付けるための地です。

数字は塗りと同じ区切りで飛びます(+0:15 → +0:30)。一拍置いている間も数字だけが動き続けると、 塗り・時計・数字が食い違って見えます。押した瞬間は +0:00 から始めます——何も出ていない状態から 現れると、数字が出たこと自体が変化に見えるためです。

この数字だけは長さの書き方が他と違います。 他の場所(かかる時間・残り時間)は「1時間30分」の形 ですが、それは字数が長さによって動くため、動きながら大きく出る数字では値が変わるたびに文字の幅が 踊ります。時分を桁で揃えた形なら踊りません。頭の + は、同じ画面に出ている時計の絶対時刻(11:00)と 見分けるためです。

色は生成りに暗い縁取りです。 移動のときは輪ごと暗幕の手前に残る(9 節)ので、明るいカードの上でも 暗幕の上でも読めるよう、塗りと縁取りの明暗を離します。純白ではなくヘッダと同じ生成りを使うのは、 画面全体が古い紙の色で組まれているためです——純白は 1 か所だけ別の素材に見えます。

8. 経過中に起きた変化の再現

経過中の tick で起きた変化は、その tick の目盛りに届いた瞬間に見せます。 45 分かかるアクションの 15 分目に食べ物が腐ったなら、実時間でもその 15 分の位置でカードが入れ替わります。時間をかけて見せて いるのに変化だけ最後にまとめて現れると、何がいつ起きたのか読み取れないためです。

ワールドは操作した瞬間に経過し切っています(Windows.md 5.2 節と同じ)。そこで 各 tick 時点の表示内容を控えておき、実時間の経過に合わせて再生します。控える時刻は tick が回る 絶対時刻なので、ドーナツグラフの目盛りと定義上一致します。控えたものを見せる動きは通常の差し替えと 同じ経路(6 節)なので、壊れた道具はその瞬間に消え、湧いたものはその瞬間に現れます。

変わった分の帯(StatusArea.md 4 節)も tick ごとに動きます。増減の三角は 「行動開始からその時点まで」の差で、経過が進むにつれて確定していきます。

行動そのものの結果(ドラッグ型の操作の成果物、探索の発見物)は経過し切った時点で出ます (ActionSystem.md 2 節の順序が、効果を時間経過の後に置いているため)。 掴んで離したカードが手元へ戻るのも同じ時点です。

演出中は子ウィンドウを開けません。 カードのタップ・現在地カード・ポートレイト・装備/怪我/地図の ボタンは、経過を見せている間と場面転換の間は反応しません。画面に出ているのは再現中の過去の時点なので、 そこから開いたウィンドウは既に古い対象を指しており、そのアクションを実行させるわけにいかないためです。

9. 移動の場面転換

道のカードから「移動する」を実行すると現在地が変わり、フィールドエリアを作り直します (Windows.md 4 節)。作り直しはフィールドエリアを暗転させた裏で行い、終わったら 明転させます(0.32 秒)。作り直しは一瞬で終わるので、そのまま行うと前の土地から次の土地へ画面が 飛びます。

暗転は移動にかかる時間の経過(時計とドーナツグラフ)と並行して進みます。そのため場面転換のぶん 待たされることはありません。ワールド自体は押した瞬間に変わっている (Windows.md 5.2 節と同じ)ので、移動を伴う行動かどうかはその時点で分かり、 時間が経ち切るのを待たずに暗転を始められます。

暗転は 0.64 秒で落とし切り、残りは暗いまま経過を見せます。 移動にかかる時間ぶんかけて少しずつ 落とすと、暗くなっていることに気付かないまま画面が入れ替わってしまうためです。明転(0.32 秒)より 長く取るのは、場面が変わる合図として落ちていく途中を見せたいためです。移動にかかる時間が 0.64 秒より 短ければ、その分だけで落とし切ります——作り直すのは経過し切ってからなので、暗転はそれまでに 終わっている必要があります。

暗くするのはフィールドエリアだけで、情報エリア・オプション/フィルターバーはそのまま残ります。 時計とステータスバーも暗転の裏で移動後の値へ変わります。ドーナツグラフは暗幕より手前に出るので、 暗い間も時間の経過が見えます。

前の土地に紐づくもの(直前の発見物・置いてきたコンテナの中身のウィンドウ)は 持ち越さず、移動の時点で手放します。移動先には無いものを見せてしまうためです。

10. 回復の粒 (Gain Particles)

操作そのものがキャラクターの値を増やしたとき、増えたステータスのアイコンが発生源の札から湧き、 ポートレイトカードへ吸い込まれます。 変化そのものはステータスバーの動きで読めますが、 安全域のステータスは並びに出ません(StatusArea.md 2 節)。出ていない行が 動いたことを知らせる手段がここにしかないので、賑やかしを兼ねてこの形で出します。

10.1 何を粒にするか

操作の効果が実体値へ直に書いた値だけです(PropertyGain)。add の対象・transfer の to_prop・ linked_add の対象が入り、modify・base で押し上げられた実効値は入りません。満腹度は誰も書かず、 胃と腸の段が押し上げているだけなので現れません——食べた操作が増やしたものとして出るのは胃と栄養です。

毎 tick の変化のうち入るのは、その操作自身が宣言した先だけです(interactions の passives、 GameElementDefinition.md 11.7 節)。休息と限界はこの形で戻すので、 経過の間に動いた分がその操作の粒になります。物が自分で宣言した増減は入りません——眠気や水分の 目減りは、誰かの操作が動かしたものではないためです。

粒が示すのは、宣言した量ではなくそのステータスが実際に動いた量です。 休息と限界の戻りは、 同じ tick にその値へ入る減りを引いた正味になる (GameElementDefinition.md 11.7 節)ので、荷を担いだまま 倒れ込めば粒もそのぶん薄くなります。宣言した量を出すと、画面が言う戻りとバーの動きが食い違います。

出すのは増えた分だけです。吸い込まれる動きそのものが「増えた」を表していて、良し悪しは表しません。 痛みと荷重は良し悪しの心配がありますが、どちらも直に書く操作が存在しません——痛みは怪我が modify で押し上げ、荷重は持ち物から導出されるので、この規則では自然に現れません。

アイコンを持たないプロパティと、range を持たないプロパティは出しません。 飛ばす絵が無く、 「満タンのどれだけか」も数えられないためです。

10.2 粒の数

ceil(10 × √(増加量 ÷ rangeの幅)) です。粒が n 個なら、満タンの n² パーセント——1% で 1 粒、 25% で 5 粒、満タンぶんで 10 粒。ceil があるので、どれだけ小さい増加でも必ず 1 粒は出ます ——安全域で見えないままの変化を知らせるのが役目なので、0 粒になっては意味がありません。

比例にしないのは、粒が数えるものではなく量として読むものだからです。40 粒と 50 粒は見分けが 付きません。比例にすると、実際に読まれる差より遥かに広い幅を数直線に取ってしまい、小さい増加の側が 消え、大きい増加の側が画面を埋めます(増加の幅がどれほど開くかは下の段落)。

この幅はステータスの間だけでなく、ステータスの中にもあります——体力への回復なら、待機の1回と 骨組みを差した寝台での睡眠とで桁が違います (tests/world-codex/beddingYaml.test.ts)。だからプロパティごとに基準量を宣言しても畳めません。 畳めるのは写像の側だけで、平方根は比を、その比の平方根まで縮めます。

上限は設けていません。粒が多すぎると感じたら、抑えるのは粒の数ではなく値の刻み方です (Characters.md)——上限で頭を打たせると、刻み方の粗さが見えなくなります。

10.3 湧いて吸われる動き

発生源の札の縁から湧き、ポートレイトカードの中心へ吸われます。 湧く点は札の中心から見て ランダムな向きの縁の上で、そこから外へ少しはみ出させます。吸われる先も中心から少し散らします。

自分の札を持たない物が発生源のときは、それを抱えている札から湧かせます。 効果の対象が 中身のスロットに居る物であれば、外側へ順に見て最初に見つかった札を使います。この並びは効果を 適用する前に控えます——消えた物は適用し終えた時点で世界から出ていて、そこからでは親を辿れません。 湧き出しは経過を見せている間いっぱいに散らし、間隔も揺らします(等間隔だと粒が列に見えます)。

軌道は始点と終点を結ぶ二次ベジェで、制御点は直線に対して垂直にずらします。ずらす量は 固定量と距離の割合の和で、符号は粒ごとに変えます。速さは離れ際が遅く着く直前が最も速く (吸い寄せられるので加速します)、飛ぶ時間の半分を過ぎてもまだ1割ほどしか進みません——増えたのが どの札からかを読ませたいので、道中より出どころの近くに時間を割きます。

現れ方と消え方は、位置ではなく経過時間で測ります。 出どころに長く留まる曲線なので、位置で測ると 湧いてから半分の時間を使って現れることになり、はっきり見えている間が残りません。

吸い込まれるまでの時間は距離で決めます。 時間を固定すると速さが揃わず、同じ演出の中で近い粒ほど 遅く、遠い粒ほど速く見えます。ただし下限は置きます——湧いた所へすぐ吸われる短い弧(発生源が キャラクター自身のとき)が、一瞬で消えて見えなくなるためです。

休息のようにキャラクター自身が起こす操作も、同じ規則のままです。 発生源がポートレイト自身に なるだけで、始点は自分の縁の外・終点は自分の中心なので、外へ膨らんでから内へ沈む短い弧になります ——泡が湧いて収まる見え方が同じ式から出るので、専用の演出を持ちません。ずらす量に固定量が入って いるのはこのためで、距離の割合だけにすると、距離がほぼ 0 のこの場合に弧が消えて直線になります。

効果が適用されるより前に粒が出ます。 ワールドは押した瞬間に経過し切っている (Windows.md 5.2 節)ので増えた量は最初から分かっており、経過を見せ終わるのを 待つ必要がありません。

粒は翳り(ScreenLayout.md 9 節)より手前・ドーナツグラフより奥に出します。 暗い時間帯でも同じ明るさで読め、経過時間の数字を隠しません。