20200906のUnityに関する記事は8件です。

UnityでPlayFabでxsollaするSDKの修正

やりたいこと

クレジットカードやPayPalやWebMoneyで100円のアイテムを変えるようにする。
要はこのドキュメントにあることをしたかっただけです。

https://developers.xsolla.com/ja/sdk/game-engines/unity/#unity_sdk

ただ各々のバージョンが合わないのか、ドキュメントに従っただけでは達成できなかったので覚書しておきます。

URLが奇形ですエラー

最初に、SDKに入っているLoginシーンを再生するとサンプルとして用意されているストアに接続できます。
ここは問題ありません。

そこで、自身で作成したタイトルのIDやAPIキーやアイテムを設定して再生し、
ログインが完了するといきなりエラーが出ます。

Curl error 3: malformed

これはPlayFabに設定しているアイテムの"アイテム イメージ URI"を設定していないためです。
適当に半角スペースでも入れるかURIを設定すれば解決します。

エラーコード 0004-0008

仮想通過で購入ができても、実際の通貨で購入しようとすると以下のページが表示されました。

image.png

サンドボックスの設定なのに本番にアクセスしているか
本番の設定なのにサンドボックスにアクセスしています。

らしいです。サンドボックスしたいです。
原因がどこにあったかというと、
PlayFabでリビジョンを編集した部分に、サンドボックスかどうかの引数を受け取る部分がありますが。

image.png

xsollaのソースコードの方で、CloudScriptArgsクラスがargs.sandboxを送れる構成になっていませんでした。

[Serializable]
public class CloudScriptArgs
{
    public string sku;
    public uint amount;
    public string orderId;
    public string sdkTag;
    public string theme;
    public int sandbox; // これが必要
}

ExecuteCloudScriptメソッドの中身も追加修正します。

                FunctionName = CLOUD_SCRIPT_DEMO_METHOD,
                FunctionParameter = new CloudScriptRequestEntity.CloudScriptArgs
                {
                    sku = itemId,
                    amount = ITEMS_QUANTITY_FOR_CLOUD_SCRIPT,
                    orderId = orderId,
                    sdkTag = PaymentsHelper.GetAdditionalInformation("playfab"),
                    theme = PaystationThemeHelper.ConvertToSettings(XsollaSettings.PaystationTheme),
                    sandbox = XsollaSettings.IsSandbox ? 1 : 0, // これが必要
                }

通過単位を円にしたい

そのままではドル単位で表示されます。やっぱり円にしたいです。
悲しいことに円表記の扱いはデフォルトには含まれていません。
RegionalCurrencyクラスを追加修正します。

        static readonly Dictionary<SystemLanguage, CurrencyProperties> Currencies =
            new Dictionary<SystemLanguage, CurrencyProperties>()
            {
                {SystemLanguage.Chinese, new CurrencyProperties {Symbol = "元", Code = "CNY"}},
                {SystemLanguage.English, new CurrencyProperties {Symbol = "$", Code = "USD"}},
                {SystemLanguage.French, new CurrencyProperties {Symbol = "€", Code = "EUR"}},
                {SystemLanguage.German, new CurrencyProperties {Symbol = "€", Code = "EUR"}},
                {SystemLanguage.Korean, new CurrencyProperties {Symbol = "₩", Code = "KRW"}},
                {SystemLanguage.Portuguese, new CurrencyProperties {Symbol = "R$", Code = "BRL"}},
                {SystemLanguage.Russian, new CurrencyProperties {Symbol = "₽", Code = "RUB"}},
                {SystemLanguage.Spanish, new CurrencyProperties {Symbol = "€", Code = "EUR"}},
                {SystemLanguage.Unknown, new CurrencyProperties {Symbol = "$", Code = "USD"}},
                {SystemLanguage.Japanese, new CurrencyProperties {Symbol = "¥", Code = "JPY"}},
            };

あとは小数表記が不要なので整数表記にします。
ItemUIクラスのToString("F2")などのF2を取ったりします。

課金のページが少し小さい

なぜか0.9かけたりしているので適宜修正する。

    private int GetActualWidth(int width)
    {
        return Mathf.Min(width, (int)(CanvasWidth * 0.9F));
    }

通貨バンドルを購入するとエラーが出る

カタログを弄りまくっていると表示されたので、
設定を間違えているだけの可能性があります。

PlayFabでは通貨も1つのバンドルとして販売するのですが、
サンプルでは通貨のバンドルはインベントリに表示しない処理になっているようです。
しかし、その表示しない処理はただnullを返しているだけなので、
受け取った方は存在するものとして処理しようとします。

とりあえずUserInventoryクラスの以下を修正し、null以外のものを取り込みます。

        _demoImplementation.GetInventoryItems(items =>
        {
            Items = items.Where(i => i != null).ToList();
            UpdateItemsEvent?.Invoke(Items);
        }, onError);

その他

PlayFabとxsollaで同じアイテムIDで金額設定を間違えてしまうと、
PlayFabのカタログ画面とxsollaの決済画面で異なる金額表示になってしまい、運営としてまずいことになります。
このあたりも統合できると思っていたのですが、どうやるのでしょうか。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】AddExplosionForceサンプル

実装動画

AddExplosionForce (float explosionForce, Vector3 explosionPosition, float explosionRadius, float upwardsModifier= 0.0f, ForceMode mode= ForceMode.Force));

とりあえず以下のパラメータで設定。

  • explosionForce = 100
  • explosionRadius = 20
  • upWardsModifier = 3.0f(球体的な爆発をシミュレートするため、見かけ上の位置を調整する。)
  • mode = Impulse

実装

cubeオブジェクト生成

爆発を受ける対象物をStart時に自動生成。
特殊なことはやらず、愚直にforで回して生成する。

CreateCube.cs
using UnityEngine;

public class CreateCube : MonoBehaviour
{
    public GameObject cube;
    public int interval = 2;

    private int startPosition = -30;
    private float startYPosition = 0.5f;
    private int finishPosition = 30;
    private float finishYPosition = 10.5f;

    void Start()
    {
        for (int z = startPosition; z <= finishPosition; z+=interval)
        {
            for (float y = startYPosition; y < finishYPosition; y+=interval)
            {
                for (int x = startPosition; x <= finishPosition; x += interval)
                {
                    Instantiate(cube, new Vector3(x, y, z), Quaternion.identity);
                }
            }
        }
    }
}

AddExplosionForceの実装

こちらののっぴの備忘録さんの記事を参考に作成。

Blast.cs
using UnityEngine;

public class Blast : MonoBehaviour
{
    public float power = 100f;
    public float radius = 20.0f;
    public float upwardsModifier = 3.0f;

    Ray ray;
    RaycastHit hit;

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            //クリック点にRayを飛ばす
            ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(ray, out hit, 100f))
            {
                //クリックした所から半径20mの範囲のColliderを取得
                Collider[] collider = Physics.OverlapSphere(hit.point, radius);
                foreach (Collider cube in collider)
                {
                    //範囲内のオブジェクトのRigidbodyに爆破の力を作用させる
                    if (cube.GetComponent<Rigidbody>())
                    {
                        cube.GetComponent<Rigidbody>().
                            AddExplosionForce(power, hit.point, radius, upwardsModifier, ForceMode.Impulse);
                    }
                }
            }
        }
    }
}

終わり

  • 爆発をシミュレートすることが出来た。ただ爆発してモノを壊すだけのゲームを作成したい。
  • 注意点として、被爆発対象の物体にはrigidbodyを付けないとシミュレートできない。
  • 数値を変えた検証動画も作成したいなぁと思ってます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity講座 #4移動を操作する

はじめに

※Qiitaに#1~#3が無いのは仕様です

動画から見てくれていた方、お久しぶりです。
動画を見てくれる人も減ってきたし、自分も動画編集にかける時間がそれほど取れなくなってしまったので、記事で更新することになりました。
この記事はこれまでの動画を見てくれていた前提でやっているので、Qiitaから来てくれた方は以下の動画を見てくださると嬉しいです。(動画に対する指摘等あればyoutubeのコメント欄にてお願いします)
Unity講座#1 インストール
Unity講座#2 操作説明
Unity講座#3 プロジェクト作成

今回の講座では、前回作った処理を改良して、
・PCスペックに依存しない移動方法へ
・ボールが壁を抜けないような移動方法へ
・入力による操作に変更
といった内容をやっていこうと思います。

開発環境

Unity 2019.4.5f1
Windows10 pro

PCスペックに依存しない処理へ

Update関数は1フレームに一回呼ばれると説明しました。
1秒間にこの関数が呼ばれる回数は、実はPCの性能によって大きく変わってきます。
ゲームでは、1秒間で何枚も画像が切り替わっています。
要するにパラパラ漫画のようなものですね。
この切り替わり枚数が多いとなめらかに動いているように見えます。(逆に枚数が少ないと動作が飛び飛びに見えてしまいます)
deltatime.png

Gameタブにある、Statsのボタンを押してみましょう。
GraphicsのところにあるFPS(Frame Per Second)が、この一秒間に何枚画像を更新できるかの情報になっています。
コメント 2020-09-06 103303.png

自分の環境では、FPSが1764になっていますね。つまり、
transform.position += new Vector3(0,0,1.0f);
が1秒間に1800回近くも行われていたため、移動速度がめちゃくちゃ早かったわけです。
秒速1800メートルとかマッハ5くらいになるのかな?
前回の最後で0.02fに直して、やっと見える速度になったのはこれが原因です。
ゲームが完成したあと、プレイする人々のPCスペックはバラバラです。
自分のPCの環境ではスムーズに動く移動速度にしたところで、自分よりハイスペックな人にとっては移動が早すぎるし、低スペックな人にとっては移動が遅すぎることになります。
そうならないようにUnity側で対処方法が用意されています。

Time.deltaTime

公式リファレンス(タイムとフレームレートの管理)
このリンクにほぼほぼここで書いている説明が書かれています。
Time.deltaTimeというプロパティを使うことで、どのようなPCでも一定の速度で移動させることができます。
このプロパティの値は前のフレームから今のフレームまでの経過時間です。
大体FPSの逆数だと考えてもらえばわかりやすいですかね。
詳しくはこのリンクを見てもらうとわかりやすいと思います。
とりあえず、速度にかける分には問題ありません。
Time.deltaTimeが返すのは秒数なので、単位にs(秒)をかけることで、左辺と右辺の単位が揃うように使わなければいけません。

さて、いきなりこんなややこしい事言われてもわからん、となるでしょうし実際にどのように修正すればいいのかについてやっていきましょう。

PlayerMove.cs
public class PlayerMove : MonoBehaviour
{
    [SerializeField]private float moveSpeed = 0.02f;
    // Start is called before the first frame update
    //このオブジェクトが作られたときに行われる処理
    void Start()
    {

    }

    // Update is called once per frame
    //毎フレーム行われる処理
    void Update()
    {
        transform.position += new Vector3(0,0,1.0f) * moveSpeed;

    }
}

以上の内容は前回の処理内容をmoveSpeedの大きさを変更することで、移動速度を変更できるようにしただけのものです。

[SerializeField]private float moveSpeed = 0.02f;
ここは、float型の変数moveSpeedを宣言しています。
[SerializeField]の部分で、インスペクタ上に表示するようにしています。
publicで宣言してもインスペクタ上に表示できるようになりますが、前回解説したとおり、外部のクラスから数値をいじれてしまうようになるので、privateにした上で、インスペクタから変更できるようにしています。

一旦この状態でプレイしてみましょう。前回の動画の最後と同じ動きをしていれば問題ないです。
(フレームレートによって移動速度は違うと思います)
コメント 2020-09-06 112922.png

さて、このように、Playerのインスペクタ上にMoveSpeedが出現していますよね?
この大きさを変更してみましょう。
例えば0.02f→1.0fにしてみると、50倍の速度になります。(プレイしてみましょう)

注意が必要なのが、スクリプト上で初期化している数値よりも、インスペクタ上で指定している数値のほうが優先されることです。
スクリプト上でいくら変更しても速度は変わらないので気をつけましょう。

さて、Time.deltaTimeを使ってみましょう。

PlayerMove.cs
public class PlayerMove : MonoBehaviour
{
    [SerializeField]private float moveSpeed = 0.02f;
    // Start is called before the first frame update
    //このオブジェクトが作られたときに行われる処理
    void Start()
    {

    }

    // Update is called once per frame
    //毎フレーム行われる処理
    void Update()
    {
        transform.position += new Vector3(0, 0, 1.0f) * moveSpeed * Time.deltaTime;
    }
}
                      正面方向に        移動速度    1フレームの時間 
単位(m)               (方向ベクトル)         単位(m/s)   単位(s)
transform.position += new Vector3(0,0,1.0f) * moveSpeed * Time.deltaTime;

上記の通り、左辺と右辺の単位が揃っています。
Time.deltaTimeを使うときはとりあえず単位を書き出すようにしてみましょう。
この状態でプレイしてみると、一秒に0.02mというすごく遅い速度で動くようになります。
どのPCでも同じ速度で動くようになったので、こうなれば速度を小さくする必要はありません。
今回はとりあえずmoveSpeedを3にしておきましょう。

壁を抜けない移動

前回軽く解説しましたが、transform.positionを変更する移動方法はワープです。
つまり、物理的に移動してないということは、物理エンジンによる衝突判定などがうまく働かないということですね。
ということで物理演算に必要なコンポーネント、Rigidbodyについて話していきます。

Rigidbodyとは

Rigidbodyは、物理演算を行うためのコンポーネントです。
オブジェクトを作成したときにはColliderが自動的に追加されますが、これとはまた違うものです。
簡単に言ってしまうとColliderは接触判定を行うだけで、物理演算をして接触して跳ね返って...のような処理はしてくれません。
IsTriggerをTrueにするとイベントマスを踏んで処理を行う、といったようなときに使えます。

さて、Rigidbodyを使うことで、物理的に動かし、物理演算をしてもらうことができます。
ということでまずは前回作った処理を変更していきましょう。
コメント 2020-09-06 204303.png
上記のようにPlayerにRigidbodyを足してみましょう。
そうすると壁にぶつかって止まりますね。

RigidbodyとColliderの使い分けですが、当たり判定は欲しいが移動はしないものにはColliderを。
両方欲しいときにはRigidbodyを入れるといいでしょう。
まあこのまとめ方もかなり細かい説明を省いているので、それぞれUnity公式のリファレンスを確認するといいでしょう。
Rigidbody
Collider

入力による移動

さて、上記の状態だと壁にぶつかったあと、壁に向かって移動し続けて、横に移動したりしますね。
現段階では球は前に進むことしかできないので、自分で動かせるようにしてみましょう。

入力を受け取る際にはUnityEngine.Inputのメソッド群を使います。
せっかくなので、キーバインドを自由にする方法で行います。
スマブラやマイクラなどをやっている方だとよく分かると思うのですが、できるならばボタンの割り当てを自分の好きにいじることができる方がいいですよね?

「Fキーでメニュー画面表示」のように実装することもできますが、拡張性が低いです。
マルチプラットフォームにも対応しているゲームエンジンなので、いちいちデバイスに合わせてif文で分岐させるなんて言うのは無理がありますよね。
つまり、「Menuボタンが押されたらメニュー画面表示」、「MenuボタンにFキーを割り当て」といった二段構えで設定することで、実装を楽にすることができます。
マルチプラットフォームの例で言うと、PS4では「MenuボタンにOptionボタンを割り当て」、Switchでは「Menuボタンに+ボタンを割り当て」という風にすればよくなり、プログラム自体を書き換える必要はなくなります。

左上にある、Edit→Project Settings→Input Managerを見てみましょう。
今回の入力で使うのは「Horizontal」と「Vertical」なので、とりあえずはここだけ見てみましょう。
コメント 2020-09-06 214322.png

ここでよく見てほしいのはNegative/Positive ButtonとAlt Negative/Positive Buttonです。
前者には左/右十字キーが割り当てられていて、後者にはa/dキーが割り当てられています。
つまり十字キーとWASDは同じ入力を意味するようにされています。
一番上のSizeの値を変えることで新しい入力を作ることができるので、自分でゲームを作った際に新しくボタンの役割を追加したい場合はぜひ活用してください。

さて、それでは実際の使い方を確認してみましょう。

PlayerMove.cs
public class PlayerMove : MonoBehaviour
{
    [SerializeField]private float moveSpeed = 3f;
    // Start is called before the first frame update
    //このオブジェクトが作られたときに行われる処理
    void Start()
    {

    }

    // Update is called once per frame
    //毎フレーム行われる処理
    void Update()
    {
        float hor = Input.GetAxis("Horizontal");
        float ver = Input.GetAxis("Vertical");
        Vector3 moveDir = new Vector3(hor, 0, ver);
        transform.position += moveDir * moveSpeed * Time.deltaTime;
    }
}

Input.GetAxis(<入力ソース名>);
は-1~1の値をスティックの倒し具合によって返します。
positive方向の入力を+、negative方向の入力を-と考えて返します。
コントローラーにスティックがあれば小数も扱えますが、PCのキーボードでは半押し不可能なので、
・-1(negative buttonを押している)
・1(positive buttonを押している)
・0(どちらのボタンも押していない)
以上のどれかになります。

入力ソース名には、先程Input Managerで確認した名前を入れましょう。
String型で入れないとエラー。Input Managerに存在しない名前を入れてもエラーになるのでタイプミスには注意しましょう。

横方向の入力(Horizontal)がx軸、縦方向の入力(Vertical)がz軸なので、その通りにmoveDirとして宣言してあげると、無事入力による移動が実装できます。
さっき確認したとおり、十字キーでもWASDでも同じ動きをしてくれることを確認してみてください。

今回は何も実装しませんが、Button系列の解説もしておきます。
Input.GetButton(<入力ソース名>);
Input.GetButtonDown(<入力ソース名>);
上記の2つは、入力ソースを軸ではなくボタンとして受け取ります。
2つの違いは何かというと、ButtonDownは押したフレームのみ動作し、Buttonは押している間ずっと動作します。

これだけじゃわかりにくいかと思うので実験してみましょう。

if (Input.GetButtonDown("Jump"))
{
    Debug.Log("Jump Button Pressed");
}

Update関数の最後尾にこの内容を付け足しましょう。
そして、ゲームをプレイしてスペースキーを押してみましょう。
コメント 2020-09-06 223154.png
Debug.Logはとても便利な関数です。
このようにConsoleに引数で渡した文字を表示させることができます。
変数の中身を表示させて正しい処理が行われているか確認したり、プロパティの中身を確認したりできます。
GetButtonDownなので、この場合は押して離すまでに1回しかログが出されません。

上記のプログラムをGetButton("Jump")に変更してみましょう。
コメント 2020-09-06 223713.png
すると、一瞬しか押していなくても複数回ログが出されます。
これは押されているフレームの間ずっとDebug.Logが実行されるためです。

ゲームで実装したい内容によっては使い分ける必要があるので、知っておきましょう。
また、サラッと説明してしまいましたが、Debug.Logは本当に重要なので覚えておきましょう。

最後に

これまで4回に渡ってUnityの解説をしてきましたが、いかがでしたでしょうか?
これで最低限は動かせるようになったのではないでしょうか。
とはいえ公式リファレンスを読めば基本的にはどの機能の使い方もわかるようになっています。
これからも、新しい機能を使ってみるときにはまず公式リファレンスを確認する癖をつけてください。
(そうは言うものの、いまいち画像が足りなかったり、英語しかなかったり、和訳がガバガバだったりと、公式だけじゃわからないときもしばしば...)

言ってしまうと、Unityでのゲーム制作は
Unity <やりたいこと>
でgoogle検索をすれば大抵は解決できてしまいます。
ただそれはソースコードをそのままコピペして解決してるだけです。
自分の講座では、なるべく何をしているかを説明していますが、説明を書いていない個人ブログなども検索に出てくることがあります。
みなさんには、なんで動いているのかよくわからないコードをコピペするだけの人にはなってほしくありません。
コピペで解決するのが悪いのではなく、動作内容を理解できていないのにコピペをして作ってしまうのをやめて欲しいということです。
(とはいえ物理演算を理解するために、物理と数学の勉強しろとは言いません)
Unityの関数の処理内容の解説をしているQiita記事などもあるので、なるべくたくさんの人の解説を見て、できるだけ処理内容を理解した上で作ってください。

当然ながらこの記事についても同様です。
なるべく色々調べて正確性を上げていますが、間違いがあるかもしれません。
この記事でわからなかったことは他の人の記事やサイトなどを確認してみてください。

参考

https://bardaxel.jp/archives/15

サークル公式Twitter
https://twitter.com/chuojoken?s=09

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【unityroom】投稿作品をアプリ化するときのエラー対応

unityroomに投稿したゲームにAdmobを追加してアプリ化するときにエラーが出てしまうことがありました。
今回はその修正方法について紹介したいと思います。

ブログ本文はこちらです。
https://tedenglish.site/cnv-uniryroom-apps-error/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】シンプレックスノイズを使ってオブジェクトをランダムかつ滑らかに回転させる

ふとUnityでオブジェクトをランダムかつ滑らかに回転させたくなったのでやってみました。

概要

こんな感じでランダムかつ滑らかにオブジェクトを回転させます。simplex_noise_rotation.gif

シンプレックスノイズを使って実現していきます。

実装

SimplexNoiseRotation.cs
using UnityEngine;
using Unity.Mathematics;
using static Unity.Mathematics.math;

public class SimplexNoiseRotation : MonoBehaviour
{
    [SerializeField] float speed;
    float speedOffset;

    void Start()
    {
        speedOffset = UnityEngine.Random.Range(0f, 1000f);
        SetRotation();
    }

    void Update()
    {
        speedOffset += speed * Time.deltaTime;
        SetRotation();
    }

    void SetRotation()
    {
        Transform trans = this.gameObject.transform;
        float x = noise.snoise(float2(0f, speedOffset));
        float y = noise.snoise(float2(64f, speedOffset));
        float z = noise.snoise(float2(128f, speedOffset));
        float w = noise.snoise(float2(192f, speedOffset));
        trans.rotation = new Quaternion(x, y, z, w);
    }
}

ランダムかつ滑らかに回転させるには、時間に対して滑らかに変化する乱数が必要です。そのような乱数にはパーリンノイズシンプレックスノイズがありますが、ここではより高性能(らしい)シンプレックスノイズの方を使っていきます。Unityにはシンプレックスノイズが既に実装されており、Unity.Mathematics.noise.snoiseから利用できます。noise.snoiseはstruct float2struct float3struct float4のいずれも引数に取ることができます。またこの記事によるとnoise.snoiseの返り値は-1.0から1.0の間です。

そしてシンプレックスノイズをどのように回転に反映させるかが重要ですが、ここでは単純にtransform.rotationの各成分にnoise.snoiseの値を代入しています。noise.snoiseの引数をわずかに変更してやればnoise.snoiseは滑らかに変化するので、transform.rotationも滑らかに変化します。noise.snoiseの第一引数の値はとりあえず異なる値を適当に入れています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

極小マイコン「Leafony」をUnityからLチカする

はじめに

昔、MCPCナノコンハッカソンに出場したときにいただいた極小マイコン「Leafony」を久しぶりに取り出して遊んでみました。

BLEモジュールや加速度センサをマイコンに載せても凄まじい小ささです。

やりたいこと

一度、下記の動画のような加速度センサで何かしらオブジェクトをぐりぐりさせてみたいです。
加速度センサでUnityオブジェクトをぐりぐりしてみた
ただUnityをつかったことないので、まずはUnityからLeafonyにのっているLEDをシリアル通信でLチカさせてみました。

つかうもの

  • macOS catalina
  • Leafony
  • Unity 2020.1.4

参考にしたもの

UnityからArduinoをつかうために,便利な有償アセットUduinoがあるようですが、それを使わなくてもUnityからArduinoへシリアル通信できます。

こちら説明とgithubリポジトリが参考になりました。

やりかた

Unity

  1. こちらのリポジトリをダウンロード
  2. ダウンロードしたパッケージをUnityにインポート
  3. こちらの動画どおりの手順を実行します

Leafony

ボードとプロセッサーは下記を選択します。
こちらは公式ホームページに書いてあります。

  • Arduino Pro or Pro Mini
  • ATmega328P(3.3V, 8MHz) image.png

プログラムはこちらのリポジトリをダウンロードをそのまま使っています。

bool lightOn = false;

// the setup routine runs once when you press reset:
void setup() {
  Serial.begin(115200);
  // make the pushbutton's pin an input:
  pinMode(LED_BUILTIN, OUTPUT);
}

// the loop routine runs over and over again forever:
void loop() {
  // print out the state of the button:
  if(Serial.available()){
    char c = Serial.read();
    if (c){
      if(c == 'A'){
        lightOn = true;
      }
      else if(c == 'Z'){
        lightOn = false;
      }
      c = NULL;
    }
  }
  if(lightOn){
    digitalWrite(LED_BUILTIN, HIGH);
    Serial.println("on");
  }else{
    digitalWrite(LED_BUILTIN, LOW);
    Serial.println("off");
  }
  delay(1000);        // delay in between reads for stability
}

動作確認

あとはUnity上で実行ボタン(下記画像の▷ボタン)を押して、上記のプログラムに記載がある「A」もしくは「Z」のキーを押すとUnityからLeafonyでLチカできました。
image.png

leafony_unity_LED.gif

おわり

公開されているリポジトリを使えば簡単にUnityからLeafonyでLチカができました。
Unity上のオブジェクトを加速度センサでグリグリできるように精進しようと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ML-Agentsのサンプルの動かし方

概要

ML-Agentのサンプルモデルの学習方法と動かし方についてまとめた記事です。大まかな流れだけのメモだと思ってください。Anacondaやpipなど使用します。これらの設定方法は各自行ってください。細かい環境などは前回の記事を参考にしてください。

環境

  • macOS Catalina 10.15.5
  • Anaconda 4.8.3
  • python 3.8.3
  • pip 20.1.1

3DBallモデル

今回はML-Agentsのサンプル内にある3DBallというモデルを使用し、学習方法などを説明していきます。3DBallはボックスの上に乗っているボールを落とさないようにするモデルのことです。

前回の記事の続きです。

左下の Assets/ML-Agents/Examples/3DBall/Scenes を開き、赤い印をつけたモデルをダブルクリックします。下の画像のようになると思います。
スクリーンショット 2020-09-05 21.40.10.png
赤く印つけた再生ボタンを押すと下の画像のようになります。サンプルのモデルはすでに学習済みなので、ボールを落とさないように動いていることが確認できます。
qiita_gif.gif
次からモデルの学習方法について説明していきます。

学習する環境を整える

まずはじめにモデルを学習させるAnacondaの仮想環境を作成します。
ML-Agentsではpython 3.6.1 以降が必要です。今回はpython 3.8.3 を使用します。

$ conda create -n mlagents python=3.8.3 anaconda
$ conda activate mlagents

次にpythonパッケージの ml-agents、 ml-agents-env をインストールします。
前回ダウンロードした ml-agents-release_6 に移動して以下のコマンドを実行します。

cd ml-agents-envs
pip3 install -e ./
cd ..
cd ml-agents
pip3 install -e ./
cd ..

これでモデルを学習させる環境が整いました。

モデルを学習させる

次に3DBallを学習させていきます。
やることは以下の3つです。

  • ハイパーパラメータを設定する。
  • Anacondaの仮想環境でプログラムを実行する。
  • unityのモデルを実行する。

ハイパーパラメータを設定する

ml-agents-release_6/config で学習アルゴリズムやパラメータを設定します。
ppo、sacというフォルダがあります。それぞれ強化学習のアルゴリズムになります。

  • PPO : Proximal Policy Optimization
  • SAC : Soft Actor-Critic

とりあえずppoを使用します。このファイル内にppoのパラメータを設定するYAMLファイルがあります。YAMLファイルを作成することでハイパーパラメータを自由に設定することができます。3DBallのパラメータはすでに3DBall.yamlに設定されているのでそのまま使用します。

Anacondaの仮想環境でプログラムを実行する

学習させるpythonスクリプトを実行します。さっき作成した仮想環境で ml-agents-release_6/ml-agents に移動し以下のコマンドを実行してください。

mlagents-learn ../config/ppo/3DBall.yaml --run-id=3DBall --train

--run-id はなんでもいいです。実行すると次の画像のようにunityのロゴが出てきます。
スクリーンショット 2020-09-06 2.24.42.png

unityのモデルを実行する

次にunity上でモデルを実行します。実行ボタンを押すだけでいいです。学習が進むと以下の画像のようになります。
スクリーンショット 2020-09-06 3.15.52.png
「Mean Reward」は平均報酬です。3DBallは最大値が100になっています。16万ステップあたりから最大になっていることがわかります。「Std of ReWard」は報酬の標準偏差です。小さくなるほど良いです。20万ステップあたりで学習仕切れていることがわかります。

1万ステップと15万ステップの挙動を以下に示します。ボールを落とさないように学習できていることがわかります。

1万ステップ
10000step.gif
15万ステップ
15000step.gif

学習後のモデル

学習したモデルは ml-agents/results にさっき指定した --run-id の名前のフォルダができています。そのフォルダの中の 3DBall.nn が学習済みのモデルになります。新しく学習したモデルを使用する場合はunityの Assets/ML-Agents/Example/3DBall/TFModels に 3DBall.nn を追加し、Agent の Behavior Parameters の Model で 3DBall.nn を選択してください。

まとめ

ML-Agentsのサンプルモデルの動かし方について記事を書きました。ML-Agentsでの学習方法は基本的にこの流れになります。間違っていることがあるかもしれないので参考程度にしてください。また公式にドキュメントがあります。

次回はカートポールのモデルを作成し、学習させる記事を書きたいと思います。

参考にさせてもらったサイト

Unity ML-Agents 0.15.0 のチュートリアル(1)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityで作ったVRアプリをOculusQuestでビルドする

はじめに

メディアアートを創った際にVR技術に触る経験をしました。
ビルドにおける負荷の部分で詰まって何度も設定をやり直した結果、Unityで作ったVRアプリをOculusQuestで立ち上げするための簡易メモが完成したので、備忘録として書き残していきたいと思います。

実行環境:
Unityバージョン 2019.4.9.f1
macOS Catalina

下準備

Android Studioのインストール。
インストール後に推奨されるモジュールを追加。

②UnityへAndroidのモジュールを追加
UnityHub → インストール

スクリーンショット 2020-09-05 21.04.40.png

③ADB(Android Device Bridge)へのパスを通す
ホームディレクトリの直下にある(ない場合は作る)
「.bash_profile」に下記を記述。

export PATH=$PATH:/Users/UserName/Library/Android/sdk/platform-tools

ADBに関する参考ページ

④Oculasアプリをスマートフォンで開き、開発者モードをオンにする
設定→OculusQuest端末番号→その他の設定→開発者モード

iOS の画像 (1).png

⑤OculusQuestとPCを接続した状態で、下記コマンドをターミナルで入力

adb devices

接続が成功していると、OculusQuestの端末番号が表示されます。

Unity内のビルドの設定

①SDKをセットする
Unity → Preferences → External Tools
Androidの項目の全てにチェックを入れる
スクリーンショット 2020-09-05 23.30.45.png

②ビルドするプラットフォームをAndroidへ変更
スクリーンショット 2020-09-05 23.36.42.png

Texture Compressionを「ASTC」へ変更。Switch Platformをクリックして、Androidでビルドする設定に変更。

③XR Plugin Managementをインストール
File → Build Setting→ Playser Setting
左側の項からXR Plugin Managementを選択。インストール。

スクリーンショット 2020-09-05 23.45.26.png
Oculasをクリック
スクリーンショット 2020-09-05 23.46.59.png

④Buildするための設定
Playser Setting内の設定を変更

④-1 OtherSettingsの設定
・Color Spaceを「Linear」へ変更
・Auto Graphics APIsのチェックを外し、OpenGLES3だけを残す
・Multithreaded Renderingにチェックをつける

④-2 Identificationの設定
・Minimum API Levelを7.1へ変更
・Scripting BackendをIL2CPPへ変更
・API Compatibility Levelを.NET 4.xへ変更

シーン内の設定

①AssetStoreからOculus Integrationをインポートする。
シーンの中でデフォルトで設定されているCameraを削除して、Oculus Integration内にあるOVRCameraRigをヒエラルキー内に入れると、Buildした時に360度カメラになります。

ビルドをしてみる

File→BuildSetting内のAndroid PlatformでBuildすることで、「.apk」の拡張子を持つファイルを作ることが出来ます。
Buildした時点でOculusQuestの内部にはアプリが保存されていますが、作成した「.apk」のファイルをターミナルから入力することで、接続されたOculusQuest内にBuildすることが可能です。

既に作成してある「.apk」の拡張子を持つファイルをOculusQuest内にインストールするには、下記コマンドをOculusQuestとPCを接続した状態で入力。

 adb install -r ファイルパス

ハマったところや開発中に悩んだことなどのメモ

①Buildをしても360度で見渡すことができない
何度Buildしてもアプリを360度で見渡すことができず、「Made with Unity」と表示される真っ黒の画面かシーンがスクリーンのように平面でBuildされ、エラーもconsoleに出力されることがなかったのでお手上げ状態でしたが、段階的にBuildしていく中でとある処理が重すぎることに気が付き、パラメータを弄ったところ、無事にBuildすることが出来ました。

②Buildしたファイルはどこにある?
ビルドしたファイルは「提供元不明アプリ」としてOculasQuest内に保存されます。
以前のOculasQuestではメニュー内のライブラリの項目からアクセス出来ましたが、新しいUIではライブラリがなくなっており、アプリ一覧から探すことになります。
アプリ → 全てのアプリ → 右上のタブ → 提供元不明
非常に分かりにくい場所にあるので、要注意。
参考記事

③OculasQuest内で保存した内容をPCヘ移したい
Android File Transferを利用。
録画したOculasQuest内の動画やファイルにアクセスすることができ、自分のPC内に保存することができます。

④ファイルをGitHubで管理したい
通常のターミナル操作だとUnityファイルの容量が重すぎるためにPush出来ず、Git LFSを利用。
参考ページ

おわりに

以上、Unityで作ったVRアプリをOculusQuestでビルドする際のフローを要点だけ掻い摘んでまとめてみました。

それでは、また?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む