#1 Unityで作成したゲームをローカライズした話

やぁこんばんはo(^▽^)o

ゲームチームのUnityエンジニア @p_chin だよ、宜しくね!o(^-^)o

このエントリーはtech.kayac.com Advent Calendar 2014の1日目のエントリーだよヾ(@⌒ー⌒@)ノ

目次

前置き

気付いたらアドベントカレンダー進行役の @MacoTasu に一日目の担当にされてたんだ!、マコタス許さんo(`ω´*)oプンプン

今年は @acidlemonIKEAで本物のアドベントカレンダーを買って頂いたので、当日の担当者が記事を書き終えたら次の人に回してカレンダーからチョコレートを取って食べます(^-^) 皆とても仲が良く、アットホームな職場だよo(^o^)o

ちなみにこのようなカレンダーを皆で回して行く予定です。

IMG_5138.JPG

パネルを一枚めくったらサンタさんにチョコレートにされてしまったと思われる少女が出てきました。

抵抗する事を諦めた顔に見えます。

IMG_5139.JPG

さて、本日は僕の方から『Unityで作成したゲームをローカライズした』話を書いて行きます( '-' *)

よろしくお願いしま-す( '-')つ===○(x_x)

Unityで作成したゲームにローカライズ対応した

今年の2月にリリースした姫騎士と最期の百竜戦争(姫ヒャク)というタイトルを、8月に英語へのローカライズ対応をしてRagingDragonsというタイトルでリリースしています。

今回はこのゲームをローカライズした時の反省などについて書いて行きます。

プロジェクトのローカライズ作業をする前に悩んだ事

  • 日本語がSceneにハードコードされてたのをどうやってローカライズ対応するか
  • Sceneが姫ヒャクの場合には120Scene程あったので各Scene毎にポチポチするの辛い
  • AssetBundleの自動ビルドの仕組みやテストサーバーへのdeploy方法どうしよう
  • AltasとAssetBundleはjenkinsで自動ビルド→テストサーバーへ自動deployしてた
  • 管理するrepositoryはどうしよう、一つにするならどのようにAssetを管理しよう
  • ローカライズ対応した後にもビルド時のオプション変更でワンソースで日本語と英語アプリのビルド出来た方が良いのだろうか
  • Unityの場合commitされるファイルにSceneや画像ファイルなどのバイナリ形式のモノが多いので、ワンソースで多言語リソースをswitch出来る様にしないと日本版での修正を英語版にバックポートする毎にファイルがconflictして辛そう...
  • UIAtlasにまとめられてるSpriteの元画像が無かったけどどうしよう...
  • デザイナーも開発中に交代したりしたので元のPSDも何処にあるか分からない闇リソースファイルがいくつかあったのでどうしよう〜(>_<*)
  • QAテストの手順とかどうしよう、同じリソースを参照する様なSceneはまとめてローカライズ対応してテスターにテスト依頼した方が良さそうだ
  • 日本語を英訳すると文字数が増加する事が多いので、UIのレイアウトから文字が飛び出してしまうのでは?
  • 文字がアニメーションしてる所は英訳すると文字数代わるのでアニメーション作りなおしなのか!?!?

実際にやった事

日本語がSceneにハードコードされてたのをどうやってローカライズ対応するか

本来姫ヒャクではNGUIを使用していたので、Scriptから特に文字列をsetしないタイプのUILabelが付いてるGameObjectにNGUIのUILocalizeも付けてLocalizationコンポーネントに参照させてるtextファイルに書いてある文字列を参照するkeyを入れておけば良かった。

しかし、姫ヒャクでは全てのUILabelにその対応がされていなかったので辛かった。

なので、今回はSceneを選択してその中にあるComponentから参照されていないUILabelにUILocalizeのComponentをアタッチする様なToolを作成しました。

ちなみにUILocalizeのCompontには{親の親のGameObject名}_{親}_{自身}の様に適当なkeyを振っておいて、tmp.txtというファイルにkey&value(元々UILabel.textにInspectorから直書きしてあった文字列)形式で書き出していました。

QAテストのフローについて

最初は一つのSceneに対して作業branchを作成し、ローカライズしたらそのbranchのビルドを作成し、QAテスターにテスト依頼をするというフローでやっていました。

しかし、複数のSceneで共通のリソースを使い回すケースが多い事に気付いたので、開発の後半では方針を変えて関連するリソースを手動で割と適当に洗い出し、関連するSceneを全てローカライズ対応したらQAテストにまわすというフローに変えました。

AssetBundleの自動ビルドの仕組みやテストサーバーへのdeploy方法どうしよう

日本版アプリの方ではAssetBundleとAtlasを自動的にビルドしてサーバーの指定環境へdeployの様なフローでやってました。

一応ラベリングのされていないリソースは使い回せるので、AssetBundleを管理してるプロジェクト内で、『共通素材』, 『日本』, 『英』の様にカテゴライズしなおしてビルドする仕組みを改修しました。 AssetBundleの方はアプリ側とは違い、同じbranchで多言語のリソースを管理する仕組みは割と簡単に実現出来た感じがします。

07599220.png

ビルド時のオプション指定でワンソースで日本語と英語アプリのビルド出来た方が良いのだろうか

これは最初に実装方針を決める頃にやりたかった事だったのですが、スケジュールが押してきたので断念しました..。 日本版の開発branchはmasterで、英語版がus-masterをbaseにして器用に開発してました(辛い)

ちなみに、やはり運用して行くと日本版アプリでしたバグ修正などの変更は、SceneやPrefabが絡むとus-masterブランチへのバックポートが捗らなくて日本版で出た新機能を英語版で出せないという辛い事も想像通りに起こりました...

UIAtlasにまとめられてるSpriteの元画像が無かったけどどうしよう...

翻訳業者に書き出す画像のサイズを伝えるのにサンプルに日本版のUIAtlasに入ってるSptireの元画像を渡したかったけど、無いと言う問題があった。

少し強引ですが、UIAltasからSpriteのoffsetを取得して、それを元にSprite毎のpngファイルを書き出すという事をして一件落着しました。

(そもそも素材の管理方法がなってなかったので、他のプロジェクトの知見にはあまりならないかも...)

日本語を英訳すると文字数が増加する事が多いので、UIのレイアウトから文字が飛び出してしまうのでは?

これを恐れて最初に日本語がラベリングされてる画像の翻訳を御願いする時に『画像サイズは変えないで翻訳して』と御願いしていたのですが、これによってやはり文字がとてつもなく潰れてしまったりして結局PSDファイルを開発者側でいじってリサイズしていく作業が発生していました。

英訳すると文字数大きくなるけど画像サイズを変えない場合の例

  • 日本語『素材不足』

b2a81f37.png

  • 英語『Materials Missing』

2d47a4b9.png

(そもそもこれくらいならフォントで表現すれば良かった感はあります)

文字がアニメーションしてる所は英訳すると文字数代わるのでアニメーション作りなおし??

作り直した箇所がいくつかありました。

そして、どうしようも出来ない箇所は英語3文字で日本語一文字分のアニメーションをさせて誤摩化したりもしてた思い出があります...

演出の一環なのでなかなかここは英語一択で作ってくれとは言えない領域ですが、最初に予測して無い作業だったので結構手間がかかりました。

今後日本語アプリのローカライズをするなら考えたい事

  • ワンバイナリで多言語対応とかするなら最近のNGUIではUILocalizeコンポーネントがcsvから翻訳してくれる様になったので、それを使うの良さそう
  • ワンバイナリ多言語対応するアプリで無ければやっぱりワンソースでビルドオプションから言語選択して各言語のビルドを作成するのは諦めたくない
  • 画像にラベリングは避けたい、フォントもBitmapフォントだとそれほどの数を使えないけどUnityでテキスト形式で翻訳出来た方が圧倒的に楽だったのでそうしたい
  • 画面デザインをする時点でラベリングする領域にはターゲットにしてる言語の中で一番長い文字列が入る事も検討して作成した方が良さそう
  • そういえばUGUIってローカライズの機能は持ってるのかな?
  • 最初からコードで日本語文字列のinstanceを取得する時にはNGUIのLocalization.Instance.Get(string key)を使っておけば良かった
  • Hierarchyのどこからも参照されてなくて日本語が直書きされてるUILabelにもUILocalizeを追加してkey経由で文字列を取得する様にする

さて明日は、僕が辛い時に飯を奢ってくれたりと頼りGayのある先輩である @Konboi の『#2 最近goで色々作った話 ~ 今年も残り18営業日 ~』です!

@Konboi 先輩には、彼に飯を奢ってもらった次の日に僕がノロウィルスにかかったという懐かしい思い出があります。

元々Rubyを書いていた所を今年ゲームチームに配属されPerlを書き、最近ではgolangも書いてらっしゃるので良い知見が共有されるのではないでしょうか(予言)

#6 「今年UnityのAssetBundle周りで頑張った事」 tech.kayac.com Advent Calendar 2013

こんばんはo(^▽^)o

Unityエンジニアとして今年4月に入社したけど7月まで@songmu先生の元でPerlを教わりながら書いてたけど、夏休みから戻ったら再びUnityエンジニアとして働く事になってた@p_chin です!

早く忘年して今年の苦悩を昇華できたらいいなーって思ってます!(フラグ

このエントリーはtech.kayac.com Advent Calendar 2013の6日目のエントリーだよヾ(@⌒ー⌒@)ノ

実はPerl書いてた頃の方が既存のイノベーションに触れる事が多かったのだけど、

今年、UnityのAssetBundleに関する自動化周りのイノベーションを起こすべく、先輩方に助けられながら頑張ってる(今もまだ頑張ってる…)ので、その事について書いて行きまーす(^ー^)ノ

もくじ

前置き

  • UnityのProjectはgitで管理しております
  • AssetBundleをビルドするUnityProjectは、ゲーム制作のProjectとは分けて別管理してます
  • AssetBundleやAtlasのビルドは基本的にjenkinsに任せてます

Textureの設定をAssetPostprocessorで自動化

2Dゲームを作成していると、設計にもよりますが大量のTextureのAssetBundleの配信する事になると思います。

その為、開発中におけるAssetBundleの更新頻度が高くなると、画像をUnityProjectに配置すると,TextureのImportSettingsを都度設定しなければいけないので、AssetPostprocessorのサブクラスが使えるOnPreprocessTextureメソッドの中に配置された画像のpathをRegexでチェックして、適切なTextureImportSettingを自動で設定する仕組みをまず書きました。

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Text.RegularExpressions;

class TextureModifier : AssetPostprocessor
{
    void OnPreprocessTexture ()
    {
        if (Regex.IsMatch(assetPath, @"Assets/AssetBundleResources/Fugu/fugu_icon_s/.*\.png$")) {
            var importer = (assetImporter as TextureImporter);

            importer.textureType = TextureImporterType.Advanced;
            importer.compressionQuality = (int)TextureCompressionQuality.Best;
            importer.npotScale = TextureImporterNPOTScale.None;

            importer.isReadable = true;
            importer.generateCubemap = TextureImporterGenerateCubemap.None;
            importer.filterMode = FilterMode.Bilinear;
            importer.mipmapEnabled = false;
            importer.anisoLevel = 0;
            importer.wrapMode = TextureWrapMode.Clamp;
            importer.alphaIsTransparency = true;
            // device setting
            importer.SetPlatformTextureSettings ("Android", importer.maxTextureSize, TextureImporterFormat.ATC_RGBA8);
            importer.SetPlatformTextureSettings("iPhone", importer.maxTextureSize, TextureImporterFormat.RGBA16);
        }
    }
}

OnPreprocessTexture()に設定を書いておくと、TextureのImportSettingsが変更された時もこのメソッドが働いてくれるので、UnityEditor内のInspectorからはカジュアルに設定を変えられないので、設定の人的ミスは避けられますね!

AtlasとAssetBundleの自動ビルド

Unityのコマンドライン起動について

現在AtlasとAssetBundleの生成はjenkinsのjobからUnityをコマンドラインから起動してEditorScriptのメソッド実行してます。

基本的にはUnityEditorを立ち上げない-batchmodeオプションで起動させますが、その場合だとScene内でアレコレする事が出来ないので、そんな時は-batchmodeオプションを外して-executeMethod <ClassName.MethodName>オプションを付けて実行すると、UnityEditorが表示されてScene内でアレコレやれたりします。

というのを、最近私の隣で仕事をしている@onevcatから教えてもらいましたので、おススメです。

Atlas自動ビルドにおける苦悩

Atlasの生成はNGUI2.6.3のUIAtlasMaker.AddOrUpdateを使ってるのですが、Atlasにまとめる画像の数が多いと、たまにUIAtlasのSpriteがずれたりするのでまだ課題があります。

ちなみにAssetBundleの生成は、特に失敗とかは無くて安定してます。

自動ビルドのScriptは秘伝のタレ化が進み、汎用化出来てないの為ここでは見せられなかったです。。。

jenkinsにビルドさせてリポジトリにcommitさせちゃってます

余りお行儀が良くないのですが、AssetBundleのProjectはリソースを淡々と追加していくだけなので、master branchにgit push -fさせてます。

人間でcommitするのが、私か素材を置いてくれるデザイナーだけだし、jenkinsは生成したAtlasとAssetBundleしかcommitしないので、コンフリクトは今の所は起きて無いです。

画像の圧縮についての小ネタ

  • PVRTC4bit

これが皆さんご存知の通り、グラデーションや透過部分の多い画像にかけてしまうと劣化が顕著に現れてしまいますので、背景とかならまだしも、何の対処も無しに厚塗りのキャラクター画像などに圧縮をかけてしまうと、デザイナーからブーイングが来ます。

これに関しては画像によって最適な圧縮が異なるので、常にUnityエンジニアとデザイナーが納得いくまで時間をかけてチューニングして行くしか無いのかな…とは思ってます。

今が、PVRTCにするものの、画像の解像度をあげてゲーム内での表示の品質をあげようとしてますが、これも今度はアプリケーションが実行されるメモリが増えて辛いので、下手に解像度が挙げられないのでギリギリまでチューニングしてます。

  • RGBA16bit

PVRTC4bit圧縮がダメなら16bitに落ち着く..くらいだと思います。

ですが、16bitRGBAをNGUIのAtlasに適用したままでNGUI2.6.3のUIAtlasMaker.AddOrUpdateを実行してAtlasの中身を更新すると、エラーが出ます。

原因は、Atlasを作詞絵する時に、画像のpixelを操作するからです。

Texture2Dのpixel操作は、RGBA32bitなどのトゥルーカラーの画像しか出来ないのが理由です

Unityのリファレンスにも書いてありますので、こちらもよろしければご覧下さい。

まとめ

AssetBundleサイコーだから、もっと色々な現場の頑張りを公開してこ!

という適当な締めをさせて頂きます!

以上となりますが、少しでも為になって頂ければ嬉しいです。

乱文失礼致しました。


さて明日の記事を書くのが、面倒見の良いiOSに詳しいイケメンおじさんかと思いきや、エロコンテンツの作成にも腕を鳴らしていらっしゃる@SOMTDさんです!

お楽しみに!