2024/12/07
伺か・伺的 Advent Calendar 2024 (第2会場) 7日目の記事です。
6日目のななっちさんに続いて、日野つみが記事を書かせていただきます。
本記事では、界隈でたびたび話題となっているサーフェス定義方針、
いわゆる「福笑い式」について界隈での動きなどを提示したのち、
私が開発した福笑い式に基づくsurfaces.txtジェネレーター「surfaces-mixer」について紹介します。
※記事で言及する便宜上本項で定義していますが、一般的な意味を定めるものではありません。
「福笑い式」とは、伺かのサーフェス定義ファイルsurfaces.txtにおいて、
サーフェス番号の桁一つに対してパーツを割り当てるという手法です。
例えば、サーフェス番号111~999の範囲で、1の位には目パーツ、10の位には口パーツ、100の位には眉パーツを割り当てるといった具合です。
「1は開いた目」 「2は閉じた目」 「3は笑った目」というように数字に対してパーツの意味を割り当てておくことで、
「普通の眉、笑った口、笑った目はサーフェス番号133番」というように、サーフェス番号からパーツを推測しやすくなるというメリットがあります。
パーツの組み合わせを網羅しているため、欲しい表情を瞬時にゴーストに適用することができます。
デメリットとしては、パーツが増えるほど組み合わせの数も指数関数的に増えていくため
手作業でのsurfaces.txtの記述が困難であることが挙げられます。
福笑い式に関する取り組みを知っている限りご紹介します。
他にもあるよ!という場合はWeb拍手等で教えていただけると幸いです。
冷やし湯さんが作成された福笑い式サーフェス定義を積んだサンプルゴーストです。
また、リンク先ページでは福笑い式についての解説もされています。
Ukiyaさんが作成されたWebアプリケーションです。
画像ファイル名をパーツ別に指定することで、福笑い式のsurfaces.txtを生成します。
クロ猫黒さんが作成されたexe形式のアプリケーションです。
パーツ別に別ディレクトリに格納されたパーツファイルを読み込んで、福笑い式のsurfaces.txtを生成します。
ななっちさんが作成されたexe形式のアプリケーションです。
パーツ画像をドラッグ&ドロップすることで、サーフェス合成プレビューを確認することができます。
また、合成したサーフェスの定義をクリップボードにコピーする補助機能も搭載されています。
本記事で紹介するsurfaces-mixerは、上記の取り組みを参考にしつつ、以下の特徴を持つsurfaces.txtジェネレーターです。
surfaces-mixerは設定ファイルに特定のフォーマットでパーツの指定を記述し、それを読み込むことでsurfaces.txtを生成します。
フォーマット(yaml)の把握と簡単なコマンドラインの操作さえ可能ならば、柔軟で強力、かつメンテナンスフリーにsurfaces.txtを生成することができます。
従来の福笑い式ジェネレーターは、surfaces.txtの一部を生成し、
残りは手作業でsurfaces.txtへ移植するという手法が一般的でした。
一方、surfaces-mixerは、surfaces.txtの全体を生成することができます。
surfaces-mixerは yaml というデータ形式を採用することで、surfaces.txtに手書きしていた
animation
やcollision
を含むサーフェス定義をそのまま記述することができます。
# サンプルファイル
# yamlファイルはraw,charactersの2分類を起点に構成される。
#
# - raw: descriptなど、組み合わせに関係のない定義。
# ここに記述された内容はsurfaces.txtの冒頭にそのまま出力される。
#
# - characters: キャラクターごとのパーツの定義。
# [構造]
# // \0キャラクターの定義
# - base: ... # 頭や胴体など、全サーフェスに共通するパーツの定義。
# parts: # 基点
# - group: 〇〇 # 「目」「口」など、そのグループ名が何であるかの目安。
# details: # 詳細情報の基点
# - name: △△ # 「半目」「閉じ目」など、そのパーツが何であるかの目安。
# text: ... # そのパーツのサーフェス定義。
# // \1キャラクターの定義
# - base: ... # 頭や胴体など、全サーフェスに共通するパーツの定義。
# parts: # 基点
# (移行同様)
raw: |
descript
{
version,1
}
characters:
# \0側キャラクター
- parts:
- group: 顔色
details:
- name: 通常顔
text: |
- name: 照れ顔
text: |
animation500600.interval,runonce
animation500600.pattern0,overlay,101,0,0,0
- group: 目
details:
- name: こっち目
text: |
animation500300.interval,runonce+rarely
animation500300.option,shared-index
animation500300.pattern0,overlay,201,0,0,0
animation500300.pattern1,overlay,209,4000,0,0
animation500300.pattern2,overlay,204,100,0,0
animation500300.pattern3,overlay,201,100,0,0
- name: あっち目
text: |
animation500300.interval,runonce+rarely
animation500300.option,shared-index
animation500300.pattern0,overlay,203,0,0,0
animation500300.pattern1,overlay,209,4000,0,0
animation500300.pattern2,overlay,206,100,0,0
animation500300.pattern3,overlay,203,100,0,0
- group: 腕
details:
- name: 前手
text: |
animation505000.interval,runonce
animation505000.pattern0,overlay,503,0,0,0
collisionex13,hand,polygon,288,423,330,410,336,414,341,422,328,446,317,436,288,442
collisionex14,hand,polygon,282,501,262,536,261,550,285,556,299,549,294,521,295,512
- name: 胸に手
text: |
animation504000.interval,runonce
animation504000.pattern0,overlay,501,0,0,0
animation590000.interval,runonce
animation590000.pattern0,overlay,601,0,0,0
collisionex13,hand,polygon,288,423,330,410,336,414,341,422,328,446,317,436,288,442
collisionex14,hand,polygon,282,501,262,536,261,550,285,556,299,549,294,521,295,512
base: |
collisionex10,shoulder,polygon,205,319,206,309,214,301,229,299,251,293,248,312
collisionex11,shoulder,polygon,292,293,309,299,332,302,339,315,301,315
collisionex7,mouse,ellipse,260,259,283,268
collisionex8,head,polygon,292,134,319,151,340,176,339,192,292,190,240,192,201,187,213,158,230,140,259,127
collisionex6,face,polygon,270,285,239,267,227,246,220,214,222,189,227,173,315,170,320,189,321,210,315,245,305,268
//素体
element0,overlay,surface1000.png,0,0
# \1側キャラクター
- parts:
- group: 素体
details:
- name: 通常
text: |
- name: 腕上げ
text: |
animation500600.interval,runonce
animation500600.pattern0,overlay,101,0,0,0
- group: 目
details:
- name: こっち目
text: |
element0,overlay,surface3000.png,0,0
- name: あっち目
text: |
element0,overlay,surface3001.png,0,0
このyamlファイルをsurfaces-mixerに読み込むことで、以下のsurfaces.txtを生成することができます。
charset,UTF-8
descript
{
version,1
}
// 顔色
surface111,112,121,122
{
// 通常顔
}
surface211,212,221,222
{
// 照れ顔
animation500600.interval,runonce
animation500600.pattern0,overlay,101,0,0,0
}
// 目
surface111,112,211,212
{
// こっち目
animation500300.interval,runonce+rarely
animation500300.option,shared-index
animation500300.pattern0,overlay,201,0,0,0
animation500300.pattern1,overlay,209,4000,0,0
animation500300.pattern2,overlay,204,100,0,0
animation500300.pattern3,overlay,201,100,0,0
}
surface121,122,221,222
{
// あっち目
animation500300.interval,runonce+rarely
animation500300.option,shared-index
animation500300.pattern0,overlay,203,0,0,0
animation500300.pattern1,overlay,209,4000,0,0
animation500300.pattern2,overlay,206,100,0,0
animation500300.pattern3,overlay,203,100,0,0
}
// 腕
surface111,121,211,221
{
// 前手
animation505000.interval,runonce
animation505000.pattern0,overlay,503,0,0,0
collisionex13,hand,polygon,288,423,330,410,336,414,341,422,328,446,317,436,288,442
collisionex14,hand,polygon,282,501,262,536,261,550,285,556,299,549,294,521,295,512
}
surface112,122,212,222
{
// 胸に手
animation504000.interval,runonce
animation504000.pattern0,overlay,501,0,0,0
animation590000.interval,runonce
animation590000.pattern0,overlay,601,0,0,0
collisionex13,hand,polygon,288,423,330,410,336,414,341,422,328,446,317,436,288,442
collisionex14,hand,polygon,282,501,262,536,261,550,285,556,299,549,294,521,295,512
}
surface.append111-222
{
collisionex10,shoulder,polygon,205,319,206,309,214,301,229,299,251,293,248,312
collisionex11,shoulder,polygon,292,293,309,299,332,302,339,315,301,315
collisionex7,mouse,ellipse,260,259,283,268
collisionex8,head,polygon,292,134,319,151,340,176,339,192,292,190,240,192,201,187,213,158,230,140,259,127
collisionex6,face,polygon,270,285,239,267,227,246,220,214,222,189,227,173,315,170,320,189,321,210,315,245,305,268
//素体
element0,overlay,surface1000.png,0,0
}
// 素体
surface1011,1012
{
// 通常
}
surface1021,1022
{
// 腕上げ
animation500600.interval,runonce
animation500600.pattern0,overlay,101,0,0,0
}
// 目
surface1011,1021
{
// こっち目
element0,overlay,surface3000.png,0,0
}
surface1012,1022
{
// あっち目
element0,overlay,surface3001.png,0,0
}
このように、パーツ別の定義を箇条書き的に記述することができます。
1. 生成したいsurfaces.txtのyamlファイルを作成します。上記サンプルを参考にしてください。
2. surfaces-mixer.exeの最新版を以下リンクからダウンロードします。
https://github.com/apxxxxxxe/surfaces-mixer/releases
3. ダウンロードしたsurfaces-mixer.exeを、surfaces.txtを生成したいディレクトリに配置します。
パスを通せる方は、任意のディレクトリに配置したのち、環境変数PATHに追加してください。
4. コマンドプロンプトを開き、surfaces-mixer.exeがあるディレクトリに移動します。
例えば、C:\Users\user1\Ukagaka\ssp\ghost\myghost\shell\master
に移動する場合は、
cd C:\Users\user1\Ukagaka\ssp\ghost\myghost\shell\master
5. コマンドプロンプトに以下のコマンドを入力します。
.\surfaces-mixer.exe -i [yamlファイル名]
例えば、yamlファイル名がsurfaces.yaml
の場合は、
.\surfaces-mixer.exe -i surfaces.yaml
福笑い式サーフェス定義はパーツ分けがされた画像群を用いてシェルを作成する際に便利な手法です。
具体的には、キャラクターなんとか機によって生成されたパーツからシェルを作る場合に効果を発揮します。
もちろん自作シェルの場合でも、パーツを分けたものを福笑い式にサーフェス定義することで、網羅的に表情を作成することができます。
ぜひ紹介させていただいたツール、あるいはsurfaces-mixerを使って、福笑い式のsurfaces.txtを生成してみてください。
ここまで読んでいただき、ありがとうございました。