おわらない

index

tips

blog

福笑い式surfaces.txtジェネレーターを作った話

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拍手等で教えていただけると幸いです。

桁ごとにパーツを指定するsurface定義

冷やし湯さんが作成された福笑い式サーフェス定義を積んだサンプルゴーストです。
また、リンク先ページでは福笑い式についての解説もされています。

サーフィス組み合わせ機

Ukiyaさんが作成されたWebアプリケーションです。
画像ファイル名をパーツ別に指定することで、福笑い式のsurfaces.txtを生成します。

サーフェス連番ジェネレータ

クロ猫黒さんが作成されたexe形式のアプリケーションです。
パーツ別に別ディレクトリに格納されたパーツファイルを読み込んで、福笑い式のsurfaces.txtを生成します。

SurfaceBuilder

ななっちさんが作成されたexe形式のアプリケーションです。 パーツ画像をドラッグ&ドロップすることで、サーフェス合成プレビューを確認することができます。
また、合成したサーフェスの定義をクリップボードにコピーする補助機能も搭載されています。

surfaces-mixer

本記事で紹介するsurfaces-mixerは、上記の取り組みを参考にしつつ、以下の特徴を持つsurfaces.txtジェネレーターです。
surfaces-mixerは設定ファイルに特定のフォーマットでパーツの指定を記述し、それを読み込むことでsurfaces.txtを生成します。
フォーマット(yaml)の把握と簡単なコマンドラインの操作さえ可能ならば、柔軟で強力、かつメンテナンスフリーにsurfaces.txtを生成することができます。

surfaces.txtのメンテナンスが容易

従来の福笑い式ジェネレーターは、surfaces.txtの一部を生成し、
残りは手作業でsurfaces.txtへ移植するという手法が一般的でした。

一方、surfaces-mixerは、surfaces.txtの全体を生成することができます。

パーツの指定方法が柔軟

surfaces-mixerは yaml というデータ形式を採用することで、surfaces.txtに手書きしていた
animationcollisionを含むサーフェス定義をそのまま記述することができます。

# サンプルファイル

# 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
と入力します。
cdコマンドで目的のディレクトリ(フォルダ)へ移動

cdコマンドで目的のディレクトリ(フォルダ)へ移動

5. コマンドプロンプトに以下のコマンドを入力します。

.\surfaces-mixer.exe -i [yamlファイル名]

例えば、yamlファイル名がsurfaces.yamlの場合は、

.\surfaces-mixer.exe -i surfaces.yaml
と入力します。
surfaces-mixerの実行

surfaces-mixerの実行


成功していれば、スクリーンショットのように「saved to ~」と表示され、surfaces.txtが生成されます。

まとめ

福笑い式サーフェス定義はパーツ分けがされた画像群を用いてシェルを作成する際に便利な手法です。
具体的には、キャラクターなんとか機によって生成されたパーツからシェルを作る場合に効果を発揮します。
もちろん自作シェルの場合でも、パーツを分けたものを福笑い式にサーフェス定義することで、網羅的に表情を作成することができます。

ぜひ紹介させていただいたツール、あるいはsurfaces-mixerを使って、福笑い式のsurfaces.txtを生成してみてください。
ここまで読んでいただき、ありがとうございました。