Unityでタイムラプスぽいことできないか試した
Unityでタイムラプスの表現できたら面白いのでは?
とアニメのOPなどをみて思いました。タイムラプスって面白いのでどうやったらそれっぽっく表現できるのか試しました。
Time.timeScaleを弄ってるだけでタイムラプスぽくなるの楽しい pic.twitter.com/Vo0537B4fU
— あるど (@OrangeGKeeper) 2020年2月2日
Unityで表現するには簡単で Time.timeScale を弄って大きいする数字にだけでタイムラプスぽく見えるようになりました。
Time.timeScaleを大きくして早送りしてからキャラクターを表示非表示を一定の間隔で行えばいけるかな?と思ったらtimeScaleを弄るだけでおわりました…
一定の値を超えたあたりからそう見えるので閾値がありそうだなとは思いました…ができたことに満足したので終わりました。。。
Unityのネイティブプラグイン(macOS/iOS/tvOS)のソースコードを共通化する
ネイティブプラグインの動作確認
iOS/tvOSのネイティブプラグインはEditorでは動かせません。そこでmacOSで同じソースコードを動かせばいいのでは?と考えて動かしてみました。
ただ全てが動くわけではないと思いますし一部機能の制限が入ります。調べ尽くしてないので、もしかすると使えます。わかっているのは以下の一点です。
- entitlementファイルを使う場合は.bundleにcodesignができれば動きそう(パッと試した感じはできなかった)
一点といいつつ結構範囲が大きいです。あくまでEditorで動かす.bundleにする際にできないというだけで.appにcodesignを使えば動くはずです。
リポジトリはこちら
Editor(macOS)での動作はもちろん、シミュレーターになりますがiOS/tvOSで動作確認をしました。
Editor(macOS) | iOS | tvOS |
---|---|---|
実装
今回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の新規作成を行ます。
UnityEditorでは.bundleというフォーマットで動作をするのでBundleのテンプレートを選択します。
次にプロジェクト名を求められるのでお好きなプロジェクト名を入力します。
これで保存場所を選択して作成完了です。
これからUnityのPlugins配下にあるファイルを参照してXcodeのプロジェクトに含めます。 ファイルを選ぶ際にコピーするかどうかのオプションがりますが別ファイルになってしまうのでOFFにしておいた方が良いです。
info.plistの入っているディレクトリを右クリックして以下の項目を選択します。
次にSwiftを使用する設定です。 先ほどのファイル追加で処理が走り、Swiftなどの設定が増えます。そこで
左の青いアイコンを選択して 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モードでビルドします。
ビルドすると Products
ディレクトリ配下にbundleができるのでUnityのPluginsディレクトリ配下におきます。
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で簡易に確認が可能かと思います。 資格情報の署名がわからず、このままでは機能が一部動作しませんが一旦はいいかなと思っています。
UnityでFirebaseのRealtime Databaseで位置同期検証してみた
Firebaseでキャラクター同期して遊べるゲームの検証
昨今UnityでもCrashlyticsやAnalyticsも内包しているFirebase使ってみようかなと思ったのがきっかけです。 特にFirebaseのRealtime Databaseを使うとFirebaseで値を保持してすぐにクライアントと同期してくれるというので試してみました。Firebaseはリアルタイムに同期するゲームには向いていないという意見をよくみてなんでだろう?と思ったので検証しました。
自分はサーバー側がわからなければFirebaseも初めて触っているので当たり前のことでもわからないため動かしました。
動かした結果は以下のツイートの動画になります。FirebaseのRealtime Databaseを使えるプロジェクトを用意してEditorで動かしました。位置は毎フレーム同期させています。
Realtimedatabaseでやってみたけど割と…
— あるど (@OrangeGKeeper) 2020年1月6日
接続数とかの問題が出ると大変なのかもだけど pic.twitter.com/xBOAaVnITR
右のEditorのキャラクターの位置がすぐに左に反映されているのがわかると思います。 この結果だけみると「意外といけるのでは?」と思っていました。 しかし、Realtime Databaseには無料枠だと制限があります。
Firebaseから情報をダウンロードするのに月10GBの制限があるのですが、2つのクライアントから数分動かしただけで27.3MBかかっています。これが人数が増える or 情報が多くなるとものの数日や数時間で10GBに到達してしまいます。従量課金制のプランにすれば上限なしでかかった分だけ払えばいいのですが一旦無料でいけるところまでやりたいので今回は検証結果をまとめるだけまとめてスルーしておこうと思います。
次はMirrorでも試してみようかと思っています。 github.com
振り返ってみる【2019】
今年を振り返ってみる
初めてこういうことを書いてみるのですが今年は色々やった気がするのでまとめてみます。
結構初めてのことをやり散らかした年なのかなと思っています。
転職
新卒で入った会社を辞めました。
最初からとんでもなく大きい出来事ですが、これが1月に辞める旨の話を会社にして初めて転職を行ったので最初に来る出来事でした。今は新しいところで前職の知識も使いつつゲームを作る日々でございます。
初LT
イベントのLTを初めてしました。身内でのLTとかはやったことあったのですが外部イベントは初めてでした。どちゃくそ緊張してgdgdだった気しかしてないです。LTをやるのも慣れだなぁとは思います。
その後もまた
LTをして経験を積んでいけたと思います。
動画まで残っているのは見返す良い機会なのですが…下手でしんどい…精進…
LINEスタンプの販売、音楽制作
プログラミング以外にも手を出し始めました。
やってみると意外とできるもんだんぁという感じですが、どちらもクオリティが高いものではなくて自分の第一歩かなと思います。いずれは頭に思ってるものをポンポン作っていけるようになりたいなぁとは思ってます。
同人誌への寄稿
前々から興味があった同人誌への寄稿を行いました。
初めての同人誌寄稿は文章校正とか大変で期限ぎりぎりで修正してました…スパン短くガンガン出してる人はすごいですね。。。苦労が少しわかるようになりました。楽しかったので良かったですけどね。
アドベントカレンダーへの参加
これも前から興味あって踏み出せてなかったひとつです。
自分が一番つかうUnityのアドベントカレンダーに参加してました。地味に役立つかもしれないものですね。仕事で欲しかったのでサクッと書いたものです。 「便利そう」って声を見かけたりしたので書いてよかったです。
MVのエキストラ参加
推しているMonsterZ MATEというユニットのMV参加募集があったので応募したら通った…
【MVエキストラ募集の予告】
— 🐺🦇MonsterZ MATE(アンジョーとコーサカ) (@monsterzmate) 2019年11月18日
新作MVの撮影(実写)にて、エキストラを募集します✨
・日時:2019年12月5日(木) 午後〜夜撮影
・場所:都内某所
・応募多数の場合抽選
※交通費等、自己負担となります。
※顔が映り込む場合があります。
まだ詳細が出せずごめんなさい🙇♂️是非続報をお待ちください!#MZM pic.twitter.com/oZMO6FHETc
まじかよという気持ちをもちつつド平日に半休とったりして行きましたよ… 公開されたのがこちら
【新作MV投稿】
— 🐺🦇MonsterZ MATE(アンジョーとコーサカ) (@monsterzmate) 2019年12月19日
🌟【MV】Beep☆CARAMEL / MonsterZ MATE🌟
🔻🔻フルはこちら🔻🔻https://t.co/kasXnq43IW
今月配信を開始した新曲『Beep☆CARAMEL』のMVを公開✨
たくさんのゲストさま、エキストラさまにご協力いただきました!(ス)#MZM pic.twitter.com/mxZLOUILUR
…最高か????いや…最高だよ… MVには写れてない気がするけど!!!いいんだ!!その空間にいたから!!!
まとめ
色々やったなぁ…って感じが強い…来年も頑張っていきたいけど今年くらい食い散らかせるかわからない。。。仕事で使う技術は掘り下げて知識蓄える気はあるけど、趣味でやることは食い散らかして色んな知識を吸収したいスタンスなのでやっていき…!
とりあえず来年はバンジージャンプすることは決まっているので飛んできます。よいお年を。
UnityのCIをCircleCIで頑張る
UnityのCIを無料で使いたい
業務だとJenkins等を使われてるイメージのあるUnityですが、個人作業だと自前でサーバー建てたくない(昔やったけど電気代がつらかった)し有料のCloudBuildを使うのも…僕はケチんぼなんでしたくない…サーバーレスで使えるCircleCIを使ってみようというのが始まりでした。
そこから CircleCIでUnityのTest&Buildを雰囲気理解で走らせた の記事を書き
Aiming Tech Book Vol.2 ここではCircleCIのOrbsを作った話をしていました。(OrbsはCircleCIのライブラリのようなもの) unity-ci(自分が作ったUnity用Orbs)でUnityのBuildやTestはある程度楽になったのですがライセンス周りは手動でどうにかする内容でした。
ここまでの記事ではUnityのバージョンごとにulfというUnityのライセンスファイルを手動で作ってCircleCIの環境変数にbase64エンコードをかけて登録する必要がありました。 そこから先日 Unityの.alfファイルから自動で.ulfをダウンロードしたい! PuppeteerというjsのUIテストツールを使用して.alfというUnityのライセンスリクエストファイルからコマンドを叩けばUnityライセンス認証ファイルである.ulfをダウンロードするツールを使って自動化までしました。
これでulfも出来たから安泰…!というわけにはいかず、後からunity-license-activateのUnityアカウントのログインによる2要素認証処理が必要だったり、unity-ciもファイルからライセンス認証をする対応が必要だったりしました。
そして最近やっと改修が落ち着いたのでまとめようと思います。改善点はまだまだありますが…一旦…
ここまでやって何が問題なの
ざっくりまとめると
- unity-license-activateが2要素認証に対応してなかった
- unity-ciがファイルからのライセンス認証に対応してなかった
ということになります。 個人開発だと安易にバージョンを上げることがあるのでバージョンの壁は自動で越えさせたかったというモチベーションがありました。
unity-license-activateとunity-ciを知らない方が多いと思いますので軽く紹介しますと
unity-license-activateはターミナル等で
node activate.js $email $password $alf_file_path
とすればemailとpasswordからアカウントでログインしてalfをulfに変えてくれるツールになります。
また、unity-ciはCircleCIでyamlを記述する際に
version: 2.1 orbs: unity-ci: mizotake/unity-ci@0.1.2 executors: unity_executor: docker: - image: gableroux/unity3d:2019.1.0f2 workflows: version: 2 unity-ci-test: jobs: - unity-ci/build: name: Build Execute Win exec: unity_executor platform: Win method: Build.Method zip: true - unity-ci/test: name: Edit Mode Test exec: unity_executor mode: editmode - unity-ci/test: name: Play Mode Test exec: unity_executor mode: playmode
上記のように記述すればCircleCIでBuildやTestが可能になるOrbsになります。
今回の追加対応した大雑把な流れ
- 開発対象のUnityバージョンで.alfを生成
- unity-license-activateをgitで落としてくる
- npmで環境設定してunity-license-activateを叩いて.ulfをダウンロード
- ダウンロードした.ulfでUnityのライセンス認証
をCircleCI上で自動化しました。
開発対象のUnityバージョンで.alfを生成
これはUnityのコマンドラインにあるので素直に
/opt/Unity/Editor/Unity -quit -batchmode -nographics -logFile -createManualActivationFile || exit 0
createManualActivationFileで生成します。しかし、終了コードがすべて失敗になるので強制的に成功させます。
unity-license-activateをgitで落としてくる
CircleCI上で行っているので、素直にgitで落としてくるものの alpine/git
のDockerImageを使いCircleCIの機能である persist_to_workspace
を使って次のjobでnodejsのImageで実行させるようにしています。
npmで環境設定してunity-license-activateを叩いて.ulfをダウンロード
以前書いた記事 Unityの.alfファイルから自動で.ulfをダウンロードしたい! で可能になったのですが初めて実行するPCでは2要素認証をクリアする必要がでてきます。そこで node activate.js $email $password $alf_file_path
という引数がデフォルトですが node activate.js $email $password $alf_file_path $verify_code
第4引数に2要素認証のコードを入れて進めるようにしました。
CircleCIでどうやってクリアするのかというと
ここにあるsshでCircleCIにアクセスする方法をとります。まず2要素認証をメールなどではなくてGoogleの「認証システム」アプリなどにします。このアプリだと認証コードが一分ほど有効です。そのためsshで接続してunity-license-activateを叩いて認証するまで時間的には間に合います。 一度認証が通ればその後は必要になりませんがプロジェクトごとに一度ssh接続して認証してあげる必要がありそうです。
手法としては力技という感じがしますが自分としては他に道が見えなかったのでこうしました!!!
unity-ciのアップデート
そして自前で作っているCircleCIのOrbsがファイルからのライセンスアクティベートに対応していなかったので対応しました。
対応してOrbsを使うときには固定の文字列を入れたりしないといけないのでまだ改修が必要な感じがしますが一旦こうなります。
version: 2.1 orbs: unity-ci: mizotake/unity-ci@0.1.2 executors: unity_executor: docker: - image: gableroux/unity3d:2019.3.0f1 jobs: setup: machine: true steps: - checkout - run: sudo mkdir -p /activateTools - run: sudo chmod -R 777 /activateTools - run: touch /activateTools/ProjectVersion.txt && cat ~/project/ProjectSettings/ProjectVersion.txt > sudo /activateTools/ProjectVersion.txt - restore_cache: key: unity-license-{{ checksum "/activateTools/ProjectVersion.txt" }} - persist_to_workspace: root: /activateTools paths: - . unity-ci-test-editmode: executor: unity_executor steps: - setup_remote_docker: docker_layer_caching: true - attach_workspace: at: /activateTools - checkout - unity-ci/unity_activate - unity-ci/test: mode: editmode - save_cache: key: unity-license-{{ checksum "/activateTools/ProjectVersion.txt" }} paths: - /activateTools/Unity.ulf - persist_to_workspace: root: /activateTools paths: - . workflows: version: 2 test: jobs: - setup - unity-ci/outputAlf: exec: unity_executor requires: - setup - unity-ci/cloneActivateTool: requires: - unity-ci/outputAlf - unity-ci/outputUlf: requires: - unity-ci/cloneActivateTool - unity-ci-test-editmode: requires: - unity-ci/outputUlf
権限付与が必要だったり、Unityプロジェクトのpathがルートにある前提だったりと改修要素が見えますがファイル認証の対応を優先して行いました。 これでバージョンの壁も突破して実行が可能になると思います。
おわり
UnityのCIをCircleCIで行うために頑張ると以上のようなことも必要になってきました…素直にCloudBuild使う方が楽な気はしますが色々と突破するための技術を学ぶのも中々幅が広くて面白いです。 しかし、Orbsである程度省略して書けるようになったので良きかなと思ってます。ご興味あれば使ってみてください…!
UnityEditorのTitlebarにディレクトリの場所を表示する
この記事はUnity Advent Calendar 2019の8日目の記事です。
レビューをするときにEditorを複数起動する
業務でも業務でなくてもコードレビューをすることがあると思います。そして、PRにもよりますがEditorで挙動確認をしたいことがあります。 その時に、自分のタスクでbranch切ってるUnityEditorで一旦PRのブランチを切ってレビューをすることもありましたが、ブランチを切ってImportさせるのは時間を食います。
そこで、私は別のReviewディレクトリを作ってそこにProjectをcloneしてレビューをするようにしてます。
ex. Unity Project ディレクトリ
├── A (Repository root)
└── Review
└── A' (Repository root)
※AとA'は同じgit Repository
例えば上記のように、Aは自分のタスクを行う場所、Reviewディレクトリ配下はレビューを行う場所としておけばUnityの多重起動をしてスムーズに切り替えれると思います。レビューのProjectをImportする間は自分のタスクが行えるので時間の無駄にもなりにくいです。
ただここで問題が起こります。 Unityの多重起動をすると、Editorの違いが見た目でわかりません!どっちがレビュー用だっけ?となりがちです。
そこで、最初はEditorの色を変えればいいかなと思いましたが無料で個人開発で同じようなことをする場合にできないこともあると思ったのでUnityEditor WindowのTitlebarを変えることにしました。(そのためWindows専用の処理になっています)
gistはこちら MizoTake/ChangeEditorTitlebar
できたもの
before | after |
---|---|
今回のEditor拡張の有無です…地味ですがTitlebarの後ろに「Review」という文字が追加されています。 正直、わかりづらいですがこれでReview用のUnityEditorかどうか判別が可能になります。
実装
using System; using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using UnityEditor; using UnityEngine; namespace ChangeEditorTitlebarFromPath { #if UNITY_EDITOR_WIN [InitializeOnLoad] public class ChangeEditorTitlebar { [DllImport("user32.dll")] static extern IntPtr GetActiveWindow(); [DllImport("user32.dll", EntryPoint = "SetWindowText")] static extern bool SetWindowText(System.IntPtr hwnd, System.String lpString); [DllImport("user32.dll", CharSet = CharSet.Auto)] static extern int GetWindowTextLength(IntPtr hWnd); [DllImport("user32.dll", CharSet = CharSet.Auto)] static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); static ChangeEditorTitlebar() { // 検索対象の文字列をディレクトリパスに含まれているかどうか判別 var target = "Review"; var path = Application.dataPath; var isMatch = Regex.IsMatch(path, target); if (!isMatch) return; // 現在ActiveなWindowを取得(InitializeOnLoadでUnityEditorが選択されている前提) var window = GetActiveWindow(); if (window == IntPtr.Zero) return; // 既にあるWindowの文字列を取得 var length = GetWindowTextLength(window); var stringBuilder = new StringBuilder(length + 1); GetWindowText(window, stringBuilder, stringBuilder.Capacity); // 取得した文字列の後ろに今回の検索対象の文字列を追加 var titleBarText = stringBuilder.ToString(); SetWindowText(window, titleBarText + $" - {target}"); } } #endif }
かなりシンプルです。この1ファイルのみを追加すれば大丈夫です。 Windowsのみですが、これで用途別に同じプロジェクトを開いても判別できると思います。
さいごに
これで一旦、用途別のWindowの判断が可能になりました。タスク用途とReviewで分けるのであれば有料版を持っていればEditorの色を黒とデフォルトで分ければいいのですが、無料版や3つ以上となるとTitlebarになるのかなと思いました。 拡張をいれるとするならプロジェクト内ではなくてUnity.exe単位の拡張で行うのが良いのかなと思っています。