MessagePipe使ってみる

メッセージングライブラリのMessagePipeがリリースされました。

qiita.com

github.com

いろいろ書いてあるんですが、動的にいろいろ動かしてみたいのでアクション寄りでいじってみたいと思います。

DIとかUnitaskとか知らない状態で雰囲気でやっているのでご了承ください。

リポジトリはこちらです github.com

f:id:Piffett:20210523195037p:plain

というわけで2Dでいつもの画面を起動します。

MessagePipeには内蔵で軽量のDIコンテナライブラリが付属しているらしいですが、今回は良さげらしいVCointainerを使ってみます。

UniTaskなどいろいろ依存ライブラリがあるので、Packages/manifest.jsonに以下のもろもろを追加します。

{
  "dependencies": {
    "...": "..."
    "com.unity.modules.vr": "1.0.0",
    "com.unity.modules.wind": "1.0.0",
    "com.unity.modules.xr": "1.0.0",
    "jp.hadashikick.vcontainer": "https://github.com/hadashiA/VContainer.git?path=VContainer/Assets/VContainer#1.8.2",
    "com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.2.5",
    "com.cysharp.messagepipe": "https://github.com/Cysharp/MessagePipe.git?path=src/MessagePipe.Unity/Assets/Plugins/MessagePipe#1.4.0",
    "com.cysharp.messagepipe.vcontainer": "https://github.com/Cysharp/MessagePipe.git?path=src/MessagePipe.Unity/Assets/Plugins/MessagePipe.VContainer#1.4.0"
  }
}

Scriptsフォルダを作って以下のC#ファイルを用意します。

MainLifetimeScope.cs

using MessagePipe;
using UnityEngine;
using VContainer;
using VContainer.Unity;

public class MainLifetimeScope : LifetimeScope
{

    protected override void Configure(IContainerBuilder builder)
    {
        var options = builder.RegisterMessagePipe(/* configure option */);
        builder.RegisterMessageBroker<TheWorld>(options);
    }
}

public class TheWorld
{
    public float speed;
}

ファイル名の末尾が「LifetimeScope」だとLifetimeScopeから継承した実装のファイルが用意されます。今回はTheWorldという名前のclassを作って、このデータを通知したいと思います。

Scene内に空のGameObjectを使って先ほど作ったMainLifetimeScopeをアタッチします。

f:id:Piffett:20210523204701p:plain

今回はシューティングゲームでも作ろうと思うので、Playerを作ります。これは上下左右に動くだけです。

Player.cs

using UnityEngine;

public class Player : MonoBehaviour
{
    void Update()
    {
        if (Input.GetKey(KeyCode.LeftArrow))
        {
            this.transform.Translate(-0.02f, 0.0f, 0.0f);
        }
        if (Input.GetKey(KeyCode.RightArrow))
        {
            this.transform.Translate(0.02f, 0.0f, 0.0f);
        }
        if (Input.GetKey(KeyCode.UpArrow))
        {
            this.transform.Translate(0.0f, 0.02f, 0.0f);
        }
        if (Input.GetKey(KeyCode.DownArrow))
        {
            this.transform.Translate(0.0f, -0.02f, 0.0f);
        }
    }
}

Enemyを作ります。messagepipeで通知を受け取ったら速度が遅くなるという仕様にしたいと思います。Playerに当たっても特に何も起きません。

Enamy.cs

using MessagePipe;
using UnityEngine;

public class Enemy : MonoBehaviour
{
    float random = 0.0f;
    float speed = 1.0f;
    ISubscriber<TheWorld> OnStop { get; set; }

    private System.IDisposable disposable;
    public void SetUp(ISubscriber<TheWorld> theWorld)
    {
        OnStop = theWorld;
        var d = DisposableBag.CreateBuilder();
        OnStop.Subscribe(ev =>
        {
            speed = ev.stopSpeed;
        }).AddTo(d);

        disposable = d.Build();
        random = Random.Range(-0.01f, 0.01f);
    }

    void Update()
    {
        this.transform.Translate(random * speed, -0.03f * speed, 0.0f);
    }

    private void OnDestroy()
    {
        disposable.Dispose();
    }
}

f:id:Piffett:20210525090417p:plain

EnemyはPlafab化

ふと思い出してBox Collider 2DとRigidBody 2DをPlayerに付けました。

Enemyを上から降らせるやつを作ります。

using MessagePipe;
using System.Collections;
using UnityEngine;
using VContainer;

public class EnemyProducer : MonoBehaviour
{
    [SerializeField] GameObject enemy;
    [Inject]ISubscriber<TheWorld> OnStop { get; set; }
    void Update()
    {
        if(Random.Range(0, 30) == 15)
        {
            var obj = Instantiate(enemy, new Vector3(Random.Range(-2.0f, 2.0f), 4.5f, 0.0f), Quaternion.identity);
            var enemy = obj.GetComponent<Enemy>();
            
            enemy.SetUp(OnStop);

            StartCoroutine(DeleteObj(obj));
        } 
    }

    IEnumerator DeleteObj(GameObject gameObj)
    {
        yield return new WaitForSeconds(3);
        Destroy(gameObj);
    }
}

こんな感じ(画質荒)

f:id:Piffett:20210526052716g:plain

MessagePipeで通知を送るために、当たったらすべてのEnemyを遅くするオブジェクトを作ります。

using MessagePipe;
using UnityEngine;
using VContainer;

public class Stopper : MonoBehaviour
{
    [Inject] IPublisher<TheWorld> stopEvent { get; set; }
    private void OnCollisionEnter2D(Collision2D collision)
    {
        stopEvent.Publish(new TheWorld() { stopTime=1.0f });
    }
}

こいつを上から降らせてもいいんですが、めんどくさいので右下に置きます。 Stopper.csをアタッチします。ついでにColiderとRigidbodyもアタッチします

最後にLifeTimeに通知を送る側と受け取る側のオブジェクトをAuto Inject GameObjectsにいれます。 f:id:Piffett:20210527064648p:plain

そうすると、[Inject]がついているIPublisherとISubscriberがInjectされて、StopperとEnemyProducerはそれぞれTheWorldのISubscriberとIPublisherでデータをやり取りできるようになります。そして、EnemyProducerはISubscriberをEnemyに受け渡しています。

最初はEnemyをLifeTimeのAuto Inject GameObjectsに直接放り込んだら行けるんじゃないかと思っていたのですが、vContainerではそういうやり方はできないみたいです。

動作はこんな感じになります(なんでこんなに色味がおかしいのかはわかってません。どっかでちゃんと編集ソフトの使い方覚えます)

f:id:Piffett:20210527071552g:plain

今思ったんですけどこれだったら別にボタン押して止まる仕様でもよかったですね。最初は頑張ってシューティングゲームを作ろうとしていたので中途半端な形になってしまいました。

UniRxとかをちゃんと使ったことがないので、使いどころはまだわかりかねています。どっかでちゃんと勉強しないとですね。

ではまた

FPSを分析する項目を考える

 ゲームの批評でもしようかなと思った。ビデオゲームの美学を読んで感動したものの、何に感動したのか全部忘れてしまった。それに、批評するほどゲームをやってない。今回は雑に、FPS(TPS含む)あたりの要素を取り上げていきたい。

やってきたゲーム

全てのFPSに共通する撃ち合いに関して

 これは単純に銃を使った撃ち合いを指す。FPSの最も面白い場面が撃ち合いであり、この撃ち合いを有利に進めるために<勝てるポジション取りをしたり、スキルを使ったり道具を使ったりする>というのがFPSの基本である。そして、それぞれのFPSゲーム固有の事情を無視しても差が出るスキルが存在し、キャラコン(WASDをベースとしてキャラクターを思い通りに動かす力)やエイム力、リコイルコントロール(銃の反動を押さえる力)などが含まれる。この中でキャラコンは多少それぞれのゲームの仕様によって事情が変わる。例えばリーンという首を傾ける操作は仕様としてできないゲームが多い。

勝利目標

 何をもってクリアとするかである。要はジャンルである。ジャンルごとに特徴がある。

チームデスマッチ

 単純に撃ち合う。最もシンプルであり、KPM(Kill per minute:1分当たりのキル数)が多いゲームである。チームごとのキル数で相手チームを上回る、あるいは指定のキル数に早く到達することで勝利となる。一般にカジュアルに撃ち合うFPSジャンルとされる。旗取り系も勝手にこれに入れている。

ボム

 片方のチームが爆弾を設置し、目標を破壊する。もう片方は設置を阻止するか、設置された爆弾を解除することで勝利となる。必ずしもキルは必要ではなく、撃ち合いがほとんど生じずに1ラウンドが終了するケースもある。マップ理解が強く求められ、キャラや武器性能が変わらなくてもメタが回りやすい傾向にある。

バトルロワイヤル

 最後まで生き残っていれば勝利となる。最もKPMが低く、一度の撃ち合いのバリューが高い。多くのゲームでは撃ち合いに勝利して相手を倒すと相手の物資を漁ることができる。また、相手を倒したものの別の人に参戦されて倒されたり物資を奪われる<漁夫>という概念が存在する。そのため、撃ち合いの場面を自分で取捨選択することが強く求められる。

FPS,TPS

 これは一人称か三人称かを指す。一人称はそのままだが、三人称であるTPSゲームは視点を個別に動かす手段が存在するケースが多い。そして三人称には一人称と比べて<一方的に敵を視認しやすい>という特徴がある。壁際にポジションを取って視点を動かしたり、丘の上にいたりすると起きる。一人称の場合、丘の上であれば三人称視点同様に有利に撃ち合うことはできるものの、一方的に視認することはない。よって、一人称よりも有利なポジションを如何にとるかが勝敗を左右する。

TtK(Time to kill)

 撃ち合いが始まった時に、どちらかがデスもしくはダウンするまでの時間である。一般的には時間ではなくアサルトライフル系の弾数でカウントされる。ヘッドショットで一発、胴体で3~4発といったケースが多い。Apex Legendsなどは14発近く必要であり、TtKが非常に長いゲームである。TtKによって立ち回りが変わり、特にクリアリング(敵がいないか確認する)に対する労力が異なる。TtKが短いゲームでは<相手より先に銃を撃つ>ことが非常に重要であり、小さいスケールでの<相手がどこにいるかの情報>が重要になる。一方TtKが長いゲームでは、ダメージレースに勝つことが重要になる。ApexLegendsで言うと、先に相手を一人ダウンできるかどうか、あるいは相手に先に攻撃されても、削られたプレイヤーが戦線から逃げることができるかといったことが撃ち合いの勝率に強く作用する。

スキル、ガジェット

 ゲームによって異なるが、相手の位置情報をスキャンしたり、体力を回復したりといった、それ自体は撃ち合いではないが、撃ち合いを有利にする能力のことを指す。特別な銃が使えるといった、それ自体が撃ち合いに近いものも存在する。

情報系

 カメラであったり、スキャン効果によって敵の位置を把握できる能力である。あるエリアに敵がいるかいないかを把握することで立ち回りを有利にするタイプのものや、寸分狂わず相手の位置を把握できることで非常に有利な撃ち合いをできるようにするもので事情が変わってくる。

回復系

 減ったHPを回復したり、一時的にHPを増強したりする。スキルの有効性はTtKと強く相関があり、即死するようなゲームでは有効に使うのが難しい。HyperScapeで全体的に武器を弱体化すると、使われなかったヒールのスキルが使われるようになるというような事例もある。

罠系

 設置し、相手が通過することで何らかの効果を及ぼすようなもの。相手が通過することを把握できるようなケースが多く、この場合はある種の情報系ともいえる。情報系と違い、一度設置してしまえば複雑な操作などが不要である。

移動系

 本来いけないところに行けるようになったり、射線を切って自分の行きたいところに行くといった様々な特徴がある。立ち回りに選択肢を与えるケースが多く、そのスキル自体が直接撃ち合いを有利にするケースは少ない。

投げもの

 グレネードであったり、フラッシュバンなどである。グレネードは相手を強いポジションからどかすのに用いる。フラッシュバンは相手の視界を奪うものであるが、レインボーシックスシージでは自分の動作音を消したり、投げ物を吸収する相手のガジェットを無効化するのに用いられる。

 銃である

サブマシンガンアサルトライフル

 ボタンを長押しすると連射される基本的なタイプである。DPS(damage per second:1秒当たりのダメージ量)が高く、武器によって得意なレンジが異なる。

スナイパー

 単発であり、遠距離武器である。基本的には遠距離が有利な武器ではあるが、一撃必殺の場合はその限りではない。その場合はサブマシンガンアサルトライフルと違って<当たるか当たらないか>の二択になり、当たらない時のデメリットが大きく、チームで削って倒すという方針が立てにくくなる。

ショットガン

 近距離であれば圧倒的な火力を持つ。<撃って下がる>を瞬間的に行って撃ち合うことが多く、この戦術をとることで被ダメージ量を最小限に抑えることができる。純粋な正面での撃ち合いではむしろサブマシンガンにDPSで劣るケースが多い。

あとがき

 というわけで自分の中にあるなんとなくのFPSに関する知識を整理した。気が向いたらそれぞれのFPSの面白さや敷居の高さなどについて語ろうと思う。

ビデオゲームの美学を読了した

www.keio-up.co.jp

読了報告。理解しきれているとは言えないが、ある程度流れを押さえることはできたと思う。

小説に関してはナラトロジーをベースにした研究が盛んにおこなわれており、少なくとも近代小説家の研究は多くの例があるのに対し、ビデオゲームに関してはどうも発展途上そうなことが分かった。以前ナラトロジーの本を読んだ時は、実際に作品を取りあげて、分析例を示していた。今回取り上げた本は、まずビデオゲームを分析するにあたって必要な様々な概念や定義をしっかりと見直し再構築したうえで、どのような分析を行えるかの理論的な枠組みを与える物であった。たしかにこの書籍内では様々なゲームを取り上げるが、あくまで分析にあたって必要な諸概念を整理するために例として挙げるにとどめた印象だった。

ビデオゲーム自体は盛んにプレイされ、RTAのような文化もあるが、ゲームの面白さを分析するのはこれからの分野なのかもしれない。しかし、静的なコンテンツの分析すら大変なのに、インタラクティブなゲームの分析をするのはなかなか骨が折れそうだとも思った

日記?

報告事項

ゲーム作りたいなぁと思いつつ、会社入ってからいくらでもできるなぁと思ってサボり中。

情報系の就活事情的な

 ちなみに僕は情報系ではないので、雰囲気で外から眺めた感想を述べてます。

アウトプットが求められる話

 エンジニア(Webエンジニア)に対してアウトプットが求められるようになった。一番の理想はポートフォリオでサービスを作ること。ほかにはツール作ったりとか、GitHubで色々PR出してcontributeするとか、そういうアウトプットが必要になってきた。私は業務経験こそあれ、そのようなアウトプットは無かったので困ったことはたびたびある。そのうえ今インターンシップに臨みたいならポートフォリオを必須といえると思う。

学部のうちにやる勉強とは差がある

 もちろん私のような非情報系の学生であれば雰囲気でRailsをやってサービス作りました!くらいで良いと思うが、情報系の学生はそれが本当に良いことなのかは考えてほしい。一度そのルートに入るとインターンシップでもバイトでもひたすらサービスを開発することになる。そうするとVueやReactの上辺の技術ばかり触るようになる。もちろん低レイヤをやれとは言わないが、例えばRailsにしてもその中身の実装がどの様になっているのかじっくり眺めたりするような経験を積んでおかないと、手早く作れはするが、中身を理解していないので技術的に責任のある仕事につけないというような事になりそうだと思った。どうせ社会人になってからRailsのようなものは勉強するのだし、学部生のうちは時間をとって勉強しないと難しいものをやるべきだ。

f:id:Piffett:20200531034157p:plain
サファリドットコムより

 まぁ僕はそもそも精進してないので基礎力も上辺の技術もないんですけどね!

学生の評価の難しさ

 さて、今までの話で学生は上辺の技術ばっかりやっていないでもっとしっかり基礎力をつけなさいといったのだが、それでうまくいくかといえばそうではない。例えば低レイヤをやっていたとしてそれが外から評価できるとも言い切れない。もちろん自作OSなどを作ったりしていれば全く問題ないのだが、それは誰にでもできるものではない。そういったアウトプットがない場合、企業目線から学生の底力を図るのは難しい。もちろん新卒は即戦力を求めるものではないから、Railsなりをバリバリに使えている必要はない。しかし、勉強はしているけどアウトプットがないですと言われて採用したくなるかといえば怪しい。現状色々勉強しながらちょっとしたポートフォリオを作るのが無難だと思う。

リサーチ芸

 僕はアウトプットはほぼ皆無ではあるが、Qiitaには結構記事が落ちている。みんなが触っているような技術でも意外と穴があったりする。大抵は日本語で落ちていないだけの情報だったりするが、それを日本語でまとめ直してQiitaに記事を上げるだけでも意味があると思う。「あ、この人はこっちでやり方教えたら自分で色々調べて解決してくれそうだな」と採用担当者に思わせられれば御の字。

ベースラインやってる?笑

open.spotify.com

ある日のこと

f:id:Piffett:20200527042849p:plain

なんか変な余白が画像の下にある。



marginもpaddingも全部消してものこる謎の余白。


vertical-alignというのを設定すると消せるらしい。vertical-alignはセル内とかで上寄せとかした寄せとかするのに使うらしい。けど画像はっつけただけやぞ?何故?それにvertical-alignをテキトーになんか設定するとよくて、baseline以外なら何でもいいらしい?


全く意味不明だったが、baselineといってそういえば

f:id:Piffett:20200527054129p:plain

こんなのがあったなというのを思い出す。日本語しか使わないから気づかなかったけど、このbaselineのことを指してるっぽい。そして謎の余白はbaselineから下の部分が余白として乗っかってるということが分かった。そもそもbaselineが基準なのは本当に欧米人ファーストを感じる。はえー日本人なのでしばらく悩んでたわキレそう。

UE4ラーニングパス「UE4入門」を終えて

まえがき

 ブログで何をどう書くのか迷ってしまうのは、この文章が一体だれのためにどのように書くのかを意識していないからだと思った。つまりは小説なので書くのが難しい

UE4とは

 UE4とはUnreal Engine 4とよばれるゲームエンジンで、要はゲームを作るためのソフトウェアである。しかし、昨今のコンピューターの性能の上昇に伴って、映画製作など様々な場面で用いられるようになっているらしい。みなさんのご存知の通り、私はゲームエンジニアとしてキャリアを始めることになったので、ゲームを作るためにこのゲームエンジンについて理解を深めようと思った。まぁしばらくはUnityをやることにはなると思うが。

講座をやった印象

 まず求められるのは覚悟である。Unityはとりあえず触らせて作らせてその中でゲームエンジンの使い方を覚えさせるが、Epic Gamesにはそんな教え方をする気は毛頭ない。ひたすらゲームエンジンを使う上での基礎を叩き込む。チームで作業するにはどうするのか、バージョン管理、レンダリングのパフォーマンス、そういうプログラマーデザイナー問わず知るべき知識をひたすら叩き込む。ちょっと触ってみようという気持ちの人間は求めていない。これはUnityと大きく違う点である。また、UE4自体が非常にプロフェッショナル向けなゲームエンジンであることも痛感した。作業の効率化が徹底されており、雰囲気で使えることよりもプロフェッショナルにとっての使いやすさを最大限に重視している。用いられている技術に対してもレベルが高いとは思うが、Unityについて深くは知らないので言及は避ける。紹介されたいくつかの技術に関してはUnityに応用できるものもあったので、Unityエンジニアにもラーニングパスを履修することをおススメする。特にUnityは「これがやりたい」にこたえるには良いが、体系的に使いこなすための教材は不足している。このラーニングパスはその助けになるだろう。

これから

 私はプログラマーなので、当然ブループリントやC++に関連するラーニングパスを履修する。ここからさらに長いラーニングパスが続く。学習ソースがあるだけうれしいのだが、このゲームエンジンを使いこなせるようになるまでの道のりの長さを感じられずにはいられない。