kidoOooOoooOOom

ゲーム開発やってます

「マンガでよく分かる 怒らない子育て」を読んだ

6歳と3歳の子育て中ということもあり、育児もちゃんと勉強していきたい分野。

今回読んだこの本は、マンガのページがそこそこ用意されていてとても読みやすく、勉強になることもたくさんあった。

まず参考になったのは、自分の子供が例えばジュースをこぼしてしまった時は「何やってんの!」と怒りがちだけど、友人の子供がジュースをこぼした時は「大丈夫?」と心配して自分の子供の時のように怒らないんじゃないですか?という話。

これは確かにそうだなと思っていて、同じジュースをこぼされるという出来事でも「自分の子供だから怒ってもいい」という認識が自分の中で気づかないうちに存在しており、怒ってもいいんだから怒るという行為に走ってしまっている。

怒りは、怒った側はストレスを発散しているように見えて実は毒を撒き散らしているようなもので、周りに悪影響を及ぼして最終的には自分にも悪影響を及ぼしてしまう。

イライラや怒りを感じてしまった時は、「イライラしている自分」に気付いて、一度時間を置いたり、なんでイライラしてしまっているかを客観的に見つめ直すことで実はなんとかなるケースの方が多い。

イライラしてしまうのは、コントロールできないものを無理にコントロールしようとしてしまうから思い通りにいかずに、その結果イライラして怒ってしまう。 自分の子供とはいえ他人なので考えていることは把握できないし、ましてや子供なんて何しでかすか分からないものとして対策をとった方がいい。

このあたりの話は、僕が大好きな「エンジニアリング組織論への招待」にも同じような内容がたくさん書かれていて、育児とチームビルディングってのはとても近いんだなぁと感じた。

ただ怒らずに甘やかせばいいって訳ではなくて、「叱る」という行為も適切に必要だし、叱る時には「ポジティブに叱る」という話もとても参考になるなと思った。

SlackBotでクイズ機能を作ってチームの学習を促す

SlackBotのランダム機能を使うと、何かの担当者(レビュー担当とか)をランダム抽選する時とかslack上でサクッとできるのでとても便利。

qiita.com

最近はこのランダム機能を使って、「今作っているプロダクトの仕様に関する質問」や、「Unityに関するクイズ」を作成している。 例えば"unity_quiz"ってのを発言すると、こんな感じで問題が出てくる。

f:id:gidooom:20190316121112p:plain

答えはスレッド内だけの返信に書いておけば、わかった人や答えを見たい人だけがスレッドを展開して確認する形になるのでクイズっぽくて良い。

脳科学の研究では、記憶というのは"思い出す"時に強化されるということが分かっているらしい。

なので、チームのみんなや自分が理解しておいて欲しいことをクイズにすることで、チームの学習が促されると思う。

ちなみに今はひたすら自分が問題を作っていてかなり大変。だけど、「問題を作ること」も相当負荷の高い勉強になって良いな感じている。

複数フラグ判定を行うenum実装とそれのUnityTestRunnerコード

ゲームでよくある武器の属性をC#enumで実装する時、こんな感じで書ける。

using System;

[Flags]
public enum WeaponElement
{
    Fire = 1,
    Water = 1 << 1,
    Earth = 1 << 2,
    Wind = 1 << 3
}

public static class WeaponElementExtension
{
    public static bool IsSatisfy(this WeaponElement e, int checkBit)
    {
        return ((int) e & checkBit) != 0;
    }
}

bit flag で宣言してるのは、属性判定を行う時に便利なケースがあるから。 例えば、何かしらのスキルや装備の効果で、「炎のみ」「炎と水」「全ての属性に対して〜」などの判定バリエーションがある時、一つのプロパティでそれらを判定できる。

上のenum実装がちゃんと動作するかどうかは、Unity Test Runner を書いておけば確認できるし、今後も自動テストとして運用できるようになる。

UnityTestRunner に作り方については、下記サイトが参考になった。

qiita.com

今回作成したTestコードは下記のとおり。属性チェック用のメソッドがちゃんと期待通りの動きをするかテストする。

using NUnit.Framework;

public class WeaponElementTest
{
    [Test]
    public void IsSatisfyTest()
    {
        int checkFire = 1;
        Assert.IsTrue(WeaponElement.Fire.IsSatisfy(checkFire));

        int checkWater = 1 << 1;
        Assert.IsTrue(WeaponElement.Water.IsSatisfy(checkWater));

        int checkEarth = 1 << 2;
        Assert.IsTrue(WeaponElement.Earth.IsSatisfy(checkEarth));

        int checkWind = 1 << 3;
        Assert.IsTrue(WeaponElement.Wind.IsSatisfy(checkWind));


        int checkFireAndEarth = checkFire + checkEarth;
        Assert.IsTrue(WeaponElement.Fire.IsSatisfy(checkFireAndEarth));
        Assert.IsFalse(WeaponElement.Water.IsSatisfy(checkFireAndEarth));
        Assert.IsTrue(WeaponElement.Earth.IsSatisfy(checkFireAndEarth));
        Assert.IsFalse(WeaponElement.Wind.IsSatisfy(checkFireAndEarth));


        int checkAllElement = checkFire + checkWater + checkEarth + checkWind;
        Assert.IsTrue(WeaponElement.Fire.IsSatisfy(checkAllElement));
        Assert.IsTrue(WeaponElement.Water.IsSatisfy(checkAllElement));
        Assert.IsTrue(WeaponElement.Earth.IsSatisfy(checkAllElement));
        Assert.IsTrue(WeaponElement.Wind.IsSatisfy(checkAllElement));
    }
}

作成したTestを実行するには、下記Windowを開いて

f:id:gidooom:20190309084022p:plain
UnityTestRunnerのWindow開く

今回はEditModeのTestとして作成したので、EditModeのタブで Play all を実行すればテスト実行できる。

f:id:gidooom:20190309084419p:plain

Unityのコードを普通に再生してテストとかすると非常に時間がかかるので、このテスト機能はとても嬉しい。

「戦略的リソース活用法」を参考にした、ゲームをプレイする前に考えること

最近、ニコニコ動画でやっているメンタリストDAIGOの有料チャンネル(月額540円)に入って効率の良い勉強法などの動画をいくつか観ているが、とても勉強になっている。

その中の一つ、「戦略的リソース活用法」というのが、勉強するときだけじゃなくてゲームをプレイする時にも効果があるような気がしたのでメモっておく。

「戦略的リソース活用法」はこちらのブログにも詳しく書かれている。

いくら勉強しても結果が出ない!を解決する「戦略的リソース利用法」 | パレオな男

今やっている仕事がゲーム開発ということもあり、勉強というテイでゲームをプレイすることが非常に多いが、ただ漫然とプレイしてしまいがちで勉強になっているかどうかは疑問。

そこで、ちゃんとゲーム開発に活かすためにゲームをする時には、下記の戦略的リソース活用法ゲーム版を自分なりにテンプレートで作ってエバーノートとかに書いてから始める。

  • 戦略的リソース活用法ゲーム版
    • インプットとしてゲームをプレイする前に以下の7つの質問に答えておく
      • 1.このゲームでどのようなことを理解したいのかを書く
      • 2.そのゲームへの理解が自分にとってどれくらい重要かを100点満点で書く
      • 3.そのゲームを理解をするのにどれくらい自信があるかを100点満点で書く
      • 4.このゲームの実際の仕様などを前情報や自分の予測などで書き出す
      • 5.このゲームで体験できそうなこと、学べそうなことを最大15個まで絞って書き出す。
      • 6.なぜその15個が体験・学べそうだと思ったかを書く
      • 7.その15個で理解したことを今後どういう風に使っていくかを書く
    • こんなことするならとっととゲームした方が良いと思うかもしれないが焦りが一番ダメ。

ゲームをプレイしている間や、プレイし終わった後にアウトプットすべきことについてもなんかヒントを得られそうなので、また考えてみる。

Unity2018.3で追加された Prefab Modeを使ってみての注意点2つ

最近チームでもUnity2018.3.1 で新しく追加されたPrefab Mode を使い始めてハマった点とか注意すべき点があったのでメモ。

Auto Save は OFFにする

Prefab Modeを触っていて最初に感じたのが、「これいつPrefabへの編集がSaveされてんの?」という点。

調べてみたら、デフォルトではPrefab Modeから離れた時に Auto Save されており、テストのつもりでちょっと触ったパラメータも気づかない間に反映されてしまいそうでちょっと怖い。

f:id:gidooom:20190223172217p:plain
デフォルトはAutoSave=ON

Auto Save のチェックを外しておくと、Prefab Mode から離れる時にSaveするかどうか確認ダイアログが開くので、とりあえず新しいプロジェクトを開いた時はチェックを外すことを推奨したい。

f:id:gidooom:20190223172235p:plain
手動Saveに変更

Prefab Modeの時の環境設定

UIパーツなどをPrefab化してPrefab Modeで編集していると、シーン上のCanvasの設定とは異なる設定で表示されてしまってPrefab Mode上で編集するのが難しい状況になった。

これも調べてみたら、ちゃんとPrefab Modeの時にどんなCanvasの設定を反映するかは Player Settings で指定することができた。

このマニュアルの下の方に書いてある(まだ英語マニュアルしかないので気づきにくい)

Editing a Prefab in Prefab Mode - Unity マニュアル

この設定をすることで、無事にPrefab Modeでも意図した見え方になって編集しやすくなった。

「ちょっとした勉強のコツ」を反復学習した

「ちょっとした勉強のコツ」を読んで、勉強になったなと思うところの整理。

勉強はかけた時間ではなく、どれだけ集中して行えたかどうかで成果がきまる。

この本で何度も出てくるテーマの1つ。休みの日に思ってたよりも勉強ができないのも、時間があると思うと人間は油断してしまうから。 適度に「タイムハングリー」でいることがポイントで、ポモドーロテクニックなど使って集中する時間を意図的に作り仕組みが大切。 マインドフルネスとかも効果があると思うので、なんだかんだでちゃんと実践していきたいと思う。

あれもこれも詰め込み学習をしても効果が薄く、量は少なくとも大事なことを何度も反復して学ぶ方が大切

自分は結構手を広げて勉強してしまいがちなので、この節はかなり心に刺さった。 理解が浅いまま頭の中にindexだけを作っていくのではなく、自分の頭の中にindex + コンテンツもしっかり構築していかないとなぁと感じた。

スタンディングデスク重要。散歩、適度な運動も効果がある。

これは最近かなり意識している。職場でも家でも基本的にはスタンディングで仕事、勉強していて、通勤もなるべく歩くように意識している。 歩きながらPodcastYoutubeなどで耳学習をすると、結構頭に残ることが多いのは散歩効果だと感じる。

学習は目と頭だけでなく、口と手も使っておこなうべし。

これも結構自分には戒めになる内容で、目と頭だけで学習を完了させがち。ちゃんと手でアウトプットし、口で誰かに説明や教えるなどしてからやっと自分の知識になるのだと意識してやっていかないとと感じた。

Unityで3Dオブジェクトをボクセル化する「unity-voxelizer」について

こちらのblogで紹介されていたunity-voxelizerを試してみて、どんな仕組みで動いているのかを調査。

baba-s.hatenablog.com

github.com

まず、デフォルトのSphereにたいして unity-voxerlizer を適用すると f:id:gidooom:20190209112341p:plain

f:id:gidooom:20190209112357p:plain

こんな感じのボクセルSphereになる。

ボクセルの密度パラメータを大きくすると、さらに細かいボクセルSphereになる。 f:id:gidooom:20190209112452p:plain

(密度パラメータを大きくしすぎるとVoxel生成しすぎてUnity固まるので注意)

仕組みとしては、ボクセル化対象となるオブジェクトが存在する空間をバウンディングボックスで定義しておき、密度パラメータに応じてボクセルを設置していく。

    [Header("ボクセル化対象のバウンディングボックスの設定")] [SerializeField]
    private Bounds bounds = new Bounds(Vector3.zero, Vector3.one);

    // 密度パラメータ
    [SerializeField] private int xDensity = 8;
    [SerializeField] private int yDensity = 8;
    [SerializeField] private int zDensity = 8;

これらのパラメータを、unity-voxelizerが提供するVoxelizerクラスに渡してインスタンス生成し、Vocelize関数を実行するとボクセル化に必要な情報を生成してくれる。

        voxeliser = new Voxeliser(bounds, xDensity, yDensity, zDensity);
        voxeliser.Voxelize(transform);

あとは、バウンディングボックス内の密度に応じて、それぞれの空間にボクセルを置くべきかどうかを Voxeliserインスタンスでチェックして置いていくだけ。

        for (int x = 0; x < xDensity; x++)
        {
            for (int y = 0; y < yDensity; y++)
            {
                for (int z = 0; z < zDensity; z++)
                {
                    if (voxeliser.VoxelMap[x][y][z])
                    {
                        var pos = worldCentre + new Vector3
                                  (
                                      x * gridCubeSize.x,
                                      y * gridCubeSize.y,
                                      z * gridCubeSize.z
                                  );
                        var go = Instantiate(m_voxelModel, pos, Quaternion.identity);
                        go.transform.localScale = gridCubeSize;
                        go.transform.SetParent(rootTransform, true);
                    }
                }
            }
        }

ただ、voxeliser.Voxelize(transform) がどうやってボクセル空間を構築しているのかが自分には難しかった・・・。

やってることとしては、ざっと以下の手順だと思われる。

  1. ボクセル化対象オブジェクトのMeshをチェックしてAABBの配列を生成
  2. 密度パラメータに応じたボクセル空間に対し、1で作ったAABBの重なりをチェック(ここのチェック処理がかなり難しい。多分、いい感じに重なっていたらtrueを返している)
  3. ボクセルの存在可否だけをまとめた "bool[] _voxelMap" が作られる

MeshやAABBの周りの操作はまだ全然できないので、今後勉強していかないと。