imog

主にUnityとかの事を書いています

Chef実践入門を読んでいる 1

先週買ったChef実践入門のログを残すことにした。 www.amazon.co.jp

Chefは業務で使われているのでレシピを読んだり軽い修正のPRはしたことあるが、1から自分で書いたことはないのでやってみようと思った。サーバサイドに疎いし。

書いたものは下記のリポジトリにpushしていく github.com

所感を事細かに書いていった方が身につきそうだけど、きつくて続かなそうだから印象に残ったとこだけ書いていく

今日の進捗 2.7まで

  • centos6.7(本は6.5だが最新)をインストールしたよ
  • chef soloをvagrant上に入れてゲストOS上でレシピ書いていったよ
  • ホストOSにknife solo入れて手元で構築するようにしたよ
  • dstat、mysqlapacheのレシピを書いたよ
  • ついでにServerspecも入れて上記の三つがインストールされているかのテストも書いたよ PR

特につまづくことはなかった。 actionで出てきた enable start がそれぞれ sbin下の chkconfig service の実行に相当すると知ったが、そもそもsbin下のコマンドを全然知らなかった。知見を得た。

Serverspecで今回はdstat、mysql、httpで三つテストファイル区切ったんだけど、どのくらいの粒度が良いのだろうかと気になった。ツールごとに区切っていくとかなり増えそう。

UnityWebRequestについてちょっと調べてみた

この記事はUnity 2 Advent Calendar 2015のエントリです。

UnityWebRequest

UnityWebRequestとはWWWに変わる新しいHTTP通信用のクラスである。

docs.unity3d.com

名前空間Experimentalが含まれている通り、まだ実験的な機能なので今後も仕様が変更されていく可能性がある事をご了承いただきたい。

それでも、WWWと比較して十分使いやすくなってはいるので普通に活用して良さそう。

使い方

例えば、以下のコードはローカルホストにアクセスして、レスポンスをログに吐く

using UnityEngine;
using UnityEngine.Experimental.Networking;

public class HTTPTest : MonoBehaviour {

    // Use this for initialization
    void Start () {
        StartCoroutine(HttpRequest());
    }

    IEnumerator HttpRequest()
    {
        var request = UnityWebRequest.Get("http://localhost:4567");
        yield return request.Send();
        Debug.Log(request.responseCode.ToString() + ":" + request.downloadHandler.text);
    }
}

コルーチンで、通信終わるまで待つという点は今までと同じ。 WWWクラスの場合コンストラクタ呼び出したタイミングで通信しに行くが、UnityWebRequestの場合はSendを呼び出したタイミングで通信する。 なので通信する前にSetRequestHeaderで諸々のヘッダ設定ができるようになった。

WWWと比較した時の違いを幾つか挙げるとこんな感じ

  • RESTに対応
  • データとHTTPのハンドリング部分が分離されている
  • DownloadHandlerScriptでロギングや加工が便利

RESTに対応

多分これが一番大きな変更点。

ついにPUT、DELETEメソッドが実装された・・・。

PUTは引数にstringとbyte[]しか渡せない。 POSTはDictionaryが使用できるのでキーバリューペアでサクッといけるがPUTは自分で整形する必要がある。ちなみに文字列をバイト配列に変換する場合下記で行ける。

System.Text.Encoding.UTF8.GetBytes("foo=get")

引数を空文字列にした場合、以下のエラーが出る。

ArgumentException: Cannot create a data handler without payload data

因みにPATCHはないので、必要があればインスタンスmethodプロパティに直打ちしよう

request.method = "PATCH";

また、現状POST以外のメソッドはContent-typeが空になっている模様。 なので、そのままパラメータ付きでPUTしてもサーバ側によってはうまく受け取ってくれない可能性が高いので以下の感じでヘッダに組み込むのがいい

request.SetRequestHeader("Content-type", "application/x-www-form-urlencoded");

ここは修正されていくと思う、多分。

データとHTTPのハンドリング部分が分離されている

UploadHandlerはリクエストを飛ばす際のパラメータデータ、DownloadHandlerはレスポンスのデータを保持する小さなクラスになっている。 その二つをUnityWebRequestが所有している。 UnityWebRequestはURLやヘッダ情報、リダイレクト回数の設定などHTTP通信に関する処理を扱う。 WWWと違い、データそのものと通信がしっかり分離しており扱いやすい。 UploadHandlerとDownloadHandlerは外部から流し込むことができるからだ。 UploadHandlerを外から設定する場合はUploadHandlerRawクラスを使う。

var request = UnityWebRequest.Get("http://localhost:4567");
var upload = new UploadHandlerRaw(System.Text.Encoding.UTF8.GetBytes("foo=get"));
request.uploadHandler = upload;

コンストラクタの引数がバイト配列なので、変換が必要。 上記で書いたが、PUTはbody部分を空文字列にするとエラーになるので「適当な文字列を入れて初期化」->「uploadHandlerに流し込む」 という流れになった。もっといいやり方ありそう。

DownloadHandlerクラスそのものは流し込むことはできるがあまり意味はない。 むしろ、後述するDownloadHandlerScriptの時に役に立つ。

DownloadHandlerScriptでロギングや加工が便利

DownloadHandlerはダウンロード時の幾つかのタイミングでコールバックされる

  • ReceiveData データを読み取った際に呼ばれるコールバック
  • CompleteContent 読み取り完了した時に呼ばれるコールバック
  • ReceiveContentLengthヘッダーからデータの長さを受け取った時に呼ばれるコールバック

データを読み取った各所でメソッドを呼ぶようになっており、Unityではそれをユーザ側でカスタマイズできるようにDownloadHandlerScriptというクラスを提供しています。

サンプルコードから抜粋

using UnityEngine;
using System.Collections;
using UnityEngine.Experimental.Networking;

public class MyDownloadHandler : DownloadHandlerScript  {
    // Standard scripted download handler - will allocate memory on each ReceiveData callback
    public MyDownloadHandler(): base() {
    }

    // Pre-allocated scripted download handler
    // Will reuse the supplied byte array to deliver data.
    // Eliminates memory allocation.
    public MyDownloadHandler(byte[] buffer): base(buffer) {
    }

    // Required by DownloadHandler base class. Called when you address the 'bytes' property.
    protected override byte[] GetData() { return null; }

    // Called once per frame when data has been received from the network.
    protected override bool ReceiveData(byte[] data, int dataLength) {
        if(data == null || data.Length < 1) {
            Debug.Log("LoggingDownloadHandler :: ReceiveData - received a null/empty buffer");
            return false;
        }

        Debug.Log(string.Format("LoggingDownloadHandler :: ReceiveData - received {0} bytes", dataLength));
        return true;
    }

    // Called when all data has been received from the server and delivered via ReceiveData
    protected override void CompleteContent() {
        Debug.Log("LoggingDownloadHandler :: CompleteContent - DOWNLOAD COMPLETE!");
    }

    // Called when a Content-Length header is received from the server.
    protected override void ReceiveContentLength(int contentLength) {
        Debug.Log(string.Format("LoggingDownloadHandler :: ReceiveContentLength - length {0}", contentLength));
    }
}

上記のコードは、コールバックの各所でログに吐くような処理をしています。 あとは、これをUnityWebRequestのDownloadHandlerに流し込むだけです。

var request = UnityWebRequest.Get("http://localhost:4567");
var download = new MyDownloadHandler();
request.downloadHandler = download;

これで、データ受信時にログに吐いたり、ゲーム用にレスポンスを加工したりなど痒いところに手が届くようになる。

まとめ

現状、content_typeの問題など、まだまだこちらでカバーしなければならない問題はありますが、WWWクラスと比較するとかなり改善されており、期待が持てるAPIっぽい

明日は @yaegakiさんのmruby on Unityです

Phaserメモ

PhaserというWEB向けのゲームエンジンがあるので最近触っているので忘れないように殴り書き

phaser.io

ブラウザゲーもUnityでなんとかしようと思っていたのだけど、WebPlayerはもう使えないしWebGL出力はそれなりのサイズになってしまうのでまだまだ軽量とは言い難い。 ということで最近結構賑わっているという噂のPhaserで作ってみようかと考えた。

ついでにtypescriptも始めて見た。jsすらあんまり書けないけど。

メモ

日本語の資料はほとんどない。唯一下記サイトがわかりやすいかなという印象

Phaser入門:HTML5/Javascript 2Dゲームエンジン - catch.jp-wiki

ただ、異常なまでにサンプルコードが充実しているのでそれをひたすら読み解くべし。 phaser.io

シーン設計

Unityなどにおけるシーンの役割は、Phaserでは State というものが担う。 preload メソッド内でリソース系のロード、 create でそのstate内のデータの初期設定をしてくれという感じ。

サンプル見た感じ、Stateの設計は下記のパターンが多い

Boot Preloader Hoge Fuga

Hoge,Fugaは実際に遊ぶであろうStateの部分。MainとかGameOverとか。 まずはBootStateを読み込ませて、create 内でゲーム上で使用するstateを全部読み込む係になっている。PreloaderとかHogeとかFugaなど全部読み込む。完了後にPreloderに遷移する PreloaderStateの preloader で画像、音声などのアセットを読み込む。

複数のサンプルでBootとPreloaderがいたから、これはPhaserのお作法っぽい。

アニメーション

xmlだとかspritesheetとか幾つかあったけど、jsonにした。

流れは以下

  1. 複数のスプライトをまとめた画像を用意
  2. 各スプライトの情報を保持するjsonファイルを用意
  3. load.atlasJSONHash で画像とjsonマッピング

  4. 複数のスプライトをまとめたatlasを用意

こんなやつ https://i.gyazo.com/d6ea4977a0e5868708b1227d60c23b99.png

上から順番に、上、右上、右、右下、下、左下、左、左上の8パターンの歩行グラフィックをそれぞれ4枚持ってる。

  • 各スプライトの情報を保持するjsonファイルを用意

texturepackerを使うと、画像をまとめるのとPhaser用Jsonファイル出力の両方ができる

www.codeandweb.com

使い方はこちら

https://www.codeandweb.com/blog/2014/12/17/creating-spritesheets-for-phaser-with-texturepacker

今回もそれで吐こうとしたが、TexturePackerですでに出来上がってるatlasに対してスプライトの情報を与えるやりかたがわからなかった。バラバラの画像をペタペタ貼っていくときはスプライトの情報が追加されていくけど、既存の1ファイルだと1つのスプライトとみなされてしまい、それの分割方法がわからなかった。

なのでjson生成スクリプト書いた https://gist.github.com/adarapata/c96048cd99f6ef7d9537 自分の持ってる画像はほぼほぼ上記のパターンなのでこれで生産できるようになった。

こんな感じ

this.game.load.atlasJSONHash("iku", "assets/images/chara_iku.png", "assets/atlases/iku.json");

アニメーションは、コード内で実装する必要がある。下記は上方向歩行モーションの設定

iku.animations.add("walk_up", ["up_0","up_1","up_2","up_3"], 10, true, false);
iku.animations.play("walk_up");

単純に配列でスプライト名を指定していけばその順番で再生してくれるみたい。 スプライト名のルールを決めておけば同じフォーマットで複数キャラ対応できそう。 UnityでのAnimatorみたいな動きはできるかもしれない。

ちなみにチュートリアルでローカルサーバ立てるためにXAMPP入れようみたいなこと書いてるけど、多分sinatraが一番楽だと思う。

UniRX使ってOnRaycast的な処理を書く

小ネタ

OnTriggerEnterとかそういう感じで、レイにぶつかった瞬間、ぶつかっている間、レイから離れた瞬間を検知したいなという気持ち。

一案としてこのような感じ

using UnityEngine;
using System.Collections;
using UniRx;
using UniRx.Triggers;
using System.Linq;

public class OnRaycastHit : MonoBehaviour
{
    Subject<Unit> onRaycastStayStream = new Subject<Unit> ();

    public IObservable<Unit> onRaycastStayAsObservable { get { return onRaycastStayStream.AsObservable (); } }

    Subject<Unit> onRaycastExitStream = new Subject<Unit> ();

    public IObservable<Unit> onRaycastExitAsObservable { get { return onRaycastExitStream.AsObservable (); } }

    Subject<Unit> onRaycastEnterStream = new Subject<Unit> ();

    public IObservable<Unit> onRaycastEnterAsObservable { get { return onRaycastEnterStream.AsObservable (); } }

    private bool isOnNext;

    public void RaycastHit ()
    {
        isOnNext = true;
    }

    void Start ()
    {
        this.UpdateAsObservable ().
            Select (_ => isOnNext).
            Buffer (2, 1).
            Subscribe (list => {
                bool before = list.First ();
                bool current = list.Last ();
                if (!current && before) onRaycastExitStream.OnNext (default(Unit));
                if (current && !before) onRaycastEnterStream.OnNext (default(Unit));
                if (current) onRaycastStayStream.OnNext (default(Unit));
                isOnNext = false;
            });
    }
}

Raycastで引っかかった時に RaycastHit を呼ぶイメージ。 そのフレームだけisOnNextがtrueになり、Buffer(2,1)で前フレームとの値と比較してOnNextの対象を変える。

isOnNextが結構強引な気がしていて、まだ良い方法あるんじゃないかと考えてる

大きい蝿

母方のじいちゃんは自分が小さい頃に亡くなっていてどんな人だったのかも覚えていないんだけど、毎年お盆には じいちゃんのお参りに行っていた。まだ元気だったばあちゃんと親族とかが集まって軽い挨拶などするのが恒例だった。

そのばあちゃんの家は、ちょっと大きい蝿が一匹いた。おじさんはその蝿をこう説明していた。

「みんなが集まると、じいちゃんが蝿になって見に来るんだよ」

見に来るのはわかるけど、よりにもよって蝿になるとはおじいちゃんはどんな罪を犯したのだと思った。 蝶とかならまだ歓迎されていたと思う。

時は流れ母方のばあちゃんも二年前に他界して、昨日はその三回忌に行っていた。お墓にお参りしたあと家に行って軽く挨拶などしたりお菓子を食べたり。

話していると例によってちょっと大きい蝿が現れた。

しかも、今度は二匹で飛んできた。

「さいきんばあちゃんも連れてくるようになってな」とおじさんは楽しそうに話した。それはいいとしてなんでやっぱり蝿なのか。

うちの家系は蝿と何かの縁があるのか。蝿の王(ベルゼブブ)の血統なのだろうか。

映画の蝿の王は割と評価良いのでどなたか土日にでも観ていただきたい。僕は見たことないです。 movies.yahoo.co.jp

今日はまた別件で告別式に参加していた。父方の伯父さん(上記のおじさんではない)に不幸があったのだ。

伯父さんは非常に人徳があったようで、想定を超える数の弔問者が訪れていた。訃報はつらいことだけど、それでもいろんな人が駆けつけてくれたことはなんだか嬉しく思えた。入りきらないほどの花を詰め、大好きだったビールを少し口につけて出棺していった。

火葬を終えて遺骨も拾い、そのまま初七日を執り行った。親族、友人で伯父さんの遺影の前で食事をしながら思い出話などに花を咲かせていたら

飲んでた缶ビールに、大きい蝿が一匹止まった。

素振りをしている

8月入ったあたりから不健康がヒートアップしてきたので、一週間前くらいから木刀素振りを始めている。

木刀とは

こちらです

木刀 - Wikipedia

なぜ素振りなのか

ジョギング、筋トレ諸々やってみたけどどれもあまり長続きしなかった。

中学時代に剣道やっていたので木刀を持っており、素振りなら昔やってたしいけるかなと思って、始めてみた。

これが結構楽しい

内容は

  • 前後素振り50
  • 跳躍素振り30
  • 片手素振り20

入部したての時くらいのメニューしかこなせないことがわかったので自分に甘くしている

メリット

外でできる

腕立て腹筋背筋を外でやると若干変な目で見られかねない。

しかし自分の部屋には冷暖房器具が存在しないので基本的にサウナ室になっており、やる気が起きない。そこで素振りである。

素振りは室内だとある程度の高さが必要なので屋外で行うことに何の違和感もない。ごく自然に、周囲に「己を鍛えています」アピールができる。「玉竜旗がんばってね」と言われるようになれば概ね成功と言えるだろう。

集中力が上がる

運動をした後は、若干集中力が上がるらしい。 ※出典なし

少なくとも、突然こんな記事を書くくらいには集中力が増す。

デメリット

通報される

一軒家で自分の敷地内であれば木刀を持とうが素振りしようが問題はないが、マンションやアパートなどであれば時間帯には気をつけたほうがいい。

22時に木刀を持った男が家から出てくる姿を見られると事案になりかねない。

しかし、これは相手の素性がわからないから事案になるわけで、入居時に挨拶、普段すれ違う際の対応、ゴミ出しルールの徹底など、そのコミュニティに所属するための人付き合いをしっかりしておけば回避できるものと思われる。

知った顔であれば、「あら、こんな時間に木刀なんか持って闇討ちかしら?」と気さくに声をかけられるくらいで済むと思う。

結論

ご近所付き合いというのは、非常に大事なのである

ArborのStateBehaviourを継承してUniRXを少し使いやすくする

無料期間中にArbor: State Diagram Editorを入手しました。

caitsithware.com

毎回statemachineを自前で書いてて面倒だと思ってたのでこれはありがたい。 昨日から触り始めているけど、特別引っかかることもなく使いやすいです。

なお、Arborの使い方とかはテラシュールブログさんが細かく書いてるのでそちらを参照すると良さそうです。 tsubakit1.hateblo.jp

これで作るスクリプト内部でUniRXをごにょごにょして、State遷移してから変更あるまでHogeHoge〜みたいな処理を書きたかったので拡張してみました。

こういう拡張どこに置くか悩んだので、とりあえず CustomArbor 名前空間を作って ObservableStateBehaviour を作った。

using UnityEngine;
using System.Collections;
using Arbor;
using UniRx;
using UniRx.Triggers;
using System.Linq;

namespace CustomArbor
{
    public class ObservableStateBehaviour : StateBehaviour
    {
        private Subject<Unit> stateBeginStream = new Subject<Unit>();

        public IObservable<Unit> stateBeginAsObservable {
            get { return stateBeginStream.AsObservable(); }
        }

        private Subject<Unit> stateEndStream = new Subject<Unit>();

        public IObservable<Unit> stateEndAsObservable {
            get { return stateEndStream.AsObservable(); }
        }

        public IObservable<Unit> updateAsObservable {
            get { return this.UpdateAsObservable().
                            SkipUntil(stateBeginAsObservable).
                            TakeUntil(stateEndAsObservable).
                            Repeat();
                }
        }

        // Use this for enter state
        public override void OnStateBegin ()
        {
            stateBeginStream.OnNext(default(Unit));
        }
        // Use this for exit state
        public override void OnStateEnd ()
        {
            stateEndStream.OnNext(default(Unit));
        }
    }
}

やってることは、状態の開始時と終了時にそれぞれストリームを用意して、通知しているだけです。

また、StateBehaviourの通常のUpdateは OnStateBegin ~ OnStateEnd の間のみ走るので、代用としてupdateAsObservableを作ってます。

  • StateAは、0.5秒ごとに A! と出力する
  • StateBは、1秒ごとに B! と出力する
  • キーボードのAを押された場合 State X Down と出力して遷移する
public class StateA : ObservableStateBehaviour {

    public StateLink nextState;

    void Awake()
    {
        this.UpdateAsObservable().
            SkipUntil(stateBeginAsObservable).
            Sample(TimeSpan.FromSeconds(0.5F)).
            TakeUntil(stateEndAsObservable).
            Repeat().
            Subscribe(_ => {
                print("A!");
            });

        updateAsObservable.
            Where(_ => Input.GetKeyDown(KeyCode.A)).
            Subscribe(_ => {
                print("StateA Down");
                Transition(nextState);
            });
    }
}

public class StateB : ObservableStateBehaviour {

    public StateLink nextState;

    void Awake()
    {
        this.UpdateAsObservable().
            SkipUntil(stateBeginAsObservable).
            Sample(TimeSpan.FromSeconds(1F)).
            TakeUntil(stateEndAsObservable).
            Repeat().
            Subscribe(_ => {
                print("B!");
            });

        updateAsObservable.
            Where(_ => Input.GetKeyDown(KeyCode.A)).
            Subscribe(_ => {
                print("StateB Down");
                Transition(nextState);
            });
    }
}

こんな感じになります。

n秒間隔で流すという処理が挟まるので、updateAsObservable 使わず SkipUntil -> Sample -> TakeUntil と書いてるけど、もっと綺麗なやり方ありそう。