LotosLabo

プログラミング技術とか気になった情報を載せていきます

VOCALOID SDK for UnityでSDユニティちゃんをリップシンクさせる

はじめに

VOCALOID SDK for Unityのサンプルコードには、
Unityちゃんをリップシンクできるコードがありましたので、
それをSDユニティちゃんでもリップシンクできるようにしてみました。


変更点

LipSyncController.csのvoid Awake()内の記述を変更します。


変更前の記述

_skinnedMeshRenderer = GameObject.Find("MTH_DEF").GetComponent<SkinnedMeshRenderer>();

blendShapeList.Add(new BlendShape(YVF.YVFVowelIDJapanese.A, _skinnedMeshRenderer.sharedMesh.GetBlendShapeIndex("blendShape1.MTH_A")));
blendShapeList.Add(new BlendShape(YVF.YVFVowelIDJapanese.I, _skinnedMeshRenderer.sharedMesh.GetBlendShapeIndex("blendShape1.MTH_I")));
blendShapeList.Add(new BlendShape(YVF.YVFVowelIDJapanese.U, _skinnedMeshRenderer.sharedMesh.GetBlendShapeIndex("blendShape1.MTH_U")));
blendShapeList.Add(new BlendShape(YVF.YVFVowelIDJapanese.E, _skinnedMeshRenderer.sharedMesh.GetBlendShapeIndex("blendShape1.MTH_E")));
blendShapeList.Add(new BlendShape(YVF.YVFVowelIDJapanese.O, _skinnedMeshRenderer.sharedMesh.GetBlendShapeIndex("blendShape1.MTH_O")));



変更後の記述

_skinnedMeshRenderer = GameObject.Find("_face").GetComponent<SkinnedMeshRenderer>();

blendShapeList.Add(new BlendShape(YVF.YVFVowelIDJapanese.A, _skinnedMeshRenderer.sharedMesh.GetBlendShapeIndex("face.MTH_a")));
blendShapeList.Add(new BlendShape(YVF.YVFVowelIDJapanese.I, _skinnedMeshRenderer.sharedMesh.GetBlendShapeIndex("face.MTH_i")));
blendShapeList.Add(new BlendShape(YVF.YVFVowelIDJapanese.U, _skinnedMeshRenderer.sharedMesh.GetBlendShapeIndex("face.MTH_u")));
blendShapeList.Add(new BlendShape(YVF.YVFVowelIDJapanese.E, _skinnedMeshRenderer.sharedMesh.GetBlendShapeIndex("face.MTH_e")));
blendShapeList.Add(new BlendShape(YVF.YVFVowelIDJapanese.O, _skinnedMeshRenderer.sharedMesh.GetBlendShapeIndex("face.MTH_o")));


このように書き換えることでSDユニティちゃんでもリップシンクが可能になります。

ライセンス表記

f:id:lo25131:20140607195201p:plain

このコンテンツは、『ユニティちゃんライセンス』で提供されています。


本コンテンツにはヤマハ株式会社の
VOCALOID SDK for Unity」が使用されています。
VOCALOID(ボーカロイド)」ならびに「ボカロ」はヤマハ株式会社の登録商標です。

Unityでひらがな化APIを利用する

はじめに


gooラボさんのひらがな化APIを利用して、
漢字、カタカナ、ローマ字をひらがなに変換してみました。


こんなかんじになります

例:

<変換前>  爽健美茶     ソウケンビチャ  soukenbitya
<変換後>  そうけんびちゃ  そうけんびちゃ  そうけんびちゃ

用意するもの


gooラボさんのAPIを利用するには、Githubのアカウントが必要となります。
上記のURLからアクセスし、「利用方法」からGithubにアクセスし、
アプリケーションIDを取得してください。


またアプリケーションやブログ等に公開するにあたって、
gooラボさんのクレジット表記も必要となります。



POSTでAPIを叩いて、Json形式で取得します。

Object→JsonJson→Objectには今回はLitJsonを使用します。
(Unity5.3より追加されたJsonUtilityはまだ調べてないので…)


LitJsonをダウンロードし、srcディレクトリ以下をpluginsディレクトリに入れてください。

今回は0.9.0を使います。
LitJSON


using UnityEngine;
using LitJson;
using System.Text;
using System.Collections;
using System.Collections.Generic;

public class PostHiraganaAPI : MonoBehaviour {

    /// <summary>
    /// GooラボApplicationID.
    /// </summary>
    private const string APPLICATION_ID = [上記のGithubにアクセス時に取得したIDを利用];

    /// <summary>
    /// ひらがな化API.
    /// </summary>
    private const string HIRAGANA_API = "https://labs.goo.ne.jp/api/hiragana";

    /// <summary>
    /// ひらがな.
    /// </summary>
    private string m_hiragana;

    /// <summary>
    /// ひらがな変換リクエスト.
    /// </summary>
    /// <param name="Sentence">変換したい文字列.</param>
    /// <param name="ConvertType">変換タイプ(1:ひらがな、2:カタカナ).</param>
    public IEnumerator HiraganaPostRequest(string Sentence, int ConvertType) {

        // JsonDataの作成.
        JsonData data = new JsonData();

        // アプリケーションID.
        data["app_id"] = APPLICATION_ID;

        // 対象文字列.
        data["sentence"] = Sentence;

        // 変換タイプ(ひらがな、カタカナ).
        switch(ConvertType){
            case 1:
                data["output_type"] = "hiragana";
                break;
            case 2:
                data["output_type"] = "katakana";
                break;
        }

        string postJsonStr = data.ToJson();

        Debug.Log("send post json: " + postJsonStr);
        
        // bodyを作成.
        byte[] postBytes = Encoding.Default.GetBytes (postJsonStr);
    
        // ヘッダー.
        Dictionary<string, string> headers = new Dictionary<string, string>();
        headers["Content-Type"] = "application/json; charaset-UTF8";

        Debug.Log("send post json: " + postJsonStr);

        // リクエストを送信.
        WWW result = new WWW(HIRAGANA_API, postBytes, headers);
        yield return result;

        if (result.error != null) {
            Debug.Log("Post Failure…");
        } else{
            Debug.Log("Post Success!");
            Debug.Log("result: " + result.text);

            JsonData jsonParser = JsonMapper.ToObject(result.text);

            // パース.
            m_hiragana = jsonParser["converted"].ToString();

            Debug.Log(m_hiragana);
        }
    }
}




また、ひらがな化APIを使用する際に、Unityのプロジェクトは
「WebPlayer」以外のプラットフォームにしてください。
WebPlayerだと「SecurityException: No valid crossdomain policy available to allow access
というクロスドメインのエラーが出てしまうので気をつけてください。


どんな風に変換されるか試しに利用してみたいという方は、
上記gooラボさんのページより、利用することができますので
そちらをご覧ください。


クレジット



supported by goo

【C#】文頭に句読点などの記号が来た時に文頭に来ないように調整する

前にこのような処理を作っていたので、公開します。

具体例

改行するような文字列があり、先頭に「、」や「。」などの句読点が来てほしくない時があります。

例:
おはようございます
。今日も元気にがんばりましょう



そのようなときにこんな感じに文頭の文字列を、文末へ持っていき修正します。

例:
おはようございます。
今日も元気にがんばりましょう!

プログラム

/*!
 * 先頭に句読点などの記号が来ないように調整するクラス.
 * 
 * @file	FirstStringCheck.cs
 * @author	Lotos
 * @date	2015-1-25 4:21
 */

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class FirstStringCheck : MonoBehaviour {

    /// <summary>
    /// 先頭に句読点などの記号が来ないように調整する.
    /// </summary>
    /// <param name="lineCount">最大表示行数.</param>
    /// <param name="text">文字列.</param>
    /// <returns>変換された文字列.</returns>
    public static string CheckText(int maxLineCount, string text) {
        string result = string.Empty;
        // 最大行数から一文字少なく表示.
        int lineCount = maxLineCount - 1;

        //  先頭に来てはいけない文字.
        string checkString = "、,.。」・};?!!?]";
        List<string> textList = new List<string>();

        // 全体文字数が最大行数を超えるとき.
        if (text.Length > lineCount) {
            // 全体文字数まで増やす.
            for (int index = 0; index < text.Length; index += lineCount) {
                // 全体文字数から最大行数分抜き出せた時.
                if (index < text.Length - lineCount) {
                    // 最大行数より一文字多く抜き取る.
                    string lineCountPlusText = text.Substring(index, lineCount + 1);
                    // 最大行数分抜き取る.
                    string lineCountText = text.Substring(index, lineCount);
                    // 一文字多く取得した文字列の一番最初の文字を取得.
                    string firstText = lineCountPlusText.Substring(lineCount, 1);
                    // 抜き出した文字が先頭に来てはいけない文字か判断.
                    if (0 <= checkString.IndexOf(firstText)) {
                        // 一文字多くリストに追加.
                        textList.Add(lineCountPlusText);
                        // 一文字多く取得したので、1追加.
                        index += 1;
                    } else {
                        // 最大行数分リストに追加.
                        textList.Add(lineCountText);
                    }
                } else {
                    // 残り文字数を取得.
                    int remainingTextCount = text.Length - index;
                    // 残り文字数を抜き出す.
                    string remainingText = text.Substring(index, remainingTextCount);
                    textList.Add(remainingText);
                }
            }
           for (int index = 0; index < textList.Count; ++index) {
            result += textList[index] + "\n";
           }
           return result;
        }
        return text; 
    }
}

使い方

例としてこれをUnity上で表示させてみます。

最大で表示してもいい行数(今回は5行)と、テキストを渡します。

 void Start() {
        string sampleText = "おはよう、今日も1日、がんばるぞい!";
        var result = FirstStringCheck.CheckText(5, sampleText);
        Debug.Log(result);
    }

テキストが5行もしくは4行ずつで改行して表示されます。
文頭に句読点などが来る場合は5行、それ以外は4行になります。


f:id:lo25131:20151109002154j:plain


現在は文頭に来てほしくない文字を
string checkString = "、,.。」・};?!!?]";
で指定してますが、もっと来てほしくない文字があれば、これに追加する形で
文頭に来なくなります。

最後に

約一年前に作った処理なので、もしかしたらもっと簡単な方法でチェックでき、
短いプログラムでまとめられるのかもしれません。
参考までにどうぞ。

【ツール紹介】EMLauncherの導入

EMLauncherとは


KLabさんより開発されたテストアプリ配信ツールです。
スマートフォンのアプリファイル(Androidはapk,iOSipa)をアップロードすることで、
手軽に端末にインストールすることが可能になります。

www.klab.com


導入

EMLauncherは個人でも使えるそうなので、導入してみました。


<準備物>
・メールアドレス
AWSアカウント
Bashとかsshで接続できるシェル

EMLauncherのAMIサンプルからAWSインスタンス作成

AWSにログインしている状態で、以下のアドレスにアクセスします。

https://console.aws.amazon.com/ec2/v2/home?region=ap-northeast-1#Images:visibility=public-images;search=ami-9b295f9a


f:id:lo25131:20151108163333j:plain

表示されている項目を右クリックから[作成]を行います。


f:id:lo25131:20151108163449j:plain


右下の次の手順へ移ります。


f:id:lo25131:20151108163641j:plain

削除保護の有効化だけチェックを入れて、
次の手順に移ります。

ステップ4は特に変更することなく、次の手順へ移ります。


f:id:lo25131:20151108163850j:plain

ステップ5ではインスタンスのタグ付けとして、
名前を入力しておきます。
今回は「EMLauncher」とかでいいと思います。

入力したら次の手順に移ります。


f:id:lo25131:20151108164142j:plain



セキュリティの設定を行います。
ルールの追加より、
「HTTP」と「HTTPS」を追加しておけば
大丈夫だと思います。

次に確認と作成を押します。


f:id:lo25131:20151108164514j:plain


ダイアログが表示されると思いますので、
一番下の「このインスタンのブートボリューム~」を選択して、
次へを押します。


f:id:lo25131:20151108165311j:plain


確認画面が表示されるので、作成を押すと、
秘密鍵を作成しろと言われるので、「新しいキーペアの作成」を選択し、
キーペア名を入力して、ダウンロードしておきます。

最後にインスタンスの作成を押して完了となります。



その後インスタンスの一覧画面へ遷移するので、先ほど作成したEMLauncherのインスタンスの状態が
「running」となれば作成終了です。

f:id:lo25131:20151108164835j:plain


EMLauncherで使用するためのストレージを作成


AWSウェブサービスより、S3を選択します。

f:id:lo25131:20151108170638j:plain


右上のバケットを作成より、新規でバケットを作成します。
バケット名は何でも構いません。

f:id:lo25131:20151108170906j:plain


入力したら作成を押して完了となります。


EMLauncherのインスタンスのIPを固定にする

作成したインスタンスではIPアドレスでは、インスタンスを再起動した時に
IPが変化してしまうので、固定として持ち続けるように設定します。


先ほどのインスタンス画面に戻り、左のメニューより「Elastic IP」を選択します。

新しいアドレスの割当を選択し、アドレスの関連付けを行います。

f:id:lo25131:20151108171337j:plain


先ほど作成したインスタンス名を入力して関連付けます。

AWSのIAMの設定

ユーザ、グループ、アクセス権を設定します。
この項目を設定し忘れるとEMLauncherは正しく動作しないので忘れないで下さい。


AWSのサービスタブより、IAMを選択します。

f:id:lo25131:20151108172138j:plain


IAMの5つのセキュリティステータスを完了すれば設定完了となります。

f:id:lo25131:20151108172151j:plain


ルートアカウントのMFAでは、表示されたQRコードを読み取ります。
QRコードスマートフォンアプリの「Authy」というアプリを使って、
読み取り、表示された認証コードを入力します。

グループの割当では、一番上のポリシーのみ選択すれば大丈夫だと思います。

個々のIAMユーザの作成では、作成したユーザのアクセスキーとシークレットキーを
今後使う必要があるので、これをメモっておきます。


sshの接続


インスタンスの作成時に取得した秘密鍵を使用してsshでサーバにアクセスし、
一部設定を変更します。
Bashからアクセスするのですが、私の場合はGit Bashでアクセスします。


まず秘密鍵に対して、パーミッションを変更しておきます。
chmod 600 名前.pem

続いて、sshでアクセスします。
ssh -i 鍵名.pem ec2-user@インスタンスのパブリックIP

設定ファイルを開きます。
vim /home/ohoflight/emlauncher/config/emlauncher_config.php


ここでは、以下の設定の変更を行います。
Google認証設定
AWSのユーザキー指定
・ストレージ名の指定


Google認証設定

ログイン時にGoogleの認証が必要となっているため、これは特に使わないので、
使用しないように設定を変更します。

変更前
'enable_google_auth' => true
変更後
'enable_google_auth' => false


AWSのユーザキー指定

IAMの個人ユーザを作成した時のキーを入力します。

変更前
'key' => 'xxxxxxxxxxxxxxxxxxxx'
'secret' => 'xxxxxxxxxxxxxxxxxxxx'
変更後
'key' => 'キー'
'secret' => 'パスワード'


・ストレージ名の指定

S3で作成した名前を入力します。

変更前
'bucket_name' => 'emlauncher'
変更後
'bucket_name' => '作成した名前'


接続の確認


インスタンスのパブリックIPを入力し、EMLauncherにアクセスできるか確認します。

http://パプリックIP


f:id:lo25131:20151108175627j:plain


ログイン画面が表示されれば大丈夫です。

メールアドレスの登録


ログインするためにメールアドレスの登録を行います。
EMLauncherでは登録する画面がないので、テーブルに直接MySQLで叩いて、
登録します。

sshで接続した状態で、テーブルを指定してメールアドレスのみ追加します。
mysql -uroot emlauncher -e "INSERT INTO user_pass (mail) VALUES ('登録したいメールアドレス');"


メールアドレスのみテーブルに登録して、ログイン画面「forget password」より、
登録したメールアドレス先にパスワードの変更画面のアクセスURLを送り、
パスワードを登録します。

なお、確認したところ一部のメールアドレスにはメールフィルターか何かにより、
迷惑メールにもいかず、ブロックされてしまいますのでGoogleMailが良いと思われます。


パスワードを登録後、ログイン画面より、メールアドレスとパスワードを入力して、
ログインできれば完了です。

登録したアプリケーションを他のユーザと共有する


登録したアプリケーションを他のユーザと登録するには、
共有したいユーザのメールアドレスをテーブルに追加した後、そのアドレスを
「Preferences」という項目からOwnerにメールアドレスを追加することで、
他のユーザとの共有ができます。


f:id:lo25131:20151108180459j:plain

セキュリティの強化

今の状態ではインターネットに接続している他のユーザにもこのページが見られてしまうため、
アクセス制限、セキュリティ強化をしなくてはなりません。

手っ取り早いのはIPアドレスによる制限ですが、SSLより暗号化したり、
また簡易ですがベーシック認証を導入したりすることが必要です。


まとめ

スマートフォンアプリを簡易的に、他のバージョンもインストールできるようにしたい。
という時にはとても便利なツールです。スマートフォンからEMLauncherにアクセスし、
インストールボタンを押すだけで端末にインストールができるのでいちいちPCに接続して、
しなくても済むので時間の節約にもなります。
是非試してみてください。

UnityとMySQLの連携

はじめに

外部データベースからUnityにデータを送受信する例を紹介します。
今回はデータベースであるMySQLphpMyAdminを通して、PHPから
C#(Unity)へとつなげていきます。

MySQLApacheは既に設定されているものとして進めていきます。
私は開発環境にXamppを使用しているので、Xamppを例としていきます。

今回、サーバーはローカルのものを使っていきますが、ローカルでも外部サーバー、
レンタルサーバーでもIDやパスワードを変更すれば基本同じです。

開発環境の準備

「開発環境」

Windows8
・Xampp ver 3.2.1
PHP ver 5.6.12
MySQL ver 5.6.26


Xamppの導入にはいくつか設定が必要なところがありますので、簡単にですが、
手順を説明します。


①インストール
https://www.apachefriends.org/jp/download.html


②日本語化(したい人のみ)

TeraPad等でUTF-8Nで保存するとよいです。


③Xamppホームに接続

http://localhost/security/index.php

versionが上がったことによって、securityを通さないと設定ページに飛ばないそうです。


MySQLのrootパスワードを変更、ディレクトリにhtaccessを設定

http://localhost/security/xamppsecurity.php


MySQLの日本語の文字化けを防止


phpMyAdminの環境設定を登録する



データベースの用意

取得するデータを予め用意しておきます。

データの作成にはphpMyAdminで行います。作成方法は紹介しませんので、他サイトを参考にしてください。


今回は「ユーザ情報のテーブル」と「ランキングのテーブル」の2つを作成しておきます。

仮にですが以下のように用意しておきました。


●ユーザ情報

ユーザID ユーザ名 性別 ユーザ作成時刻


<テーブル構成>

カラム 型数 Null AI その他
uid int 11 いいえ はい Primary, Unique
name varchar 255 はい いいえ
sex int 1 はい いいえ
create_time varchar 255 はい いいえ


<サンプルデータ>

uid : 入力せず
name: user1
sex : 1
create_time: 関数(UNIX_TIMESTAMP)

uid : 入力せず
name: user2
sex : 2
create_time: 関数(UNIX_TIMESTAMP)


性別の登録は以下の方法が良いとされていますが、今回は仮でもあり、
UIとして男か女のみ選択できる場合であれば、1か2でいいと思います。

作成時刻にはUNIXTIMEを入れておきます。


[性別情報の登録参考サイト]
ISO - DBテーブルに性別カラムを作るなら、男=1, 女=2が標準 - Qiita


●ランキング情報

ユーザID カテゴリ 得点 登録時刻


<テーブル構成>

カラム 型数 Null AI その他
uid int 11 いいえ いいえ
category int 2 はい いいえ
point int 11 はい いいえ
create_time varchar 255 はい いいえ


<サンプルデータ>

uid : 1
category: 1
point : 2500
create_time: 関数(UNIX_TIMESTAMP)

uid : 2
category: 2
point : 500
create_time: 関数(UNIX_TIMESTAMP)

phpからMySQLの接続

MySQLへの接続を行います。
接続を行う際に以下の情報が必要となるので準備が必要です。

MySQL接続ドメイン
MySQLユーザID
MySQLユーザPW

ドメイン名についてはローカルでおこなうので、「localhost:3306」で接続します。

接続するためのPHPファイルを作成します。


MySQLへの接続ですが、以前まではmysql_connectで接続できていたのですが、PHP 5.5.0から非推奨となり、使用できなくなりました。
mysql_connectを使うと、「それは古いからmysqliかPDOを使って」と言われてしまいます。
今回はmysqli形式で書いたものを紹介します。


mysql_connect.php

<?php

// MySQLに接続(ドメイン名、ユーザID、パスワード、データベース名).
$mysqli = @new mysqli( 'localhost:3306','ユーザID','パスワード', 'データベース名' );
if($mysqli->connect_errno) {
  die( 'Connect Error: ' . $mysqli->connect_error() );
}

// データベースのコードを選択.
if(!$mysqli->set_charset( 'utf8' )) {
  die( 'Error loading charaset: ' . $mysqli->connect_error() );
}
?>

このmysql_connect.phpをデータを取得する際に呼び出していきます。


接続テストを行うには、このファイルを
\xampp\security\htdocs\php 等の中にでも入れて、

http://localhost/security/php/mysql_connect.php

で呼び出します。
特にエラーがでなければ成功です。

データを取得する

データベースで登録されてあるデータを取得していきます。
まずPHPからデータを取得していき、Jsonの形で出力し、C#でUnityの画面にDebug.Logで出力します。


・引数なしのデータ取得

PHP側 user_get.php

<?php

// 接続処理.
require_once( dirname(__FILE__). "/mysql_connect.php" );

// 出力形式の設定
header( 'Content-type: application/json; charset=UTF-8' );

$query = "SELECT `uid`, `sex`
          FROM `user_table`";

// クエリ文の実行.
if($result = $mysqli->query( $query )) {

	$user = array();

	// 結果をオブジェク形式で出力.
	while($data = $result->fetch_object()) {
		$user[] = array(
				'uid'=> $data->uid,
				'sex'=> $data->sex,
				);
	}

	// 出力結果が空の時は、nullを出し、JSON形式で変換.
	if(empty($user)) {
		$user = null;
		echo json_encode( $user );
	}else{
		echo json_encode( $user );
	}

	// 結果を解放.
	$result->close();
}

// 接続を切断.
$mysqli->close();
?>

接続テストをしたい場合は、
http://localhost/security/php/user_get.php

にアクセスします。


<Unity側>

今回はJSONObjectを使って取得しますが、UnityではLitJsonを使っても取得できますので、
両方覚えておくと良いです。

JSONObjectを使うには、以下のライブラリをUnityのPluginsディレクトリに入れる必要があります。
http://wiki.unity3d.com/index.php?title=JSONObject#Download

const string LOCALDOMAIN = "ローカルドメイン";
string m_url = "http://" + LOCALDOMAIN + "/security/php/user_get.php";


void Start() {	
 StartCoroutine(GetUser());
}

IEnumerator GetUser() {
 WWW result = new WWW(m_url);
 yield return result;

 if(result.error == null) {
 	JSONObject rdbUserGet = new JSONObject(result.text);
 	for(int i = 0; i < rdbUserGet.Count; ++i) {
 		JSONObject jsonPos = rdbUserGet[i];
 		JSONObject jsonUid = jsonPos.GetField("uid");
 		JSONObject jsonSex = jsonPos.GetField("sex");
 		string uid = jsonUid.int;
 		string sex = jsonSex.int;
 		Debug.Log("ユーザID:" + uid + "性別:" + sex);
 	}
 }
}


[出力結果]
f:id:lo25131:20151017234940j:plain



・引数ありのデータ取得

PHP側 user_get2.php>

引数ありの場合はPHP側では、値を渡してもらうために変数を宣言しておきます。
今回はuidをもらって、そのuidのデータを返してもらうようにします。

●変更点

$uid = $_REQUEST['uid'];

$query = "SELE `name`, `sex`
          FROM `user_table`
          WHERE `uid` = '$uid'";

接続テストをしたい場合は、
http://localhost/security/php/user_get2.php?uid=

にアクセスします。

よくWebのURLみたいに 「?カラム=値」 という形で、
urlの後ろに引数として渡します。 


<Unity側>

Formを作成して、値を送信してからその結果を受取る形になります。

●変更点

WWWForm form = new WWWForm();
form.AddField("uid", uid);
WWW result = new WWW(m_url, form.data);



データを登録する

データベースのテーブルにデータをセットします。


PHP側 ranking_post.php

<?php

// 接続処理.
require_once( dirname(__FILE__). "/mysql_connect.php" );

// 出力形式の設定
header( 'Content-type: application/json; charset=UTF-8' );

$uid = $_REQUEST['uid'];
$category = $_REQUEST['category'];
$point = $_REQUEST['point'];
$createTime = time();

$query = "INSERT INTO `ranking_table`(`uid`, `category`, `point`, `create_time`)	 
          VALUES('$uid', '$category', '$point', '$createTime')";

// クエリ文の実行.
if(!$result = $mysqli->query( $query )) {
	die( 'Error data set: ' . $mysqli->connect_error() );
}

// 接続を切断.
$mysqli->close();
?>


<Unity側>

const string LOCALDOMAIN = "ローカルドメイン";
string m_url = "http://" + LOCALDOMAIN + "/security/php/ranking_post.php";

void Start() {
	StartCoroutine(PostRanking(1, 2, 2555));
}

IEnumerator PostRanking(int uid, int category, int point) {
	WWWForm form = new WWWForm();
	form.AddField("uid", uid);
	form.AddField("category", category);
	form.AddField("point", point);
	WWW result = new WWW(url, form.data);
	yield return result;
	if(result.error == null) {
		Debug.Log("登録完了!");
	}
}

まとめ

Unityでデータを保存する方法はいくつかありますが、今回はMySQLからデータを
送受信する方法を紹介しました。
内部でのデータの保存だと、PlayerPrefs(クラス)、SQLite(データベース)
を使用する方法もあります。
このブログでは紹介しませんが、気になる方はそちらも利用してみると、どん
なときにそのデータの保存方法を使用したらいいか、
使い分けが可能になると思います。

UnixTimeを日本語表記に変換する

UnityでUnixTimeを日本語表記に変換した例
現在時刻を求めるときに使います。

例として、1443627101というUnixTimeを変換

/// <summary>
/// UnixTime.
/// </summary>
private int m_unixTime = 1443627101;

void Start() {
  string unixTime = UnixTimetoDate(m_unixTime);
  Debug.Log(unixTime);
}

/// <summary>
/// UnixTimeを渡して年月日時秒に変換.
/// </summary>
/// <param name="unixTime">UnixTime.</param>
/// <returns>UnixTimeを年月日時秒に変換した文字列.</returns>
private string UnixTimetoDate(int unixTime) {
   var localDate = new System.DateTime(1970, 1, 1, 0, 0, 0, System.DateTimeKind.Utc).AddSeconds(unixTime).ToLocalTime();
   string Str_unixTime = localDate.ToString("yyyy" + "年" + "MM" + "月" + "dd" + "日" + "HH" + "時" + "mm" + "分" + "ss" + "秒");
   return Str_unixTime;
}


出力結果:

2015年10月01日00時31分41秒

localData.ToStringの中の秒や分を除けば、分までの表記というのもできます。


例: 分までの表記

localDate.ToString("yyyy" + "年" + "MM" + "月" + "dd" + "日" + "HH" + "時" + "mm" + "分");

UnityによるProcess出力の日本語文字化け対策の奮闘記録

はじめに


前回紹介した外部プロセスの記事の内容から、Subversionバージョン管理システム)のプロセスをUnityから呼び出す処理を試しみました。


しかし、その記事にも書いていたのですが、Subversionから出力を取る際に、日本語の文章が文字化けしてしまいました。
WindowsMacで両方で試してみたのですが、どうやらMacのみ文字化けしており、その問題点と解決方法をまとめてみました。


問題点


------以下、文字化けした結果-----


WindowsSubversion
f:id:lo25131:20150929231926j:plain                  

WindowsのUnity
f:id:lo25131:20150929232001j:plain


MacSubversion
f:id:lo25131:20150929232220p:plain

MacのUnity
f:id:lo25131:20150929232140p:plain

このようにMacのUnityの出力だけ、文字化けしてしまいました。
「?\227?\129?\138?.......」

Shift-JISかな?UTF8に変換してあげればいいかな。

試行錯誤中


~以下、試行錯誤の記録~


・出力のエンコード設定を変更

StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8;

結果:失敗


・取得したデータを一度Unityのオブジェクトに入れる

string data = args.Data;
Debug.Log(data);

結果:失敗


・取得したデータをUTF8に変換

System.Text.Encoding enc = System.Text.Encoding.GetEncoding("Shift_JIS");
System.Text.Encoding utf8 = System.Text.Encoding.UTF8;

byte encByte = enc.GetBytes(data);
byte
encConByte = System.Text.Encoding.Convert(enc,utf8,encByte);
string encText = utf8.GetString(encConByte);
Debug.Log(encText);

結果:失敗

対策の発見へ


Twitterで聞いてみました。

> 参考となるサイトを紹介してもらいました。ありがとうございました。

MacでSubversionを利用する際に発生する文字コード問題の解消方法 - Shuichi’Tec


どうやらSubversionの方に問題があったようで、一度Macに入ってるSubversionをアンインストールして再度インストールしてみました。
私のMacではXcodeのCommadn Line ToolsのSubversionを使っていたため、Xcode自体を一回アンインストールしました。


そして新たに上記のサイトを参考にしてSubversionをインストール。
以下コマンド

sudo port install subversion + unicode_path

そのままコマンドを叩くと、Subversion1.9.2がインストールされました。
見た目ではヘルプ等の文字が日本語化されていました。


次に、UnityでSubversionを起動させてみます。
しかし、svnコマンドは使えないと言われてしまいます。

どうやらターミナルで叩いているsvnコマンドと、Unityから起動するプロセスのsvnコマンドでは起動しているパスが異なっているようです。
↑解決方法がわからないので、御存知の方いらっしゃればご教授よろしくお願いします。


なので直接先ほどMacPortからインストールしたSubversionのパスからSubversion
プロセスを起動します。
Subversionのパスは、ターミナルから取得することができます。

which svn

多分デフォルトは以下の場所にインストールされるかと思います。
> /opt/local/bin/svn

上記の場所を指定してプロセスを立ち上げます。

すると、先ほどの文字化け文字に変化がありました。


以下変化画像
f:id:lo25131:20150930000115p:plain

{U+30C6}{U+30B9}{U+30C8}.....

見覚えのあるコードが出てきました。

30C6 -> テ
30B9 -> ス
30C8 -> ト

[参考サイト]
ASCIIコード変換機


あとはこれをすべて文字に直す作業です。

文字化けコードの変換


変換する流れとしては…

①一行分のログが変換できるかどうか (できる場合は変換、できない場合はそのまま取得)
②文字化けコード全てを取得
③文字化けコードの中のASCIIコードのみ取得
④ASCIIコードを16進数に変換して文字列に変換
⑤元の文字化けコードの場所に変換した文字列を置き換える


これをプログラムにしていきます。

以下プログラム

// 出力された文字列.
string data = args.Data; 

if(!string.IsNullOrEmpty(data)) {
  string encData = EncodeBinaryToString(data);
  Debug.Log(encData);
}

/// <summary>
/// 文字化けした文字列を日本語文字列に変換.
/// </summary>
/// <param name="data">コンソール出力文字.</param>
/// <returns>文字化け文字を日本語変換された文字.</returns>
private string EncodeBinaryToString(string data) {
  string Result = null;
  
  List<string> asciiArray = new List<string>();
  List<string> codeArray = new List<string>();

  // ASCIIコードのみを取得するためのパターン.
  string getAsciiPattern = @"(\{U\+)(?<Result>.+?)(\})";

 // 文字化け文字列全てを取得するためのパターン.
 string getcodePattern = @"(\{.*?\})";

  System.Text.RegularExpressions.Match asciiMatch;
  System.Text.RegularExpressions.Match codeMatch;

  // マッチされない場合はそのまま返す.
  if(!System.Text.RegularExpressions.Regex.IsMatch(data, getcodePattern)) {
   return data;
  }

  // 文字化け文字の取得.
  codeMatch = System.Text.RegularExpressions.Regex.Match(data, getcodePattern);

 // マッチしている間.
 while(codeMatch.Success) {
     codeArray.Add(codeMatch.Value);

     // 次のマッチングへ.
     codeMatch = codeMatch.NextMatch();
  }

  // ASCIIコードのみを取得.
  asciiMatch = System.Text.RegularExpressions.Regex.Match(data, getAsciiPattern);

  while(asciiMatch.Success) {
     asciiArray.Add(asciiMatch.Groups["Result"].Value);
     asciiMatch = asciiMatch.NextMatch();
  }

  List<string> japaneseCharArray = new List<string>();

  // ASCIIコードを日本語文字列に変換する.
  for(int index = 0; index < asciiArray.Count; ++index) {
     // 16進数を基に32bit符号付き変数に変換.
     int intCode16 = Convert.ToInt32(asciiArray[index], 16);

     // char型に変換.
     char conChar = Convert.ToChar(intCode16);

     // string文字列に変換.
     string strChar = conChar.ToString();
     japaneseCharArray.Add(strChar);
  }

  // 元の文字列を日本語文字列に置き換える.
  for(int index = 0; index < japaneseCharArray.Count; ++index) {
     data = data.Replace(codeArray[index], japaneseCharArray[index]);
  }

  encResult = data;
  return encResult;
}


結果

f:id:lo25131:20150930005059p:plain


コードについて


ASCIIコードから文字列に変換するプログラムは以下のQiitaの投稿を参考にしました。


全体的に、もうちょっとスマートにならないかどうか考えてるけど、これで精一杯でした。


まとめ

結果としては日本語に置き換えることができました。


流れとしては...

Subversionのアップデート → 新しいSubversionで起動する → 文字化け文字を変換する

という感じです。


しかし一つ問題として、濁点・半濁点がなくなっています。
考えられる理由としては、Subversionのインストール時にunicode_pathのオプションが
うまく実行されていなかったため、濁点・半濁点が文字化けした時に
ユニコードとして出力されていなかった可能性があります。


例えば本来、

デスト → 30C7 30B9 30C8  のはずが

テスト → 30C6 30B9 30C8  として置き換わっています。


こちらについては原因を特定中ですが、やはりインストールに失敗しているというところが問題っぽいです。


今回の文字化けからの日本語への変換に関して、かなり強引に変換してみました。
もしかしたら設定次第でなんとかなるのかもしれませんが、こんな風にしても変換できるということを紹介させていただきました。