勉強不足で至らんブログ

勉強不足ですが、何か発信できればと思っています。

箱庭の音

音を基軸としたコンテンツを作ってみたかった

たまにMVとかを自動化できたら面白そうかなとか思っていたので形にするならどうなるんだろう?と思って作りました

youtu.be

音によって色々なパラメーターが変わるコンテンツです

※音が出ます

mizotake.github.io

音に合わせてカメラが揺れたり、傘の移動速度が変わったりします。

さらに音を好きな音楽に変えることができてwavファイルのドラッグ&ドロップで放り込めば切り替わって、切り替えた音を取得して動きが変わるコンテンツになります

音によって空間の動きが変わるけど一部しか観れないので箱庭っぽいなぁということで「箱庭の音」というタイトルにしています(多少キャッチーなタイトルがよかったかも)

影しか写らない横断歩道は自分の世界観なだけなので特に理由がないです

開発環境など

github.com

コアとなる部分はUnityで作っていてドラッグ処理などをVue.jsで繋げています

有料Assetsも使ってるのでリポジトリを公開しているもののUnityプロジェクトは誰でも触れるものにはなってないです。。。

Vue.jsから11MBのファイルをUnityに渡すためにbase64するとメモリが足りなくなったりと意外と気を遣うところが出てきたりしました。。。

あとはVue.jsをまともに触るのは初めてだったので作りがかなりイケてないんだろうなと思ってますが作りきることのが大事だと思ってるのでとりあえず作りました(cssが相対的でなかったりビルド後のファイルパスを相対的に治したり…設定があるんだろうけど動かしたかった)

wavファイルを動的ロードする際にUnityWavというのを使ったのですがバイナリの読み取りに柔軟性がなくforkして修正するなどしてました → forkしたリポジトリ

そしてAudioの数値取得は

AudioSource-GetSpectrumData - Unity スクリプトリファレンス

で通常はできるのですがWebGLだと動かないため

assetstore.unity.com

を使って実装しました、、、動いてよかった

ホントはSoundCloudapiを叩いて自由度もあげたかったけどノウハウなさすぎたので一旦断念中

実は昔のプロジェクトをベースとしている

UnityをVueで動かすノウハウ Unityで吐いたWebGLをPWAで動かしてみた - Qiita

遊んでただけの音からパラメーター取るロジックや

見た目に凝ろうとして途中断念したプロジェクトを掛け合わせて作りました

そのため二週間くらいで作りきれたので蓄積大事だなと思っています

さいごに

今後「箱庭」の種類を増やして音を分析して自動的に見た目を変えたりしていきたいと思っています

そのために

github.com

を使ってもっと取得できるパラメーターを増やして遊べるとよさそうだなぁと思ったり

動画とはちょっと違うところがありますが動画としてみれるようにpinp(ピクチャーインピクチャ)機能を使う表示も視野にいれてみたい…

Unity2019.3からのXcodeプロジェクトでSwiftが使えるのか検証

obj-cを書きたくない

シンプルにそれだけ

僕はSwiftが使いたい

blogs.unity3d.com

そして来たるUnity2019.3…Unityのコア部分が.frameworkになるらしい

まぁそれだけなら気にしないしBuildのPostProcessを変えるくらいだろうと思ったら

下のコメントに

However for iOS, we won’t be supporting SWIFT for now, our focus in on Objective C.

Swiftのサポートは考えてない…?

え、まじで

まずは動かす環境を整える

2019.3.5f1を検証に選びリポジトリは以前

Unityのネイティブプラグイン(macOS/iOS/tvOS)のソースコードを共通化する - 勉強不足で至らんブログ

で使用した

GitHub - MizoTake/ApplePlatformNativePluginSample

を使うことに

検証のためにリポジトリにあるPostProcessは全部コメントアウトした

動かそう

UnityビルドしてXcodeでビルドするが案の定エラー

エラーが出てきて解決していくが

"Umbrella header not found" というのだけ解決ができなくて悩んだ

ただネイティブの記事で

qiita.com

というのがありネイティブで可能ならUnityもできるはずと思い調べる

https://forum.unity.com/threads/build-ios-umbrella-error.838879/

Which states that it is a regression bug and is not happening in 2020.1 beta.

まじかよ

ということで2020.1をインストール

f:id:MakeTake:20200318194947p:plain

動くやんけ

しかもSwiftのバージョン勝手に設定してくれる様になってるやんけ

最高かよ

まとめ

2020ベータなら動いたので2019.3でSwiftのネイティブプラグインを使うのは避けた方が良さそう

これからもSwiftネイティブプラグインは使用可能!

ScreenBrightnessRangeSettingを公開しました

Androidネイティブを作ってみたかった

興味本位と勢いで作ってリリースしました

とてもとても業務レベルには至らないと自分で思いつつ開発していました

play.google.com

スマホの画面輝度の自動調整を範囲制限できるものになります

iOSでできなさそうなものを考えて作ってみました

github.com

ソースコード自体は全部公開してますが設計思想も何もないです

初めてのAndroidネイティブアプリでKotlin要素のみという経験でした

バックグラウンドで動かすあたりがとても怪しく勢いです

一番知見だったのは、Google Playストアでもきちんと審査されるようになっているんだな…と…昔は数時間でリリースできたのに今回は4日前後かかった気がします

今後は暇作ってUIとかアプリ名とかぼちぼち更新していこうかなと…

StateMachineBehaviourにInjectする

StateMachineBehaviourにInjectする方法

ZenjectでStateMachineBehaviourを使ってみたいと思ったのが発端で

検索すると自動的にInjectできるようになったそう…だがMonoBehaviourと同じように[Inject]を付けても実行されない…

調べると

ZenjectStateMachineBehaviourAutoInjecter というのがある

中身をみるとシンプルで

using ModestTree;
using UnityEngine;

namespace Zenject
{
    public class ZenjectStateMachineBehaviourAutoInjecter : MonoBehaviour
    {
        DiContainer _container;
        Animator _animator;

        [Inject]
        public void Construct(DiContainer container)
        {
            _container = container;
            _animator = GetComponent<Animator>();
            Assert.IsNotNull(_animator);
        }

        // The unity docs (https://unity3d.com/learn/tutorials/modules/beginner/5-pre-order-beta/state-machine-behaviours)
        // mention that StateMachineBehaviour's should only be retrieved in the Start method
        // which is why we do it here
        public void Start()
        {
            // Animator can be null when users create GameObjects directly so in that case
            // Just don't bother attempting to inject the behaviour classes
            if (_animator != null)
            {
                var behaviours = _animator.GetBehaviours<StateMachineBehaviour>();

                if (behaviours != null)
                {
                    foreach (var behaviour in behaviours)
                    {
                        _container.Inject(behaviour);
                    }
                }
            }
        }
    }
}

となっており手動でComponent追加すればStateMachineBehaviourにInjectする感じぽい

ただ前提として 最初からSceneにあること なので動的にやるとき用に少しだけ変えて

using UnityEngine;
using Zenject;

namespace Hoge.Components
{
    public class StateMachineBehaviourInjector : MonoBehaviour
    {
        public void InjectionTo(Animator animator)
        {
            var behaviours = animator.GetBehaviours<UnityEngine.StateMachineBehaviour>();

            if (behaviours == null) return;
            foreach (var behaviour in behaviours)
            {
                // DiContainerがProjectContextでいい場合
                ProjectContext.Instance.Container.Inject(behaviour);
            }
        }
    }
}

って感じで外から呼べるようにして使うようにした

ちゃんとInjectされたのでめでたしメモ

UnityのEditModeTestsをdotnetで実行させる

UnityのTestをUnityEditorを使わないでどうにか走らせれないか?

と考えのがきっかけです。

UnityのCIをCircleCIで頑張る - 勉強不足で至らんブログ

過去CircleCIでUnityEngineが入ったDockerを使っていたりしましたがDockerコンテナのセットアップで

f:id:MakeTake:20200204230713p:plain

長くて3分弱かかります早くて1分程度にはなります。 docker_layer_cachingを使えば10秒くらいのにもできますがUnityEngineの入ったDockerを使おうとすると工夫が必要になります。

工夫なく手軽に使えたらいいのに…と思ったところで

booth.pm

にある

  • 第5章:Unityと.NET Coreでのコード共有

を思い出しました。これでdotnetのtestから走らせればいいのでは…と思ってやってみました。

結果的に今回はEdit Mode Testsであれば可能でした。最後の方に記述しますがPlay Modeももしかするとできるかもしれません。

今回のリポジトリ github.com

CircleCIの結果 https://circleci.com/gh/MizoTake/UnityTestFromDotnet

セットアップ

基本的なセットアップ手順は 第5章:Unityと.NET Coreでのコード共有 にありますのでそちらの手順に添えば大丈夫です。 サンプルリポジトリも公開してるそうです。 github.com

自分は追加でdotnetのプロジェクトの.csprojに

  <ItemGroup>
    <PackageReference Include="NUnit" Version="3.12.0" />
    <PackageReference Include="Unity3D.UnityEngine" Version="2018.3.5.1" />
    <PackageReference Include="coverlet.collector" Version="1.0.1" />
    <PackageReference Include="NUnit3TestAdapter" Version="3.16.0" />
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
  </ItemGroup>

を追加しています。基本的にNuGetで検索すればでるはずなので導入方法はやりやすいものがいいと思います。

注意なのは Unity3D.UnityEngine のバージョンが2018台のいくつかしかないことです。バージョンを超える何かを行たい場合は工夫が必要になると思います。

Testを実行する

普通にC#でEdit Mode Testsを記述します。今回はサンプルで

using NUnit.Framework;

public class TestSample
{
    [Test]
    public void Passed()
    {
        Assert.AreEqual(true, true);
    }
    
    [Test]
    public void Failed()
    {
        Assert.AreEqual(true, false);
    }
}

としました。これをUnityのTestRunnerが認識するように作ります。

ただ、少し踏み入ってUnityEngineの参照を行おうとすると参照できないことがあるのでdllの解決をうまくやる必要がありそうです。自分も確認不足でしたのでわかり次第更新します。

あとはdotnet test を実行すればtestが走り、結果が得れます。

手元で得るよりはCIで走らせて見れた方がいいと思うのでCircleCIで走らせました。

version: 2.1

executors:
  dotnet:
    docker:
      - image: mcr.microsoft.com/dotnet/core/sdk:3.0

jobs:
  test:
    executor: dotnet
    steps:
      - checkout
      - run: dotnet tool install trx2junit
      - run: "dotnet test --logger trx || : ; dotnet trx2junit dotnetProject/TestResults/*.trx --output results"
      - store_test_results:
          path: results

workflows:
  version: 2
  test-flow:
    jobs:
      - test

途中でdotnet toolで trx2junit というのを導入していますが dotnet test だとtestの結果は.trxという形式で吐き出されるためです。CircleCIではJUnitCucumberしか対応していないので変換させるためにtrx2junitを使用します。

一度手元でdotnet tool install trx2junitを実行すれば.configというディレクトリに

{
  "version": 1,
  "isRoot": true,
  "tools": {
    "trx2junit": {
      "version": "1.3.0",
      "commands": [
        "trx2junit"
      ]
    }
  }
}

が作成されます。これがあればinstallできるぽいです。もしかすると.configはignoreしていいディレクトリかもしれません。

ともかくこれでCircleCIのTest Summaryに登録でき、エラーがあった場合に f:id:MakeTake:20200204234208p:plain という風に見れるので対処もやりやすくなると思います。

またdotnet test実行時のコマンドは、この形式でないとテストがこけた際にtrxから変換ができずにTest Summaryが使えず終わってしまうのを回避するためのものです。

さいごに

ここまででUnityのEdit Mode Testsをdotnetで実行させる方法の説明は終わりです。UnityEngineがなくても実行できる環境というのは結構魅力的だと思っています。さらにはUnityのactivateが必要ないのでかなり良いです。

いずれPlay Mode Testsも実行させれるようにしてみたいため調べてみると www.nuget.org

があったので試しましたがそのままでは動きませんでした。ただ工夫をすればいけるような感じだったので時間のある時に挑戦してみようかと思います。

Unityでタイムラプスぽいことできないか試した

Unityでタイムラプスの表現できたら面白いのでは?

とアニメのOPなどをみて思いました。タイムラプスって面白いのでどうやったらそれっぽっく表現できるのか試しました。

Unityで表現するには簡単で Time.timeScale を弄って大きいする数字にだけでタイムラプスぽく見えるようになりました。

Time.timeScaleを大きくして早送りしてからキャラクターを表示非表示を一定の間隔で行えばいけるかな?と思ったらtimeScaleを弄るだけでおわりました…

一定の値を超えたあたりからそう見えるので閾値がありそうだなとは思いました…ができたことに満足したので終わりました。。。

Unityのネイティブプラグイン(macOS/iOS/tvOS)のソースコードを共通化する

ネイティブプラグインの動作確認

iOS/tvOSのネイティブプラグインはEditorでは動かせません。そこでmacOSで同じソースコードを動かせばいいのでは?と考えて動かしてみました。

ただ全てが動くわけではないと思いますし一部機能の制限が入ります。調べ尽くしてないので、もしかすると使えます。わかっているのは以下の一点です。

  • entitlementファイルを使う場合は.bundleにcodesignができれば動きそう(パッと試した感じはできなかった)

一点といいつつ結構範囲が大きいです。あくまでEditorで動かす.bundleにする際にできないというだけで.appにcodesignを使えば動くはずです。

リポジトリはこちら

github.com

Editor(macOS)での動作はもちろん、シミュレーターになりますがiOS/tvOSで動作確認をしました。

Editor(macOS) iOS tvOS
f:id:MakeTake:20200202160024p:plain f:id:MakeTake:20200202160042p:plain f:id:MakeTake:20200202160047p:plain

実装

今回Swiftにてコアのコードを記述しました。

import Foundation

@objcMembers
public class Sample : NSObject {
    
    public override init() {
        super.init()
    }
    
    public func Call() -> String {
        "From Swift Code"
    }
}

Objective-CでラップしてC#側でStringをTextMeshProForUGIに表示させています。

Editorで動かすためのXcodeProjectを作る

UnityのPluginsディレクトリに.swiftや.mmがある前提で話をします。

まずはXcodeでProjectの新規作成を行ます。 f:id:MakeTake:20200202160853p:plain

UnityEditorでは.bundleというフォーマットで動作をするのでBundleのテンプレートを選択します。

次にプロジェクト名を求められるのでお好きなプロジェクト名を入力します。

これで保存場所を選択して作成完了です。

これからUnityのPlugins配下にあるファイルを参照してXcodeのプロジェクトに含めます。 ファイルを選ぶ際にコピーするかどうかのオプションがりますが別ファイルになってしまうのでOFFにしておいた方が良いです。

info.plistの入っているディレクトリを右クリックして以下の項目を選択します。 f:id:MakeTake:20200202172214p:plain

次にSwiftを使用する設定です。 先ほどのファイル追加で処理が走り、Swiftなどの設定が増えます。そこで f:id:MakeTake:20200202172228p:plain

左の青いアイコンを選択して Build Settings を選びます。そこから Basic Customized All と選ぶポイントがあるので All にして検索ボックスに -swift.h と検索します。

そして Objective-C Generated Interface Header Name のところをUnityのPlayerSettingsで設定するProduct Nameを確認して {ProductName}-Swift.h と入力しておきます。

こうすることでUnityでiOS/tvOSのプロジェクトが吐かれた時にエラーが出なくなります。

これで準備ができたのでXcodeのRunボタンでDebugモードでビルドします。 f:id:MakeTake:20200202162612p:plain

ビルドすると Products ディレクトリ配下にbundleができるのでUnityのPluginsディレクトリ配下におきます。

f:id:MakeTake:20200202172243p:plain

Show in Finder を選択するとFinderでドラッグ&ドロップできるのでおすすめです。(xcodeのpostprocessに移動するscriptを書けばいいのですがめんどくさかった…)

Editorで動かす準備ができました。

C#プラグインを呼ぶ

C#で呼ぶ処理を書いて動かしてみましょう。

今回はC#でこう書きました。

using System.Runtime.InteropServices;
using TMPro;
using UnityEngine;

namespace ApplePlatformNativePlugin {

    public class SampleText : MonoBehaviour
    {

        [SerializeField] private TextMeshProUGUI centerText;
        
#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
        private const string LibraryName = "XcodeProject";
#elif (UNITY_IOS || UNITY_TVOS) && !UNITY_EDITOR
        private const string LibraryName = "__Internal";
#endif
        
        
        [DllImport (LibraryName)]
        private static extern string CallNativeString();
        
        void Start()
        {
            centerText.text = CallNativeString();
        }
    }
    
}

これでSceneに配置してUIに表示させています。

おわりに

以上がAppleのプラットフォームのネイティブプラグインを共通化させEditorで確認する方法でした。これであれば実機でしか動かせない!という時も処理だけならEditorで簡易に確認が可能かと思います。 資格情報の署名がわからず、このままでは機能が一部動作しませんが一旦はいいかなと思っています。