ボアブログ

へっぽこUnityエンジニアの色々

【RPGツクールMV】GameStrings的なアレその2

いつもの二日坊主です。
今日は昨日の記事の続き、というか少し処理を更新してみたので変更内容についてです。

JSONの中身を変更

少しだけスプレッドシートのコードを変えました。

function onOpen() {
  var menu=[
    {name: "To Json", functionName: "convert"}
  ];
  SpreadsheetApp.getActive().addMenu("Convert", menu);
}

function convert()
{
  var sheet = SpreadsheetApp.getActiveSheet();
  var keys = sheet.getRange(2, 1, 1, sheet.getLastColumn()).getValues()[0];
  var data = sheet.getRange(3, 1, sheet.getLastRow()-2, sheet.getLastColumn()).getValues();
  var list = {};
  data.forEach(function(row){
    var obj = {};
    for(var i=1; i < keys.length; i++)
    {
      obj[keys[i]] = row[i];
    }
    list[row[0]] = obj;
  });
  
  sheet.getRange(1,2).setValue(JSON.stringify(list));
}

どう変えたかは前回の記事と見比べて頂くとして、前回のコードで生成されたJSONと今回のコードで生成されたJSONを比べます。

旧
[
    {
        "en": "English.", 
        "jp": "日本語です。", 
        "key": "MESSAGE_001"
    }, 
    {
        "en": "Switch to Japanese.", 
        "jp": "英語に切り替えます。", 
        "key": "MESSAGE_002"
    }
]
新
{
    "MESSAGE_001": {
        "en": "English.", 
        "jp": "日本語です。"
    }, 
    "MESSAGE_002": {
        "en": "Switch to Japanese.", 
        "jp": "英語に切り替えます。"
    }
}

昨日までのコードではkeyまで含めた連想配列の配列としてjson形式にしていました。その場合、対象の文字列を探す時総当りなりする必要があるのですが処理的にちょっと面倒です。
その為、今回のコードでは1列目をキーにした連想配列連想配列にしました。こうしておくことでコード上では$gameString["MESSAGE001"]のような形でアクセス出来るようになり簡素化しています。
プラグイン側でもこの形に沿う用に変更してあります。

jsonファイルはdata/Translate/以下に配置

詳しくは後述しますが、ファイル数が増える設計になったため翻訳専用のフォルダを作って配置しました。

マップ毎にJSONを読み込む

昨日時点でのプラグインでは「全ての文言」をGameStrings.jsonに入れ、そこから読み込む形で翻訳していました。
この「全ての文言」には現在いるマップ以外のマップに配置されたイベントの文章等も含まれます。基本的にそれらは、該当するマップに居なければ使用しないものなのでちょっとメモリに優しくありません。

そこで文章等はマップごとのjsonに分け、MapDataと共に必要なものだけ読み込む事で少し軽減してます。

はじめにエディタ側でマップ名を設定しておきます。

f:id:weakboar:20170725233602p:plain

シート側でシートを分け、それぞれデータを入力します。出力したjsonはそれぞれ[マップ名].jsonにしてTranslate以下に配置します。

f:id:weakboar:20170725233831p:plain

f:id:weakboar:20170725233846p:plain

f:id:weakboar:20170725234053p:plain

こうしておくことで、読み込むMapDataのマップ名とファイル名を紐付けて、マップに必要なjsonを読み込むようにしてあります。

ちなみにコード上ではGameStrings.GetText(key)を使用することでマップ毎のjsonから文言を取り出せます。

GameStrings.jsonは据え置き

配置こそTranslate以下になりましたが、ゲーム開始時に読み込むGameStrings.jsonは残してあります。
メニューのコマンド等の文言、固有名詞等はマップに関わらず必要になるためです。

何も変わっていない代わりと言っては何ですが、サンプル代わりに一部固定文言の翻訳に対応しています。

マップ名表示と

f:id:weakboar:20170725235207p:plainf:id:weakboar:20170725235215p:plain

メニュー(サンプルではアイテムとスキルのみ)です。

f:id:weakboar:20170725235421p:plain f:id:weakboar:20170725235439p:plain

これらはそれぞれMapDataの表示名や用語をGameStrings.jsonのキーに指定することで実現しています。

おわり

実際にこのプラグインローカライズ対応のために用いるにはアクター名やパラメータ名、さらにいえば\N[1]なんかの制御構文まで対応する必要があります。とはいえ、ローカライズを考慮したゲーム開発の足がかりにはなるかなという感じなので今後は大きな変更がない限り更新はしないと思います。多分。

言い訳をするとRPGツクールMVはかなりプログラミングもやれる開発環境なので小学生や中学生のプログラミング初学者に触れてほしく、考える余地を残している感じです。

学生向けのキャンペーンもやっているようなので是非やってほしいですね。 学生を対象にした「RPGツクールMV」の抽選プレゼント企画が開催。通常販売も6割引きに - 4Gamer.net

【RPGツクールMV】GameStrings的なあれを作ってみた

某discordの某チャンネルにて
はー、ローカライズするのめんどくせー。
みたいなあれを見て簡単に作ってみました。

ちなみに強そうなのは既にあります

github.com

完成物

とりあえず出来たやつです。とりあえず「文章の表示」にのみ対応してます。

github.com

流れ

簡単な流れは下記の通り

  1. Google SpreadSheetにキーと日本語と英語を入力
  2. jsonで出力
  3. エディタでキーを表示する
  4. プラグインで表示!

簡単でしょ?

SpreadSheetの用意

f:id:weakboar:20170725040306p:plain

まず、こんな感じでデータを作ります。

次にjsonを出力する必要があるので ツール → スクリプトエディタ からエディタを開きます。
開けたら何も考えず以下のコードをコピペ

function onOpen() {
  var menu=[
    {name: "To Json", functionName: "convert"}
  ];
  SpreadsheetApp.getActive().addMenu("Convert", menu);
}

function convert()
{
  var sheet = SpreadsheetApp.getActiveSheet();
  var keys = sheet.getRange(2, 1, 1, sheet.getLastColumn()).getValues()[0];
  var data = sheet.getRange(3, 1, sheet.getLastRow()-2, sheet.getLastColumn()).getValues();
  var list = [];
  data.forEach(function(row){
    var obj = {};
    for(var i=0; i < keys.length; i++)
    {
      obj[keys[i]] = row[i];
    }
    list.push(obj);
  });
  
  sheet.getRange(1,2).setValue(JSON.stringify(list));
}

ざっくり説明すると、メニューに出力の項目を追加して、それを押すと2行目をインデックスにして、3行目からをデータとして、json作って、1行目に表示、です。
何も考えては行けない。

このスクリプトを保存するとスプレッドシートのメニューにConvert → To Jsonが追加されている筈なのでそいつをクリックしましょう。jsonが1行目に出力されます。

jsonをdataに入れる

出力したjsonをdataの下(なんちゃら.jsonが沢山あるところ)にGameStrings.jsonという名前で保存しましょう。
MVにおいてjsonは命の源です。

プラグインを導入

いつも通りプラグインとして入れましょう。説明は省きます。

文章を表示

いつも通りにイベントを作って文章を入力・・・とは行きません。下の画像の様に入れましょう。 f:id:weakboar:20170725041053p:plain MESSAGE_001スプレッドシートに入力したkeyと同じ物を入れます。要するにこれを元に言語別に文章を探し、表示するわけです。

試しにここで実行してみると、対象のイベントに話しかけると日本語文章(jaの列に入力した文章)が表示されると思います。

言語を切り替えてみる

プラグインの70行目付近のGameStrings.language = "jp";GameStrings.language = "en";にして実行してみましょう。
なんと英語(enの列に入力した文章)になります。

何をやっているか

入力された文章をkeyとしてデータ内を探索します。
見つかったら喜々として選択中の言語に合わせたデータを出力します。
見つからなかったら絶望に飲まれてキーのまま出力します。

嬉しい所

ローカライズが楽になります。日本語版開発中は日本語だけデータとして入れておいて、いざローカライズしたくなったら翻訳していってjsonを更新&言語変更すれば英語になるのです。便利。

また、文章がスプレッドシートで管理出来るようになります。ライターさんがスプレッドシートに記入していって終わったらデータを出力すればよいのです。ちょっとした変更も簡単に出来ます。チーム開発が捗りますね。

つらい所

翻訳すると文章の長さって変わりますよね。不思議です。
増えてメッセージウィンドウからはみ出した所で我々には何もする手立てはありません。諦めましょう。

また、エディタ上では「MESSAGE_001」みたいな意味が分からない言葉が並びます。人間にはもはや読めません。ツクラーの皆さんがんばってください。

更に、データに不備があるとそのまま「MESSAGE_001」みたいに表示されます。テスターの皆さん頑張ってください。

さいごに

いかがでしょうか。取り敢えず今回は文章の表示だけ対応しましたが、選択肢の文言なんか表示しているコードをフックしてモニョモニョすれば対応出来るはずです。メニューの文言なんかは冒頭に紹介したプラグインの方が管理がしやすそうですが文章ではこういう形も良いのではないでしょうか。冒頭のプラグインで簡単に管理出来たらごめんね。

RPGツクールMV用フィルターを作りました

f:id:weakboar:20170517220917p:plain

RPGツクールMV向けにフィルタープラグインを作ってみたので、その紹介です。
RPGアツマールで動作確認することが出来ます。また、プラグインgithubにて公開中です。

フィルタープラグイン動作確認
プラグイン(github)

デフォルト

f:id:weakboar:20170517222431p:plain
こちらがフィルターを使っていない状態です。安心感があります。

ブルーム

f:id:weakboar:20170517222552p:plain
ブルームとは光が溢れているような様子を表現する方法です。
わかりやすいのは雲や雪の周りで光の反射が起きているような表現が出来ています。地味なところで言うと城のハイライト部分等も影響を受けています。

技術的な話で言うと「輝度が高いところを抽出し」「ぼかして」「元の画像に重ねる」と言うことをやっています。

ティルトシフト

f:id:weakboar:20170517223145p:plain
ティルトシフトとは元々カメラのレンズの種類で風景写真がジオラマ風になることで知られています。
ゲーム開発(画像処理)では中央からの距離が遠いほど強くぼかすような処理をティルトシフトと呼んでいます。

MVでやってみた所、思いもよらず立体感が出ました。

グレースケール

f:id:weakboar:20170517224410p:plain
ご覧の通り灰色の世界に変えるフィルターです。
画像処理的にはピクセルに光度の情報しか含まれていないことを言います。

ちなみに標準で入ってます。知らずに実装しました。

セピア

f:id:weakboar:20170517224812p:plain
セピア調にするフィルターです。回想シーンなんかで使えそうです。 RGB値に対して適当な数字をかけるとこんな色合いになります。

これも標準で入ってます。知らずに実装しました。

まとめ

今回は上記4点のフィルターを実装しました。
MVではフィルターと呼ばれていますが、ゲーム開発ではシェーダーやポストエフェクトと呼ばれています。
例えば「ノイズ シェーダー」で検索すると画面にノイズを走らせるようなシェーダーがあったりします。

注意点としてはフィルターによっては負荷が高いものがあります。今回で言うとブルームは少し負荷高めです。
ブルームとティルトシフトを併用するとスマートフォン環境では格段に重くなるので、バランスを見つつ導入したりモバイル端末ではフィルターをオフにするように扱う必要があります。

それでは楽しいゲーム開発ライフを!

unity1weeksで気になった作品

二日坊主なので二日目は記事を書きます。

昨日の記事の最後で言いましたが気になる作品の紹介記事です。

素晴らしい作品は沢山あるのですが個人的な主観で特に気になったゲームの紹介になります。

超速のブロック崩し(仮)

超速のブロック崩し(仮) | ゲーム投稿サイト unityroom - Unityのゲームをアップロードして公開しよう

f:id:weakboar:20170502010451g:plain

Unity界隈で有名なあのテラシュールブログの方が作ったゲームです。 ちなみに今確認したら開発の流れの記事がありました。後で読もう。

ゲームの内容は任意の場所にバーを出せるブロック崩しと言う感じです。

このゲームの特徴的な部分はボールが超速で動くところです。それこそ目にも留まらないほどの速さです。ですが常に超速で動いているわけではなく、移動するとゲームオーバーになる時は凄いゆっくりになります。

ゲーム性、演出、どちらも完成度が高く普通に一時間くらい遊んでました

跳ねろノミ 〜猫の血を吸え〜

跳ねろノミ 〜猫の血を吸え〜 | ゲーム投稿サイト unityroom - Unityのゲームをアップロードして公開しよう

f:id:weakboar:20170502010454g:plain

狙いを定めて威力を決めて跳ねる事でゴール(猫)を目指すゲームです。

今回のゲームジャムのテーマは「跳ねる」だったわけですが、ノミというモチーフには意外性と納得感を感じ軽く感動しました。

ゲーム内容もわかりやすく、往年の名作「蚊」のような雰囲気のゲームになっています。Twitterを見ていると何やら動いているようなので今後にも期待しています。アバターモードとか実装しないかな。。。

跳ねるおっさん

跳ねるおっさん | ゲーム投稿サイト unityroom - Unityのゲームをアップロードして公開しよう

f:id:weakboar:20170502010614g:plain

最後にこちらのゲームの紹介です。まずアイコンに漢気を感じます。

ゲームの内容はおっさんが跳ね転がっていくので左右のボタンを押しておっさんをゴールに導くものになってます。

おっさんの挙動に漢気を感じます。何ていうか漢気を感じるゲームでした。 ちなみに昨日の記事でも書きましたが、この方のツイッターを見て僕も参加を決めました。楽しそうに作っていて見ていてほっこりしました。

まとめ

数あるゲームの中から本当にごく一部だけ、簡単にご紹介しました。今回紹介したゲーム以外にも楽しいゲームが沢山ありました。QWOPを彷彿とさせる物とか、めちゃくちゃ面白いです。

70の作品が登録されているようなのでぜひ遊んで見てはいかがでしょうか。

Unity 1週間ゲームジャム | ゲーム投稿サイト unityroom - Unityのゲームをアップロードして公開しよう

ゲームジャムに参加しました。

unityroomunity1weeksというゲームジャムに参加しました。 お題は「跳ねる」で月曜から本日(日曜)の20時までにアップロードする、という流れです。

ちなみに完成品がこちら。 HaneShoot | ゲーム投稿サイト unityroom - Unityのゲームをアップロードして公開しよう 見ればわかりますがかなりシンプルなゲームです。

このゲームジャムに参加するに至った経緯ですが

こちらのツイートを見て存在を知りました。このツイートが本日の15時56分。 この時私は外出中(帰宅中)でした。

この時点で残り時間が約4時間。家に付くまでに30分程度。 つまり3時間半ほどの時間があることに気付いたのです。 僕は思いました。

3時間半もあるじゃん

こんな感じで参加を決めたわけです。 その3時間半でやったことをまとめていこうと思います。

企画を決める

3時間半と書きましたがその前に移動時間が30分ほどあります。 3時間半フルでプログラムを書くためには企画を決めておく必要があります。 そこで移動中に企画を決めました。方針としては「シンプル」「定番」「簡単操作」です。 「定番」から決めるのがかなりやりやすかったです。 物理挙動のゲームで、壁に当たると跳ねて、引っ張りアクション。 で出てきたのが例のゲームです。

過去のプログラムをインポート

さて、肝心要の3時間半で行けるだろうと思った理由がここにあります。 このゲーム以外にも色々ゲームを作っているのですが、その中で「あ、よく使うな」というものはライブラリ化しているものがちらほらあります。 良くあるので言うとSingletonBehavior的なやつとかDontDestroyObject的なやつとかです。 これを他のプロジェクトから放り込みました。

加えて「Game Jam Template」というアセットをインポートしました。 これは簡単にタイトル画面を作れるすぐれものです。タイトル通りゲームジャムで使うことを想定しているのでしょう。

この作業だけで数百行のプログラムが一瞬で書き終わったのと同じ状態になるのでかなり時間短縮になりました。 書いててよかった汎用コード。

諦める所は諦める

アセットをインポートしたわけですが、もちろん新規に描いたコードもそれなりにあります。 玉が画面外に出た時の処理やステージ選択何かがそれにあたります。 その中で妥協していった部分が幾つかあります。

最適化しない

例えばキャッシュした方が良さそうなものとかありますが基本的にしていません。

不具合出そうなところを許容する

簡単に言うとNull踏みそうな箇所を気にせず描いています。 少ないコードで書くのでそう簡単には踏まないし踏むとしてもすぐわかるだろうという判断です。 実際なんとか動いてます。これはリスクを背負って時間短縮をした感じになりました。

演出はこだわらない

演出ってなんだかんだ時間がかかるものです。クリア時とか画面の切り替えとか。。。 そこもライブラリ化できていれば良かったのですがしていなかったので無くしました。 ここは時間があればやった方がゲームとして面白いので少し後悔しています。

仕様を落とす

最初の想定ではステージクリア型で徐々にステージが解放されるものを考えていました。 ですが、ステージって普通ステージ1から順番にやりますよね?殆どの人がそうだと思います。 そこは人の心理を信じてごっそり削りました。

リリース

実はunityroom使うのが初めてでした。普段はWindows向けかスマートフォン向けに開発をしているのでUnityのWebGL向けBuild環境も入って居ませんでした。 これを急いで入れつつビルド、アップロードという感じでリリースしました。 リリース方法に関してはunity1weeksのページにまとめられていたので迷うことはなかったです。 開発が〆切15分前とかに終わったのでここが一番焦ってましたw

感想

こんな感じで紆余曲折を経て冒頭に紹介したゲームが完成しました。 ゲームジャム参加は初めてだったのですがこれまでの経験もといコード資産をフル活用した感じになりました。 完成した瞬間の達成感とその後色々な人が作ったゲームを遊ぶのがとても楽しかったので何かあれば、また参加しようかなと思います。

明日は余裕あれば遊んだゲーム紹介していきたいな。

ポーズ画面の仮実装

こんな感じのポーズ画面を実装しようと思いました。f:id:weakboar:20170312203009p:plain

  • ゲーム画面が停止する
  • ぼかす

この辺が必要な仕様です。また、実装にあたって下記の記事を参考にしました。その内ちゃんと勉強したいなぁ。

「いけにえと雪のセツナ」グラフィック解説

下準備

ポーズ画面実装にあたってグラフィック解説を参考に

  • カメラ1でモデルをRenderTextureに描画
  • カメラ2でRenderTextureを描画

というような構成にしました。記事を参考にやってみたけど合ってるのだろうか。

実際にぼかしてみる

ぼかし方は簡単に下記の通り

  1. Pauseを押したらカメラ1のenabledをfalseにする
  2. カメラ2のBlurコンポーネントのenabledをtrueにする
  3. Resumeを押したらカメラ1のenabledをtrueにする
  4. カメラ2のBlurコンポーネントのenabledをfalseにする

カメラ1を切ることでレンダリングコストが下がる事を期待している。カメラ1を切ってもRenderTextureには既に描画されているのでカメラ2にはカメラ1を切る直前の画面が描画され続ける。内部的には動いているが(本実装するときにはちゃんと止める)画面上は止まるのもちょっと良い。

比較

さて、実装自体は出来たわけだがパフォーマンス的に効果がないとやる意味も無いのでProfilerで比較してみた。比較対象は下記の通り。

  1. カメラ1をそのままゲーム画面に描画
  2. カメラ1にBlurをアタッチして画面をぼかす
  3. 本記事でのぼかししょり

f:id:weakboar:20170312205128p:plain f:id:weakboar:20170312205252p:plain f:id:weakboar:20170312205452p:plain

 CPU Usageは全体として下がっている。Scriptが若干上がっているのは気になる。もしかしたら誤差かもしれない。

 そして当然といえば当然なのだがRenderingのTrianglesとVerticesが著しく下がっている。モデルを描画しているカメラをオフにしているのだから当然である。Memoryは・・・上がっている・・・?

最後に

正直開発も初期段階で描画しているモデル数もMagicaVoxel製のものが1つとPlaneが1枚なので比較はあまり出来ていない感じはする。 とりあえず本記事の実装方法で進めていくけど今後効果が出ると・・・いいなぁ・・・!

【Unity】画面の比率を固定にする

書きかけの記事が消えたので悲しいので簡単に終わらせます。 目的は表題の用に「画面比率を固定にした画面づくり」です。

カメラの仕様と対処

 私はUnityのカメラの比率を固定する方法を知らない。表示サイズによって横に広がったりとかするものだと思っている。ただそれだと視覚的情報が増えるわけでユーザーに有利不利が発生してしまう可能性がある。

RenderTexture

 そこでやるべきことは単純である。表示比率を固定にしてやればいいのだ。はみ出した部分はよくある黒で塗りつぶそう。先程は出来ないと行ったがそれはカメラの設定でと言う話だ。道はいくらでもある。今回はRenderTextureと言うものをつかう。

 Project内にRenderTextureを作る。そしてカメラのTargetTextureに付ける。そうするとカメラの描画先がゲームシーンからRenderTextureになる。Gameシーンにかかれている事は一旦無視して良い。    下図を元に説明する。スクショの左下には現在のRenderTextureが写り込んでいる。Gameビューで操作するとRenderTexture内のキャラが動いているのがお分かりいただけるだろう。 f:id:weakboar:20170312054719g:plain

RenderTextureをカメラに映す

 さくっと終わるほう法でやりたい。

  1. カメラを作る。SolidColorとかで良いだろう。
  2. 作ったカメラの下にCanvasを作る。
  3. CanvasのInspectorからScreenMathchModeを探しExpandに変更する。
  4. CanvsのRenderModeをCamera、RenderCameraを親のカメラにする。
  5. Canvasの下にRawImageを作りTextureの所にRenderTextureをいれる。ついでにMaterialも適当に作って入れておく

これだけでRenderTextureをカメラに移せる。しかも比率は固定だ!!すごーい! 余った箇所は黒くするとかレターボックス作って黒の塗りつぶしになるように作るとかやっておけばいいと思います!!!