Unity で BehaviorDesigner を導入する際の役割分担など
設定値の管理ってむずかしい。 最近ようやっと Behavior Designer を本格導入し、「Behavior Designer 内に専用 variable あるのか・・」と概念の広がりを感じたのでなおのこと。
Unity で個人制作をしている場合、当然ながら「作業者は全部俺!」となるので全ての領域に対してアクセスできてしまう。 このため、開発中は「UnityEditor から MonoBehavior の public 変数にアクセスできるから、とりあえず急ぎ開発中だしココで!」とかしてしまってた。 くわえて「クラスの中にマジックナンバー(あるいは定数)埋め込んだ・・けど、どこだっけ。どんな名前だっけ」とかにもなってた。
全部が全部そうしていたわけではないが、焦っている時などは前述の行動をとりがちだったのだ。 ので、自戒の意味も込め、迷子にならないように自分用の地図をメモしておく。
左上の丸、世界・環境の設定
レベルデザイン。地形・照明・3Dオブジェクトの配置や、NavMesh生成・調整などなど。 sceneで管理するもよし、シングルトンとScriptableObjectでゴリゴリ管理するもよし。
中心の丸、人物・モノの思考や経験の設定
バランス調整。体力・移動速度といった変数の調整や、BehaviorTree の思考の組み替えをおこなう。 ゲームプレイ中は不変だが、ゲーム作成中は柔軟に調整したいものをこの領域におく。 難易度調整はここだけ触ればOK、になれるとよし。
右下の丸、人物・モノが自身・世界へ影響を与える行動の設定
意思決定は中心の丸に全て委ねるので、ここではActionの内容作ればよい。
攻撃の場合だと、 直前の行動はなにか
大・小どんな攻撃が選択されたか
ブレンドするアニメーションはなにか
などから判断をしてアトミックな行動を演出する。
これらは Asset のコンポーネントだったり、自身が作ったクラスだったりよしなに。
Unity で三角比を使って辺の長さや角度を求める
3D空間で、Shaderのテカリを制御したり、カメラやオブジェクトの挙動などを制御したい際には、とにかく角度や2点間の距離を求めることが多い。
そして残念ながら、使う側の人間(私)は度数法に染まりきっているため、ラジアンだとどれくらいの角度かパッとイメージできない。くやしい。 (「最大角度 0.2 rad まで許容」みたいな入力項目には「具体的にどんくらいだよ・・」ってなる残念な頭である。とはいえ、物理カメラの画角なども一般的には度数法で表すので、一般的・・のハズ)
なので、わたしでもビャッと使える関数群を用意してみた。よかったらお使いください(意外とネットにはこういったサンプルコードが転がってなかったので・・)
using UnityEngine; public static class Util { // 斜辺 public static float HypotenuseByBoAn(float bottom, float angle) => bottom / Mathf.Cos(angle * Mathf.Deg2Rad); public static float HypotenuseByBoHe(float bottom, float height) => bottom / Mathf.Cos(Mathf.Atan2(height, bottom)); public static float HypotenuseByHeAn(float height, float angle) => height / Mathf.Sin(angle * Mathf.Deg2Rad); // 底辺 public static float BottomByHeAn(float height, float angle) => height / Mathf.Tan(angle * Mathf.Deg2Rad); public static float BottomByHyAn(float hypotenuse, float angle) => hypotenuse * Mathf.Cos(angle * Mathf.Deg2Rad); public static float BottomByHeHy(float height, float hypotenuse) => Mathf.Sqrt(Mathf.Pow(hypotenuse, 2) - Mathf.Pow(height, 2)); // 高さ public static float HeightByBoAn(float bottom, float angle) => bottom * Mathf.Tan(angle * Mathf.Deg2Rad); public static float HeightByHyAn(float hypotenuse, float angle) => hypotenuse * Mathf.Sin(angle * Mathf.Deg2Rad); public static float HeightByBoHy(float bottom, float hypotenuse) => Mathf.Sqrt(Mathf.Pow(hypotenuse, 2) - Mathf.Pow(bottom, 2)); // 角度 public static float AngleByBoHe(float bottom, float height) => Mathf.Atan2(height, bottom) * Mathf.Rad2Deg; public static float AngleByBoHy(float bottom, float hypotenuse) => Mathf.Acos(bottom / hypotenuse) * Mathf.Rad2Deg; public static float AngleByHeHy(float height, float hypotenuse) => Mathf.Asin(height / hypotenuse) * Mathf.Rad2Deg; }
浮動小数点の演算なので、許容誤差 0.00001
に設定、直角三角形を題材にしてテストを実施している。
[Test] public void HypotenuseByBoAn() { var delta = 0.00001f; var route2 = Mathf.Sqrt(2); var route3 = Mathf.Sqrt(3); Assert.AreEqual(2, Util.HypotenuseByBoAn(route3, 30), delta); Assert.AreEqual(route2, Util.HypotenuseByBoAn(1, 45), delta); Assert.AreEqual(2, Util.HypotenuseByBoAn(1, 60), delta); } [Test] public void HypotenuseByBoHe() { var delta = 0.00001f; var route2 = Mathf.Sqrt(2); var route3 = Mathf.Sqrt(3); Assert.AreEqual(2, Util.HypotenuseByBoHe(route3, 1), delta); Assert.AreEqual(route2, Util.HypotenuseByBoHe(1, 1), delta); Assert.AreEqual(2, Util.HypotenuseByBoHe(1, route3), delta); } [Test] public void HypotenuseByHeAn() { var delta = 0.00001f; var route2 = Mathf.Sqrt(2); var route3 = Mathf.Sqrt(3); Assert.AreEqual(2, Util.HypotenuseByHeAn(1, 30), delta); Assert.AreEqual(route2, Util.HypotenuseByHeAn(1, 45), delta); Assert.AreEqual(2, Util.HypotenuseByHeAn(route3, 60), delta); } [Test] public void BottomByHeAn() { var delta = 0.00001f; var route2 = Mathf.Sqrt(2); var route3 = Mathf.Sqrt(3); Assert.AreEqual(route3, Util.BottomByHeAn(1, 30), delta); Assert.AreEqual(1, Util.BottomByHeAn(1, 45), delta); Assert.AreEqual(1, Util.BottomByHeAn(route3, 60), delta); } [Test] public void BottomByHyAn() { var delta = 0.00001f; var route2 = Mathf.Sqrt(2); var route3 = Mathf.Sqrt(3); Assert.AreEqual(route3, Util.BottomByHyAn(2, 30), delta); Assert.AreEqual(1, Util.BottomByHyAn(route2, 45), delta); Assert.AreEqual(1, Util.BottomByHyAn(2, 60), delta); } [Test] public void BottomByHeHy() { var delta = 0.00001f; var route2 = Mathf.Sqrt(2); var route3 = Mathf.Sqrt(3); Assert.AreEqual(route3, Util.BottomByHeHy(1, 2), delta); Assert.AreEqual(1, Util.BottomByHeHy(1, route2), delta); Assert.AreEqual(1, Util.BottomByHeHy(route3, 2), delta); } [Test] public void HeightByBoAn() { var delta = 0.00001f; var route2 = Mathf.Sqrt(2); var route3 = Mathf.Sqrt(3); Assert.AreEqual(1, Util.HeightByBoAn(route3, 30), delta); Assert.AreEqual(1, Util.HeightByBoAn(1, 45), delta); Assert.AreEqual(route3, Util.HeightByBoAn(1, 60), delta); } [Test] public void HeightByHyAn() { var delta = 0.00001f; var route2 = Mathf.Sqrt(2); var route3 = Mathf.Sqrt(3); Assert.AreEqual(1, Util.HeightByHyAn(2, 30), delta); Assert.AreEqual(1, Util.HeightByHyAn(route2, 45), delta); Assert.AreEqual(route3, Util.HeightByHyAn(2, 60), delta); } [Test] public void HeightByBoHy() { var delta = 0.00001f; var route2 = Mathf.Sqrt(2); var route3 = Mathf.Sqrt(3); Assert.AreEqual(1, Util.HeightByBoHy(route3, 2), delta); Assert.AreEqual(1, Util.HeightByBoHy(1, route2), delta); Assert.AreEqual(route3, Util.HeightByBoHy(1, 2), delta); } [Test] public void AngleByBoHe() { var delta = 0.00001f; var route2 = Mathf.Sqrt(2); var route3 = Mathf.Sqrt(3); Assert.AreEqual(30f, Util.AngleByBoHe(route3, 1), delta); Assert.AreEqual(45f, Util.AngleByBoHe(1, 1), delta); Assert.AreEqual(60f, Util.AngleByBoHe(1, route3), delta); } [Test] public void AngleByBoHy() { var delta = 0.00001f; var route2 = Mathf.Sqrt(2); var route3 = Mathf.Sqrt(3); Assert.AreEqual(30f, Util.AngleByBoHy(route3, 2), delta); Assert.AreEqual(45f, Util.AngleByBoHy(1, route2), delta); Assert.AreEqual(60f, Util.AngleByBoHy(1, 2), delta); } [Test] public void AngleByHeHy() { var delta = 0.00001f; var route2 = Mathf.Sqrt(2); var route3 = Mathf.Sqrt(3); Assert.AreEqual(30f, Util.AngleByHeHy(1, 2), delta); Assert.AreEqual(45f, Util.AngleByHeHy(1, route2), delta); Assert.AreEqual(60f, Util.ngleByHeHy(route3, 2), delta); }
在宅勤務14週間と経過の雑記とマイクケーブル等のDIY
生活の変化
- 運動は復活!あったかくなってきたので、汗を流す量が増えて気持ちいい
マイクケーブルのDIY
長い在宅勤務。勢いで ATEM Mini Pro とアナログミキサーをポチってしまったので、それらをつなぐためのXLRケーブルが必要に。 ついでに今使ってるマイクケーブルも10年たったし、PC周りで使うには長すぎる(60cm程度で十分)なので、自作しますぞ。
作り方はサウンドハウスさんが動画を公開しているので「やってみたい」となったらコチラを参考にしよう
部品は前述のサウンドハウスから取り寄せ。電線の作業する際、ワイヤーストリッパーはほぼ必須なくらい便利(ハサミだと絶縁体を切るのに切れ味が物足りなかったり、ニッパーでは銅線まできっちゃったり)
ハンダする際は手が何本も生えて欲しいくらい手が足りない。ので、東急ハンズとかで売ってるメモクリップを使う。安くて便利。
クランプなどを組み合わせれば、位置調整はすべて任せてしまって、自分はハンダづけに集中できる。
成果物は ミキサー to オーディオインターフェイスのLRケーブル、マイク用の短めのケーブル。 これくらいのハンダ作業であれば、小学校で習ったレベルでできるので大変おすすめ。 (安くすむし、自分が必要な長さに調整できるので)
嫁友とDiscord飲み会に参加
嫁友夫婦3組で Discord 通話つなげながら飲み会するなどした。 食卓に iPad をおいて、カメラOffで適当にワーキャーいいながら飲み、どうぶつの森やスプラトゥーンをやるなどして am4:00 に解散。 金はかからないし、好き勝手に飲み食いできるし、介護はおのおのの家庭でできるので大変楽ちんでした。
あと、やっぱり関西人が飲みの場にいると盛り上がって楽しい。
在宅勤務12週間と経過の雑記とキッチンラックのDIY
生活の変化
「お仕事で疲れたから」を言い訳にちょっと筋トレをサボり気味。これが3ヶ月のマンネリってやつか!復活させます・・
キッチンラックのDIY
在宅勤務6週間と経過の雑記 - kumak1’s blog にて、CADで図面をざっくり引いていたのがやっと物理召喚できました。 作業している中で、「あ〜、これwebエンジニアでも大事なことだなぁ」と別角度から再確認できる学びがあったのでメモしておく。
- 作業者のスキルセットを考慮する
スキルが十分でない
x作業箇所
でプロダクトが失敗する確率
が爆上がりする- 企画物(2x4材、接続金具、ビス)を極力使って、独自モノ(流木、薬剤調合、自身による材料カット数)を減らすことが大事
- 外部からの攻撃につよくする
- 利用者の合意をとる
- 自分の部屋に自分だけが使うものを作るならひとりで作ってもいいが、共同で使うものは多くのレビューを受けよう
- 設計段階から利用者(家族)にわかりやすい形のモック(3DモデルのAR表示)でプレゼン->要望抽出->改善 というPDCAっぽいサイクルをぐるぐるとまわす
- 作成作業も「ものを支えてもらう」程度でいいので手伝ってもらおう。「自分がつくったもの」だと許容範囲は大きく向上する。
- 逆に、手伝ってもらえないと既製品の完成度と比較されるのでツラい
- 自分の部屋に自分だけが使うものを作るならひとりで作ってもいいが、共同で使うものは多くのレビューを受けよう
- なるべく楽をする
- 核心部分以外の手間とスピードを金(ツール導入)で解決できるなら、解決したほうがよい
- DIYは「自分にぴったりのもの」を作ること、そしてその精神を磨くのが主目的と捉えたい(私は・・)。
- 電動ドライバと電動丸のこ最高です
- 全てを自分で背負うのは辛いので、皆で仲良く、リリース時期も必要に応じて延期しつつやりましょう
- 核心部分以外の手間とスピードを金(ツール導入)で解決できるなら、解決したほうがよい
成果物
Before
After
溢れ出す生活感! が、手前に張り出した段ボール類がなくなったり、フライパン ミルクパンが収納できたり、コーヒーいれたりご飯をよそうスペースができたので満足! ・・見てくれは今後アップデートしていこう・・
購入したもの
- 接続金具やビス
- 棚受け
- 支柱の支え
- 材木
Unity 2019.2 -> 2019.3 で動作しなくなった箇所をメモる
Unity は破壊的な変更をちょくちょく行うのだけど、大方は Console Window で警告してくれるので、それに沿って修正すればOK。だけど時折 無言で死ぬので注意が必要。 2019.2 -> 2019.3 では Editor の見た目が変わったり・・などもあって変更が多かったようで、バージョンアップに手がかかってしまう。 修正に悩んだものをメモしておく。
EditorGUILayout.Foldout()
EditorGUILayout-Foldout - Unity スクリプトリファレンス
Inspector の拡張で「折りたたみ」を実装する際に使う。
2019.2 マデ
EditorGUILayout.Foldout(serializedProperty.isExpanded, "Label String");
2019.3
EditorGUILayout.Foldout(serializedProperty.isExpanded, "Label String", true);
第3引数 toggleOnLabelClick
に true
を渡さないと折りたたみ・展開してくれなくなった
AssetDatabase.LoadAllAssetsAtPath()
AssetDatabase-LoadAllAssetsAtPath - Unity スクリプトリファレンス
2019.2 マデは FBXファイル の assetPath を渡してやれば、Animation Clips の中身など、配下の色々なデータを取得できていたのだが、2019.3 では何も取得できなくなっている。 ナニカその他の手順など踏めば取得できそうではあるが、まだ対処法を見つけられていない。開発効率をあげる独自拡張機能で重要なものなので、解明が急務。
在宅勤務10週間と経過の雑記
在宅勤務が開始となって10週間が経ちました。神奈川では桜が咲いたり雪が降ったり春一番が吹いたりと、くるくると気候が変わっている。
生活の変化
体調面
趣味も仕事も追い込んでやっているので、なかなか疲れ気味の2週間だった。 「あっというま」だとか「気がついたら」というのが似合う時間の過ぎかただったなぁ・・大事に時を過ごしていきたい。
その他
今までは、仕事も 趣味も DIYも 家事も、「よ〜し、今日中にまとめて一気にやるぞ!」という勢いに任せた動きが多かったのだけど、 「今日はここまで、他のこともやる」みたいな動きが多くなってきた今日この頃。
これが、在宅勤務だからか、加齢によるものなのかは定かではないが、「やる時は短い時間でガっと進める。頭もスッと切り替える」が今後も大事になってきそう・・という予感を感じる。 やっていこう
在宅勤務8週間と経過の雑記
在宅勤務が開始となって8週間が経ちました。約2ヶ月。在宅勤務が一時的な措置ではなく、日常になりつつある昨今。
生活の変化
体調面
6 ~ 8 週については特記するような体調の変化はなかった。 会社の制度的には、昼後の15:00頃から15分程度、散歩が推奨されるようになった。引き篭れるタチの人は、1週間ずっと陽の光を浴びない・・といったこともありそうなので、とても良い。 運動不足解消のベースアップはよきよき。
精神面
2ヶ月の間、仕事するのも趣味プログラミングするのも自分のデスクだけだと流石に飽きてきた。 だが、喫茶店やファミレスなどの外に出てしまうのも、自宅勤務の経緯を考えると本末転倒だなと思いとどまった。 こういうときに「無理やりに景色を変えてリフレッシュを計る」というガツっと効果が高く、数日間効果の続く手をとれないのはキビシイ。 なので、1日 1 ~ 2時間程度は自宅ベランダで作業し、ゆる〜くリフレッシュすることにしてみた。
今日のリモートワークの会場(ベランダ)です pic.twitter.com/DLbzayucuR
— くまき (@kumak1) 2020年3月19日
これが思った以上に快適で、風と陽の光にあたるのは大事だなぁ・・と、当たり前のことをしみじみと感じるのであった。
3/20 に「あつまれ どうぶつの森」が発売され、私ももれなくプレイしている。 このゲーム、スローライフを楽しむものなので、他の多くのゲームより疲れにくく、気付いたら「数時間プレイしていた・・もっと他のことしなくちゃいけなかったのに・・」と、癒されるハズが自責の念にかられることが多い。(牧場物語とかもね・・) のでエアロバイクを漕いでじんわり汗をかきながらやっている。 これなら「ダイエットしてるから!」というのと、長くても40分程度で風呂入りたくなって中断するので、罪悪感を感じず癒されている。 オススメです。