image1.jpg

はじめに

1年間で8本のアプリをリリースするときにやったことをまとめました。

著者が企画・開発したUnityアプリ

いずれも全世界公開していて、そのうち4つがApple Storeでフューチャー★されました。中でも「ねずみタイマー」が一番人気です。

アイコン 内容
xhdpi.png どうぶつまるカード
ことば学びを育むパズルゲーム
xhdpi.png えこみゅ
気持ちを伝えるカードアプリ
xhdpi.png ねずみタイマー
時間の長さが見えるタイマー
xhdpi.png こえキャッチ
声であそぶボイトレゲーム
xhdpi.png にゃんタップ
同じにゃんこを見つけるマッチングゲーム
xhdpi.png やることカード
シンプルで使いやすい絵カードスケジューラー
xhdpi.png おかね星人
おかねの計算が身につくゲーム
brushinghero.png 年内リリース予定

やったこと

  • テキストをなるべく含めない
  • 低コストで素材をそろえる
  • 低コストでローカライズする
  • その他にやったこと
  • アプリのアイデアを出す

テキストをなるべく含めない

image2.jpg
Designed by stock-world-on / Freepik

LITALICOアプリはお子様がメインターゲットなので、以下のルールを守っています。

  • 広告を入れない
  • 障害の有無に関係なく使える
  • 幼児から大人まで楽しめる

これらのルールを守るにあたって、設計時には以下を意識しています。

  • テキストをなるべく含めない
  • 子供がわからない表現は含めない
  • 子供が使えるインターフェースにする

テキストに頼らずに自然に使い方がわかるものを目指して設計すると、国籍や年齢を問わず、誰でも使えるものになりますし、テキストが少ないとローカライズコストも抑えられるのでオススメです。

低コストで素材をそろえる

image3.jpg
Designed by Freepik

著者は前職でソーシャルゲームを企画・開発していましたが、素材制作のディレクションコストには常に悩まされていました。もっとはやく以下のサービスを活用していたらと後悔しています。同レベルとまではいきませんが、小規模のアプリには十分な素材が無料またはおこづかい程度でそろいます

◆アート素材

https://www.freepik.com/
ベクター、ラスター、写真など、様々な素材がそろっています。

https://www.flaticon.com/
ベクターアイコンの宝庫。テイストも豊富で使いやすいです。

https://www.shutterstock.com/
良いのがないときはこちらで購入します。高品質な素材が安く手に入ります。

◆効果音素材

https://soundeffect-lab.info/
クオリティが高いです。声素材や鳴き声などもあります。

http://www.kurage-kosho.info/
UI関連や演出用の効果音はこちらが充実しています。

http://taira-komori.jpn.org/freesound.html
生活音も含め、いろんなジャンルがそろっています。

◆BGM素材

https://dova-s.jp/
さまざまなジャンルのBGMがあります。いつもお世話になっています。

https://audiostock.jp/
良いのがないときはこちらで購入します。ジングル、効果音もあります。

サウンド素材はループにしたり、長さを調節したいときがよくあります。そのときは Audacity というフリーソフトで加工しています。

低コストでローカライズする

image4.jpg
Designed by Jannoon028 / Freepik

LITALICOアプリは上記のとおりテキスト量がかなり抑えられていますが、お子様が見ることのない、設定画面やエラーダイアログにはテキストが含まれます。世界配信するときにはそれらをローカライズしています。

手順1:まずは英訳

英語が得意な人が身近にいないときは Google翻訳 を使います。日本語を機械が翻訳しやすい言い回しに調整して入力し、出力された英訳をGoogle翻訳で和訳してみて、正しければOKとしています。

手順2:Gengoで多言語化

クラウドソーシングの翻訳サービスはいくつかありますが、著者は Gengo を使っています。クオリティはまあまあですが、上がってくるのが早いところが気に入っています。

手順1で作った英訳リストをファイルにして依頼しましょう。なぜ先に英訳を用意したかというと、日本語から多言語化するより、英語から多言語化したほうが時間と価格を節約できるからです。ただし、分量が多いときは手間をかけたくないので、日本語のまま Gengo に依頼して英訳もおまかせしましょう。

翻訳のクオリティはビジネスレベルを選択。過去にリリースしたアプリの利用動向をみて、対象言語は以下の6つにしています。

  • 中国繁体
  • 中国簡体
  • 韓国
  • ロシア
  • スペイン
  • ポルトガル(ブラジル)

これ以外にも、フランス語、ドイツ語、イタリア語はGoogle翻訳で対応しています。できる限り多くの言語に対応したほうがApple Storeでフューチャーされやすいです

手順3:翻訳データをアプリに反映

手順3はけっこう手間ですが、一度やってしまえばずっと使いまわせます。

1) Googleスプレットシートで管理

手順2の翻訳データを Googleスプレットシート で以下のように管理します。各言語名はUnityの SystemLanguage の名称とあわせています。

key English Japanese ChineseSimplified ChineseTraditional French German Italian Korean Portuguese Russian Spanish
alermMessage Squeak! (It's time.) チュー!(じかんだよ。) 吱!(是时候了。) 吱!(是時候了。) Couic! (C'est l'heure.) Quiek! (Es ist Zeit.) Squittio! (È tempo.) 쥐 우는 소리! (때가됐다.) Rangido! (Está na hora.) Пи-пи-пи! (Пора.) ¡Chirrido! (Es tiempo.)

2) JSON形式で出力

スプレットシートの「ツール > スクリプトエディタ」で以下のスクリプトをコピペして保存します。

JsonExport.gs
function myFunction() {
  //今開いているシートを取得する
  var sheet = SpreadsheetApp.getActiveSheet();

  // シートの一部分を取得する
  var rowIndex = 1;
  var colStartIndex = 1;
  var rowNum = 1;
  var keys = sheet.getSheetValues(rowIndex, colStartIndex, rowNum, sheet.getLastColumn())[0];
  var data = sheet.getRange(rowIndex + 1, colStartIndex, sheet.getLastRow(), sheet.getLastColumn()).getValues();

  var list = [];

  data.forEach(function(elm,index){
    var template = indexBy(keys);
    var member = generate(elm,template);
    if(member.key){
        list[index] = member;
    }
  });

  Browser.msgBox(JSON.stringify(list));

  function generate(elm,obj){
    var i = 0;
    for(var key in obj){
      obj[key] = elm[i];
      i++;
    }
    return obj;
  }

  function indexBy(ary){
    var obj = {};
    for(var i = 0, len = ary.length; i < len; i++){
      var key = ary[i];
      obj[key] = key;
    }
    return obj;
  }
}

上記のスクリプトを対象のシートを開いた状態で実行すると、シート上にダイアログで以下が出力されます。


[{"key":"alermMessage","English":"Squeak! (It's time.)","Japanese":"チュー!(じかんだよ。)","ChineseSimplified":"吱!(是时候了。)","ChineseTraditional":"吱!(是時候了。)","French":"Couic! (C'est l'heure.)","German":"Quiek! (Es ist Zeit.)","Italian":"Squittio! (È tempo.)","Korean":"쥐 우는 소리! (때가됐다.)","Portuguese":"Rangido! (Está na hora.)","Russian":"Пи-пи-пи! (Пора.)","Spanish":"¡Chirrido! (Es tiempo.)"}]

これをテキストファイルにペーストし、Unityプロジェクトの Resources/Texts フォルダにLocalizeData.txt という名前で保存します。(フォルダ構成やファイル名は自由です。)

3) Unityで読み込む

先ほどのテキストファイルをUnityの JsonUtility で読み込むのですが、その前にJSONの構造にあわせて以下のクラスを作ります。

LocalizeData.cs
using System;
using System.Collections.Generic;
using UnityEngine;

[Serializable]
public class LocalizeDataList
{
    public List<LocalizeData> list;
}

[Serializable]
public class LocalizeData
{
    public string key = null;
    public string English = "";
    public string ChineseSimplified = "";
    public string ChineseTraditional = "";
    public string Japanese = "";
    public string French = "";
    public string German = "";
    public string Italian = "";
    public string Korean = "";
    public string Portuguese = "";
    public string Russian = "";
    public string Spanish = "";
}

読み込むためのコードは以下です。


TextAsset textAsset = Resources.Load ("Texts/LocalizeData") as TextAsset;
string jsonString = "{\"list\":" + textAsset.text + "}";
LocalizeDataList localizeDataList = JsonUtility.FromJson<LocalizeDataList> (jsonString);

あわせて以下の関数を用意しておけば、keyを渡すだけでユーザーの言語設定に応じたローカライズテキストが取得できます。非対応の言語が設定されているときは英語を返します。


public string GetLocalizeText (string key)
{
    string str = "";
    SystemLanguage lang = Application.systemLanguage;

    foreach (LocalizeData data in localizeDataList) {
        if (data.key == key) {
            if (lang == SystemLanguage.ChineseSimplified) {
                str = data.ChineseSimplified;
            } else if (lang == SystemLanguage.ChineseTraditional) {
                str = data.ChineseTraditional;
            } else if (lang == SystemLanguage.French) {
                str = data.French;
            } else if (lang == SystemLanguage.German) {
                str = data.German;
            } else if (lang == SystemLanguage.Italian) {
                str = data.Italian;
            } else if (lang == SystemLanguage.Japanese) {
                str = data.Japanese;
            } else if (lang == SystemLanguage.Korean) {
                str = data.Korean;
            } else if (lang == SystemLanguage.Portuguese) {
                str = data.Portuguese;
            } else if (lang == SystemLanguage.Russian) {
                str = data.Russian;
            } else if (lang == SystemLanguage.Spanish) {
                str = data.Spanish;
            }
            if (str.Length < 1) {
                str = data.English;
            }
            break;
        }
    }
    return str;
}

ローカライズの手段はたくさんありますが、この方法はスプレットシート上の翻訳データを即座にアプリに反映できるので気に入っています。

その他にやったこと

image5.jpg
Designed by jcomp / Freepik

FirebaseでAnalytics&強制アップデートに対応する

ユーザーにアプリの更新を促すためにFirebaseを使っています。導入は以下を参考にしています。
サーバレスでUnity開発できるFirebaseを導入する - Analytics & 強制アップデート編

App PreviewやYouTubeの動画を低コストで作る

ストアには動画があるほうがダウンロード数が多く、フューチャーもされやすいそうです。動画はこちらの方法でキャプチャーしたものを、iMovie で編集するだけです。クオリティはいまひとつですが、テキストを含まなければそのまま世界に展開できます。
作った動画はこちら(YouTubeチャンネル)

デフォルト言語はEnglish(US)にする

ストアを構築したり、YouTubeに動画を追加するときは、非対応言語の環境で日本語が表示されて敬遠されないように、英語をデフォルトにしましょう。

課金アイテムは非消費型にする

LITALICOアプリは無料で利用できますが、機能を解放したり、効率よく進めるための課金アイテムを用意しています。非消費型アイテムは消費型に比べて復元が容易なため、万が一のメンテナンスコストが抑えられます。少人数でどんどんリリースするために今はこの方針で開発しています。

アプリのアイデアを出す

LITALICOアプリの場合は、発語を促したい、時間を学ばせたいといった、解決すべき「課題」があって、その課題をいかに楽しく解決するかを考えて企画しています。課題の解決に既存のゲームやアプリのシステムを参考にすると、ゼロから発想するより考えやすいです。

このように、新たにアプリを企画するときは、課題や要件を見つけて、それを楽しくする、便利にする、という考え方は近道かもしれません。そのためのアイデアをひねり出す方法は以下のブログにまとめました。

アイデアをひねり出すための10の方法 | higopage

さいごに

最後までお読みいただきありがとうございます!ドキドキの初 Qiita 記事でした。「いいね!」していただけるとすごく励みになります。

LITALICO Engineers Advent Calendar 2017 にはLITALICOエンジニアの良質な記事がどんどん公開される予定ですので、よろしければぜひご購読ください。明日は@Takuan_Oishiiさんの「CloudFront → ELB → EC2(Rails App)な構成でTurnoutのallowed_ipsをいい感じに機能させる」です。お楽しみに!