0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

カードゲームの(オンライン)テストプレイと入稿用ファイル作成を自動化する

Posted at

概要

  • 初めてアナログゲームを作るにあたり、「テストプレイ用」と「印刷所入稿用」のデータ作成をスクリプトで半自動化した
  • テストプレイはユドナリウムを使ってオンラインで何度か行った。テストプレイの度にデータを修正するので、その都度カード画像を書き出す必要があった
  • 印刷所への入稿は印刷所指定のIllustratorテンプレートファイルでカード1枚につき1ファイル作成する必要があった
  • それら2種類のファイルを1つのマスターファイル(TSV)から繰り返し作成する為の手順の備忘録

作るゲームについて

  • 「推しの名前を叫びたい」という、カードに書かれた属性を満たすキャラクターを宣言するゲーム
  • 「メガネをかけてる」「ライバルがいる」「髪が青/緑」みたいなキャラクターの特徴が書かれたカードが150枚入ってるいる
  • カードには「カテゴリ」「タイトル(キャラクターの特徴)」「補足説明(箇条書き)」「難易度(★)」という4つの要素がある
  • 今回はマスターデータからこれらの要素を画像ファイル(テストプレイ)、.aiファイル(入稿)として書き出したい
  • (宣伝)ゲームマーケット2023秋 2023年12月9日(土)にて頒布予定
  • 詳しいルール等についてはXアカウントにて告知予定です!

マスターファイルの準備

...
自信家	そういう描写や言及があればOK	肩書・内面	2	1
自信が無い	そういう描写や言及があればOK	肩書・内面	2	1
マザコン/ファザコン/ブラコン/シスコン		肩書・内面	2	1
ギャル/チャラ男	周囲にそう思われてるだけでもOK	肩書・内面	3	1
優等生/真面目	そういう描写や言及があればOK	肩書・内面	2	1
...
  • TSVで「タイトル」「説明」「カテゴリ」「難易度(★)」の順に並べただけのファイル
  • Googleスプレッドシートで管理してTSVとして書き出す

方針

  • 最初は「Imagemagickを使って、ユドナリウム用PNG画像とXMLを書き出すRubyスクリプト」と「Illustratorファイルを書き出すイラレscript」の2つを使っていた
  • しかしカードの要素やレイアウトを試行錯誤する度に2つのスクリプトを修正するのは面倒なので、まずイラレファイルを生成し、それを元にPNG画像を書き出すフローに変更。ユドナリウム用XML生成は別途元のRubyスクリプトを使う(こちらはカードの要素やレイアウトの影響を受けないので修正の必要が無い)

マスターファイルからIllustratorデータを作る

テンプレートファイルを作る

  • 今回は萬印堂さんに印刷をご依頼するので、萬印堂さん指定のIllustratorテンプレートファイルをこちらからDLする
  • そのテンプレートファイルを元に、当ゲーム用テンプレートファイルを作る
  • 以下のようにテキストフレームを配置
    • スクリプトでテキストフレームの生成や各種設定を行えばこの工程は不要だが、非直感的でわざわざスクリプトでやる意味が無い

Illustratorファイル生成スクリプト

app.userInteractionLevel = UserInteractionLevel.DONTDISPLAYALERTS;
var csvPath = "/{任意のディレクトリ}/card_csv.csv";
var csvFile = new File(csvPath);
csvFile.open('r');

var templatePath = "/{任意のディレクトリ}/template_card.ai";
var titleIndex = 2;
var descIndex = 1;
var categoryIndex = 3;
var starIndex = 0;

var i = 0;
while (!csvFile.eof) {
  i++;
  var line = csvFile.readln();
  var values = line.split("\t");

  var templateFile = new File(templatePath);
  app.open(templateFile);

  var doc = app.activeDocument;

  var category = values[2];
  var categoryItem = app.activeDocument.textFrames[categoryIndex];
  categoryItem.contents = category;

  var starNum = parseInt(values[3]);
  var starText = "";
  for (var j = 0; j < starNum; j++) {
    starText += "";
  }
  var starItem = app.activeDocument.textFrames[starIndex];
  starItem.contents = starText;

  var textItem = app.activeDocument.textFrames[titleIndex];
  textItem.contents = values[0];

  var desc = app.activeDocument.textFrames[descIndex];
  desc.contents = values[1];

  var outputFile = new File("/{任意のディレクトリ}/tmp_ai/card_"+i+"_front.ai");
  doc.saveAs(outputFile);
  doc.close();
}
csvFile.close();
  • jsでDOMを操作するようなノリで、要素を取得してフィールドにセットすればOK
  • 実際はカードのカテゴリによってテンプレートファイルを変えたり、「補足説明」を箇条書きに変えたりといった細かな処理を足している
  • 最終的な入稿用データとしては、機械的なルールでは処理できない部分(フォントサイズの細かな調整等)を手動で行った

ユドナリウム用データを作る

最終的に作りたいもの

  • ユドナリウムにはルームデータをzipでインポート/エクスポートできる仕組みがある
  • ルームデータはXMLで管理されているので、そのXMLと、XMLから参照される画像データを生成できればルームデータが作れる
  • こんな感じで8つの山札が置かれたルームを生成したい(テーブル画像等は後から設定すればOK)

カード画像を作る

  • 「方針」の通り、まず入稿用IllustratorファイルからPNG画像を書き出す
  • 入稿用ファイルはカード画像以外の要素が色々あるので、「お客様の作業領域」というレイヤーのみをPNG書き出しする
  • そのままだと解像度が低いので3倍にスケールさせる
var options = new ExportOptionsPNG24();
options.antiAliasing = true;
options.transparency = true;
options.horizontalScale = 300;
options.verticalScale = 300;

var inputDir = "/{任意のディレクトリ}/fix/";
var outputDir = "/{任意のディレクトリ}/v1/";
for (var i = 1; i <= 150; i++) {
  var file = new File(inputDir + "card_"  + i + "_front.ai");
  var doc = app.open(file);

  for (var j = 0; j < doc.layers.length; j++) {
    doc.layers[j].visible = false;
  }
  var targetLayer = doc.layers.getByName("お客様の作業領域");
  targetLayer.visible = true;

  var outputFile = new File(outputDir + "card_" + i + ".png");
  doc.exportFile(outputFile, ExportType.PNG24, options);
  doc.close(SaveOptions.DONOTSAVECHANGES);
}
room_template.xml
<?xml version="1.0" encoding="UTF-8"?>
<room>
  <game-table name="最初のテーブル" width="20" height="15" gridSize="50" imageIdentifier="testTableBackgroundImage_image" backgroundImageIdentifier="imageIdentifier" backgroundFilterType="" selected="false" gridType="0" gridColor="#000000e6"></game-table>

  <card-stack location.name="table" location.x="0.0" location.y="452.8333688050696" posZ="0" rotate="0" zindex="5" owner="" isShowTotal="true">
    <data name="card-stack">
      <data name="image">
        <data type="image" name="imageIdentifier"></data>
      </data>
      <data name="common">
        <data name="name">名前</data>
      </data>
      <data name="detail"></data>
    </data>
    <node name="cardRoot">
      __card1__
    </node>
  </card-stack>
  <card-stack location.name="table" location.x="300.0" location.y="452.8333688050696" posZ="0" rotate="0" zindex="6" owner="" isShowTotal="true">
    <data name="card-stack">
      <data name="image">
        <data type="image" name="imageIdentifier"></data>
      </data>
      <data name="common">
        <data name="name">年齢</data>
      </data>
      <data name="detail"></data>
    </data>
    <node name="cardRoot">
      __card2__
    </node>
  </card-stack>
  <card-stack location.name="table" location.x="600.0" location.y="452.8333688050696" posZ="0" rotate="0" zindex="7" owner="" isShowTotal="true">
    <data name="card-stack">
      <data name="image">
        <data type="image" name="imageIdentifier"></data>
      </data>
      <data name="common">
        <data name="name">特徴</data>
      </data>
      <data name="detail"></data>
    </data>
    <node name="cardRoot">
      __card3__
    </node>
  </card-stack>
    <card-stack location.name="table" location.x="0.0" location.y="660" posZ="0" rotate="0" zindex="5" owner="" isShowTotal="true">
      <data name="card-stack">
        <data name="image">
          <data type="image" name="imageIdentifier"></data>
        </data>
        <data name="common">
          <data name="name">名前</data>
        </data>
        <data name="detail"></data>
      </data>
      <node name="cardRoot">
        __card4__
      </node>
    </card-stack>
    <card-stack location.name="table" location.x="300.0" location.y="660" posZ="0" rotate="0" zindex="6" owner="" isShowTotal="true">
      <data name="card-stack">
        <data name="image">
          <data type="image" name="imageIdentifier"></data>
        </data>
        <data name="common">
          <data name="name">年齢</data>
        </data>
        <data name="detail"></data>
      </data>
      <node name="cardRoot">
        __card5__
      </node>
    </card-stack>
    <card-stack location.name="table" location.x="600.0" location.y="660" posZ="0" rotate="0" zindex="7" owner="" isShowTotal="true">
      <data name="card-stack">
        <data name="image">
          <data type="image" name="imageIdentifier"></data>
        </data>
        <data name="common">
          <data name="name">特徴</data>
        </data>
        <data name="detail"></data>
      </data>
      <node name="cardRoot">
        __card6__
      </node>
    </card-stack>
      <card-stack location.name="table" location.x="0.0" location.y="960" posZ="0" rotate="0" zindex="5" owner="" isShowTotal="true">
        <data name="card-stack">
          <data name="image">
            <data type="image" name="imageIdentifier"></data>
          </data>
          <data name="common">
            <data name="name">名前</data>
          </data>
          <data name="detail"></data>
        </data>
        <node name="cardRoot">
          __card7__
        </node>
      </card-stack>
      <card-stack location.name="table" location.x="300.0" location.y="960" posZ="0" rotate="0" zindex="6" owner="" isShowTotal="true">
        <data name="card-stack">
          <data name="image">
            <data type="image" name="imageIdentifier"></data>
          </data>
          <data name="common">
            <data name="name">年齢</data>
          </data>
          <data name="detail"></data>
        </data>
        <node name="cardRoot">
          __card8__
        </node>
      </card-stack>
</room>

ルームデータを作る

  • マスターファイルに従ってXMLを作る
  • ドキュメント等は無いのでエクスポートしたファイルを見てみた所、ユドナリウムでは「data.xml」というファイルにルームデータを記述すれば良いようなので、そのようにzipファイルを作る
  • 画像アセットをzipに含める方法は分からなかった(そもそもできるのかな?)ので、画像はクラウドストレージに置いてそのURLをXMLに記述する
  • 後はユドナリウムを開いて「ZIP読み込み」すればOK!
0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?