読者です 読者をやめる 読者になる 読者になる

てんちょーの技術日誌

自分がつまづいたこととかメモ

【Unity】UNET(PC-Android) をしてみたお話

はじめに

UNETの基本的な使い方は我らが凹みTipsにまとまっています。

tips.hecomi.com

UNETのよくわからなさ加減はizmさんの記事の太字だけでもさらっと目を通すと、つらさがわかると思います…

qiita.com

いくつか抜粋します

対応策:スクリプトの名前を動くようになるまで適当に変えます。(つらい)

とか

NetworkSimulationは期待した通りに動きません

かなしみ

今回は個人的にハマったりしたポイントや理解しにくいとこをまとめてみます。 Android6.0.1(Galaxy S6 Edge)-PC(Windows 7)間の通信がメインです。

PCをHost、AndroidをClientとして考えます。

Unityは5.6.0f3です。

ちなみにUnityをまともに初めて2-3ヶ月くらいなので、間違いとかは多めに見て欲しいです…(間違いがあれば教えてください)

ハマリポイントたち

Androidでの実機テスト

いちいち実機に移してテストするのは面倒だったのでPCでテストして、区切りのいいとこで実機テストしてました。

怠惰ゆえにUnity-Android間でテストしたくなりますが、出来ないっぽい…?

一応NetworkManagerのnetworkAddressにPC側のIPAdressを設定していても駄目でした。 どうやら、Client側がHost側を見つけられない → TimeOut のようなので 同一LAN内からUnityEditorが見えてないのかなと思ったり。

そのため、毎回PC版ビルドとAndroidに転送しなければテストできない… (方法があれば教えてください…)

ちらっとようてんさんに聞いたところ、Android側が悪さをしている可能性があるらしく、カーネルをゴニョゴニョするといけるかもとのこと。(やりたくない

悩める民たち(解決してなさそう)

https://forum.unity3d.com/threads/wifi-issues-on-lan-or-android-client-windows-server.336183/#n10

この辺ググっても全然でなくてみんなPhoton使ってるのかな…

この記述をみてもしや…と思って出来たくらい情報がない…

ネットワーク上の別PCと通信するには、ビルドしたアプリを配布して行う。LAN Client にホスト側のIPを設定するのを忘れずに。

qiita.com

おまけ

実行時に勝手にServer、Clientを判断してStartするのはこんな感じで書きました。

こいつはNetworkConnector.csとして作成して、NetworkMangerがAttachされてるGameObjectに 一緒にAttachしてます。

using UnityEngine;
using UnityEngine.Networking;

public class NetworkConnector : NetworkBehaviour
{

    NetworkManager manager;

    //こいつを用意しておくとInspectorから変えれてPC上でのデバッグに割りと便利 お好みで
    public bool isStartAsHost = true;

    public string serverIPAdress = "(対象のPCのIPAdressをいれる 指定しないとlocalhostっぽい)";

    // Use this for initialization
    void Start()
    {
        manager = GetComponent<NetworkManager>();

        if (Application.platform == RuntimePlatform.WindowsEditor || Application.platform == RuntimePlatform.WindowsPlayer)
        {
            if (isStartAsHost)
            {
                manager.StartHost();
                Debug.Log("Start as Host");
            }

            else
            {
                manager.networkAddress = serverIPAdress;
                manager.StartClient();
                Debug.Log("Start as Client");
            }

        }

        else if (Application.platform == RuntimePlatform.Android)
        {
            manager.networkAddress = serverIPAdress;
            manager.StartClient();
            Debug.Log("Start as Client");
        }
    }

}
}

参考

simplestar-tech.hatenablog.com

Attribute

UNETはAttributeをつけることで、いろいろ挙動を制御できます。 Serverだけで実行したい関数、ClientからServerにデータを送りたいなどなど。

あちこちみても、結局この図に集約されている気がします。

f:id:shop_0761:20170420000254j:plain

まず、冒頭の凹みTipsの記事より

まず大前提として、UNET では同じゲームのコードでクライアント・サーバ共に動かしています。サーバ専用の言語を覚えたりする必要はありません。

これを把握していないと混乱して死にます。(死んだ)

ちょっと言い換えると、"一つのソースでServer、Clientが共存している" といったイメージです。

なので、同じソース内でServerとClientのやり取りをすることになります。 (ココらへんは混乱ポイントな気がする)

ので、"この変数は今Clientで更新したんだな"とかを把握しておかなきゃいけないわけで…

イメージ図を書いてみました。こんな感じで共存しています。緑のやつが実際に呼べる関数です。

f:id:shop_0761:20170420012553p:plain

Attributeの中で一番ハマったのはCommand / ClientRpc Attributeです。

またまた凹みTipsより

クライアントからサーバへのコマンドの送信 Cmd から始まる関数に Command アトリビュートをつけるとサーバで実行されるクライアントから呼び出せる関数になる

サーバからクライアントの RPC(リモートプロシージャコール) Rpc から始まる関数に ClientRpc アトリビュートをつけるとクライアントで実行されるサーバから呼び出せる関数になる

ポイントは “○○で実行される△△から呼び出せる関数” の部分です。

ちょっと自己流に言い換えるなら “実行するのは○○にある関数だけど、呼べるのは△△からだけだよ” って感じだと思ってます。

この"△△からだけ"ってのが重要で、

凹みTipsにもある

ただし、サーバかクライアントかといったことや、参照しているオブジェクトが各クライアントから見てローカルなのかリモートなのかは強く意識する必要があります。

ここに繋がるのではないかと思ってます。

もちろん呼び出すところを間違えるとエラーが出ます。

ただし、izmさんの記事より

[ServerCallback] クライアントから呼ばない時に付けますがエラーや警告が出ません。

同様に

[ClientCallback] サーバーから呼ばない時に付けますがエラーや警告が出ません。

ので注意しましょう。

— 2017/04/24追記

また、NetworkManagerからPlayerとしてSpawnしたPrefabには権限(LocalPlayerAuthority)が付与されます。

権限がない他のPrefabからCommand Attribute のついた関数を呼び出そうとするとWarningが出ます。

Trying to send command for object without authority.

ので、基本的にはCommandはPlayerで使うものになりますが、Unity5.2から他のオブジェクトにも 権限を持たせられるようになったそうです。

詳しくはこちら

docs.unity3d.com


NetworkBehaviour を継承しておいて、 isServer、isClient、isLocalPlayerなどを使って分岐しましょう。

ただこれらも注意しないと同時にフラグが立ったりする可能性があるので、一応InspectorをDebug表示にするなどしてEditor上で確認するのがよいかと。

例) Hostとして起動した時のPlayer

f:id:shop_0761:20170420111259p:plain

参考

docs.unity3d.com

SyncVar

変数をServerとClientで同期できます。 が、

izmさんの記事より

変数をサーバーからすべてのクライアントに自動的に同期するために使用されます。クライアントからそれらに割り当てないでください。クライアント側での割り当ては無意味です

はい。 Clientで更新した変数はSyncVar Attributeで同期できません。

ので、こんな感じで書きました。

[SyncVar (hook = "OnUpdatePlayerID")]
int playerID = 0;

[Client]
void setPlayerID(int id){
  playerID = id;
  CmdUpdatePlayerID(id);
}

[Command]
void CmdUpdatePlayerID(int id)
{
    playerID = id;
}

[Client]
void OnUpdatePlayerID(int id)
{
  //処理
}

流れ

  1. ClientのどこかでsetPlayerID() -> ClientのplayerIDを更新 Syncされない
  2. CmdUpdatePlayerID() -> ServerのCmdUpdatePlayerID()を実行
  3. Server側のplayerIDが更新されるのでここでSyncする
  4. ついでにhookしておいたOnUpdatePlayerID()が呼べる(ただし、SyncしたのはClient側なのでClientで呼ばれる)

と、これを同一コード内でやるので、ごっちゃごちゃする可能性が…

hookのところはあってもなくてもおっけーです。(hook あまり自信ない…

hookに関してはこちらを

hiyotama.hatenablog.com

Network Message

Attributeよりわかりやすい気がします。(ただ、こいつも同じコード内でやり取りするとこを書くけど)

参考

docs.unity3d.com

適当に書いてみたやつを貼ります。Network Messageを使いたいコード内に書いちゃえば使えます。(やっつけ) まあFindしてるのは重たいのでホントはやらないほうがいいですが。

(手直ししてる部分があるので、あやしいとこがあるかも)

public NetworkClient client;
int playerID;

//MessageTypeを判別するのに使う
public class MyMsgTypes
{
    public static short MY_MES = 1001;
};

//送りたいMessageのクラス MessageBaseを継承しておくこと
public class MyMesssge : MessageBase
{
    public byte[] bytes;
    public Vector3 pos;
    public bool isHit;
    public int playerID;
}

public void SetupClient()
{
    NetworkManager manager = GameObject.Find("NetworkManager").GetComponent<NetworkManager>();
    Debug.Log("Find NetworkManager: " + manager);
    client = manager.client;
    client.RegisterHandler(MsgType.Connect, OnConnected);
    Debug.Log("Setup Client");
}

//OnHogehogeを登録しておく
public void SetupServer()
{
    NetworkServer.RegisterHandler(MyMsgTypes.MY_MES, OnHogehoge);
    Debug.Log("Setup Server");
}

//繋がったときに呼ばれる
public void OnConnected(NetworkMessage netMsg)
{
    Debug.Log("Connected to server");
}

//送る時用 適当に作った
//MyMessageをnewして、値をセットして、client.Send()すればなんでもいいはず
//Client Attributeをつけるといいかも
public void SendMes(){
    MyMesssge msg = new MyMesssge();
    msg.bytes = ...
    msg.pos = ...
    msg.isHit = ...
    msg.playerID = ...
    client.Send(MyMsgTypes.MY_MES, msg);
    Debug.Log("Send Msg");
}

//受け取ったときに呼ばれる 今回はServer側に登録してあるので、Serverで呼ばれる
public void OnHogehoge(NetworkMessage netMsg){
    MyMesssge msg = netMsg.ReadMessage<MyMesssge>();
    byte[] bytes = msg.bytes;
    Vector3 pos = msg.pos;
    bool isHit = msg.isHit;
    int playerID = msg.playerID;
    Debug.Log("recieved Msg");
}

RegisterHandlerでデリゲートを追加する感じで使えると思います。

SetupClientはあってもなくてもいいですが、client.Send()は使えるようにどこかでclientを格納しておく必要があります。

これはClient→Serverですが、RegisterHandlerを同じように使えば逆もできるはず…(やってないけど)

サンプルがpublicになってたので、なんとなくpublicにしてあります(変な地雷を踏みたくないので)

– 2017/04/25追記

playerにIDを割り振りたい

参考

hiyotama.hatenablog.com

だいたいどこを見ても、

playerNetID = GetComponent().netId;

で持ってきています。確かにユニークです。

ただ、playerに0始まりでIDを振りたいとなると話は別です。

ここから想像のお話なので、あってるかはわかりません。詳しくはソースを読んで下さい。

この netId 恐らくScene上のNetworkIdentity Component の数に依存している気がします。

というのも、netIdで取ってきた数値がなぜか 4 始まりだったので、

playerNetID = GetComponent<NetworkIdentity>().netId - 4;

とかやってました。

ですが、他のprefabでNetworkIdentityを使うことになったので、追加するとErrorが吐かれてしまいました。

つまり、今後SceneにUNET周りを使いたいPrefabなりなんなりが増えるたびにIDがズレます。

しかも恐らくplayerはSceneの最後でSpawnされるのかどんどん後ろにずれていく気がします。

        public override void OnStartLocalPlayer()
        {
            if (isClient)
            {
                playerID = GameObject.FindGameObjectsWithTag("MainCamera").Length - 1;
            }
        }

とかで取ってくるほうがよい気がしました…

想像おわり。

おまけ -AndroidでScreenShot-

普通はApplication.CaptureScreenshotを使うらしいのですが、 これは真っ黒になるので使えませんでした。

こちらを参考にRenderTexture経由のほうがよいです。

qiita.com

ついでに、保存先はAndroidの場合 Application.dataPath ではなく、 Application.persistentDataPathのほうがいいそうです。(というかこっちでないと保存できない)

PCに送りたいときはできたbyte配列をNetworkMessageで送ってやればよいです。 ただし、サイズが大きいと怒られるので分割して送って受信側でくっつけてやればよいです。 (正しく送れるとは言っていない)

おまけ2 同一LAN内のはずなのに繋がらない

Network初心者あるある(だと勝手に思ってる)

テスト環境で複数Wifiが飛んでいて、ついつい全て端末に登録しておくと 勝手にWifiを繋ぎ変えられてデバッグで死ぬ可能性があります。

そのため、1つしか登録しないとか、繋がらないときは端末のIPAdressに pingを飛ばして確認したほうがよいです。(1時間くらい悩んだ)

あとはTimeOutの時間を伸ばしておくと良いかもです。 NetworkManager → timeouts → Connect Timeout で設定できます。

まとめ

  • PC-Android間のデバッグはPC側もビルドしたものを
  • Command / ClientRpc Attributeはちょっと厄介かも
  • Network Message のほうがわかりやすい!便利!

さいごに

デバッグがつらい!! 毎回ビルドしなきゃいけない!!

聞いた話によるとPhotonのほうが楽らしいです。 そっちは見てないのでわかりません。

以上ここ1週間くらい格闘している(進行形)お話でした。 (つづくかも

なにかあれば@shop_0761まで

あなたにUNETのご加護があらんことを

【UE4】UnityChanLIVE-UE4Ver-を作ってみた & 公開してみた

はじめに

github.com

前々からどこまでいけるか作ってみたかったので、作りました。

面倒事が多かったのでしんどかったですが、とりあえず形になりました。

動画

youtu.be

githubにあげてみましたので、参考にどうぞ

f:id:shop_0761:20170409004354p:plain


2017/05/07 追記

Androidに移植してみました

プロジェクト

github.com

とりあえず実行したい方は、現段階での.apkがあるのでそれも配布してます

AndroidSDKがあれば、端末をPCに繋ぎzip展開後にInstallからはじまる .bat を実行すれば入る…はず

なければ .apkが同梱されてるのでそちらを直接入れるのがいいかと


問題点

  • Sound Visualization Plugin の使い方がいまいち分からないため、音量に応じて変わるやつは全てCSV書き出し&floatCurve
  • 髪がいい感じに揺れない

Unity側で髪の揺れまでAnimに焼き付けたもの(300MBくらい)はあるのですが、FBXにできないため詰んでる

Mayaに持っていくフリーのアセットを見つけてやってみたものの、Rotation周りで死亡しました。Exportしっぱい。


2017/05/07追記

  • メモリ周りがアレなので、一周すると安定するはず…(一周目は最初の2回ほどフックします…

こだわりポイント

最適化するにあたってこだわったところを忘れないうちに書いておきます

  • UnityChan Shader は手を入れない (ほぼそのまま使う
  • UE4内で完結させる (Mayaとかでモデルをいじったりしない
  • Particleはゼロにしない
  • backScreenを一枚絵でごまかさない

まとめ

時間を見つけて、大変だったとことかを書いていこうかなと思います。 なにかあれば、@shop_0761までご連絡くださいまし。


2017/05/07追記

Android版はmasterとbranchを分けてあるので、Androidへの最適化の練習になればと思います


【GAS】GoogleAppsScriptを使ってイベントごとの持ち物をslackに通知するやつを作ってみた

はじめに

ちょいちょいイベントに参加させてもらう機会が増えてきました。

遠征が多いので、泊りがけが多くよく持ち物リストを作ります。

が、毎度作り直してEverNoteでチェック…そして追加忘れ、忘れ物…のパターンが何回もありました。名刺忘れたり…

ので、最近お気に入りのGASで作ってみました。

今回は割りと丁寧に書いてます。 詳しい方にとっては見にくいかもですが、ご了承ください…

作成したGASはGistにあるので、そちらを参考にしてもらってもいけるかと思います。

GASとは

GoogleAppsScriptといって、Google系のサービスとお手軽に連携できるスクリプトが書けます。

ライフハック的なことがしやすくて気に入っています。

自分だけのslackチームを作ってあるのでそこで色々遊んだりしてます。

ググったら色々見つかると思うので、細かいことは割愛します。

概要

Calendarに適当に予定を追加しました。

f:id:shop_0761:20170204023918p:plain

spreadSheetには適当に値を入れてあります。

f:id:shop_0761:20170204022220p:plain

今回は見やすく黄色くハイライトされているワードがカレンダーのイベント名に入っていると、その下の持ち物が表示されます。

こんな感じ

f:id:shop_0761:20170204023543p:plain

一応複数入っててもいけます。

f:id:shop_0761:20170204023656p:plain

もちろん列は増やせます。みやすさ優先でハイライトしただけ。

持ち物は複数ワードにまたがっても重複しないようにしてあるので安心。

手順

SpreadSheet経由で作ります。(連携がラクになるので)

GoogleDriveからSpreadSheetを作って、ツール→スクリプトエディタ を選択。

f:id:shop_0761:20170204022039p:plain

するとスクリプトが書けるページが開きます。

参考

ascii.jp

GASのコードはこちら。このまま貼り付けておっけーです。

gist.github.com

ちょい足ししなきゃいけないことがあります。

コードをちょっと書き換えるところ

tokenを追加

“tokenを貼る"のところには使いたいslackのtokenが必要です。 slackにpostするのに使います。

参考

qiita.com

var token = "xoxp-hogehoge";

てな感じになります。

channel_idを追加

post先のチャンネルを入れます。

var token = "random";

とか

botNameを追加

雰囲気を出すためにbotの名前を入れます。

var botName = "もちものチェックやさん";

カレンダーを指定する

Google CalendarにはIDがあるので、それが必要です。

参考

tonari-it.com

これを"カレンダーIDを入れる"のところに入れます。カレンダーIDがhogehoge@gmail.comの時は

 var calendar = CalendarApp.getCalendarById("hogehoge@gmail.com");

こんなかんじ。

GAS側の設定

ライブラリを追加

Slack用のライブラリを追加します。

スクリプトエディタのリソース→ライブラリへ

M3W5Ut3Q39AaIwLquryEPMwV62A3znfOO

を検索して、最新版を選択します。

f:id:shop_0761:20170204025637p:plain

参考

qiita.com

Triggerを追加

GASは指定タイミングで関数を実行できるTriggerなるものがあるので、追加します。

スクリプトエディタのリソース→現在のプロジェクトのトリガーへ

毎週月曜でよければこんな感じで

f:id:shop_0761:20170204025957p:plain

毎日設定にもできますが、そのときはスクリプト

var checkDayNum = 7;

を調整してください。

デフォルトが7なのでこのまま毎日設定すると、毎日一週間先の通知が"ダブって"postされます。

ので、1とかにするのがよいかもです。

運用のしかた

こんな感じでチェックを入れて使うのがいいかと思います。

f:id:shop_0761:20170204030645p:plain

TimeStampベースで、ログを取って、全てチェックが入ったらそのpostを消す…みたいなことをしてもよかったのですが、 ちょっと面倒だったので気が向いたり需要がありそうなら作ります…

一応対象チャンネルを一掃する clearSlackMessage関数があるので、これを上手く組み合わせて使うとか…

おまけ

今回たまたまフライトの予定がカレンダーにあったので、フライトの度に持ち物通知されても…とおもったので、 それだけチェックしないイベントにしてます。

あと

getItemListAndPost(events[idx].getTitle(), false);

これをfalse→trueにすると、A列の内容がデフォの持ち物として表示されるようになるので上手く使うと便利かも。 モバイルバッテリーとか充電器とか共通の持ち物みたいな使い方とかできそう。

まとめ

思いつくまま作りました。コメントはそれなりに頑張って書きました。 なにかあれば@とかにご連絡ください。

GASは早くGooglePhotosに対応して欲しい。GAS側からGoogleDriveの指定フォルダにある画像でアルバムとか作りたい。

新しいVR内入力方法を考えてみたお話

はじめに

つい最近まで、音声認識オンリーで生活していました。

その時に思いついた新しい入力方法についてそれとなくまとめておきます。

参考はこちら

shop-0761.hatenablog.com

簡単な解説

キーボードという概念にとらわれすぎないようにと、ふと浮かんだ手法です。名前はまだありません。

勝手に意味分からない名前をつけたり、Assetの名前はありますが

使い方

50音表的なやつから、文字を掴んで空中に配置します。

それをOculusTouchのThumbStickに触りながらポイントしていくと青色になり、離すと辿った文字が入力されます。

これだけ。

この入力方法のポイント

ツイートにまとめても良かったんですが、流れちゃうので忘れないようにまとめておこうかなと。

今回のポイントは 自分でキーボード的なものを作れる ところにあります。

これだと従来のキー配列にとらわれることなく自分で生成できます。生成と言っても、大層なものではなく、キー配列を覚える/覚え直す 必要がなくラクです。

ついでに簡単なセーブ/ロード機能を付けてあります。 空間にそのまま文字を保存できるので複数個用意できれば、Twitter用によく使う3パターンを作るなんてこともできるかと。

文字をなぞる順番もなく右から左になぞっても入力できるので、ユーザーのTwitterの直近20000ポストくらいから 本人がよく使うこの入力方法用の文字列を生成する なんて研究もできそうですね。

オススメの文字配列をTwitterで共有したりもできそうです。

深く考えてなかったのですが、ViveやLeapMotionにも対応できる気がするのでコントローラー依存ではない入力方法だと思ってます。

まとめ

とりあえず整理したあとにOculusHomeのPreviewAppに更新をかけてみて、もろもろの反応を見た後にこれを作り続けるか決めようかと思います。

実際手でポイントするのは微妙な気がするので何か考えたいところですが。

興味がある方は@shop_0761等にご連絡いただければPreviewAppのテスターに招待しますー (ReviveでViveでもできるかも

VRキーボードのためにキーボードを封印したお話

はじめに

ちょっと前にGOROmanさんがこんなことを言っていました。

じゃあ実際にやってみよう!!ってことでやりました。 

マウスを封印するお話はいくつか聞いたことがありますが、キーボードを封印するお話は聞いたことがなかったので面白いかなと。

VRキーボードを除いたのはTwitterができない可能性があったので一応保険的な意味です。(結局使わなかった

条件

キーボードと名のつくものを封印します。

例として

  • PC向けの普通のキーボード
  • スマホで使えるキーボード類
  • ATM等の数字を入力する系のキーボード

などを封印しました。基準としては、数字や文字を選択してからEnterで確定するものをキーボードと定義しました。

事前準備

使ってるマイクはこれ

http://www.yodobashi.com/ec/product/100000001001262667/index.html

ATM

Cortana

ピクチャパスワード

kiritsume.com

windows音声認識

特に書いてませんが、Siriのセットアップもしました。

だが

音声認識ツールの使い心地

Cortana

対話式なので、一気にしゃべらないといけない点を除いて多分1番精度がいい。

だができることが少ない。もったいない。後述のwindows音声認識の機能を全てCortanaで出来るようにすればもっといい。

認識精度が良すぎなので、これを作った。なお全て音声認識で記事を書いてます。

スクリプトはさすがにコピペ祭りですが。

shop-0761.hatenablog.com

windows音声認識

windowsの操作が色々できるので便利っちゃ便利。 CortanaだとEnterができないので、その度にこいつでEnterを入力していました。

一応ここまで出来る。

未来感ありますね!!  ただ非常に面倒。(何回も撮り直しをしている

コマンド一覧はこちらに。

https://support.microsoft.com/ja-jp/help/12427/windows-speech-recognition-commands

多分こいつは教育できるので精度は上がる…はずなんですが、

と、ほぼ部屋に一人の状態かつ、BGMもかけられない感じでアレです はい。

Siri

Siri自体も簡単なセットアップがあるのですが、なぜかHeySiriで起動しない…

それもあってあまり使っていない…

けど、副産物的に利用できるようになる音声入力がありました。

weekly.ascii.jp

こいつが意外と使えます。対話式ではないので、多少考えながら発話できます。

ただ、途中で変換予測が変わったりして荒ぶったりすることもありますが。

iPhoneにもAndroidのパターンロックが使えるようになって欲しい…(指紋認証できるけど、ミスると結局キー入力なのでロックを切ってた

使ってみた感想

いいところ

意外と生活できるし、メールも返信できました。

ただ時々思ったように変換してくれなくて、不必要な部分をカットしたり、ペーストしてツギハギしたりしてました。

主婦さん(@Somelu01)さんとも普通にDMしたりできました。

そして、手が疲れない!!大事!!

悪いところ

誤認識時の修正が面倒。 固有名詞が認識できない。(これは辞書がないのでしゃーないけど

打ちたい内容がダダ漏れ。 居間とかでTwitterが出来ないし、話しかけたと思われてしまう。

コードが書けない。

不思議なお話

これ、結構不思議な話で、ある程度意識的に口を閉ざしている場面が幾つかあり、なぜか無口になる時がありました。

多分なんですが、音声認識される環境に居続けると余計な発言までも認識されてしまうと思ってしまい不必要な発言を避けてしまうのかも。

これはこれで卒論が書けてしまいそうですね…

まとめ

音声認識 割りといける。Juliusも使ったことがありますが、未調整のと比べるとかなり精度がよくなってきています。

一度Cortanaを封印しないで使ってみては?

コルタナの音声認識の結果をクリップボードに貼り付けるスクリプトを書いてみた

はじめに

キーボードを封印して音声認識だけで生きています

この記事も音声認識だけで書いています

コルタナの音声認識の結果がかなり良いのでそれを利用したいと思いパワーシェルのスクリプトを書いてみました( なおキーボード封印中

今回書いたもの

スクリプト更新しました( 2017年1月4日 簡単なDebug出来るようにしました

追記 2017/01/04

以下のスクリプトをパワーシェルに貼り付ける分には動くっぽいのですが、.ps1にするとアウトっぽいので取り急ぎdropboxのリンクを貼っておきます

時間がある時に修正します…

www.dropbox.com

while(1)
{
  $psArray=[System.Diagnostics.Process]::GetProcesses()
  $str=""
  foreach ($ps in $psArray){
    if($ps.MainWindowTitle -like "*Microsoft Edge"){
      #[System.Console]::WriteLine("Microsoft Edgeを発見 Handle: " + $ps.Handles + " MainWindowTitle: " + $ps.MainWindowTitle)
      Add-Type -AssemblyName system.Windows.Forms
      $cp=[Windows.Forms.Clipboard]
      $ps.MainWindowTitle.foreach{
        if($_ -match "(.*)\s[-]\sBing"){
          #[System.Console]::WriteLine("Bing検索してるMicrosoft Edgeを発見")
          $str=$matches[1]
          if($str -match "コピー終了"){
            [System.Console]::WriteLine("終了します")
            $ps.CloseMainWindow()
            $ps.Close()
            exit
          }
          $cp::SetText($str)
          [System.Console]::WriteLine("$str")
          $ps.CloseMainWindow()
          $ps.WaitForExit(3000)
          $ps.Close()
          break
        }
      }
    }
  }
}

これをパワーシェルのスクリプトで起動します

コルタナは反応に困ったらマイクロソフトエッジのbing検索を使うので、

マイクロソフトエッジのプロセスを監視してそのメインウィンドウのタイトルから正規表現で認識結果を切り取ります

追記ここから

スクリプトを更新しました

これでコピー終了というとスクリプトを停止できます

ダブルクリックで実行できるファイルを作る

このスクリプトをメモ帳などに貼り付けて、.ps1形式で保存した後に、ショートカットを作成します

そのショートカットのプロパティからリンク先の先頭に以下のように追加します

powershell -NoProfile -ExecutionPolicy Unrestricted "ファイル名"

これで適用するとpowershellの部分が勝手にpowershellがある場所のパスに変わりますがおっけーです

実質、powershell~Unrestricted までコピーして、ファイル名の前に貼っ付ければ終わりです

そうするとダブルクリックで起動できます

後はpowerShellが起動するので、コルタナに話しかけてbing検索する際にMicrosoft Edgeが一瞬起動しますが、 勝手に閉じて、クリップボードにその結果が貼り付けられてます。

ログが一応powerShellの方に表示されます。

追記ここまで

まとめ

パワーシェルのスクリプト初めて書きました

人に読ませる文書にするにはちょっと大変だけど音声認識でとりあえずここまできました

これでとりあえず快適にツイッターができます

【UE4】OculusTouchでHapticEffectが使えないとき

PlayHapticEffectが動かない

Touchのコントローラの振動にはPlayHapticEffectを使えとあります。

developer3.oculus.com

要約すると、ここからHaptic用アセットを作って適用できるよと。

f:id:shop_0761:20161023023737p:plain

  • Haptic feedback Effect Buffer 数値指定
  • Haptic feedback Effect Curve カーブで指定
  • Haptic feedback Effect Sound Wave 音声ファイルから生成

と3つあります。

今回は適当にカーブを作りました。

f:id:shop_0761:20161023023959p:plain

でHapticEffectに入れて終わり。あとは好きなところで。

f:id:shop_0761:20161023024214p:plain

これで使えるようになります。

しかし、手を抜きたいあまり、Riftのセンサーを片手で塞ぎながら空いてる手でデバッグすると反応しませんでした。

どうやらTouchを持った時に生じる揺れ(人の手は完全に静止しないので)をTriggerにしてるようです(勘)。

なので両方持つか、ちゃんと被るか、足にでもつけるかしないと振動しません。