かばちんのエンジニアブログ

日々の経験の中で培った内容を備忘録も兼ねて記録していくブログです。少しでも誰かの役に立つために頑張って続けていけたらなと思います。

Automatine を使ってみた

■ピュア C# で動く Timeline

Automatine というピュア C# で動くユーティリティが公開されたので使ってみました。
github.com

■Automatine ってなに?

一言で言うと Timeline のようなものですが、Unity に標準搭載されている Timeline とは違います。
Timeline はどちらかと言うと AdobeFlash に近い感じなのですが、
Automatine はフレーム単位で状態を管理できるステートマシン?(ともちょっと違うかな?)という印象です。

■それって何がいいの?

例えばフレームで管理されている代表例として格ゲーで言うと、
「必殺技を出した時、10フレーム目から20フレーム目まで無敵」とか
「通常技を出した時、5フレーム目から20フレーム目までの間だけ、次の技のコマンド入力を受け付ける」とか
そういった制御が GUI で設定出来るようになっています。

■他にも良い点が

コードがピュア C# & データが JSON というところが便利でよかったです。

リアルタイム通信のゲームを作る時、不正を防ぐためにクライアントと同じ処理をサーバ側でもやるような作りにしたりするのですが
このような手法で開発を行う場合、Unity 自身に搭載されている機能を使ってしまうとサーバ側で同じコードが動かなかったりします。

ピュア C# だと同じ処理をクライアントとサーバで動かせるので、1ソース化ができ開発がとてもやりやすいかつバグりにくくなります。
そしてデータ形式JSON なので、クライアントで動かしているデータをサーバでも使うことができます。

■導入方法

github に UnityPackage が置いてあるので、これを入れるのが手っ取り早いと思います。
github.com

■データの作り方

UntiyPackage を入れると Window -> Automatine というメニューが出てくるので、そこから編集画面を表示できます。
この Automatine 画面で Auto データを作ります。

Auto データとは Automatine で作成するタイムラインデータのことで、
「○フレーム目から○フレーム目までは A という状態」
「○フレーム目から○フレーム目まで、B という Coroutine を毎フレーム実行させる」
といった情報が入っています。

■Autoデータを作ってみる

ここではキャラクターを移動させるような簡単な Auto データ (Locomotion_Auto) を作ってみたいと思います。
Auto (+) から Auto を作成。
f:id:kabatin:20190806141123p:plain

Automatine ウィンドウの空白を右クリックで「Add New Timeline」

Timeline 右クリックで「Add New Tack」
Locomotion はループするようなモーションなので、Unlimited Span (Tack を選択すると Inspector に出てきます)をチェック
f:id:kabatin:20190806141206p:plain

■移動する処理を入れる

Coroutines (+) から Coroutine を生成。
f:id:kabatin:20190806144044g:plain

(Open を押すとエディタが起動してソースを編集できます)
ここで作られた Coroutine が、Tack に設定した帯の長さ(フレーム数)だけ呼ばれます。
最後に [Export As Runtime Code] をクリックすると、動的にクラスを生成してくれます。

■動かしてみる

新しいシーンを作ってテキトーに Cube を作り、以下のコードをアタッチ。

using UnityEngine;
public class Player : MonoBehaviour
{
    Info info;
    Vector3 pos = new Vector3();
    void Start()
    {
        info = new Info();
    }
    void Update()
    {
        var speed = Input.GetAxis("Vertical");
        info.OnUpdate(speed);
        
        pos.x = info.position.x;
        pos.z = info.position.z;
        transform.localPosition = pos;
    }
}

上記コード中の Info クラスは以下のものを使っています。

using Automatine;
public class Info
{
    public Position position = new Position();
    int frame;
    Auto<Position, Position> auto;
    public Info()
    {
        auto = new Locomotion_Auto<Position,Position>(frame, position);
    }
    public void OnUpdate(float speed)
    {
        position.speed = speed;
        auto.Update(frame, position);
        frame++;
    }
}

public class Position
{
    public float x;
    public float z;
    public float speed;
}

「移動する処理を入れる」章で作った Coroutine を以下のコードに修正

using System.Collections;
using Automatine;
public partial class RoutineContexts <InitialParamType, UpdateParamType> : RoutineBase<InitialParamType, UpdateParamType> {
    
    public IEnumerator Locomotion_Coroutine (InitialParamType initialParam) {
        var pos = initialParam as Position;
        while (true)
        {
            pos.z += pos.speed;
            yield return null;
        }
    }
}

実際に表示するものは Player.cs で、位置などの管理は Info.cs に分けられました。
最後に [Export As Data] を押すと JSON が生成されます。
出力先は「Automatine > Runtime > Generated > Json

auto を変更する時は

auto = new Hoge_Auto<Fuga, Fuga>(frame, fuga);

という感じで auto 自体を入れ替えてしまえば良いです。
auto を JSON から読み込む時は

string json = "JSONデータ";
RuntimeAutoData data = AutomatineJsonConverter.JsonToAutoData (json);
auto = Automatine.Auto<Fuga, Fuga>.RuntimeAutoGenerator (data);

とやればいいみたいです。

■まとめ

今回は動かしてみるだけの簡単なものでしたのが、普通にゲームを作るとかなり複雑な状態管理が必要になるので、
そういった時に Automatine の真価が発揮されるのではないかなと思います。

カジュアルアプリにAppLovinのSDKを導入してみた

[もくじ]

AppLovin広告SDKの導入

 久しぶりの投稿になります。

 さて、タイトルの通りですが新しく全世界向けに配信することになったカジュアルゲーム
AppLovin の広告SDKを導入してみたので、導入の仕方から実際のリリースに至るまでの一連を備忘録として残したいと思います。

[開発に使用した環境]

なぜAppLovinにしたのか?

 これまでに、アドフリくん、アイモバイル、UnityAds、Fello、AdGenerator などいろいろな広告SDKを導入してきました。
今回 AppLovin を選んだ理由としては以下になります。

  • 全世界配信前提なので海外に対応していること(必須)
  • 導入説明を見る限り比較的簡単に導入できそうだったこと
  • バナー広告と動画広告の両方があったこと
  • 逆に自社で広告を出す場合に費用対効果が高いと評判がよかったこと


以上が、今回AppLovinを選んだ主な理由です。

AppLovin の公式サイトはこちら
www.applovin.com



SDKの導入

 SDKの導入自体はとても簡単でした。
公式サイトからダウンロードできる UnityPackage を入れれば基本的には特に何もすることはありません。
気をつけなければいけない点を挙げるとすれば、AndroidManifest.xml が既に存在する場合は自分でマージが必要になります。
それ以外は特に気にすることはないので Import してしまって大丈夫です。

しかしながらSDK導入時にはよくあることですが、ハマったポイントもあるので解説していきたいと思います。


Xcode で Archive したあとの Validation が通らない

 順調に Unity での開発を終え、Xcode プロジェクトを書き出し、Xcode でビルドし実機にて動作確認をします。
ここまでは非常にスムーズに行うことができました。

その後課金周りのテストをしたかったため、一度 AppStore へアップロードしようと思い、
ひとまず Validation を実行したのですが、「Symbols tool failed」というエラーが発生して Validation が失敗します。

f:id:kabatin:20190322185045p:plain
エラー画面

このエラーがなかなか厄介で、ググっても全く情報が見つかりませんでした。
そもそもですが、AppLovin 自体の情報が他の広告会社と比べるとかなり少ない気がします。

海外の広告会社だから日本語のサイトが少ないのは分かるのですが、英語で検索しても本当に少ない。
それが、この記事を書こうと思った大きな理由でもあります。

やっとの思いでヒントになるページを見つけました。
stackoverflow.com

このページの下のほうにこんな書き込みをされている方がいました。

Basically some framework has been added to Copy Bundle Resources. Remove it to resolve the issue!

要約すると「既にバンドルリソースはコピーされているからそれを削除しましょう。」


Xcode の BuildPhases にある Embed Frameworks に libAppLovinSdk.a が追加されている状態なので、
それを削除して再度 Archive を行ってから Validation をしたら成功しました。


動画広告再生時のクラッシュ問題

 他のアプリを Xcode でビルドする際にいつもお決まりで設定している項目があるのですが、
AppLovin を導入しているアプリではそれが原因で、動画再生時にクラッシュすることがあったので記述しておきます。


[Build Settings]

  • Enable Bitcode を NO にする
  • Architectures を Standard architectures(armv7,arm64) にする
  • Build Active Architecture Only を NOにする

[Build Phases]

  • Compile Sources の AL で始まるソースに -fno-objc-arc フラグを設定する (ALAppLovinLogger.m以外)


この中のどれが主な原因になってクラッシュを起こしているのかまでは追跡しませんでしたが、
簡単に言うと AppLovin に関しては UnityPackage を入れたままの状態で正常に動作します。

これはとても素晴らしいことではあるのですが、公式サイトの導入説明には -fno-objc-arc を設定する
指定があったので、マニュアルの状態も最新の状態にしておいて欲しいなと思いました。


まとめ

 今回初めて AppLovin の広告SDKを使ってみましたが、総評としては良かったと思います。
海外向けに広告モデルでアプリを開発する際には導入もしやすく、もしバズった場合などに
追加で広告を出したい状況などが出てきたら恩恵を受けられるのではないかなと思いました。

Unity 5.5 バージョンアップに伴うエラー解消事例

f:id:kabatin:20170209114218p:plain

Unity バージョンアップ時エラー解消について

Unity 5.3.5p8 から Unity 5.5.1p2 にバージョンアップした際に発生したエラーの解消方法のメモです。

事の発端

Unity 5.5.1p2 へアップデートしてもろもろの動作確認を行っていたところ、PC 上では正常に動作が確認できた。
念のため実機でも確認しておこうと思い APK ファイルを作成して実行してみたところ Unity ロゴが出る以前の段階で
画面が真っ暗な状態のままフリーズ。

原因調査

adb logcat で E/Unity を grep しながらログを確認したところ以下のようなエラーが発生していた。

E/Unity   (XXXXX): Unable to find AudioPluginOculusSpatializer

ネットで検索

"Unable to find AudioPluginOculusSpatializer" というキーワードでいろいろ検索すると海外サイトが多数ヒット。
しかし、具体的な解決策は見つからずに途方にくれていたところ、Unity 上で OculusSpatializer という文言にたどり着く。
[Editor] → [Project Settings] → [Audio] から AudioManager を表示すると、Spatializer Plugin というプルダウンがある。
その中に Oculus Sptializer というのがあったので、これを選択した状態で再度ビルドを試みてみた。

が、失敗。

Unity 上で発生していたエラー

着目点を少し変えて Unity を起動した直後に表示されていた以下のエラーを調査。
[XX] の部分の数字が数パターンあり、いくつかのプラグインが正しく読み込めていないような感じ。

InitializeUnityExtensions: Must have a valid path for the plugin [XX]
Extension was not registered, that means it relies on default UnityExtensions settings, please register extension and apply necessary settings for it in the callback.


いろいろ検索した結果、以下のサイトを参考に [Reimport All] を試したところ無事解消!
fantom1x.blog130.fc2.com


エラー解消手順

Unity エディターの Project ウィンドウ上で右クリックし、[Reimport All] を実行する。
自分の場合は Unity がクラッシュして落ちたけど、再起動したらアセットの再読み込みが始まり無事に起動。
InitializeUnityExtensions のエラーも消えており、この状態で APK を作成して実機確認したところ正常に動作した。

もしくは、試してはいないが Library フォルダを一度全削除して再起動することでも直ると思われる。


原因

公式な文書は見つけられなかったので完全に推論にはなってしまうが、
Unity ではバージョン間でのキャッシュファイルのフォーマット差があるので、そのキャッシュが悪さしていたのではないかと思う。

最新の Unity で発生している事象なので同じような状況の方の手助けに少しでもなれば幸いです。

アプリ開発に役立つ便利サイト集

自分がアプリ開発する時に活用する便利サイトの紹介です。

随時追加していきたいと思います。



素材系

無料写真素材集

人物を含む高画質な写真をいろいろと提供してくれるフリー素材サイト
www.pakutaso.com



サウンド系

魔王魂

言わずと知れたサウンドフリー素材サイト
maoudamashii.jokersounds.com


Music is VFR

質の高いBGM・SEをかなりの数提供してくれている
musicisvfr.com


あみたろの声素材工房

ボイス素材をたくさん公開してくれている
www14.big.or.jp

Unityで使える便利な無料アセット一覧

f:id:kabatin:20170127144614p:plain

自分がこれまでに利用してきた中で役立ったアセットの紹介です。

随時追加していきたいと思います。

Unity-Log-Viewer

UnityでビルドしたアプリからUnityのConsoleログを表示するアセット
Asset Store

「ぬこしょうぎ」におけるリアルタイム通信

f:id:kabatin:20160907142256p:plain

リアルタイム将棋「ぬこしょうぎ」をリリース

先日こんなアプリをリリースさせて頂きました。
ぬこしょうぎ - ヤルキマントッキーズ


将棋をモチーフにコマの動きは将棋そのままで、将棋からターン制をバッサリと取り除いたゲームです。
ルールはシンプルなので将棋を知らない方でも楽しめる仕様になっています。

(不思議なことにターン制を取り除いてもやっぱり将棋を知っている人が若干有利になるようです!)


通信をどのような構成で、何を使ってやっているか

◆サーバサイド(コネクションサーバ)

クライアントからの WebSocket 接続を受け付けるサーバ。
知人が作成した nginx-luajit-websocket-pubsuber を利用して WebSocket 接続を受け付けている。
github.com


簡単に説明すると、nginx で接続を受け付けて WebSocket コネクションを維持し、
送られてきたデータを Disque に格納する仕組みです。(←この部分を lua が担っている)

※Disqueとは
Redis の開発者が作成した、オンメモリで動く Queue システムです。
github.com


◆サーバサイド(ゲームコンテキスト)

ゲームコンテキスト側ではとにかく Disque からデータが取得さえ出来ればあとは自由に処理ができます。
そこで利用したライブラリが、同じく知人が作成した Disquuun という C# で作成された Disque ライブラリです。
これにより、コネクションごとのデータを自由に出し入れできるようになります。
github.com


◆クライアントサイド(Unity 5.3.5p8)

クライアントからコネクションサーバに対して WebSocket 接続を行う必要があります。
利用したライブラリは、これまた同じく知人が作成した WebuSocket という C# で作成されたライブラリです。
github.com


全体の構成図

f:id:kabatin:20160907144618p:plain


この構成の最大の特徴1

何と言ってもこの構造で素晴らしい点、それは全てが非同期で行われているということです。
基本的に WebSocket 接続だと、何か送ったらそれをトリガーにしてサーバが処理を行い結果を返すと思います。
そうなってしまうと、サーバ側の処理が遅延した場合に後続の処理がすべて引きずられてしまいます。


この仕組みでは、クライアントから来た通信を元にまず nginx-lua が Disque にデータを格納します。
この時点でクライアントが送ったデータの処理は完了します。


その後、ゲームコンテキストがゲームループ周期のタイミングで Disque からデータを吸い上げて
結果を返すために必要な処理を行い、クライアントへ送るデータを Disque にまた書き出します。


そのデータを nginx-lua が Disque から吸い上げ、クライアントへデータを Push します。


この構成の最大の特徴2

サーバサイドの負荷の低さ、サーバコストの安さです。
IDCF の最も安価なサーバである S1 サーバ(月額200円+ディスク代300円=500円/月)で同時接続500人に耐えられます。


ぬこしょうぎでは、プレイタイムがだいたい1分〜2分前後であるのにも関わらず、
リリースして間もない時期に同時接続が70人を上回る時がありましたが、全く問題なく S1 サーバ1台で処理しています。


サーバのスペックをそれなりのものに変更すると、なんと20,000接続以上も耐えることができます。
もちろん1台でとにかく多くさばけばいいというものでもないので、リスクとのトレードオフがありますが
負荷の軽さについてはだいたい想像がついたのではないでしょうか。


UnityEditorとの相性の良さ

サーバサイド(ゲームコンテキスト)が C# で書かれているため、なんとUnity上でも動きます。
サーバサイドであるゲームコンテキストが Unity 上で動くので、個人端末でクライアントとサーバサイドの
両方を同時に開発することが可能になります。


世界初の DotNetCore 実用サービス

あくまで現時点での想定ではありますが、DotNetCore を実際に使用してリリースされた世界初のサービスです。
すでにお気付きの方もいらっしゃったかもしれませんが、サーバサイドを C# で書いているので Windows サーバだと
思った方も多いかもしれません。


が、しかし。
ぬこしょうぎは Ubuntu 14.04 LTS を利用してリアルタイム通信を実現しています。


そうです。
CoreCLR を利用して Linux上で C# のコードを動かしています。
.NET - Powerful Open Source Development


まとめ

知人すごい。これに尽きる。

まだ大規模な実用で使われたことはない構成ではあるが、個人的にはものすごく理にかなった仕組みだと思っている。
開発のしやすさ、スケールのしやすさ、運用コストの低さ、負荷の低さ、どれを見ても群を抜いている気がする。

また UnityEditor 上でも動作する仕様上、開発のしやすさも兼ねておりいずれ標準的なモノになるのではないだろうか。
今後もこの仕組みを利用したアプリをたくさん出していきたい。

CoreCLRでNewtonsoft.Jsonを試してみた

前回こちらの記事でCoreCLRでNugetからライブラリを取得する方法をご紹介しました。
kabatin.hateblo.jp


実際にNugetからライブラリを取得し、使用できるのかを試してみましたので共有したいと思います。

サンプルソース

using System;
using Newtonsoft.Json;

namespace ConsoleApplication
{
    public class Person
    {
      public string name { get; set; }
      public int age { get; set; }
    }

    public class Program
    {
      public static void Main(string[] args)
      {
        try
        {
          var person = new Person {
            name = "sample",
            age = 30
          };

          var json = JsonConvert.SerializeObject(person);
          Console.WriteLine(json);
        }
        catch (Exception e)
        {
          Console.WriteLine(e.Message);
        }
      }
    }
}

実行結果

$ dotnet run
Project JsonTest (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
{"name":"sample","age":30}

結論

動いた!!