Quantcast
Viewing all 181 articles
Browse latest View live

本を売らない本屋

最近は出版不況で本が売れないそうで、閉店に追い込まれてる書店が多いそうです。

そんな中でも生き残ってる書店の中には、”本を売らないでも問題ない”本屋があります。

本屋以外の普通のお店なら、先に商品代を払って商品を仕入れるので、商品が売れなければどんどん赤字になります。

しかし、書籍は他の売り物と違って再販制度があります。

出版取次から書店に配本してもらう時にはお金はかかりませんし、売れた本の分だけお金を払えばいい。そして売れなかった本はいつでも返本できます。

ゆえに、大金を払って仕入れた本が売れなくて不良在庫になって大赤字!なんてことにならなくて済みます(岩波文庫など一部の出版社は返本できないのでそうなり得ますが)。本が売れなくても儲けが出ないだけです。

その代わりに書籍は売れても書店の利益は小さくなってます。(粗利益21~24%)

日本ではこの再販制度の前提がある事によって”本を売らない本屋”が成立します。

ヴィレッジヴァンガード 本なんて飾り?

「ヴィレッジ・ヴァンガードで休日を」というビレバン社長、菊地さんの書いたエッセイ本を読んでます。

そういうタイミングで三茶のビレバンを通りかかったので中に入ってウロウロ店内を眺めてみました。

ビレバンは本屋ですが、あんまりベストセラー本とか置いてなく、趣味に偏った本が並んでいて、周りには関連雑貨がギッチリ置かれています。

そうしていて、「あっ、ビレバンって本が売れなくても大丈夫な本屋なんだな」と気付きました。

つまり、ビレバンがお客さんに提供しているのは世界観だという事です。

ビレバンにはテーマ毎にセンスのいいチョイスで書籍が並べられていて、お客さんは書籍をあれこれ立ち読みしている内に世界観に浸ってきます。

そうやって世界観に浸った後は、読んでた本は買わずに置いて、周りの関連雑貨を買っていきます。

ディズニーランドに来た人がディズニーの世界観にどっぷり浸った後にお土産を買って帰る感じです。(実はディズニーランドの売り上げの37%はお土産販売です)

つまりビレバンの書籍は商品というより世界観を盛り上げるための飾りの一部のようなものかもしれません。

そうやって散々立ち読みされた本は売れなかったと言って返本されます。

それは別に問題の無い事です。普通の書店だってやっている事ですから。

しかし、著者が苦労して書いた書籍を使って再販制度にフリーライドして悪用して雑貨販売の金儲けに使っているというような見方もできなくはないかもしれません。

この仮説を裏付けるように、ビレバンの直近の決算資料を確認すると、驚くべき事に、雑貨の売り上げは全体の86%を占めており、書籍はたったの7.8%しかありません。

ただ、菊池さんのエッセイを読んでいる限り、狙ってこのようなビジネスモデルにしたというよりは、とにかく自分の趣味全開の本屋が作りたい!と思って自分の好きな本だけを仕入れたけど全然売れなかった結果、自然とそうなっていったような感じみたいです。

別にビレバンのそういうやり方が悪いなどと言うつもりは無いです。やっていい事の範囲でそういうことができてしまう再販制度の方を見直した方がいいでしょうし、出版不況の現状では本屋は本の売り上げだけではやっていけないのでこんな感じで工夫するしかないという現状でもありましょう。

蔦屋書店

代官山の蔦屋書店に行くと、ビレバンとはまた違った感じでオシャレ風な書籍が大量に並んでいます。

しかも店内にはたくさんソファが置かれていて、お客さんは立ち読みどころか座り読みしてくつろいでいます。

普通の本屋だと立ち読みなんてしてたら下手したら店員さんから怒られますよね。ブックオフでも立ち読みしてたら店員さんが不自然にそばに来て本の整理を始めたりしますよ。それが蔦屋だとどうぞ座り読みしてくださいってなもんです。

それにいざ本を買おうとしてもセルフレジがおざなりに置かれてるだけだったりして、ホントに本を売る気があるのかしらと思ってしまいます。

それどころか、

なんと買っても無い本をスタバに持ち込んで読んでいいというじゃありませんか。

たしかに店内のスタバで本を読んでいる人が一杯いましたが、まさか買わずに持ち込んでるなんて思わずに私なんか最初はみんなそうしてると思って買ってから持ち込んでましたよ。

こんな事が可能なのも、実は代官山蔦屋は本を売る気が全然無いかもしれないんだそうです。売り上げはスタバや周りのテナントからのテナント代で賄ってるんだとか。

つまり、タダで本が読み放題の雰囲気のいい店にお客さんを呼び込む事で、そこのテナントにもお客が来るようにして、テナント代を徴収するという仕組みです。

だからこれも本を売らなくていい本屋です。

代官山蔦屋についてはこちら↓の記事が詳しいです。

夜の歌舞伎町に外国人が殺到する理由

文喫

2018年12月11日に六本木にオープンした「文喫」は、入場料1500円払えば1日居放題で本読み放題、コーヒー飲み放題の”本屋”です。マンガ喫茶じゃないですよ、本屋です。

入場料のある本屋「文喫」は高いのか、安いのか?店内を一足先にレポ

ビレバンや蔦屋にはそれなりに工夫がありましたが、来ましたよ。もう「本を売る気はありません!入場料で儲けます!」って言ってるようなもんじゃないですか。

図書館だって一応書籍を買って本を入荷してますが、こちらは再販制度を使ってタダで仕入れてるというわけです。

もちろん何も悪いことをしてるわけでは無いですよ。しかし、本を書いた著者のみなさん、自分たちが書いた本をタダで読まれまくって儲けられて自分には一銭も入ってこない仕組み見てどんな気持ちですか?

まあ一応本を売ってもいますから、これで沢山本が売れればそれはいいですが、入場に1500円払って入った人が果たして中でまた本を買うのかな…?それなら普通の本屋で買った方がいいと思う。

まとめ

という訳で、最近は本を売らない本屋が出てきたという話でした。

私は別に「こんなズルはやめろ!」とか言うつもりはありません。普通に本だけ売ってても食っていけないという現実がある以上、色々工夫するしかないのです。

逆に、こういう巧妙なビジネスモデルがある事を知って、他の分野とかでも応用する事で、みんなも合法的にできるズルをやって儲けようぜ!と言いたい。

ただ、明らかに自分達の書いた本がいいようにダシに使われてるようなケースは著者が気の毒なような気がします。


賃貸探しの失敗から学んだ事

引っ越したいなと思って賃貸物件を探してました。

どういう風に探したのかというと、とりあえずスーモのページを開いて引っ越したいエリアで検索して良さそうな物件を問い合わせました。

問い合わせると「まだ空いてますよ」というので内見したいですと伝えると、一旦店に来いと言うので行きました。

そしたら「その物件は実は隣にキチガイが住んでるから安いんですよ~」とか色々ディスッてくるので、「何わけわからん事言ってんだ?いいから部屋見せろよ。そもそもそういう事は人を呼び付ける前に電話で教えとけよ」という事を穏便に伝えると、なんか怒り出して「残念!問い合わせましたが、たった今先に申し込まれて埋まっちゃいましたよ!」とか言ってきます。他にも色々物件はありますからって他の物件を色々出してきますが、どれもAD100%とか書いてます。ADってなんだ?

「あなたが昨日行った不動産屋さんは自社の管理物件ばっかり押し付けてきたでしょ?ウチは仲介専門で自社管理物件持ってないから日本中の物件を紹介できるんですよ。このレインズっていう不動産屋しか見れないサイトで全国の物件が見れるんです」とかも言ってました。自社管理物件ってなんじゃ?

「どうも不動産屋さんってのは単に私のために頑張っていい部屋を探してくれるってわけじゃなさそうだぞ」と私は思いました。

帰ってから色々調べてみると、どうも僕は何にもわかってない情弱でダメすぎる部屋の探し方をしていたらしい事がわかってきました。

不動産屋の基礎知識

不動産屋さんが一体どういう利害関係で動いてるのかって所から調べない事にはいい部屋を見つけることはできないんじゃないかと思い、色んな用語について調べてみました。

大家さんが貸したい部屋を私が借りるまでの流れを簡単に書いてみます。(大ざっぱな理解で書いてるので細部は実情と異なるかもしれません)

まず大家さんは町の小さな不動産屋さんに「部屋を貸したいんでお客さんに紹介してください」とお願いします。大家さんから依頼を受けた不動産屋さんを元付けと言います。

元付け不動産屋さんは借り手を探しますが、中々見つからない時はその物件をレインズに掲載して他の不動産屋さんに探してもらいます。

そういう他の不動産屋の物件を紹介する不動産屋を客付けと言います。駅前にある大きくて派手な不動産屋は大体客付け専門です。レインズに載ってる沢山の(売れ残り)物件をお客さんに紹介します。

私が客付け不動産屋で物件を契約した場合、大家さんは元付けに事務手数料を支払い、借り手(私)は客付けに仲介手数料を支払います。これがそれぞれの不動産屋の儲けです。

スーモに物件掲載してるのは大体客付け専門不動産屋です。スーモの掲載料は月額3万円で1枠もらえる感じだそうです。結構高いですがお客さんを呼びこむためにスーモなどのサイトに掲載します。

さて、客付けがもらえる仲介手数料は家賃の1ヵ月分までと法律で決まってます。(仲介手数料無料の場合は代わりに大家さんから仲介手数料をもらいます)

という事は仮に私が「仲介手数料を大目に払うからいい物件を探してくれ」と言ったところで、それは法律違反になるから無理だという事になります。

しかし客付け不動産屋にとっては家賃一ヵ月分ではちょっと物足りません。そこで出てくるのがADです。客付けは契約成立に成功したら元付けからADという宣伝料を追加でもらいます。AD100%なら家賃一ヵ月分のお金が追加でもらえます。ADが多い物件は客付けも頑張って紹介しようとします。

先ほどの話に出てきた自社管理物件とは何か?というと、それは不動産屋自身が大家である物件の事です。大家なんだから無理にでもお客さんに貸したいに決まってます。だから自社管理物件持ちの不動産屋は多少無理にでもとにかくそれを我々借り手に押し付けようとしてくる事になります。

客付け専門不動産屋の動機

ここまで理解すると不動産屋さんの不可思議な言動の理由も見えてきます。

まず私が行ったのは駅前の客付け専門不動産屋さんだったことが分かりました。

客付け専門の特徴としてイチイチどこかに電話をかけてます。電話の相手は元付けの不動産屋です。まだ本当にその物件が空いているか聞かないとわからないからです。それからADがもっと増やせないかの交渉もこっそりしてます。一応オマケで家賃下げの交渉できないか訊いてくれたりもします。この電話の最後に決まって「ご紹介頑張らせていただきますので~」って言ってます。このセリフだけでも客付けが借り手のために頑張ってる訳じゃなさそうな事が伝わってきますね。

前述した事から分かる通り、客付けのモチベーションはとにかく仲介手数料とADを多くゲットする事にあります。借り手の都合なんて二の次、三の次です。

スーモにはオトクそうな物件を色々掲載してますが、これはとにかく客に店まで来てもらうためのエサです。客付けは借り手にとってオトク(家賃が安い=報酬が少ない)な物件なんて選ばせる気はサラサラありません。だから客が来てからスーモ物件をメチャメチャにディスって契約阻止しようとします。この時の言い訳は「この物件は虫が一杯でるらしい」「隣人がやかましいらしい」「退去時にぼったくられそう」とか人によって違いますがかなり適当かつムチャクチャな事言ってます。何でこの物件についてだけそんなに事情に詳しいんだよ。レインズにもそんな事まで書いてねえだろ。

さらに言うと、簡単に借り手が見つかるような優良物件なら、ADを付ける理由なんてありませんし、そもそもレインズに掲載する前に借り手が見つかります。高値のADが付いてる物件というのは、借り手が全然見つからないからやむを得ずADを多くしているという事でしょう。

結論から言うと、高AD物件なんて必然的にゴミ物件が多いという事。そしてレインズに載っててADが多い物件を借り手に押し付けてくる客付け専門不動産を利用するのは情弱のカモがやる事かもしれないという事です。

それを今回やってしまってるのが私です。

しかし、客付け専門業者にもメリットはあります。自分で自慢してるように、自社管理物件を押し付けてくる事はしませんし、元付け業者(町の小さな不動産屋)よりも沢山の物件を扱えるのは間違いないです。だからとりあえず色々な物件を内見したい時は客付け業者の方がいいかもしれません。ADが欲しいだけで、それ以外のややこしい利害を抱えて無いのは逆に言えばわかりやすいかも。

情強の部屋探し

じゃあもっと賢く部屋探しする方法はあるのでしょうか。

とにかくスーモで見つけて内見したかった物件を実際行くとブロックされて見せてくれないのが腹が立ちます。わざと無駄足を踏まされて時間を無駄にされるなら逆にこっちにお金を払って欲しいくらいですよ。

客付け業者と借り手の利益相反が問題の元だと言えます。そもそも客付け業者なんていう余計な物を仲介してるから結果的に借り手の払う額が大きくなるのです。客付け業者を使わずに直接元付け業者の不動産屋に問い合わせるという手があります。そうすれば元付けにはADとか客寄せ物件とか関係無いので見たい物件が見れるでしょう。

となればスーモなんて見てる場合じゃないですね。不動産屋しか見れないっていうレインズを私にも見せてくれよと思ってしまいます。ちなみにレインズは1回検索するたびに5円とか利用料がかかるそうです。

ところが実は、レインズと同等の情報が誰でもタダで見れるサイトがあるんです。

それが、不動産ジャパンです。

このサイトには、おとり物件とかはありません。レインズと同じような正確な情報が載ってます。素晴らしいのは、掲載してるのが全て元付け業者だという事です。

元付け業者なら自分が取り扱ってる物件ですからわざと内見させないなんて事する理由が無いですからね。

私も昨日までこのサイトの存在を知りませんでした。イマイチ存在が知られてないのは、このサイトが知られ過ぎると客付け専門業者が全部潰れちゃうからだとか。こんなサイトがあるなら平気で客にウソつくような客付け業者をわざわざ使う必要が無くなってきますからね。

まあ、こんなサイトがあるからこそ客付け業者は客を騙してまで必死こくハメになってるという事なのかもしれませんが。

私も今回の学びを活かして次に引っ越す時は是非このサイトを活用しようと思ってます。

そもそも内見は諦めた方がいい?

不動産屋さんから聴いた話ですが、そもそも都心では物件の内見は諦めて探した方がいいという説があります。

というのも、都心の賃貸物件は解約の2ヵ月前通告が通例になってるそうです。2ヵ月前は早すぎますね。急な転勤などで2ヶ月も待てるわけがない。

とにかく解約通告から退去まで2ヵ月もあり、大抵は退去するまでに次の人が決まっちゃうそうです。内見もしないまま決めちゃう人に取られちゃうという事ですね。

というわけで例によって内見できる時点でそれは売れ残り物件かもしれないという。だから対抗してこっちも内見できなくてもさっさと決めちゃった方がいいかもしれないという話でした。

繁忙期は避けよう

「安い物件探してるなら1~3月の繁忙期はやめた方がいい。8月の閑散期に比べると同じ物件でも5千円くらい家賃高いよ」という話も聞きました。

1~3月は入学や就職で引っ越してくる人が大量にいるので不動産屋の繁忙期になります。ゆえに足元見て家賃も上がるのでしょうが、しかし時期によって同じ部屋で家賃が5千円も上下するとは驚きですね。

しかも引っ越し屋さんも当然繁忙期になるので、引っ越し費用がまったく違ってくるそうです。

就職などの事情がある人はやむを得ませんが、特に理由もないのに繁忙期に引っ越すのはやめた方が良さそうですね。

こういう記事もあります。

2月に引っ越しする奴はバカ

ちなみに私もなんとなくで繁忙期に引っ越すことにしたバカです。

Unityでオブジェクトのミラー描画

Image may be NSFW.
Clik here to view.

TiltBrushにはミラー機能があって、左側にストロークを描くと右側にも鏡写しのようにストロークが描かれます。

これと同じような物(ただし、ストロークが2つ引かれるんじゃなくて表示上片方のストロークが両側にミラー表示される感じ)をUnityのシェーダで実現しようと思いましたが、若干悩んだので備忘録を残しておきます。

Unityのヒエラルキー上では”Sketch”という親のオブジェクトに”Stroke”という子オブジェクトが一杯付いてる状態を想定してます。

シェーダでミラー描画を実現したければ、1パス目で普通に描画して、2パス目でX座標をマイナスにして(カリングモードもFrontにする)描画すればいいだけなので、一見簡単そうです。

しかし実際にそうしたら、Strokeオブジェクトのローカル座標においてミラー描画されてしまいます。求めたいのはStroke(子)のローカル座標でもワールド座標でもなく、”Sketch”(親)オブジェクトのローカル空間におけるミラー座標です。

ですので、子Strokeローカル座標を親Sketchローカル座標に変換するマトリックスをシェーダに渡す事にしました。

C#コード(部分)

public void OnWillRenderObject()
{
        if (renderer == null) { renderer = GetComponent<Renderer>(); }
        var parentT = transform.parent;

        var localToWorldMatrix = renderer.localToWorldMatrix;
        var worldToParentMatrix = parentT.worldToLocalMatrix;
        var localToParentMatrix = worldToParentMatrix * localToWorldMatrix;

        var parentToWorldMatrix = parentT.localToWorldMatrix;
        var worldToLocalMatrix = renderer.worldToLocalMatrix;
        var parentToLocalMatrix = worldToLocalMatrix * parentToWorldMatrix;

        Material strokeMaterial = SketchManager.Instance.strokeMaterial;

        strokeMaterial.SetMatrix("localToParentMatrix", localToParentMatrix);
        strokeMaterial.SetMatrix("parentToLocalMatrix", parentToLocalMatrix);
}

頂点シェーダコード(部分)

uniform float4x4 localToParentMatrix;
uniform float4x4 parentToLocalMatrix;

void vert(inout appdata_full v, out Input o) {
	UNITY_INITIALIZE_OUTPUT(Input, o);
	o.vertColor = v.color;
	o.uv_MainTex = v.texcoord.xy;

        //ローカル座標を親座標に変換
	v.vertex = mul(localToParentMatrix, v.vertex);
        //X方向でミラー
	v.vertex.x = -v.vertex.x;
        //親座標をローカル座標に戻す
	v.vertex = mul(parentToLocalMatrix, v.vertex);
}

まず第一の罠ですが、TransformコンポーネントとRendererコンポーネントがそれぞれ localToWorldMatrixを持ってます。どっちを使えばいいのか?

リファレンスによれば、シェーダに渡すパラメータに使う場合はRendererコンポーネントのマトリックスを使う必要があります。何故なら、スタティックバッチングが適用されてる可能性があり、その場合はtransformのマトリックスでは正常に座標変換できないからです。

OnWillRenderObject()によって、オブジェクト毎にそれぞれ個別のシェーダパラメータを渡すことができます。

これを実行してみたら、一見正常に動いたようで、ストロークが複数になるとミラー表示がおかしくなりました。

なぜ?

調べてみたところ、Renderer.localToWorldMatrixを使っても、ダイナミックバッチングが適用されてるケースでは複数オブジェクトがまとめて描画されるため、個別にパラメータを渡せないので正常に座標変換できないらしいです。これが第二の罠です。

じゃあどうすればいいかと言うと、シェーダ内で自動で定義されている、ビルトインのシェーダ変数を使えばいいそうです。この中のUNITY_MATRIXとかは、ダイナミックバッチングとかも諸々考慮されていい感じに座標変換してくれるそうです。

というわけで、最終的にコードはこうなりました。

C#コード(部分)

public void OnWillRenderObject()
    {
        if (renderer == null) { renderer = GetComponent<Renderer>(); }
        var parentT = transform.parent;

        var worldToParentMatrix = parentT.worldToLocalMatrix;
        var parentToWorldMatrix = parentT.localToWorldMatrix;

        Material strokeMaterial = SketchManager.Instance.strokeMaterial;

        strokeMaterial.SetMatrix("worldToParentMatrix", worldToParentMatrix);
        strokeMaterial.SetMatrix("parentToWorldMatrix", parentToWorldMatrix);
    }

頂点シェーダコード(部分)

uniform float4x4 worldToParentMatrix;
uniform float4x4 parentToWorldMatrix;

void vert(inout appdata_full v, out Input o) {
	UNITY_INITIALIZE_OUTPUT(Input, o);
	o.vertColor = v.color;
	o.uv_MainTex = v.texcoord.xy;

	v.vertex = mul(unity_ObjectToWorld, v.vertex);
	v.vertex = mul(worldToParentMatrix, v.vertex);

	v.vertex.x = -v.vertex.x; //X方向でミラー

	v.vertex = mul(parentToWorldMatrix, v.vertex);
	v.vertex = mul(unity_WorldToObject, v.vertex);
}

Renderer.localToWorldMatrixを使うのをやめて、ビルトインシェーダ変数のunity_ObjectToWorldを使うようにしました。

これで正常にミラー描画が実現できました。

参考リンク

Unityでなるべくシェーディング処理を自作してみる

箱根ぼっちキャンプ

箱根に行ってぼっちキャンプしてきました。

経緯

毎年桜の季節になると、近隣の桜の名所を一通り巡ってます。

毎年恒例の目黒川

新宿御苑

千鳥ヶ淵の桜ライトアップ

旧芝離宮恩賜庭園

上野公園

墨田公園

もう十分堪能した感じがありますが、今年はダメ押しで小田原の小田原城址公園と紹太寺にも行ってみようと考えました。

しかし小田原まではかなり交通費と時間がかかります。片道2時間半かけて日帰りで帰るのもバカらしいなと思いました。

どうせなら1泊しようかと思い付き、各安宿を検索しました。

出てきたのがこちらのパンシオン箱根さん。何と1泊3100円で泊まれるそうです。

早速予約しようとしたら、残念な事に去年に閉館してしまったそうです。

他には目ぼしい格安宿は無さそう…どうしよう…

そうだ!キャンプすれば安く泊まれるじゃん!

という訳でこちらの芦ノ湖キャンプ村さんでキャンプする事にしました。

日程は4月7日(日)~8日(月)です。

4月7日(日)

バスで出発

1日目はとりあえず先にキャンプ場に行ってから観光するつもりです。

キャンプの荷物はものすごくかさばります。こんな重い荷物を背負ってては観光どころじゃないので、とりあえずキャンプ場にチェックインして荷物を置いてから遊びに出かけるプランです。

極力荷物を背負っての移動を減らすために、新宿バスターミナルからキャンプ場そばまで一発で行けるバスを使う事にしました。バスの荷物置き場にクソデカリュックを預けられるのも嬉しいです。

小田急箱根高速バスで、新宿~箱根レイクホテル前まで、所要時間2時間半、料金は2010円です。

10時発の便に乗ったので、12時半にはキャンプ場にチェックインできる予定でした。

バスが出発するまでの間にテントサイトをWeb予約します。当日に予約するのは天気が悪ければ行くのやめようと思ってたからです。一応前日に電話で混み具合を確認しておきましたが、日曜なので全然空いてるとの事でした。

しかし、当日のWeb予約は8時までしか受け付けてないとの事。私のスマホは通話できないMVNOなので、公衆電話から予約しました。

ファミマで朝食のホットドッグとコーヒー、あと昼食用に唐揚げ弁当と水を買っておきます。

渋滞で大遅延

そうこうしてる内にバスが出発しました。何だかやけに乗客が少ないな…空いてるのは嬉しいけど…

乗客が空いてる理由はすぐにわかりました。東名高速道路の東京料金所の辺りで今朝事故が起きており、物凄い渋滞が発生してまったくバスが進みません。

twitter検索したら事故を起こしたポルシェの写真が晒されてました。

恐らくこの情報を察知していた人達がバスに乗るのを取りやめたから乗客が少なかったのではないでしょうか。

私も渋滞リスクを想定して事前に高速渋滞情報をチェックしておけば…と悔やまずにはいられません。結局バスは現地まで一時間遅れとなりました。

バッテリーは死活問題

このバスにはフリーwi-fiに加えてコンセントまで備え付けられてあります!すばらしいですね。

旅行中はなんと言ってもギガとバッテリーの確保が一番の死活問題です。私はバッテリーは8000mAhの物と20000mAhのクソデカい物の2つのモバイルバッテリーを持ってきました。

しかし、間抜けな事にACアダプタを持ってこなかったのでせっかくの電源の恩恵を受けられませんでした。それどころか逆にバスに3時間半乗ってる間に小さい方のモバイルバッテリーを使い切ってしまいました。次回は絶対ACアダプタ持ってくるぞ。

車内トラブル発生

そういえばバスが出発して早々にトラブルが発生してました。

どうやらサラリーマンが後ろの乗客のおじさんに無断で全力でリクライニングしたら注意されて逆ギレして喚いているようです。

サラリーマン「僕には座席をリクライニングする権利がある!リクライニングしちゃいけないならできるような座席にしてないはずだし!よって、リクライニングして欲しくないならアンタは自分の前の座席と2席分買えばよかった話でしょ!」

おじさん「無断でリクライニングするのはマナー違反でしょ。一声かけるべきだろう」

サラリーマン「そんなんあなたの常識を他人に押し付けるのやめてもらえませんかねえ?」

最終的にはサラリーマンは憤懣やるかたないといった顔で別の空いてる席に移動してました。

どうなんですかね。てか座席に入ってる注意書きにも「リクライニングする時は後ろのお客様に一声おかけしてください」って書いてるんですが。

僕は後ろに乗客いなきゃ全力リクライニングしたでしょうけど、乗客がいらっしゃって、一声かけるのも面倒だったのでリクライニングしませんでした。

他の乗客も、せっかく日曜に箱根に楽しい観光に出かけてルンルン気分だったのが、お通夜みたいに車内がシン…としてしまいました。

バスは一番前の席を選べばリクライニングトラブルを防げてオトクですね。ちなみにバス事故で一番致死率が高いのは一番前の左側の席で、一番安全なのは一番前の右側の席だそうです。何故なら事故りそうになったら運転手さんはとっさに自分を守るためにバスの左側がぶつかるようにハンドルを切るからだそうです。

到着

高速を降りて山道に入るといよいよ目的地に近づいてきます。

途中、乙女峠という場所の辺りで富士山が綺麗に見える瞬間があります。

写真だとうっすらとしか見えませんが、実際に見ると結構インパクトあります。

あと、金時山の辺りで降車アナウンス音声の人が急に「足利山の金太郎~♪」とか歌いだすので普段の冷静なアナウンスとのギャップが衝撃で必聴です。

13時半ごろに現地に到着しました。

芦ノ湖が綺麗ですね。人が一杯いてバーベキューとかやって賑わっています。日曜でも泊まる人が一杯いるのでしょうか。騒々しいキャンプになりそうだなと思いました。

フロントに行って受付します。フロントの営業時間は8時~20時です。色々キャンプ道具をレンタルできますし、隣の売店ではちょっとしたコンビニみたいに色々売ってます。カップ麺、即席コーヒー、パスタ、冷凍食品まで。レンジとポットもあります。周辺には一切コンビニとか無いのでありがたいですが、ちょっと便利すぎて、気合入れてカセットバーナーまで持ってきたのは何だったんだって気もします。

テントサイト一つの料金が2500円との事。えっ、Webサイトだと2000円って書いてますけど…今朝予約した電話口でも2000円って言ってたし…と伝えたら2000円になりました。なんかWeb予約しないと500円増しになるんだそうです。

それに加えてゴミ処理協力費が一人につき200円かかります。

受付を済ませてテントサイトに向かいます。それにしても2000円って結構高くないか…観光地とは言え…(ちなみに閑散期は1000円)普通は500円とかじゃないの…

テントサイトに付くと、私以外にはもう一組だけいました。4人くらいでバーベキューしてます。

そうか、2000円って言っても普通は一人でキャンプなんてしないもんな…4人なら一人につき500円で妥当だ…

一番木陰になってる場所はそのもう一組に取られていたので、二番目に木陰になってる場所に設営します。どうして木陰を選ぶのかというと、後で述べますが夜露を防ぐためです。

設営はすぐ完了。テントを設置して、内側に銀マットを敷いてその上に寝袋を敷いたら完成です。

寝袋はSnugpakのナビゲーターというものです。今は売ってないみたいですが、コスパのいい寝袋です。実は家でもめっちゃ寒い時は寝る時に布団の中に入れて使ってます。便利です。

銀マットは WILD-1というアウトドアショップで500円で買いました。

このテントはドッペルギャンガーのT1-51というもので、テントというよりツェルト…いやビビーサック…?

以前に野宿旅に出かけようと目論んだ時に買ったものです。野宿って正式なキャンプ場じゃなくて適当に寝れそうなところに寝る感じなので、テントを張っちゃうと怒られる可能性がありますが、このテントなら寝袋カバーですと言い張ればなんとなく大丈夫そうと思って選びました。

でも結局一回使ったっきり押し入れにしまってました。このテントの弱点は夜に屋根の内側がメチャメチャ結露する事です。いや、どのテントでも結露はするのかもですが、これはとにかく屋根が低いので寝袋に触れてしまい寝袋がびしょ濡れになってしまいます。野宿連泊はとてもじゃないけど不可能でしょう。

しかし今回は対策を練ってきました。テントが結露する原因は夜露のせいだと言われています。夜露とは、空気中の水分が夜に冷えて見えない雨のように落ちてくる現象です。つまり、屋根のある場所やタープを使えば結露を防げるかもしれません。

というわけでホームセンターで129円で買ったブルーシートをかけてみました。これで夜露はブルーシートに落ちて、結露はブルーシートとテントの間に発生するだけで、テントの内側は無事なハズです。

ただ一つ問題があって、見た目が非常に公園に住んでる人っぽくなってしまうのが弱点です。

観光

14:30くらいに設営完了したので、今朝買った弁当をお昼ご飯に食べます。

景色がきれい。

ペットボトルの水は飲み終わったら水筒代わりに使います。炊事場の飲用水を補給。水道水だけど美味しいです。

荷物を全部テントの中に入れて遊びに出かけます(後で気付きましたがフロントの脇にコインロッカーがあるので用心するならそっちに入れた方が安全です)

大涌谷というところに行ってみます。ロープウェイで行くルートとバスで行くルートがありますが、ロープウェイだと千円、バスなら360円なのでバスで行きます。

バスに乗ろうとしたら、運転手さんが「大涌谷行きはメッチャ渋滞してるから、帰りのバス無くなるかもしれない。ロープウェイの方がいいよ」という情報をくれました。今朝バスの渋滞リスクを実感したばかりなのに、またバスリスクに引っかかりかけた!

しょうがないので桃源台駅からロープウェイに乗ります。

こんなところでもいらすとやさんが使われています。

ロープウェイは一分間隔でじゃんじゃんやってくるので待たずに乗れます。

これは気分が悪くなった時に使う酸素ボンベ

大涌谷に向かう道路がメチャメチャ渋滞してるのが見えます。バスで行かなくてよかった…運転手さんに感謝

という訳で大涌谷(おおわくだに)に着きました。

よく知らないで来てしまいましたが、なんか凄いですね。メッチャ硫黄の匂いがします。

散策できる道があると思いきや、通行止めみたいです。なんで?とググッたら、2015年に水蒸気噴火がおきて火山活動が活性化していて危険だからだそうです。

散策したかったなー

黒たまごというのが名物みたいですが、5個入りしか売ってなかったので買いませんでした。

ジオミュージアムという資料館があるので入ってみます。入館料100円です。

噴火で色々大変だったみたいです。

以上、大涌谷でした。

ロープウェイで帰りますが、帰りは途中の姥子駅で降ります。

姥子駅周辺には特に何も無いです。ここからバスで温泉に向かいます。

「姥子温泉 芦ノ湖 一の湯」に着きました。ロッジですが、日帰り入浴ができます。キャンプ場周辺で夕方以降も入れる(営業時間13:00~20:00)お風呂はここしかありません。料金は770円です。キャンプ場にも共同浴場がありますが、今日は営業してないそうです。

浴槽は4人くらいしか入れないサイズで、他は洗い場しか無くて結構狭いです。でも何といっても姥子温泉の源泉かけ流しなのが嬉しいです。13:00~15:00の間なら露天風呂にも入れるそうですが今回は間に合わなかった。

外国人宿泊客が一杯来てるみたいで、私が風呂に入った後続々と入って来てました。

お風呂から出てサッパリした頃には18時を過ぎてました。歩いてキャンプ場に戻ります。

キャンプ場に戻ってみると、あれだけ昼間賑わってたキャンプ場が、誰もいなくなってました。

なぜ…みんなバーベキューしてただけでキャンプ客じゃなかったのかな…

日も落ちて暗くなってきて、さみしくなってきた…

気を取り直してバーベキューをするぞ!

バーベキュー

キャンプ場にはバーベキュー場もあるし、炊事場のカマドもありますが、どちらも有料です。今回は持ち込みのバーベキューコンロを使います。テントサイトは直火禁止で焚き火も禁止ですが、バーベキューコンロは使えます。

家から100gあたり99円の牛肉を300gほどジップロックに入れて冷凍させたまま持ってきてます。あとお茶碗1.5杯ぶんくらいのご飯をラップで包んだおにぎりも。

コンロは先週買ったYolerの折り畳みコンロを持ってきてます。

このコンロはキャプテンスタッグのカマドのパチモノですが、本物のB6カマドよりもちょっと大きくて、個人的にはバーべキューしやすいサイズで気に入ってます。

燃料はダイソーで買った燃料炭を持ってきてます。着火剤無しで簡単に着火できてそのまま燃料にできるそうです。これまたダイソーで買ったターボライターで着火します。

しかし、全然着火しませんね…オイオイ…しょうがないのでその辺の枯葉を拾って炭の上に乗せて燃やして焚きつけます。

焚き火みたいでいいですね。

ホントは火が消えてから炭から出る赤外線の熱でじんわりと肉を焼くのがバーベキューですが、前に火が消えるまで待ってたら炭が灰になってた事があったので、もうさっさと直火で焼く事にします。

肉を焼いてる様子。

周りがメッチャ暗いですね。LEDランタンとかは持ってきてないですが、一応こういう感じのLEDヘッドライトを装着してます。

ヘッドライトで照らさないと肉が焼けてるかどうか分からないので危険です。

肉には持参した塩コショウだけかけて食べます。ホントは焼き肉のたれとか使いたいですが、そうするとお皿も必要になりますし、ただでさえ左手におにぎり持ってて右手で箸持って肉を焼いたりペットボトルの水を飲んだりして忙しいのに、この上お皿まで持つなんてのはテーブルが無い状況ではオペレーションが多忙すぎて却下です。

ほとんど肉を食べ終わった頃にようやく炭がいい感じになって来てますが、もう遅いです。

バーベキューも終えて、誰もいない(フロントも営業終了して従業員の人も多分いなくなった)真っ暗なキャンプ場で特にする事もないので、テントに入ってプライムビデオでゆるキャンを観ます。(アプリ設定で画質を最低にしてギガ節約にするのを忘れずに)

ゆるキャンのしまりんはぼっちキャンプたのしそうですが、実際やってみるとクッソ心細いよ…暗いしさびしいし怖いし…こんな事になるって分かってたら来なかったかも…私にはスナフキンみたいな生活は無理や…そういやフロントの人がイノシシが普通に出ますって言ってた…こんな所で熊とか殺人鬼に襲撃されたらオシマイや…

そんな事を考えてたら、テントの内側がメッチャ結露してきてる事に気付きました。うわあ…ブルーシート意味なかった…というか仮にブルーシートが夜露を凌いでくれているとしても、結局内外の温度差でテントが普通に結露するのは免れないのでは。

あ~あと思いましたが、幸いこごえるほどの温度では無いので、寝袋が濡れても気にしない事にして寝ました。

4月8日(月)

夜中にパタパタという音で目が覚めました。

ゲッ!雨が降ってる!ついてね~!

とにかく慌てて外に出してた靴をレジ袋に入れてテントの中に収納しました。

テントに浸水してきたらどうしよう~このキャンプもう全然ゆるくない!

あとはもうなるようになれと思ってとりあえずまた寝ました。

起床

6時半ごろに目が覚めて、周りも明るくなってたので起きる事にしました。雨はまだメッチャ降ってます。

このテント、結露はひどいですが、朝まで雨はまったく浸水しませんでした。結構防水能力すごいですね。見直しました。

今朝の様子。屋根のある所が炊事場ですが、今思うと炊事場にテント置いて寝れば快適だったろうな…

とりあえず昨夜のバーベキューの片づけをします。炭捨て場に灰を捨てて、炊事場でコンロを洗います。

テントを炊事場に引き上げたりしつつ、朝食のカップ麺を準備します。イワタニジュニアガスバーナーにMoritaのクッカーを置いてお湯を沸かします。

カップ麺できた

朝飯食ったら昨日売店で買っておいたインスタントコーヒーも作ります。

2杯セットなので2杯飲みます。

コーヒー飲みながら周辺を散策します。ちなみに折り畳み傘を持ってきてます。

キャンプ場に戻ってもろもろ片付けて荷物をまとめます。

ブルーシートは129円だし、びしょびしょに濡れてるし、これを持って帰って再利用するのか…?と思ったので、捨てちゃうことにしました。

そういえばフロントでUSBのACアダプタを借りた(100円)んですが、挿すコンセントの電源はどこを使えばいいのか分からなかったので、結局使わないまま返却しました。

元箱根

キャンプ場を後にして、海賊船乗り場に向かいます。

雨は止んできました。

これに乗ります。芦ノ湖の桃源台から元箱根まで、9時半に乗って10時10分頃到着。料金は1000円。

乗り込みます

途中の港でこっちの海賊船に乗り換えです。

元箱根に到着しましたが、霧がむっちゃ濃いです。

ちなみに霧が濃すぎてこのあと海賊船は一時間おきの運行になったそうです。

隣のバス乗り場のコインロッカーに荷物を預けて箱根神社に行ってみます。

でかい鳥居

またでかい鳥居

なんか湖面に浮かんでる有名な鳥居の方に行きます

なんと有名な鳥居は工事中でした。でもこれはこれでカッコいい。

階段を登って本殿へ

本殿です。

苔がめっちゃ生えてる狛犬

九頭竜神社の手水

霧がメチャメチャ濃い

霧が濃すぎて水墨画みたいになっとる

11時頃、この辺で唯一のコンビニであるローソンに行ってお昼ご飯を食べます。周りの飲食店は観光地価格で高めですが、ローソンは普通のお値段です。(Paypayが使えるので20%バックキャンペーンも付きます)

外は霧が出てて寒いですが、このローソンには広々としたイートインがあります。なんかコロッケとかウインナーが乗ってるカレーをチンしてもらってイートインで食べます。

イートインにはコンセント電源もあるうえ、なんとUSB電源まであって至れり尽くせりです。ありがたく充電させてもらいました。素晴らしいですね。このローソンは元箱根の激オシスポットです。

お昼ご飯を食べたので、元箱根からバスで入生田(いりうだ)という所へ行って、当初の目的だった紹太寺へ向かいます。

元箱根のバス停はgoogleマップが指し示す場所がすごい適当なので、結構探すハメになりました。

入生田

というわけで入生田に着きました。

実は入生田駅前の「神奈川県立生命の星・地球博物館」にも行ってみたかったんですが、残念な事に月曜日は休館日でした。残念…

入生田駅にはコインロッカーぐらいあるだろうと考えてましたが、ありませんでしたので、クッソ重い荷物を抱えたまま紹太寺まで行くハメになりました。

なんか神社がありますね。

こちらが紹太寺です。

たしかに桜は咲いてますが名所ってほどでは…

この案内板によると、名所の桜は紹太寺の裏の山のてっぺんにあるとの事。な、なんだってー

なんか廃墟

これを登るのか…

まだメッチャ階段あるやん

へえ、昔はここに立派な伽藍があったらしい。幕末に焼失したらしい。

今は畑が広がるばかりだ

結局名所の桜はどこやねん

あっ、これかあ!…って散っとるやん!完全に!どうしてくれんのこれ!クッソ重い荷物しょってこんな山の上まで必死こいてやって来たというのに

上を見ても何もなかった

しょうがないのでバスでもう一つの目的地である小田原城に向かおう。もしそっちの桜も散ってたらガッカリすぎる…

小田原

小田原駅のコインロッカーに荷物を預けて小田原城へ。

一番近い入り口から小田原城に入ろうとしたら、正面入り口はこっちじゃないよ!って案内板でやけに誘導されるけどなんなん?

おおーっ、正面入り口の通り、桜がメッチャ綺麗!これを見せたかったのか

小田原城前まで来ました。

ローソンで買っておいたマーガリンジャムパンをおやつに食べます。

何故かサルがいる

小田原城の脇の常盤木門SAMURAI館とかいう所へ

ほ~ん

やたらカッコいい兜

ハトがピョコピョコ跳ねてて、キャワイイ~と思ってよく見たら片足無くてあっ…ふ~ん

いよいよ小田原城に入ります

小田原城は北条氏の本拠地だったけど、豊臣秀吉に包囲されて開城するハメになったらしい

天守閣からの眺め

こども遊園地ってなんじゃ

良心的な値段設定

豆汽車80円

バッテリーカー80円

謎のベールに包まれた自動遊具30円

小田原城も観終わったので帰ります。

帰りの電車はJR東海道本線と小田急線の2択があって、小田急線の方が500円くらい安い代わりに30分くらい到着が遅い。疲れてて早く帰りたかったのでJRで帰りました。

おわりに

というわけでぼっちキャンプ箱根2日間の旅でした。

紹太寺の桜が散ってたのは残念ですが、小田原城の桜は満開だったし、キャンプとバーキューもできて一石二鳥で良かったと思う。

夜中に雨が降ったのは残念だけど、結構あったかくて虫もほとんどいないいい気候でした。

正直テントはもっと普通なソロテントに買い替えたいですね…これとかでいいんじゃないの。

ゆるキャンだと原付や車で荷物運ぶからかさばっても平気ですが、電車バス、徒歩だとこれ以上荷物増やせないですね。むしろ減らしたい。

てか免許あるんだからレンタカー借りればいいだろって話なんですが、いかんせんペーパードライバーなもので…

これからアウトドアにいい季節だから、キャンプまでいかなくともお出かけついでにバーベキューするとかは荷物もそんなに要らないし面白そうですね。

英語のコメントを日本語に翻訳するVisualStudio拡張が動作しなくなってたので何とかした

以前作成して公開していた、英語のコメントを日本語に翻訳するVisual Studio拡張ですが、この前使おうとしたら動作しなくなってました。

そもそもこの拡張機能では、何故かタダで使い放題の怪しいGoogle翻訳APIエンドポイントを叩いて翻訳していました。

つまり、ついにこの怪しいエンドポイントの穴が塞がれた結果、拡張機能が動作しなくなったという事みたいです。

まあ怪しい機能使ってた私が悪いんですが。

私は英語でコメント書かれてるソースを読む機会が多いので(そして英語もロクに読めないので)、ハッキリ言ってこの拡張機能が無いと困ります。

というわけで、拡張機能を作り直してみました。マーケットプレイスにアップしてる奴も更新済みです。

https://marketplace.visualstudio.com/items?itemName=umiyuki.TranslatorVSIX

前の拡張機能との大きな違いとして、使用するまでに前準備が必要になってしまいました。

Google Cloud Translation API V2という正式な翻訳APIを使うので、ユーザーのみなさんが、自分でGoogle Cloud Platformにプロジェクトを作成して、APIキーを設定する必要があります。

しかもTranslation API V2は無料枠無しで即座に課金が始まります。値段は100万文字あたり20ドルです。つまり500文字につき1円くらいかかります。まああんまり高くなさそうですが課金されるのはつらいですね。

Translation API V3を使えば無料枠がありますが、V3はAPIキーが使えなくて認証がややこしいので無理でした。

課金してでも使いたい!という方のために、使用準備手順です。

要課金 拡張機能セットアップ手順

注意:GCPプロジェクトは細心の注意をもって扱ってください。そして拡張機能の使用は自己責任でお願いします。知らない内に課金額が膨れ上がってた!APIキーが盗まれて悪用された!などのトラブルが起きても私は一切責任を持てません。

1.GCPコンソールから新しいプロジェクトを作成します。

2.プロジェクトに Cloud Translation API を有効にします。(多分クレカ紐付け必須です)

3.プロジェクトのAPIキーを作成して文字列をコピーします。

4.拡張機能がインストールされているVisual Studioを開き、メニューからツール→オプション→TranslatorENtoJP→General→API Keyにコピーした文字列をペーストします。

これで準備完了です。お疲れさまでした。

あっさりと書いてしまいましたが、Visual Studioをバリバリ触ってるような人なら大抵GCPのプロジェクトとかも作った事ありそうだから多分大丈夫でしょう。

ちなみにオマケとして、今までは決め打ちで英語のコメントを日本語に翻訳してましたが、今回のバージョンでは設定画面から言語コードを変更すれば好きな言語から好きな言語へ翻訳させられます。

というわけで、今まではグレーゾーンな拡張機能だったのが、晴れてホワイトな機能になったのは喜ばしい事ですが、

私は課金したくない!絶対に課金したくないでござる!!

というわけで、主に自分向けに課金を回避するオプションを実装しました。

課金したくない人向けセットアップ手順

どうやって無課金を実現したのかというと、こちら↓

3 分で作る無料の翻訳 API with Google Apps Script

の記事で、Google Apps Scriptを使って自分で無料のGoogle翻訳APIを作成しちゃうという方法を参考にしました。

まずは上記の記事の通りにGoogle Apps Scriptを使ってウェブアプリケーションを作成して、エンドポイントのURLをコピーします。

そして拡張機能をインストールしたVisual Studioのメニューから ツール→オプション→TranslatorENtoJP→General→裏オプション→Google App Script APIの欄にコピーしたURLをペーストします。

API Keyの方が入力されてると、そっちが優先して使用されてしまうので、Google Apps Scriptで翻訳したい方はAPI Keyの欄は空にしてください。

これだけです。これだけで引き続き無料で英語のコメントを日本語に翻訳できます!

やったぜ!

余談

余談ですが、こういうAPIキーみたいな機密にしないといけない情報を入力させるような拡張機能とかはあまり使わない方がいい気がします。

お前が作ったんだろ!と言われると何も言えませんが。

何でかというと、拡張機能の制作者がこっそりサーバとかにAPIキーを送信して勝手に使われて知らない内に課金額が膨れ上がってるなんてリスクも無いとは言えません。いや私はそんな事してないですが。

そういうリスクが気になる人は、この拡張機能のソースはGitHubに公開してあるので、ソースを読んで問題無い事を確認して、ソースからビルドして使えば安心です。

https://github.com/umiyuki/VisualStudioExtensionTranslatorENtoJP

このリポジトリの途中のコミットでミスってAPIキーを書き込んだままのソースを上げちゃって、慌ててGCPコンソールからAPIキーを無効化したみたいな出来事もありました。

まあGCPの方じゃなくてGoogle Apps Scriptの方使ってタダで使っちゃおうという人にはどっちみち関係ない話ですが。

UnityでSDF(符号付き距離フィールド)をマーチンキューブでメッシュ化する

最近SDF(符号付き距離フィールド)について勉強してます。

SDFをどうやったらメッシュ化できるのか?って具体的な話がググっても出てこなかったので挑戦してみました。

SDFって何?マーチンキューブって何?って思う方もいらっしゃるでしょうが、そこから話し始めるとキリが無いので、その辺の解説はまた別途記事にするかもしれません。ひとまず今はググって調べてください。

まず、イチからマーチンキューブのプログラムを書くのは面倒なので、

https://github.com/pavelkouril/unity-marching-cubes-gpu

↑コチラのUnityでGPUでマーチンキューブを実行するプロジェクトをダウンロードして開きます。

このプロジェクト(以下MCプロジェクト)をちょっと改造して、SDFに対応させましょう。

MCプロジェクトでは、このような処理が行われます。
①メッシュ化したい物体の密度を3Dテクスチャ(サイズは64x64x64)に書き込む
②3Dテクスチャをコンピュートシェーダで読み込んでマーチンキューブでメッシュ(三角形ポリゴン)を生成する
③生成されたポリゴンを描画

しかし今回の挑戦では、①のような普通に各ピクセルに密度が書き込まれた3Dテクスチャでは無くて、SDFの3Dテクスチャを使います。
なので、どっかからSDFの3Dテクスチャを持ってくる必要があります。

https://github.com/xraxra/SDFr

↑こちらのSDFrプロジェクトは、UnityでメッシュをSDFの3Dテクスチャに変換することができます。ちょうど本記事でやろうとしてるSDF→メッシュの逆パターンですね。

SDFrのプロジェクトの中に、「sdfData_NC_Bunny」という名前の3Dテクスチャアセットが入ってます。これはスタンフォードバニーをSDFの3Dテクスチャに変換したものです。サイズが64x64x64で、MCプロジェクトで使われてる3Dテクスチャと同じサイズで都合がいいので、これをMCプロジェクトにコピーします。

MCプロジェクトのExampleシーンを開いて再生してみると、なんか球のメッシュがでかくなったり小さくなったりするのが表示されます。まあこれが普通のマーチンキューブです。

ヒエラルキービューのVoxelGridというオブジェクトを見ると、MarchingCubes、DensityFieldGeneratorという2つのスクリプトが付いてます。

MarchingCubesはマーチンキューブを実行して描画するスクリプトで、 DensityFieldGeneratorは物体の密度の分布を格納した3Dテクスチャを生成、更新するスクリプトです。

今回の挑戦では DensityFieldGeneratorは不要なので削除します。代わりに以下のようなスクリプトを作ってアタッチします。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SDFMarchingCubes : MonoBehaviour
{
    public Texture3D sdfTex;
    [SerializeField] PavelKouril.MarchingCubesGPU.MarchingCubes mc;

    // Start is called before the first frame update
    void Start()
    {
        mc.DensityTexture = sdfTex;
        mc.isoLevel = 0f;
    }
}

sdfTexにはSDFrからコピーしてきた 「sdfData_NC_Bunny」 を、mcにはMarchingCubesをセットします。

このスクリプトで、MarchingCubesにスタンフォードバニーのSDF3Dテクスチャを処理させます。

Image may be NSFW.
Clik here to view.

ところで、MarchingCubes.csのisoLevelという変数は私が勝手に追加したものなので、追加してください。

20行目
+       public float isoLevel = 0.5f;
74行目
-       MarchingCubesCS.SetFloat("_isoLevel", 0.5f);
+       MarchingCubesCS.SetFloat("_isoLevel", isoLevel);

isoLevelというのは、マーチンキューブでメッシュを生成する密度のしきい値です。つまり、これより密度の値が大きい場所は物体の内側で、それ以外は物体の外側という事になります。

MCプロジェクトはisoLevelが0.5fで固定されていましたが、変数にして変更できるようにしました。

というのも、SDFの場合は当然物体のしきい値は0にする必要があるからです。

さて、とりあえずここまででシーンを再生してみます。
もうスタンフォードバニーが表示されました!ハイ完成…ではないです。

なんかメッシュの向きが逆向きに生成されてます。
何でこうなるかと言うと、通常のマーチンキューブでは、密度が高いほど物体の内側ですが、SDFでは距離値が小さいほど物体の内側なので、大小が逆なせいでメッシュの方向が逆向きになってしまうわけです。

まあ、これは単に生成されるポリゴンの向きを変えればいいだけですので、MarchingCubes.computeというコンピュートシェーダのファイルをちょっといじります。

441行目
-			t.v[0] = v0;
-			t.v[1] = v1;
-			t.v[2] = v2;
+			t.v[0] = v0;
+			t.v[1] = v2;
+			t.v[2] = v1;

これで面が正常な向きに描画されました。
でもまだなんか表示が変です。法線も逆向きに生成されてしまってます。
法線の方向も逆にします。

437行目
-			v0.vNormal = normalize(CalculateGradient(v0.vPosition));
-			v1.vNormal = normalize(CalculateGradient(v1.vPosition));
-			v2.vNormal = normalize(CalculateGradient(v2.vPosition));
+			v0.vNormal = -normalize(CalculateGradient(v0.vPosition));
+			v1.vNormal = -normalize(CalculateGradient(v1.vPosition));
+			v2.vNormal = -normalize(CalculateGradient(v2.vPosition));
Image may be NSFW.
Clik here to view.
メッシュ化されたSDFのスタンフォードバニー

はいOK!
ただしくSDFをマーチンキューブでメッシュ化して描画できましたよ!
簡単でしたね。

ついでなのでメッシュをアセット化して保存してみましょう。
MarchingCubes.csに以下のようなコードを追加します。

[ContextMenu("SaveMesh")]
        void SaveMesh()
        {
            int[] args = new int[] { 0, 1, 0, 0 };
            argBuffer.SetData(args);

            ComputeBuffer.CopyCount(appendVertexBuffer, argBuffer, 0);

            argBuffer.GetData(args);
            int triangleCount = args[0];

            float[] buffer = new float[(Resolution - 1) * (Resolution - 1) * (Resolution - 1) * 5*18];
            appendVertexBuffer.GetData(buffer);

            int nextIndex = 0;
            List<int> triangleList = new List<int>();
            List<Vector3> vertexList = new List<Vector3>();
            List<Vector3> normalList = new List<Vector3>();
            for (int i = 0; i < triangleCount; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    int baseIndex = i * 18 + j*6;
                    triangleList.Add(nextIndex++);
                    vertexList.Add(new Vector3(buffer[baseIndex], buffer[baseIndex + 1], buffer[baseIndex + 2]));
                    normalList.Add(new Vector3(buffer[baseIndex + 3], buffer[baseIndex + 4], buffer[baseIndex + 5]));
                }
            }

            Mesh mesh = new Mesh();
            mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; //65536頂点超えても大丈夫にする
            mesh.vertices = vertexList.ToArray();
            mesh.triangles = triangleList.ToArray();
            mesh.normals = normalList.ToArray();

#if UNITY_EDITOR
            UnityEditor.AssetDatabase.CreateAsset(mesh, "Assets/savemesh.asset");
            UnityEditor.AssetDatabase.SaveAssets();
#endif
        }

メッシュの情報が保存されてるGPU上のバッファからデータを取り出して保存する処理です。(今回はやってないですが、実用するなら同じ座標の頂点を一つにまとめる処理を入れた方がいいです)

プレイモードに入ってMarchingCubesのコンテキストメニューから”SaveMesh”を実行するとAssets/savemesh.assetとしてメッシュが保存されます。

Image may be NSFW.
Clik here to view.
アセットとして保存されたメッシュ

以上で、SDFをマーチンキューブでメッシュ化して取り出す処理が実現できました!

簡単でしたね。

あとはobjファイルに加工してBlenderに持っていくなりなんなりして好きにできます。

GPUによるマーチンキューブは高速なので、毎フレームリアルタイムで実行し続ける事もできます。ただし、現状はなんのひねりも無く総当たりで処理してるので、空間の解像度が上がると処理負荷が厳しくなってくると思われます。不要な場所の処理をスキップする最適化の余地はあると思います。

SPH法による流体シミュレーションについて

前置き

こんにちは。

今日は、マーチンキューブについて記事を書きたかったんですが、そもそもマーチンキューブって何の役に立つのかを知らないと興味を持てないと思うので、まず先にマーチンキューブがよく活躍する流体シミュレーションについて紹介したいと思います。

流体シミュレーションとは何かというと、水とかの動きをシミュレーションする事です。ゲームに流体シミュレーションを活用すると、リアルな水の表現が可能になるかもしれません。

流体シミュレーションには色々な手法がありますが、私が知ってるのはSPH法です。なのでこの記事ではSPH法について紹介します。

SPHとはSmoothed Particle Hydrodynamicsの略です。直訳すると「平滑化された粒子の流体力学」です。名前の通り、SPH法では水を沢山の粒子(粒々)の集まりとして表現します。というのも、実際に水は水分子の粒々の集まりだからです。それぞれの粒々の動きを一つづつ物理シミュレーションする事で全体として水みたいな動きになります。

「沢山の粒々を物理シミュレーションするだけなら、SPHとか使わなくてもUnityで大量のスフィアコライダ突っ込めばいいんじゃね?」

はい、今読者の心の声が聞こえてきましたね。
たしかにぶっちゃけUnityで大量のスフィアコライダをぶち込むだけでも割とそれっぽくシミュレートできるかもしれません。

ただし、Unityの物理演算では水の粘性とかが考慮されないので、よりリアルな水表現を追い求めるならSPHを使うといいかもしれません。
ゲームに使うだけならそれっぽく見えればそれでいいかもしれませんが、流体力学を研究してる人とかは、当然一番リアルに水を再現できる手法を使いたいでしょうね。

SPHを使うとこんな水表現ができるらしいです↓

ちなみになんで私がSPHについて知ってるかと言うと、私は学生の頃の卒論でSPHとマーチンキューブで水を描画する研究やってました。十数年前の話ですが。

SPH法

というわけでSPHをやっていきましょう。

沢山の粒子で水を表現するという事なので、早速つぶつぶをばら撒いてみました。

Image may be NSFW.
Clik here to view.

さて、それぞれの粒子をどうやって動かせばいいんですか?
そのためには、流体を表現するナビエストークス方程式というのを使います。
SPH向けのナビエストークス方程式はこれです↓

Image may be NSFW.
Clik here to view.
(1) ナビエストークス方程式

「うわ…わけわかんねえ数式出てきた…やばい…こわい…ブラウザ閉じよ…」
まあ大丈夫です。冷静に眺めるとこの方程式の言わんとする事はこういう事です。

Image may be NSFW.
Clik here to view.

つまり、”ある粒子の加速度は、その粒子の位置の圧力項と粘性項と外力(重力とか)を足し合わせたものですよ”と言っているだけにすぎない。

簡単でしょ?

「でもなんか三角形のわけわからん記号∇とか出てるやん、こんなん学校で習ってねえぞ」
∇ってのはナブラって言って、なんかベクトルとかスカラー場に付けると勾配(傾き)を意味する?らしいです。偏微分とかして求めるらしいですが私もよく知りません。その内勉強するかもしれません。まあ今はぶっちゃけどうでもよくないっすか。どうせ実装する時はコードにナブラとか出てこないんで。

離散化

私もナブラとか言われてもよく分からんのと同じように、パソコンだってナブラとか言われてもよく分かりません。
パソコン「数式とかじゃなくてもっとソースコードで説明してくれないと分かんない」
パソコンが喋った

パソコンは数式とか分からないので、パソコンでもわかるように近似的に計算で求められる形に離散化してあげる必要があります。

ところで、一つの水粒子の場所の密度とか圧力って、そこの周りにどんだけ他の粒子が集まってるかで決まりそうですよね。
つまり、近くの粒子同士が影響し合って、かつ粒子同士の距離が近いほど大きな影響を与えることになります。
その事を数式として表現するとこうなります。

Image may be NSFW.
Clik here to view.
(2) 離散化した奴

なんちゃらは”重み関数”と言って、距離が離れるほど影響が小さくなる感じの関数が入ります。距離がhを超えると影響ゼロになるようになってます。

とにかくこれを使って密度やら圧力やらを計算できます。

密度を求める

密度を求めるには、密度ρを上の(2)の方程式のφのとこに突っ込めばOKです。

Image may be NSFW.
Clik here to view.

「Wpoly6って何やねん!?」
これはね、SPHの研究してる人が考えた、「これ使うと密度がそれっぽく求められるよ」っていう重み関数です。具体的には、

Image may be NSFW.
Clik here to view.

こんな感じです。これは3次元の時に上手く動くヤツで、2Dでシミュレートする時はまた別の重み関数を使います。
otherwiseってなんやねん?と言うと、つまり粒子間の距離がhより小さい場合だけ計算すればよくて、hより大きい時は0、つまり無視してくださいという意味です。

数式だとサッパリ意味不明ですが、実際にC#の疑似コードで書くと大して難しくないです。

//粒子
class Particle
{
    public Vector3 position; //座標
    public Vector3 velocity; //速度
    public Vectore force;    //力
    public float   density;  //密度
    public float   pressure; //圧力
}

float h = 0.012; //影響半径
float particleMass = 0.0002f; //粒子の質量
float densityCoef = particleMass * 315f / (64f * Mathf.PI * Mathf.Pow(h,9)); //密度計算で使うヤツ

//粒子の密度計算
void CalcDensity(Particle[] particles)
{
    float h2 = h*h; //事前にhの二乗を計算しておく
    for(int i = 0; i< particles.length; i++) //一つづつ粒子の密度を計算
    {
        var nowParticle = particles[i]; //今回計算する粒子
        float sum = 0; //足し合わせる変数
        for(int j =0; j< particles.length; j++) //他の粒子全てについて
        {
            if(i==j){continue;} //自分自身だったらスキップ
            var nearParticle = particles[j];
            
            var diff = nearParticle.position - nowParticle.position; //粒子距離
            float r2 = Vector3.Dot(diff,diff); //粒子距離の2乗

            //粒子距離がhより小さい場合だけ計算する
            if( r2 < h2 )
            {
                float c = h2 - r2;
                sum += Mathf.Pow(c,3); //(h2-r2)の3乗
            }
        }

        nowParticle.density = sum * densityCoef; //密度が求まった
    }
}

簡単でしょ?
このコードは適当に書きましたが、まあこんな感じで密度が求まります。

圧力

圧力を求めるには、状態方程式というのを使います。

Image may be NSFW.
Clik here to view.
状態方程式

kは圧力を調整するための単なるパラメータです。ρ0は基本密度です。密度が基本密度に戻ろうとする圧力が流体にかかります。

C#の疑似コードで書くとこうです

float pressureStiffness = 200f; //圧力係数
float restDensity = 1000f; //静止密度

//粒子の圧力計算
void CalcPressure( Particle[] particles)
{
    for(int i = 0; i< particles.length; i++) //一つづつ粒子の圧力を計算
    {
        particles[i].pressure = pressureStiffness * ( particles[i].density - restDensity );
    }
}

圧力項

圧力が求まったので、圧力項も密度と同じノリで計算できます。
(1)のナビエストークス方程式の圧力項に(2)を適用するとこうなります。

Image may be NSFW.
Clik here to view.

当然こうでしょ?と思うんですが、実はこれだとダメだそうです。
なんか、これだと”作用反作用の法則”を満たさないから、”対称化”する必要があって、

Image may be NSFW.
Clik here to view.

こっちの式を使えだそうです。私も何のこっちゃ分からなくなってきたのですが、しょうがないので言われるがままに従います

∇Wspikyとかいう重み関数(の勾配)は、

Image may be NSFW.
Clik here to view.

これを使います。今までのノリと同じように計算できると思うので、もうC#コードは載せません。(面倒くさくなってきた
ノリさえ分かってれば、他の人が書いたSPHのコードとか見てもらえば大体意味が分かると思います。

粘性項

粘性項も圧力項と同じ感じで、これも対称化が必要だそうで、対称化した式はこうなります。

Image may be NSFW.
Clik here to view.

∇²Wviscとかいう重み関数(のラプラシアン)は、

Image may be NSFW.
Clik here to view.

こうです。

衝突判定

ここまででいい感じに圧力項とかが求まってきましたが、そういえば、水槽みたいな壁や床を用意してあげないと、このままでは粒子が重力で真っ逆さまに落ちていきますよね。

壁や床との衝突判定には、ペナルティ法という手法が利用できます。
ペナルティ法では壁を突き抜けそうな粒子に跳ね返す力を与えて壁を突き抜けないようにします。

Image may be NSFW.
Clik here to view.

数式だとこんな感じです。
例えば粒子のx,y,z座標がそれぞれ-1~1の範囲に収まるようにするには、左右、上下、奥手前の6回ペナルティ法の計算を行う事になるでしょう。

粒子の座標が求まった!

というわけで、やっと粒子の加速度が計算できます。
ある粒子の加速度aは、

a = 圧力項 + 粘性項 + 衝突判定の力 + 重力

となります。
加速度さえあれば、速度も求められますね。
速度vは、

v = v + deltaTime * a;

速度があれば、座標もわかります。
座標posは、

pos = pos + deltaTime * v;

簡単ですね。
こんな風に普通に加速度から速度、座標を求める方法は、”前進オイラー法”という手法になります。
これは実は精度が低い方法です。普通のゲームの感じで1秒に60回の実行では発散(ぐっちゃぐちゃになる)してしまうかもしれません。もっとタイムステップを小さく刻む必要があるでしょう。

タイムステップ小さくするのも面倒だな~という場合は、前進オイラー法より安定度の高い手法を使う手があります。
例えばリープ・フロッグ法だとこうなります。

pos = pos + v * deltaTime + 0.5 * a * deltaTime * deltaTime;

v = v + 0.5 * ( prev_a + a ) * deltaTime; //prev_aは前回のフレームのaという意味

おわり

以上の説明で、SPHをプログラミングして実行できる知識が身に付きましたね!
「え、マジ?」
まあそこまでは行かなくても、他の人が書いたSPHのソース見てもなんとなく理解できるくらいにはなったかもしれません。

あとは誰かが書いたSPHのプログラムを拾ってきて実行して遊んで改造したりしてみてください。

UnityでSPHやってるソースとかもGitHubとかで見つかると思います。

https://github.com/khskarl/sph-unity

マーチンキューブに向けて

「ところで、SPH法では水の粒々を動かしてるけど、記事の最初の方に出てきた動画では、一塊の水みたいに描画されてるけど、どうやったらただの粒々が水の塊になるんですかね?」

するどい指摘ですね。そうです。その話がしたくて今回の記事を書いたんですが、水の粒々をいい感じに水の塊として描画できるようにするために必要なのが、マーチンキューブなんです!

というわけで、次の記事ではいよいよマーチンキューブについて説明できればいいなと思います。

オマケ:最適化について

記事中のコードでは、何の工夫も無く総当たりで粒子と他の粒子との計算を行ってました。しかし、これでは計算量はO(n²)となってしまい、粒子数が増えるにつれて計算量が爆発的に増えてしまいます。
もっと効率よく計算する最適化の余地がありますね。

例えば、空間全体を縦、横、奥行きがそれぞれh(影響半径)のグリッドで区切って、各タイムステップでの計算の最初に全ての粒子をそれぞれグリッドに割り振ります。

Image may be NSFW.
Clik here to view.

今までの説明で分かっている通り、粒子の計算では、距離がh以上離れている他の粒子からの影響は0なので、無視していいはずです。

Image may be NSFW.
Clik here to view.

このケースでは、計算に必要な他の粒子が存在する可能性があるのは、明らかに計算する粒子の前後左右奥手前の27箇所(3次元の場合)のグリッドのみとなります。
それらのグリッドに所属する粒子とだけ計算を行えばいいので、大幅に計算量を減らせます。

オマケ2:他の最適化について

上のやり方のような手法以外にも、マルチスレッドで並列処理して高速化したり、GPUで計算を行って高速化するアプローチの手法が考えられます。

都合がよい事に、SPHでは粒子の計算がそれぞれ独立して行えるので、メッチャ並列化しやすいです。

SPHをUnityのジョブシステムとバーストコンパイラを用いて並列化する方法について解説してる記事がこちらにあります↓

https://medium.com/@leomontes_60748/how-to-implement-a-fluid-simulation-on-the-cpu-with-unity-ecs-job-system-bf90a0f2724f

Unity Graphics Programming vol.1 という書籍では、コンピュートシェーダを用いてSPHをGPU上で計算する手法についての記事があります。↓

https://indievisuallab.stores.jp/items/59edf11ac8f22c0152002588

サンプルプログラムのリポジトリはこちらです↓

https://github.com/IndieVisualLab/UnityGraphicsProgramming

他にも、GPU上でSPHをやっているリポジトリがあります↓

https://github.com/MangoSister/SPHFluid

参考資料

Unity Graphics Programming vol.1  (書籍)

水の実時間アニメーション (論文)

[CEDEC 2014]剛体から流体まで,セガのプログラマーが語る「位置ベース物理シミュレーション」の最前線 (記事)

Position Based Dynamics Omelette コンピュータグラフィックス関連の最新論文紹介 (上の4Gamerの記事で紹介されてるCEDECの講演。CEDiLにログインすると講演資料がDLできます)

その他参考リンク

https://bigtheta.io/2016/05/23/particle-based-fluid-simulation.html

https://bigtheta.io/2017/07/08/implementing-sph-in-2d.html

http://yuki-koyama.hatenablog.com/entry/2014/05/18/054909

http://yuki-koyama.hatenablog.com/entry/2014/08/17/001312

http://yuki-koyama.hatenablog.com/entry/2015/10/12/181318

【メニーコア時代突入】Ryzen3950Xを買った

家のパソコンのCPUをRyzen3950Xに買い換えました。3950Xは10万円します。
今までは5年以上前に買ったCore i5 4690K(4コア/4スレッド 3.5~3.9GHz)をずっと使ってました。4690Kは当時2万5千円くらいだった気がします。

色々買い換えるハメになった

CPUのメーカーがIntelからAMDに変わり、当然CPUのソケットも変わったので、マザーボードも買い換える必要がありました。

AMDのマザボは最初のZenコアからずっとAM4ソケットが使われてるので昔のマザボでも3950Xは動かせます。最近の奴だと2万円くらいのX570か、1万円くらいのB450の二択です。
X570はPCI-Express 4.0規格に対応しており、B450は対応してないという大きな違いがあります。
現時点ではPCI-Express 4.0に対応してる機器はほとんどありませんが、例えばこちらの記事で紹介されてるSSDは対応しており、リードが5000MB/s、ライトが4400MB/sというヤバいくらいの速度があります。ちなみにPCI-Express 3.0だと速度が3500MB/sで頭打ちになります。

https://akiba-pc.watch.impress.co.jp/docs/sp/1200648.html

せっかくZen2コアのCPUを使うならPCI-Express4.0の爆速SSDを使いたいな(理由は後述)と思い、X570マザボと1TBのPCI-Express4.0対応SSDを買うことにしました。

選んだマザボはASUSのTUF GAMING X570-PLUSというヤツです。パソコン工房の通販で3950Xとセット割引されてたのでこれにしました。ASUS PRIME X570-P/CSMというヤツも選べましたが、正直どっちでもよくて、TUFの方がSATAの数が多いからTUFにした気がします(その分USBが少ないけど)

ちなみに数日前の記事によると、B450とそれより古いマザボはZen3(次のAMDのCPU)への互換性が切られてしまうようです。X570はサポートされます。B450にしないで良かったです。どうしてCPUソケットがAM4のままなのに互換性が切られてしまうの?という疑問がありますが、古いマザボでBIOSアップデートを頑張ってもマザボメーカーは一文も得しないしそれより最新のマザボに買い換えてほしいみたいな事情があるらしいです。

また、B550というマザボも6月に発売されるそうです。これはX570のようにPCIe4.0に対応しており、なおかつB450くらい安いらしく、発売されたらこれが鉄板でしょう。(でもTUF GAMING X570-PLUSは高いだけあってVRM電源回路が14フェーズ(例えばTUF B450-PRO GAMINGは6フェーズ)もあったりするので、やっぱ3950XみたいなハイエンドなCPUを動かすならそれでもX570の方が安牌という説もあるかも)

メモリも今までのPCではDDR3でしたが、このマザボではDDR4しか動作しません。しょうがないのでDDR4のメモリの16GBx2個セットを買いました。1万5千円くらいです。メモリのクロックは3200MHzで、これはZen2CPUのメモリ定格動作周波数の最大値です。メモリクロックなんてPC性能に対して影響あんま無さそうですが、AMDのCPUはIntelよりメモリクロックによる性能への影響が大きいらしいです。そういえばメモリはマザボのスロットに端から詰めて刺そうとしましたが、マザボの説明書に「メモリは一個開けて差さないとデュアルチャンネルが効かないよ」的な事が書かれてたので刺し直しました。そんな細かいルールがあったとは。

Ryzen3950XにはCPUクーラーが付属してません。Ryzenの他のCPUは結構立派なクーラーが付属することに定評がありますが、3950Xともなるとちょっとやそっとのクーラーでは冷やしきれないからという事だそうです。もちろん4690K付属の小さいクーラーを使い回すのも無理です。というか空冷クーラーじゃなくて簡易水冷クーラーという、なんかポンプで水を循環してラジエータで冷やすみたいなゴツイ仕組みのクーラーが公式では推奨されています。しかし、簡易水冷というのは機構が複雑な分だけ値段が高い上に故障率が高く、動作音もうるさいとデメリットが目立ちます。ネットの記事では簡易水冷じゃなくてもハイエンドの空冷なら十分3950Xを冷やせるみたいなことが書かれていたので、一番最強の空冷クーラーと言われているNH-D15を買いました。1万円くらいです。

このCPUクーラーはこのマザボのソケット(AM4)に対応する金具が入ってないので、AM4に対応させるための金具も別途買う必要があります。500円くらいです。

https://www.pc-koubou.jp/products/detail.php?product_id=630142

NH-D15にはCPUグリスが付属していますが、せっかくなので性能の良いグリスにしようと思って、よく知りませんがオーバークロッカーの清水さんモデルとか言うSMZ-01Rを買いました。千円くらいです。

実際のところNH-D15で3950Xを冷やせるのか?という点ですが、今のところ普通に冷やせてます。CPUが全コア100%でぶん回り続けても温度は60度くらいから動きません。Ryzen Masterを見てみると、温度よりも先にEDCの140W制限に引っかかってて、発熱に余裕があってもそれ以上CPUのクロックは上がりません。なのでCPUファンが全力で回ってるような音がした試しがないです。

最低限必要なパーツは揃いましたが、この際PCケースも新しくしようと思ってP110 Silentというヤツを買いました。9千円くらいです。今まで使ってたPCケースは10年以上前のBTOで買ったPCの奴をずっと使い回していて、ファンはケース背面に一個しか付いてなくて、今となってはエアフローに不安を覚えます。新しいケースはファンがいっぱい付けられる奴にしようと思って探しました。P110 Silentはケースの前後に一つずつファンがついていて、別途4つくらい追加で設置可能です。とりあえず以前のケースのファンを奪い取って前面に追加しました。他にP110 Silentを選んだ決め手としては、遮音性能に優れてる(CPUファンがでかいので遮音性がある方が良さそう)のと、ストレージが結構沢山積めるのがメリットです(買い換えるたびにHDDが増えちゃってるのをせっかくなので全部積みたい)。

このケース、結構でかいですが、組んでみると内部スペースが割とスカスカです。こんなに奥行きサイズが必要あるんでしょうか?まあ内部スペースが大きい方が冷却的に有利だったりするのかな…?

それと、NH-D15を使う場合はこのPCケースはオススメできません。CPUファンがでかすぎてサイドパネルが付くか付かないか本当にギリギリでした。NH-D15の高さは165mmで、P110 Silentの対応CPUクーラーは165mmなので、スペック的には大丈夫なはずですが、クーラーの2つ目のファンを付けると位置的にメモリに干渉するので少し上にずらして取り付ける必要があり、高さが上がってしまいます。メモリはプレーンな形でヒートシンクで高さが上がったりしてなかったので本当にギリギリケースに収まりましたが、ちょっとでも特殊な形のメモリだったらアウト(つまり2つ目のCPUファンの設置を諦める)だったと思います。

最近ストレージの容量に不安を覚え始めてたので、この際なので容量のでかいHDD買おうと思いましたが、東芝の8TBのものが売り切れだったので、いっそ東芝10TBのヤツを買いました。2万2千円くらいです。Seagateの8TBのヤツなら1万4千円くらいで安く買えますが、今まで買った内臓HDDの中で唯一Seagateの物だけが故障しているので安いとはいえSeagateは何となく避けてます。こちらの記事でもSeagateの壊れやすさが証明されてます。

https://news.mynavi.jp/article/20150418-a103/

購入までの流れ

4月の頭くらいから、急にPCを新しく刷新したいという考えに囚われ始めて、色々検討を始めました。

最近はIntelよりAMDの方がコスパがいいという話を聞いていたので(主に野生の男さんがtwitterで死ぬほどRyzen推してたのを見て)次はRyzenにしよっかなと思ってました。

最初に狙っていたのはRyzen3700Xです。4万円くらいで8コア16スレッドという、数年前なら考えられない数のコアを積んでいます。しかもこの値段でIntelの上位モデルのCorei9-9900Kに匹敵する性能らしいのでコスパ最強でしょう。

しかし、ちょうどその時Amazonのタイムセールで3700Xが格安で売っていた事をタイムセールが終わった後に知りました。これが悔しすぎて、3700Xを買う意欲が減退しました。じゃあどうせなら安売りされてなかった3900X(12コア24スレッド 6万円くらい)にしちゃおうかな!でも3700XがTDP65Wで済んでしまっていたのに比べて3900Xは105Wに増えてしまいます。じゃあどうせなら3950Xも105Wだしそっちにした方がワッパ高くてエコなのでは?という勢いで4/17に3950X購入に踏み切り注文しました。

あと政府のコロナ支援で全国民に10万円配布されると発表され、じゃあ3950Xは実質タダじゃんと思って購入が後押しされました。

まああれやこれやと買ってたら結局20万円くらいかかっちゃったんですけど。

平常ならアキバのツクモとかドスパラに行ったりしてあれこれ現物を見てから何を買うか決めるところですが、外出自粛の風潮だったので全てを通販で買うことにしました。

何をどこでどう買えば一番オトクかはかなり頭を捻りました。例えばドスパラやパソコンSHOPアークのサイトでクレカで買えばキャッシュレス5%還元が受けられます。パソコン工房では受けられません。たかが5%とは言え、購入額が20万ともなると還元額は1万円にも達します。還元はなくてもパソコン工房は品揃えに優れてますし、2万円以上のPCパーツを買うと10%ポイント還元キャンペーンもやっていました。

さらに色々調べてみると、Paypayモールで購入すれば何を買っても10%還元が受けられるし、パソコン工房もPaypayモールに出店しているので、じゃあ全部Paypayモールで買えばいいじゃんと気付きました。ただし、ややこしいのですがPaypayモールの10%還元は1か月間に1万円が上限だったりします。あとパソコン工房はなにげに自社通販サイトよりPaypayモールでの商品価格を上げてたりするのでそこは駆け引きがあります。

エクセルで色々計算した結果、還元の上限1万円分まではPaypayモールのパソコン工房で買って、残りはパソコン工房通販サイトで買って10%還元を受けるのが一番オトクと判断して、そういう感じで買いました。

どうしてパソコン工房で統一して買い揃えたのかというと、PCを組んでみたけど何だか分からんけど動作しない。みたいなトラブルが起きた場合に、パソコン工房のようなPCショップならパーツ一式送り返して動作確認してもらうみたいなサポートが受けられるらしいからです。Amazonで購入するとこういうサポートは受けられないでしょう。

ちなみに3月までならPaypayモールは20%還元だったらしいので、還元額が10%に減ってしまった4月は正直時期は良くなかったかもしれませんが、終わってしまっていたものはしょうがないです。

今、3950Xを買うという選択

今まで5年間も4690Kを使っていた私ですが、当時Coreiシリーズは登場して以来、ハイエンドのi7でも4コア8スレッドで周波数も代り映えしない状況が続いていました。

2010年に発売されたi7-880は4コア8スレッドの3.06~3.73GHzで、2017年のi7-7700Kでもいまだに4コア8スレッドで4.2~4.5GHzで、このような微妙な進化速度では大して買い換えたい意欲も湧きません。

まあ、当時はソフトウェアもマルチスレッド対応されてないものが多かったので、これ以上のスレッド数は必要なかったという事もあるかもしれません。私も4コア4スレッドの4690Kで特に不便を感じない時代が続いていました。

そういう状況だった2017年にやってきたのがAMDのRyzenです。いきなりRyzen1700(329ドル)は8コア16スレッドが搭載されていました!ハイエンドのThreadripper1950X(999ドル)に至っては16コア32スレッド搭載です。

コンシューマ向けに限らなければ当時すでにIntelもコアをたくさん積んだワークステーション向けプロセッサがありました。例えばXeon W-2175は14コア/28スレッドで1947ドルでした。1950Xの登場で同じくらいのコア数が半額で使えるようになりました。

2017年の年末、IntelのCore i7-8700Kが登場し、今までずっとi7は4コア8スレッドだったのが、6コア12スレッドになりました。

翌年の2018年、Ryzenは、2700はスペックアップしつつ1700と比べて30ドル安い299ドルで登場。16コアのThreadripper2950Xは1950Xから100ドル安くなって899ドルで登場。最上位の2990WX(1799ドル)に至っては32コア64スレッドをあっけなく達成してしまいました。

2018年には、Intelの第9世代が登場。i7-9700Kは8コア8スレッドです。i7のさらに上位のi9-9900Kも登場しました。8コア16スレッドです。さらなる上位のi9-9980XEは18コア36スレッドを達成しており、価格は1999ドルです。i9-9960Xは16コア32スレッドで1699ドル。

そして来る2019年に登場した第3世代Ryzenでは、今までハイエンドのThreadripperにラインナップされていた16コアCPUがコンシューマ向けのRyzen3950Xとして登場しました。価格も2950Xから150ドル安くなって749ドル。TDPが180Wから105Wに大きく下がってる所も注目点です。最上位の3990Xに至っては64コア128スレッドという化け物レベルの領域に突入してしまっています。価格も3990ドルで化け物級です。

2020年に登場した第10世代i7-10700Kは8コア16スレッド、i9-10900Kは10コア20スレッドです。18コア36スレッドのi9-10980XEは、前世代の9980XEに比べて半額の1000ドルで発売されたのが衝撃的です。

5年位前の停滞感のある状況に比べると、ここ数年はかなりドラマティックな展開を見せているCPU業界。Ryzenのコスパの高さに刺激されてIntelのCPUも劇的に値下げされてます。16コアのRyzen3950Xは749ドルで買えるし、18コアのi9-10980XEは1000ドルです。数年前なら2000ドルくらいしたクラスのものが今は半額以下になってます。今は結構時期がいいんではないでしょうか。Ryzenの値下がりも一服した感じで、むしろ値上げしてる傾向もある(例えば32コアのThreadripper2990WXは1799ドルだったのが3970Xで1999ドルに値上がった)ので、この先はしばらく大きな値下がりは起きないかもしれません。

Ryzen3950Xはちょうど3700Xの2倍のスペックくらいの感じで、値段も3700Xの2倍にちょっと色を付けたくらいの感じです。CPUは2倍の値段で2倍の性能が得られるのが凄いですね。この前ホームセンターで千円くらいの包丁を買いましたが、それまで使っていたダイソーの100円の包丁の10倍の性能は得られなさそうです。

3950X以前の16コアCPUは、コンシューマ向けではなかったので値段の高い特殊なマザボが必要でしたが、3950Xは普通のコンシューマ向けのAM4ソケットで動かせます。TDPも105Wで普通のCPUレベルなので、電気代もヤバくはなく、発熱も空冷クーラーで冷やせるレベルです。3950Xの登場で16コアCPUが何の苦労もなく使えるレベルまで簡単に使えるようになったという事です。(価格はコンシューマ向けというにはまだ高いけど)

PC組み立て

PCの組み立てについては取り立てて書くことはありません。普通に組み立てたら普通に動いたので良かったです。

アホみたいにでかい箱がいくつも届いたので開封して組み立てるのが億劫な気分でしたが、早いとこ組み立てて全部のパーツが動作する確認しないと初期不良の対応してくれるのは購入後2週間までとかですからね。

しいて言えば、やっぱりNH-D15がクソデカすぎだと思いました。これを付けるとグラボが外せなくなります。グラボの端子のロックのところにまったく手が届かなくなるからです。ググったらみんなこれには困ってるみたいで。金属製の定規を隙間から差し込んでロックを外したりしてるみたいです。ヤバいですね。あと取り付け時に相当ドライバーに力入れて押し込まないと取り付けねじが回らないので大変でした。

そういえば、今回買い足したパーツはCPUとマザボとメモリとCPUファンとNVMeSSDと増設HDDとPCケースです。ほとんどパソコン一式買い直してますが、電源とグラボと既存のSATASSDとかHDDは流用してます。電源は玄人志向の600Wのやつで、グラボはGTX1080です。

電源といえば、マザボの補助電源のピンは8ピンと4ピンのソケットが一つずつあって、説明書には両方刺すのが推奨と書かれてました。それに対して電源から出てる補助電源のピンは4ピンが2つでした。これどうすればいいの?と悩みましたが、ググってみると4ピンが2つの場合は両方刺せば8ピンとして使えるそうなので、8ピンだけ刺しました。よっぽどじゃない限り8ピンだけでもとりあえず大丈夫らしいです。

組み立て中はなんやかんやCPUファンのヒートシンクとかで指をちょっと切ったりしました。PC組み立てって結構力仕事というか、疲れますよね。ケースが重すぎるし。昼から初めて夜中には一応起動するくらいまで持っていけた感じでした。

正直BTOでRyzen3950X搭載PC買っても20万円くらいだしそれ買った方が簡単だったんじゃないの?って気もしますが、グラボはまだ現役だから買い換えるのもったいないしバラ売りパーツで買ってしまいました。

今までのPCバラシて新しいPC組むのも今のタイミングはリスキーだなと感じました。ちょうど会社の仕事がリモートワークに切り替わったところで、仕事で使うPCをバラしちゃって、新しいPCで初期不良が出て交換対応とかなっちゃったらその間仕事どうすんの?っていう。一応サブのノートPCがあるので最悪そっちを使えばいいんですが。

新しいNVMeSSDをシステムドライブとして使いたかったので、事前にEaseUS PartitionMasterというソフトで以前のシステムドライブのSATASSDからクローンして、ブートできることを確認しておきました。

クローンしたおかげでそのまま新PCに作業環境を引き継げましたが、Windows10が未認証の状態になってしまいました。どうやらPCのパーツ構成が大幅に変わると、別PCにコピーされたとみなされて認証が切れてしまうらしいです。たしかにほとんど別PCになってしまってるのでそれはそう。でもあくまで環境を移行しただけで、不正にコピーとかしてるわけじゃないし、Windows10Proを買い直すのは痛いので、どうにかなるもんならしてほしい。と思ってマイクロソフトサポートに電話してみました。色々あって認証を通してもらえました。良かったですが、3時間くらい通話してましたよ。3時間携帯電話で通話したら料金いくらですか?1分で40円として3時間で7200円。ヤバい。今確認したらマイクロソフトサポートの電話番号はフリーダイヤルだったのでセーフです。どうでもいい話ですがサポート中にサポートの女性が私のPCをリモート操作する必要がありました。私のPCのデスクトップは画像フォルダからランダムに画像がコラージュされて壁紙になる仕組みになっていて、なんかちょっとエッチなイラストとかも表示されてます。これをマイクロソフトのサポートの女性に見られてしまうのか…背に腹は代えられないのでやってもらいましたが、お互い特にその事には触れませんでした。

このタイミングで買う理由

正直言って発売から5カ月経ったCPUを買うのって微妙な気もします。あと半年くらいすればもっといいRyzen4950Xが発売するのは分かりきってますからね。

それでも半年待てずに4月に買ってしまったのは、ちょうどリモートワークが始まったので、家で仕事としてPCを駆使するこの時期にハイスペック化しちゃう方がアドバンテージがあると考えました。結局緊急事態宣言は延長されて5月一杯はリモートワークが続くわけです。さらなる延長の可能性もありますから、PCスペックアップした事による進捗アップの効果は大きそう。

なんかみんな同じことを考えているのか、リモートワーク需要で微妙にPCパーツの品薄感が出始めている時期でした。私は滑り込みで間に合った感じでしたが、現在Amazonとかを見ると結構品切れしてます。紙の書籍とかも売り切れ続出してるらしく、それというのも流通がパンク気味らしく、不要不急な商品よりも生活必需品の入荷が優先されているらしいので、その事も関係してるかもしれません。

あとRyzen3950Xは発売当時(2019/11/30発売)に買おうとしても売り切れててなかなか買えなかったらしいですね。

vTuberたちのPCスペックに負けたくない気持ち

vTuberの人達は普通につよつよPC使ってます。

https://wikiwiki.jp/nijisanji/%E3%83%A1%E3%83%B3%E3%83%90%E3%83%BC%E3%83%87%E3%83%BC%E3%82%BF%E4%B8%80%E8%A6%A7/PC%E3%82%B9%E3%83%9A%E3%83%83%E3%82%AF

なんでこんなハイスペックが必要なのか?というと、まず普通にゲーム実況するのでゲーミングのスペックが要求されますし、さらにvTuberはゲームしながらゲーム画面をキャプチャして配信しつつ、表情認識してアバターを表示するソフトウェアとかも同時に動かす必要があります。とにかくマルチタスクが必要なので、メニーコアのつよつよPCがほぼ必須となります。

そんなvTuberの方々に対抗するには3950Xの投入はやむを得ない。

ちなみに桜凛月さんという方は3950XとRTX2080Tiを積んでます。

負けた。

16コアも実際必要あるの?

私も最近までは4コア4スレッドの4690Kで特に不便を感じることはありませんでした。

そもそも最近は重いタスクはGPUにやってもらう流れですよね。ディープラーニングや仮想通貨のマイニングなんかもGPUで行います。

でもGPUに移植しずらいタスクもありますから、そういうものはCPUで実行せざるを得ません。Unreal Engine 4でアセットが初めて表示される時にシェーダのコンパイルが走りますが、重いシーンを開こうとすると何千や何万ものシェーダコンパイルが走ってしまい、今までのPCだとコンパイルに一晩かかってしまうというレベルでした。しかし3950Xだと数分で終わってしまいました。それはさすがに盛りすぎやろと思うかもしれませんが、私が一番驚愕しました。こちらの記事ではi7-4790とRyzen3900Xでシェーダコンパイル時間を比較しています。

http://historia.co.jp/archives/13261/

37分かかっていたコンパイル時間が1分に短縮されています。圧倒的な差です。普通に考えるとコア数が3倍になるんだからコンパイル時間もせいぜい33%になるのではって感じですが、実際は30倍もの差が付いてしまう場合もあるという事です。さすがにこれだけ違うなら16コアに移行するメリットはあると言えます。

UnityはUnreal Engine 4に比べるとメニーコアのメリットは薄い(コンパイルやビルドはシングルスレッドで行われる)ですが、それでもアセットインポート時に部分的にマルチコアが使われたり微妙にメリットはあります。あとC#7.2やJobsystemによって並列処理が書きやすくなったので、Unityアプリから簡単にメニーコアをしばけるようになりました。

他にもマルチコアに対応したソフトウェアは以前より充実してきているので、メニーコアのメリットを実感する機会は増えてきています。

ちなみに今までのPCで一番不満だったところは、ブラウザのtweetdeckでカラムを増やし過ぎててツイート読み込み時に頻繁に画面が固まるところですが、これは3950Xにしても特に改善しませんでした。CPUマターじゃなかったんだね。

PCIe4.0のSSDが必要な理由

HDDからSATASSDに交換するとかなりPCが快適になるという話がありますね。HDDの読み取り速度は大体200MB/sで、SATASSDは500MB/Sで2.5倍も違うので体感速度も違うはずです。

しかし、SATASSDをNVMeSSDに交換してももはや大して差を実感できないという話もあります。NVMeSSDは速度2500MB/sくらいありますからSATASSDの5倍も違いますが、すでに十分早かったのでそれがさらに何倍も速くなっても知覚できないという事でしょうか。

ましてやPCIe4.0対応SSDで速度5000MB/sになったところでだからどうしたという話かもしれません。

ちなみにPCのメインメモリの転送速度は、DDR4-3200で25GB/sほどです。PCIe4.0SSDの速度はメインメモリの20%ほどに達してるという点に注目です。

という事は、PCIe4.0SSDを仮想メモリとして割り当てれば、事実上ちょっと遅いメモリが数百GB使い放題になるという事ですよね。

例えばUnreal Engine 4でちょっと重い処理、具体例を挙げると巨大な3Dモデルに対して「アクタのマージ」を実行すると、CPUの全てのコアを長時間ぶん回すのに加えてメモリも200GBくらい使用します。当然物理メモリがいくらあったところで足りないので仮想メモリを使用することになります。頻繁にスワップが行われるので、ストレージ速度が処理速度に直結する状況です。

こういう状況が今後結構起きそうだなと見越して、SSDを容量が巨大なメモリであると見立ててPCIe4.0SSDを買いました。

大メニーコア時代に突入

Intelが長い間core i7を4コア8スレッドで据え置いてた事で、CPUはみんなある意味平等な時代が続いていましたが、AMDがRyzenを投入して1700でさえ8コア16スレッドで、最上位Threadripperは16コア32スレッドが登場して状況は一変しました。

第2世代Ryzenでは32コア64スレッドの2990WXが、第3世代では64コア128スレッドの3990Xが登場してしまいました。

RyzenはCPUの設計上、いくらでもコア数を増やせるという話をどっかで見た気がします。現実に、世代が増えるごとに最大コア数が倍増しています。ただし、単純にコア数の分だけCPUを並べているのでコア数に比例して値段も上がるようです。このまま行くと次の第4世代では128コアCPUが登場してしまう可能性もなくはないです。(そこまでのコア数にニーズがあればの話ですが)

つまり、世の中は急激に大メニーコア時代に突入しつつあるという事です。

今まではみんな平等にi7の4コア8スレッドで作業していたのが、大メニーコア時代では4コアしか使えない人もいる一方で、128コアを駆使できる人もいる状態になります。CPUコア格差社会です。メニーコアに最適化されたタスクでは、同じタスクをこなしててもパフォーマンスが32倍も違ってくることになりますよね。

何かで言ってる人を見たんですが、これからの時代は、優秀な人ほど計算資源を沢山使える時代だそうですよ。

例えば、優秀な会社員は出世すると部下が増えて、部下に仕事をさせる事で自分のパフォーマンスをエンパワーさせていると言えます。

一人の人間が発揮できるパフォーマンスには限界があります。例えば荷物を運搬する仕事で一人でどれだけ睡眠時間とか削って頑張ってもたかが知れています。だから他の人に手伝ってもらう事でエンパワーします。

ですがこれからの時代は一人の人間でも沢山の計算資源にアクセスすることでエンパワーできる時代です。例えばAIの研究者とかは、研究予算をぶち込んでAWSで沢山のサーバぶん回してAIの学習を沢山やればやるほど成果が出せるという面もありそうです。

優秀な人ほど潤沢な予算を獲得して大量の計算資源にアクセスできるし、逆に大量の計算資源にアクセスできるほどパフォーマンスが上がるとも言えるかもしれません。

ディープラーニングでイラストを生成させる研究とかもありますが、一人の人間がどれだけ頑張っても描けるイラストの数には限界がありますが、AIに書かせれば計算資源さえ投入すれば1日で千枚描けたりといった事も可能になるかもしれません。

ある人が手作業で1年間かけてやっている作業を、別のある人はサーバのインスタンスぶん回して一日で終えてしまうかもしれない。計算資源次第では、一人の人間が発揮できるパフォーマンスが300倍も違ってきてしまうかもしれない時代というわけです。

Googleマップで建物を3D表示させる機能がありますが、あの沢山の3Dモデルは昔はユーザーに手作業で作らせていましたが、最近はAIが自動生成しているらしいです。計算資源を大量に持ってるGoogleだからこそできる事ですね。計算資源を持ってるだけならレンタルサーバの会社とかだって沢山サーバ持ってるのに何でGoogleみたいな事ができないのか?という疑問がありますが、サーバだけ沢山持っててもしょうがないかもしれないですね。処理するためのデータも必要です。Googleで言えば、Googleは衛星写真のデータを死ぬほど持ってるから、それをAIに食わせて処理させたわけです。レンタルサーバの会社はデータを持ってないからAIにさせる仕事がないわけですね。

じゃあ個人だってメニーコアCPUあっても処理するデータが無いじゃんと思うかもしれませんが、例えば静岡県は誰でも無料でアクセスできる大量の点群データを公開しています。静岡県の点群データを公開するからこれ使って何か面白い事やってくださいというわけです。15TBものデータが誰かに処理してもらうのを眠って待っています。

これから先、静岡県に倣っていろんなデータを公開する自治体が増えるかもしれません。兵庫県も県内の1m解像度メッシュデータを公開しています。つまり、個人がアクセスできるデータは今後どんどん増える見込みなのです。点群処理なんかはマルチコアが得意な処理なので、コア数が多ければ多いほど速く処理できます。こうなってくるとCPUコア数の格差がそのまま発揮できるパフォーマンスの格差に直結してきます。

私は今は静岡県の点群をUnityで表示する事を目論んでいます。日本の風景を表示したい場合に、自分でイチから建物やら何やら一つずつ3Dモデリングするよりも点群データをそのまま表示する方が圧倒的に手が抜け…生産性が上がりますよね。そういう作業をする時にはCPUのコア数がそのままパフォーマンスに直結します。

そういうメニーコア時代に突入しつつある今、メニーコアを活用する機会は広がりつつあります。みなさんも新時代に備えてメニーコアCPUの購入を検討してみてはいかがでしょうか。


UE4のアセットをUnityにエクスポートする方法

Epicは、UE4のマーケットプレイスの有料アセットを毎月月替わりでいくつかチョイスして無料配布しています。

2020年5月の今月の無料アセットはこちら

Drivable Cars Basic Pack: 3D assets +

↑かっこいい車のアセット。6476円→無料

Materialize VFX

↑なんかエフェクトのアセット。2354円→無料

Modern City Downtown with Interiors Megapack (Urban Building / Buildings)

↑まるごと一つの街のステージ!17666円→無料

Sci Fi Robot

↑ロボットのアセット。1411円→無料

The Targeting System

↑照準システム。1293円→無料

合計27907円の5つのアセットが無料です!これはゲットするしかない!
特にModern City Downtown with Interiors Megapackがオススメ中のオススメ。普段なら17666円するのに無料!公園やビル、地下鉄の階段を下りれたりハンバーガーショップの中に入れたり、マケプレのアセットの中でもトップクラスにすごいアセットです。今月中に絶対手に入れよう!

ちなみに5/21までEpic GamesであのGTAVも無料配布されてます。Epicのアカウントを持ってるとUE4無料アセット以外にも、無料配布のゲームを大量に入手できます。私ももらいすぎてまったく遊びきれてません。(よく思うんだけど、遊びきれないほどゲームがタダでもらえる時代に自分が作ったゲームを遊んでもらうのって大変だよね)

話が逸れましたが、UE4ユーザーの方はもちろん、今はUE4さわってなくても将来的に触るかもしれない方にも是非毎月の無料アセットをゲットしてもらいたい。
将来UE4やUE5(基本的にUE4と互換あるらしい)を触る時に、アセットを全然持ってない状態で始めるのと、数十万円分のハイクオリティなアセットを入手済みの状態で始めるのとでは、ドラクエで言えばゲーム開始時に装備してるのが、「ひのきのぼう」と「はじゃのつるぎ」くらいの格差がありそうです。

「オレはUnity一筋だからUE4のアセットなんて関係ないね」なんて思ってるUnityユーザーのあなたにも是非手に入れてもらいたい。
何故なら、UE4アセットの3DモデルはUnityに持っていける(場合がある)からです。

UE4マケプレの利用規約でも、マケプレのアセットはUE4以外(例えばUnity)で使用しても基本OKみたいな事が書かれています。(ただしEpic公式アセットは基本UE以外で使うのはNG)
ちなみに逆にUnityアセットストアのアセットをUnity以外で使うのも最近OKになりました。

つまり、UE4アセットの3Dモデルは実質Unityアセットとして使えるということです。

この記事ではその方法を紹介します。

シンプルな例

とりあえずUE4を開いて先ほどの街のアセットをDLしてインポートしてみます。

UE4のアセットをUnityに持っていくといっても、エクスプローラで見ると、UE4では3Dモデルもテクスチャもuassetという謎のファイル形式になってるのでそのままではUnityで開けません(親切なアセットはFBXファイルも同梱してくれてたりするらしいです)

Image may be NSFW.
Clik here to view.

例えばこのハンバーガーの看板をUnityに持っていきたいとします。

Image may be NSFW.
Clik here to view.

看板のアセットを選択して、詳細タブ→Static Meshの虫眼鏡アイコンを押して、コンテンツブラウザ上の元アセットを見つけます。

Image may be NSFW.
Clik here to view.

元アセットを右クリックして、アセットアクション→エクスポートを選ぶと、指定した場所にFBXファイルとして保存できます。簡単ですね。
直接Unityプロジェクトのアセットフォルダの中にエクスポートすれば手っ取り早いです。

これでFBXはエクスポートできましたが、マテリアルはエクスポートされない事に注意してください。UE4では複雑なノードで作られたマテリアルが作れますが、FBXファイルには複雑なマテリアルは互換性が無いためにそのような仕様になってるようです。

Image may be NSFW.
Clik here to view.

今回のアセットのマテリアルを確認すると、単に各テクスチャを出力に突っ込むだけのシンプルな作りだとわかります。

Image may be NSFW.
Clik here to view.

マテリアルはUnityで再設定するとして、次はテクスチャをUnityにエクスポートします。
詳細のMaterialsのテクスチャボタンを押して、コンテンツブラウザ上のテクスチャを探します。

Image may be NSFW.
Clik here to view.

マテリアルに設定されてた4枚のテクスチャを選んで右クリック→アセットアクション→エクスポートを選択して、各テクスチャの保存場所(FBXファイルと同じ場所)を指定します。

必要なものはエクスポート完了したので、Unityエディタを開きます。

さっきエクスポートしたFBXファイルがインポートされてるので、とりあえずMaterials→LocationでUse Embedded MaterialsになってるのをUse External Materialsに変更してマテリアルを編集可能にします。

Image may be NSFW.
Clik here to view.

マテリアルにアルベド、ノーマルマップ、エミッションマップを設定します。赤いテクスチャは使い道がわからなかったのでとりあえず放置します。

Image may be NSFW.
Clik here to view.

FBXのオブジェクトをシーンに配置すれば、ちゃんとハンバーガーショップの看板をUE4からUnityに持ってくる事ができました。

一つや二つのアセットならこの手順で十分ですが、全部のアセットをUnityに持っていきたいとなるとなかなか手間です。

UE4エディタの操作はPythonを書く事で自動化できるらしいです。ここでは手順は説明できませんが、自動化すれば全てを一括自動エクスポートさせる事も可能かもしれません。

ややこしい例

上の例ではシンプルなアセットを選びましたが、もっとややこしいアセットだと上の方法では難しくなります。

例えば、アセットが複数のマテリアルを使ってる場合や、沢山のオブジェクトに分かれているアセットの場合や、一番問題なのが、複雑なノードで組まれたマテリアルの場合です。複雑なマテリアルは単にUnityでテクスチャを割り当てるだけでは再現できません。

こういうややこしいケースの場合もUE4は対応可能です。

例えばこのビル一つを丸ごとエクスポートする事を考えてみます。

Image may be NSFW.
Clik here to view.

すっごい大量のオブジェクトに分かれてるし、マテリアルも沢山持ってるし、マテリアルのノードもさっきより複雑です。
さっきの方法でやろうとしたら地獄を見そうです。

このヤバい状況をなんとかするのが「アクタのマージ」機能です。
これはUnityで言えばMesh Bakerというアセットのような機能で、複数のオブジェクトを一つにマージしてくれて、マテリアルもマージしてくれるし、テクスチャもベイクしてくれます。すごい!

Image may be NSFW.
Clik here to view.

マージしたいオブジェクトをすべて選択した状態で、ウインドウ→デベロッパーツール→アクタをマージを選択します。

Image may be NSFW.
Clik here to view.
Image may be NSFW.
Clik here to view.

「アクタのマージ」の設定画面が開きます。

とりあえずLOD選択タイプを「Use specific LOD level」に変更し、特定のLODを0に設定。
マテリアルのマージにチェックを入れ、テクスチャサイズを設定します。今回は4096にしました。ターゲットライトマップ解像度もテクスチャサイズと同じサイズを設定してください。
とりあえず今回は法線マップとスペキュラマップを出力しようかなという感じでそれらのチェックをオンにします。(ほかに欲しいテクスチャがあればそれも選択する)
メッシュライトマップUVの再使用という項目については、これはオンの場合とオフの場合を両方試してもらえばわかりやすいんですが、オンだと元のUVを再使用する感じになって、オフだと新たに自動UV展開される感じになります。結果が良い方を使うといいと思います。今回はオンにしました。

Image may be NSFW.
Clik here to view.

「アクタのマージ」を実行すると、ちょっと処理に時間がかかりますが、完了するとコンテンツブラウザにマージされたFBXやテクスチャが出てきます。

あとはこれらを先ほどと同じようにUnityにエクスポートすればOKです。

Image may be NSFW.
Clik here to view.

ジャーン!

あんなにややこしかったUE4のアセットを簡単にUnityに持ち込めました。ちなみにスペキュラマップは結局単なるグレーだったので出力する意味が無かったのでアルベドとノーマルマップだけ設定してます。

こんな風にUE4のアセットをUnityに持ち込んで使える事が分かったので、ぜひUnityユーザーもUE4のアセットを積極的にゲットしましょう!

今回紹介した方法が100%うまく行くわけでは無いことに気を付けてください。何らかの原因でアクタのマージが失敗したり、表示がおかしくなったりするケースもあります。その場合は…残念ですがあきらめましょう!

さらに、今回のアセットは多分大丈夫ですが、メチャメチャでかいデータに対してアクタのマージをするとメッチャメモリ消費してUE4が落ちる事がありました。この場合、PCの仮想メモリをあらかじめ大量に割り当てておいたら成功するケースもありました。(200GBくらい仮想メモリ食ってました)

そのような注意点もありますが、UE4のアセットをUnityでも使いたい!という方は是非チャレンジしてみてください。

【禁断のテクニック】UE4のレベルを丸ごとBlenderとUnityに持っていく

先日書いたこちらの記事ですが、

UE4のアセットをUnityにエクスポートする方法

UE4の大量のアセットを一つずつUnityにエクスポートするのは手間だという問題がありました。
色々試したところ、UE4のレベル(Unityで言えばシーン)を丸ごとUnityに持っていく方法を発見しました!

大量のアセットを一括でUnityに送りたい場合はかなり手間が減らせると思います!さらに、この方法では途中でBlenderを経由させるので、ついでにUE4のレベルをBlenderに持っていく方法もわかります。
さっそくその方法を紹介します。

1.UE4上での手順

とりあえずサンプルとして、UE4ユーザーにはおなじみの、StarterContent→Maps→Minimal_Defaultレベルを開いてみます。

Image may be NSFW.
Clik here to view.

メニューからファイル→「すべてエクスポート」を選択します。すべてじゃなくて一部のオブジェクトのみをエクスポートしたい場合は、必要なオブジェクトを選択した状態で「選択されたものをエクスポート」を選択します。

Image may be NSFW.
Clik here to view.

保存するフォルダの選択ダイアログが出るので、保存場所を指定してください。前回と違って、Unityのアセットフォルダ以外の適当な場所を指定してください。ファイルフォーマットは.objにしてください。

Image may be NSFW.
Clik here to view.

↑このようなダイアログが出るので、「はい」を選んでください。
前回の方法だと手作業でテクスチャをエクスポートしましたが、今回の方法では必要なテクスチャを自動で全てエクスポートしてくれます。ラクチンだ!

2.エクスプローラでの手順

エクスポートが完了したらエクスプローラで出力されたフォルダを見てみましょう。

Image may be NSFW.
Clik here to view.

こんな感じで、objファイル、mtlファイル、Gameフォルダができてます。
objファイルの中にレベルからエクスポートされたアセットが全部入ってます。
mtlファイルがありますが、前回の方法と違って、この中にアセットのマテリアル情報がちゃんとエクスポートされてます。
Gameフォルダは中を見てもらえばわかりますが、テクスチャが入ってます。色んなフォルダに散らばって入ってます。

ここで残念なお知らせですが、Gameフォルダ以下の色んなフォルダに散らばってるテクスチャ画像をobjファイルと同じ階層に移動させる必要があります。すごい面倒くさそうですね。

そこで、エクスプローラの右上にある検索機能を使います。エクスポートされたテクスチャは全てbmp形式なので、”bmp”という単語で検索すれば、色んな場所に散らばったテクスチャが全て表示されます。これらをすべて選択して、「切り取り」してobjファイルがあるフォルダに「貼り付け」すればOKです。

Image may be NSFW.
Clik here to view.

3.Blenderでの手順

次はobjファイルをBlenderにインポートします。「なんでobjをそのままUnityにインポートしないの?」というと、Unityは何故か分かりませんがUE4からエクスポートしたobjのmtlファイルを読み込んでくれないので一旦Blenderを経由します。

Image may be NSFW.
Clik here to view.

Blenderに最初からデフォルトでいるCamera、Cube、Lightはいらんので削除します。

Image may be NSFW.
Clik here to view.

ファイル→インポート→Wavefront(.obj)を選択します。

Image may be NSFW.
Clik here to view.

ファイル選択ダイアログが出るので、さっきのobjファイルを選択します。この時、ダイアログの右側にインポート設定画面があるので、「Split by Object」と「Split by Group」にチェックを入れてください。「OBJをインポート」ボタンを押すとインポートされます。

Image may be NSFW.
Clik here to view.

おお、UE4のレベルがBlenderで読み込めました!
テクスチャが表示されない!という人は、3Dビューのシェーディングモードがマテリアルプレビューモードになってることを確認してください。(上の画像の一番右上のやつ)

おおむねちゃんと読み込まれてますが、この時点で失われてるマテリアルもありそうです。例えば椅子の下の床は真っ白になっちゃってます。
UE4からのエクスポート時に割とテクスチャのベイクとかはしてくれるみたいですが、複雑なマテリアルだとうまく行かなかったりするのかもしれません。確実に成功させる方法はまだ分かりませんが、「アクタのマージ」とかしておいた方が成功しやすかったりするかも?

うまく行ってない箇所はあとで手作業で調整してください。

次に、Blenderからglbファイルをエクスポートします。ファイル→エクスポート→glTF 2.0(.glb/.gltf)を選択します。

Image may be NSFW.
Clik here to view.

ファイル保存ダイアログが表示されるので、適当な場所を選んでください。ダイアログ右側の保存オプションで、フォーマットはglTFバイナリを選択。すべてエクスポートしたいので「選択したオブジェクト」のチェックは外してください。エクスポートボタンを押すと保存されます。

glbファイルが出力されますが、この一つのファイルの中にテクスチャとかも全部入ってます。

4.Unityでの手順

ようやくUnityにたどり着きました。Unityエディタを開きましょう。

UnityでglTFファイルを開くには、UniVRMの中に入ってるUniGLTFが必要です。

https://github.com/vrm-c/UniVRM/releases

↑こちらのページから最新版のUniVRMパッケージをダウンロードしてUnityにインポートしてください。

完了したら、blenderから出力したglbファイルをUnityに放り込みます。

インポートされてできたプレハブをシーンに放り込んでみます。

Image may be NSFW.
Clik here to view.

やったぜ。

なんも手作業しなくてもマテリアルが維持できている事に感動しますね。
BlenderからFBXを出力してUnityに持っていくとテクスチャ参照がはがれちゃったりしますが、gltf形式だとそのまま持っていけます。(テクスチャ参照してるだけのシンプルなPBRマテリアルの場合です。複雑なノードのマテリアルだと無理でしょう)

とは言え、Blenderの時からさらに失われてしまってる部分もありますね。テーブルの上の置物が真っ黒になってしまってます。他はおおむね大丈夫そうですが、ダメになっているところは手作業で調整が必要ですね。

結果から言うと、必ずしも100%完璧ではないですが、UE4のレベルを丸ごと一発でUnityまで持ってくることに見事成功しました。

一つずつ手作業でエクスポートしなくて済むので絶対便利ですね。

いくつか注意点がありますが、まず何故かUE4からのエクスポート時にテクスチャが全てbmp形式にされちゃうので、元のテクスチャのアルファ値が失われてそうな気がします。
また、UE4上ではインスタンスとして配置されていたオブジェクトが、エクスポートするとイチイチ別のオブジェクトとして書き出される点に注意してください。今回の例では二つの椅子が別のオブジェクトにされちゃってそれぞれ別々にメッシュが出力されちゃってます。という事は同じ木を100本生やすとメッシュのデータが100倍に増えます。

その辺に気を付けつつ、是非みなさんも今回のテクニックを使ってUE4のオブジェクトをじゃんじゃんUnityに持って行って使い倒しましょう!

UE4のDatasmithでV-Ray for 3ds Max向けの3Dモデルをインポート

UE4の「無料3種の神器」をご存じですか?

1.毎月の月替わり無料アセット

2.Megascans使い放題

3.Datasmith(Unreal Studio)

この3つです。これらのおかげでUE4は1円もお金払わないで爆アドが得られます。多分合計で100万円分くらいアド取れてるんじゃないかな。

1の無料アセットで、毎月数万円分の有料アセットがタダでもらえます。

2のMegascansで、1万以上の高品質なフォトグラメトリアセットが全て無料で使えます。

3のDatasmithはピンと来ないかもしれませんが、これも最強クラスにすごいです。
Datasmithを使うと、CADソフトや3ds Max、Cinema 4D、Sketch upなどのファイルをそのままUE4にインポートできちゃいます。

https://docs.unrealengine.com/ja/Engine/Content/Importing/Datasmith/SupportedSoftwareAndFileTypes/index.html

↑Datasmithで対応してるファイル形式はこちらに一覧されています。

「別にDatasmithとか無くても、FBXファイルに変換すれば何だってインポートできるじゃん?」と思うかもしれませんが、FBXファイルでは元のソフトウェア上のマテリアルをあんまり再現できない事が問題になります。これだと、UE4にインポートした後にマテリアルをアレコレ再調整し直しになって、相当な手間がかかります。

それより何より大きい問題は、例えば3ds MaxとSketch UpとAutoCADのファイルが手元にあって、これをFBXにエクスポートしたいとします。そしたらあなたはこれら全部のソフトを購入した上に使い方を覚えないといけないですよね?それは大変すぎるでしょう?

企業でも、手元にCADデータはいっぱいあるけど、これをUE4でビジュアライゼーションしたくてもCADソフトの使い方が分かんない。みたいなケースもよくありそうです。

そういう問題を解決してくれるのがDatasmithです。

ただし、Datasmithでは元ファイルを直接UE4で読み込める場合と、元ファイル用のソフトにエクスポートプラグインを入れて、udatasmithファイルに変換する必要がある場合の2パターンがあります。
3ds Maxは後者のケースなので、結局3ds Maxのアプリケーションは必要になってしまいます。

Datasmithはかなり神です。これが無料で使い放題ってのは本来ありえません。本来は月額49ドルのサブスクで提供されるはずだったのが、いつの間にか無料になってました。やばい。

個人レベルでDatasmithとか必要なの?

個人レベルでも便利です。

考えてみていただきたいんですが、UnityやUE4を使ってて、例えば日本の街の3Dモデルが欲しいなあと思ったとします。
そしたらアセットストアやマーケットプレイスを探しますよね?それでも見つからなかったらどうしますか?

それなら他のサイトで探すことになりますよね。この時、大抵の3Dモデルはそのままではゲームエンジンで読み込めない、プリレンダー用のモデルなんですよね。
特に3ds Maxのv-Ray向けのモデルが多いです。これが業界のデファクトスタンダードなのでしょうか。

せっかく目的の3Dモデルを見つけても、それが3ds Max向けのモデルだったら、ゲームエンジン向けに変換するのが厄介な作業なので、諦めてしまうかもしれません。でも、Datasmithを使えば諦めずに済みます!

ちなみに、過去の記事でも紹介しましたが、DatasmithでUE4に読み込めるという事はUnityにも持っていける事を意味します。

UE4のアセットをUnityにエクスポートする方法

【禁断のテクニック】UE4のレベルを丸ごとBlenderとUnityに持っていく

UnityユーザーもDatasmithで爆アド!

実際に試してみる

実際にDatasmithを使ってV-Ray for 3ds Max向けのモデルをUE4に読み込んでみましょう。

とりあえず3ds Maxのインストールが必要です。無料で一カ月間体験できます。それ以降は有料サブスクリプションになります。

さらに、3ds Maxに”V-Ray for 3ds Max”プラグインもインストールする必要があります。

https://www.chaosgroup.com/vray/3ds-max

この”V-Ray for 3ds Max”も一カ月間無料体験ができて、それ以降は有料です。年間470ドルします。めっちゃ高いですが、実はDatasmithを使うだけなら期限が切れた体験版のままでOKです。期限が切れるとV-Rayでのレンダリングができなくなるだけで、V-Rayマテリアルは普通に読み込めるからです。

“V-Ray for 3ds Max”プラグインをインストールしたら、3ds Max用Datasmithエクスポータプラグインもインストールします。これは無料。

https://docs.unrealengine.com/ja/Engine/Content/Importing/Datasmith/SoftwareInteropGuides/3dsMax/InstallingExporterPlugin/index.html

ここまで完了したら、インポートしたい3Dモデルを用意します。例として、こちらの無料のおもちゃの3Dモデルをダウンロードしてみます。

Image may be NSFW.
Clik here to view.

3ds Maxを起動して、ダウンロードしたファイルの中のToys.maxを開いてみると、上の画像みたいな感じになってます。

3ds Maxの使い方なにも知らんので、視点の回転方法とかさえよくわかりませんが、Datasmithを使うだけなら何も知らなくて大丈夫です。

Image may be NSFW.
Clik here to view.

ファイル→書き出し→書き出しを選択すると、保存場所選択ダイアログが出ます。ファイル形式は「Unreal Datasmith」を選んで、適当な場所に保存してください。3ds Max上での作業はこれだけで終わりです。

UE4を起動してください。

Image may be NSFW.
Clik here to view.
Image may be NSFW.
Clik here to view.

編集→プラグインを選んで、Datasmith Importerを探して、Enabledにチェックを入れてください。UE4の再起動を要求されるので、再起動してください。

Image may be NSFW.
Clik here to view.

なんかここの所にDatasmithという項目ができてるので、クリックすると、インポートするdatasmithファイルを選択するダイアログが表示されるので、さっき3ds Maxで保存したudatasmithファイルを選択します。

Image may be NSFW.
Clik here to view.

うわ、読み込まれたけど画面が真っ白です。

Image may be NSFW.
Clik here to view.

画面が真っ白なのは3ds Maxのファイルの中のライトがまぶしすぎるせいなので、一旦それらを非表示にします。

Image may be NSFW.
Clik here to view.

おもちゃ達が表示されました!やった!

ただし、例によって完全再現はできてないようです。積み木が黒地になってしまってるものがありますね。(本来は木目)

多少調整は必要そうですが、一発で3ds Maxのデータをそのままインポートできましたね。

ちなみに3ds Max上ではこんな風にすごいややこしいマテリアルが組まれていました。

Image may be NSFW.
Clik here to view.

これをDatasmithはどういう風に変換してくれたのかというと、

Image may be NSFW.
Clik here to view.

こんな風にゴリッゴリにブループリントに変換してくれてます。本来なら手作業で苦労してやんなきゃいけなかったマテリアル変換作業、Datasmithのおかげで一発自動変換です。ありがてえ。

「もっとシンプルなマテリアルにしてほしい」という場合は、この後”マテリアルのマージ”とかでマテリアルを単純化できます。

3ds Max→udatasmith変換の自動化

大量に3ds Maxのファイルが手元にある場合、一つ一つudatasmithに変換するのも面倒です。

3ds Maxではmax scriptというスクリプト言語を使って処理を自動化できます。

というわけで、指定したフォルダ内の3ds maxファイルを順番に読み込んでudatasmithファイルに保存するmax scriptを用意しました。

https://gist.github.com/umiyuki/9a5ff7098a02db73e9f7c87a10cec103

使い方を紹介します。とりあえず上のリンクからスクリプトの内容をコピーしてテキストエディタに貼り付けてください。
そしてスクリプトの6行目のファイルパスの所を、自分のPCの変換したいmaxファイルが詰め込まれてるフォルダに書き換えます。
そうしたらexportdatasmith.msという名前で適当な場所に保存してください。

次に、3ds Maxを開いてスクリプト→スクリプトを起動を選択して、保存したexportdatasmith.msを選択します。

Image may be NSFW.
Clik here to view.

あとは自動で処理してくれます。フォルダ内のmaxファイルが一つずつ読み込まれ、同じフォルダにudatasmithファイルとして保存されます。

便利!

UE4での自動化は?

ここまで来たらUE4でudatasmithを読み込んでUnity用にFBXファイルとしてエクスポートする作業とかも自動化したいですよね?

ですが、残念ながらまだそこは手を付けられてません。もし誰か作ったらやり方教えてください。

とりあえず今は参考になりそうなリンクを貼るだけにとどめます。

https://forums.unrealengine.com/unreal-engine/unreal-studio/1525119-batch-translate-solidworks-headlessly-via-python

今、Unityでネットワークマルチプレイ作るのに何を使えばいいのか

前置き

Unityエンジニアは最近、圧を受けている人が多いと思います。

近頃はバトルロイヤルゲームが流行ってますが、100人マルチプレイを実現しているPUBGFortniteUE4製ですから、会社の偉い人が「こういうの作れないの?」と仰っても、「UE4じゃないとUnityじゃこういうの無理ですよ」と言って誤魔化せていました。

そんな中、Unityで作られた60人マルチプレイのFallGuysが登場してしまいました。こうなるとUnityエンジニアは会社の偉い人から「Unityでもこういうの作れるやんけ!」と詰められてしまいますが、返す言葉もないといったところでしょう。

Unityテクノロジーズもブログ記事とかで「Unityでもこんなすごいネットマルチプレイゲームが作れます!」と積極的に喧伝してます。

Fall Guys が試練を乗り越えて、グローバルに展開できた理由

正直言ってUnityテクノロジーズのこういう態度を見てるとイライラさせられます。「UnityでFallGuysみたいなゲームが作れるよ!」という割には、UnityはFallGuysのような多人数マルチプレイネットワークが作れる基盤を提供してません

Unityが現在提供してるネットワーク機能はUNetですが、Unityは2018年8月にUNetの段階的廃止を発表しました。ハッキリ言ってUNetは失敗でした。現在は事実上放棄されています。以下の記事ではUNetのサポートは2018.4LTSで2年間提供されると書かれていますが、今は2020年11月ですからUNetは完全に終了しています。

UNet を乗り越え、マルチプレイヤーゲームはさらなる進化へ

さて、この記事では「UNetが廃止される代わりに、次世代ネットワーク機能がすぐに提供されます」という興味深い事が書かれています。次世代ネットワーク機能とは”Unity NetCode“の事を指してると思われますが、この記事が書かれてから2年、NetCodeは全然できてません。”すぐに”って何年後までが”すぐ”なんだよ。

つまるところ、Unityは現在利用可能なネットワーク基盤を何も提供していません。ですのでFallGuysも何らかの独自またはサードパーティのネットワーク基盤を利用してると思います。(具体的に何のネットワークライブラリを使ってるかの情報はありません)Unityは「FallGuysはUnity製!」なんて偉そうに宣伝する資格はありませんよ。それで偉い人に詰められて困るのは我々のような末端のUnityエンジニアです。

例えるなら、自動車会社が売ってもいない車のCMを打ってるようなものじゃないですか?それでお客様から問い詰められて困るのはディーラーです。

まあそれはいいとして、実際Unityには「マルチプレイゲーム作るのにUNetは廃止だしUnityNetCodeはまだできてない!一体どうすりゃいいんじゃ!」という問い合わせが殺到しているようで、(そりゃそうだ)Unityから問い合わせに答える記事が出ています。

Unity のマルチプレイヤー Netcode の移行ガイド

Image may be NSFW.
Clik here to view.

この記事内のチャートを要約すると、「①チートとか遅延が気にならないならUNet+P2P使えば?②そうじゃなければ専用ゲームサーバーが必要。2021年Q2以降ならNetCodeがあるけど間に合わないなら自前で頑張れ。」という感じです。ひでえなあ。

「自前で頑張れ」と言われてもネットワーク基盤を自前でイチから作るのは無理があります。現実的にはサードパーティのネットワークライブラリを使う形になるでしょう。

この記事はいくつかのネットワークライブラリの概観を見て、今Unityでネットワークマルチプレイゲームを作るなら何を選ぶべきか検討してみたいと思います。

UnityのNetworkView(廃止済み)

せっかくなので最初にUnityが提供していて今は廃止されたNetworkViewというネットワーク機能についても書いてみます。

GameObjectにNetworkViewというコンポーネントを貼り付けるだけでネットワークで同期できる、手軽で便利な機能でした。

プレイヤー間の接続は素のP2Pです。プレイヤーの誰か一人がホストになって、他のプレイヤーがゲストとしてそこに接続します。NATを越えるためには基本的にホストはポート開放設定をしておく必要がありました。ホストのAさんとゲストのBさんが一緒に遊ぼうと思ったら、AさんはBさんにLINEなどで事前にグローバルIPと解放したポート番号を伝えないといけないという、プレイヤーとしてはかなり不便な状態でした。

この不便な状況を改善するために、Unityからマスターサーバーというものが提供されていました。自前のサーバー(開発中はUnity公式ホストされたマスターサーバーをデフォルトで利用できた)でマスターサーバーをホストしておけば、ホストのプレイヤーはマルチプレイの部屋を建てた事をマスターサーバーに登録できるようになります。ゲストプレイヤーは今ゲーム内で建ってる部屋の一覧を検索、参加出来て、わざわざゲーム外で連絡しあわなくても簡単にマルチプレイできるようになりました。

マスターサーバーにはもう一つの重要な機能、NATパンチスルーがありました。NATパンチスルーでNAT越えすれば、わざわざポート開放設定を行わなくてもマルチプレイのホストになれました。ただしNATパンチスルーはルータの相性などによっては失敗します。適当ですが7割くらいの環境で成功する感じでしょうか。NAT越えできない人はポート開放するかホストになるのは諦めてゲストで我慢する感じです。

Photon Cloud

Unityのネットワークは元々NetworkViewしかありませんでしたが、いくらNATパンチスルーで7割くらい接続できるようになったとは言え、3割も接続できないというのは問題っちゃ問題です。

ネット対戦がオマケ機能だった頃と違って、ネットワークマルチ前提のゲームでは100%接続できないと話になりません。

そんな中、たしか2013年ごろに登場したのがPhoton Cloudです。
リレーサーバのホスティングとネットワークライブラリが一体になったサービスです。無料プランでは20人まで同時接続できます。

サーバを使ってるといっても、サーバで何か計算処理を行ってるわけではありません。リレーサーバは通信を中継するだけで、誰かが送ったメッセージを他のプレイヤーに送るだけです。WebRTCで言うところのTURNサーバみたいなもんです。なのでネットワーク機能としてはP2Pと変わりません。プレイヤーの誰かが自動的にマスタープレイヤー(ホスト)となります。

リレーサーバを経由すると通信が遠回りになるのでP2Pに比べて遅延が悪化さえします。じゃあ何でP2Pじゃなくてリレーサーバを使うのか?というと、NATパンチスルーだと接続確率は7割程度だったのが、リレーサーバだとほぼ100%接続できるというメリットがあります。

ほぼ確実に接続できるのは大きなメリットですが、同接プレイヤーが増えると利用料金がどんどん高くなるという問題があります。

もう一つのデメリットは、どれだけ高いプランでも、部屋当たりの秒間メッセージ数は500に制限されているという問題があります。もし部屋にプレイヤーが10人いた場合、誰かが1回メッセージを送るごとに9人に送られるので、9メッセージ数を消費します。秒間500メッセージというのは厳しい制限です。
この制限により、実質的にPhotonCloudでのマルチプレイ人数は4~8人くらいで頭打ちになります。

また、サーバー側の処理が書けないので、チート対策などができません。

PhotonはPhoton Cloudとは別にPhoton Serverというものもあります。これは自前でサーバーをホストする必要がありますが、秒間メッセージ制限はなくなりますし、サーバー側の処理も書けます。

ちなみにPhoton CloudはUnityから以下の記事で採点されてます。

自分のゲームに適したネットコードを選ぼう

Photon PUN Unity評価
安定性 ★★★★
使いやすさ ★★★★★
パフォーマンス ★★★
スケーラビリティ ★
機能性 ★★★★

スケーラビリティが最低評価です。やはり秒間メッセージ制限による人数の頭打ちが大きな問題のようですね。使いやすさは星5ですね。たしかにPhotonCloudは簡単に使えます。

モノビットクラウド

モノビットクラウドは使ったことは無いのですが、izmさんの記事が参考になりました。

モノビットエンジンについて調べてみたので書く

要するに、機能的にも価格的にもほとんどPhotonCloudと同様のサービスという事みたいです。

PhotonCloudに比べてのメリットは、秒間メッセージの制限が無い事です。これにより、数人の接続で頭打ちにはならなくなります。

懸念としては、海外リージョンのサーバがどれくらい充実してるか分からないので世界向けのサービスに向かないかもしれないとの事。

とにかく、NetworkViewで確実に接続できないという問題はPhotonCloudのようなリレーサーバで解決しましたし、その次にPhotonCloudでの問題だった秒間メッセージ制限もモノビットクラウドで解消しました。20人くらいでマルチプレイするならモノビットクラウドを使えば問題無さそうな雰囲気です。

UNet(ほぼ廃止済み)

Unityのブログ記事にはこのような記述があります。

ピアツーピア(P2P)トポロジーでは一度に 24 人を超えるプレイヤーを同期しようとすると問題が生じることが多いため、25 人以上のプレイヤーに対応するセッションに関しては、専用ゲームサーバー(DGS)トポロジーへの移行が推奨されます。

https://blogs.unity3d.com/jp/2019/06/13/navigating-unitys-multiplayer-netcode-transition/

PhotonCloudやモノビットクラウドのような、P2P+リレーサーバの構成では、マルチプレイ人数が25人を超えてくると仕組み的にもはや無理があるという事です。

何故なら、ゲームプレイの快適さはホストのPCスペック次第だからです。下手するとホストはスマホだったりするわけで、何十人分もの処理をこなすのは無理が出てきます。

また、クライアントで全てを処理してしまうので、チートし放題という問題もあります。

Unityブログ記事では、問題の多いP2Pから専用ゲームサーバー構成に移行しようと書かれています。

というわけで悪名高いUNetの話です。

UNetはNetworkViewの置き換えとして登場しました。NetworkViewはホストモードとゲストモードの2つのモードで動作してたのに対して、UNetはサーバーモードというのが用意されました。

以前からあったホストモードはサーバ処理しつつも自分もプレイヤーとして参加するモードでしたが、新しいサーバーモードはサーバ処理だけでプレイヤーとしては参加しません。
そんなもん何に使うのか?というと、つまり自前で用意したサーバに、UNetのゲームを入れてサーバーモードで起動して放置しておけば、いつでも誰でもそのサーバにアクセスして遊べるという事になります。

要するにこれが専用ゲームサーバー構成です。マイクラのサーバとかに似てます。

しかし、普通に考えてUnity製ゲームをそのままサーバに置いて起動するなんて馬鹿げた話です。Windowsサーバなんて高いし、GPUが入ってないとUnityゲームは起動できません。

そこでUnityはLinux向けにもビルドできるようにして、ヘッドレスモードでゲームをビルドできる機能も用意しました。UNetサーバーは誰もプレイしないので画面が出るだけ無駄です。ヘッドレスモードだと画面無しでUnityアプリが起動できるので、GPUを持たないサーバでも起動できます。

これで普通のEC2インスタンスなどでもUnityの専用ゲームサーバをホストできるようになりました。

UNetはNetworkViewの時みたいなマスターサーバーは提供されませんでした。今さら3割くらいは接続失敗しちゃうNATパンチスルーなんか使ってもしゃーないからです。

代わりにUNetではPhotonCloudみたいにリレーサーバをホストするサービスが用意されました。しかしこのサービスはかなり遅延に問題があるようです。

専用ゲームサーバ構成を実現したのは画期的ですが、UNetはとにかく問題だらけで将来性も薄いって事で廃止が決定されたので今UNetを使うのはやめた方がいいでしょう。

MLAPI

UNetの代替として頭角を現し始めてるのがMLAPIです。

Unityテクノロジーズの社員の人がほぼ一人で開発してるようです。多分仕事としてやってるんじゃないでしょうか。

かなりパフォーマンスをチューニングしたことで、専用ゲームサーバ構成で最大64人までのマルチプレイが実現できるとの事。FallGuysが60人だから、説明が本当ならいよいよFallGuysを実現できる領域に到達した事になります。

MLAPIと同じようなネットワークライブラリにMirrorというものがありますが、Unityの比較記事ではMLAPIの方がパフォーマンス評価が上回っており、Unityが一番推薦してるのもMLAPIです。

MLAPI用のリレーサーバも用意されてます。GitHubにあるのでこれを自前サーバに置けば、P2P+リレーサーバ構成も実現できます。

ちなみにMLAPIはトランスポート層のコードが何種類か用意されていて、簡単に切り替えられます。デフォルトだとUNetトランスポートが使われていますが、これはUDP通信なので、受信したデータの順番が前後する事があります。順番が前後するとアニメーションの同期が崩れて動きがギクシャクになったりして、「MLAPIってダメダメじゃね?」とか勘違いしてしまいますが、トランスポートを例えばRufflesというものに変えるとReliable UDP通信になってデータの順番も保証されるので問題が起きなくなります。

Photon Quantum

PhotonQuantumはかなり野心的なネットワークサービスのようです。

今まで紹介してきたネットワークサービスでは、基本的な仕組みとしては毎フレーム自キャラの位置を送信して同期するという方法を使ってます。

しかし、よく考えてみると数十人ものプレイヤーキャラを毎フレーム位置を同期するなんて、無駄に通信帯域を消費して、馬鹿げたやり方なのではないでしょうか?

だって、位置なんて同期しなくても、各プレイヤーのコントローラの入力だけ送信すれば、入力が同じなんだから全員の画面が一致するはずじゃないですか?これなら通信量も大幅に減らせます。

一見頭が良さそうなアイデアですが、実はうまく行きません。Unityの物理は入力が同じでも出力が同じとは限らないからです。端末の違い、計算誤差などで段々ズレていってしまい、自分の画面では自分が勝ってるのに、相手の画面では相手が勝ってるなんて事になりかねません。

そこでPhoton Quantumでは独自の決定論的な物理・数学エンジンが用意されてます。どういう意味かというと、このエンジンではどんな環境からでも入力が同じなら出力が一致する事が保証されているという事です。

ですので、先述したような「ネットワークマルチでは入力情報だけを送信し合えばいんじゃね?」論が実現出来ちゃいます。

入力だけを送信し合う事で、チートを抑止する効果もあります。自キャラの座標を改竄したって他のプレイヤー画面では何も起きないからです。

さらに、決定論的ロールバックという機能もあります。普通だとみんなから入力情報が送られてきて出揃うまではシミュレーションのステップを進められませんが、それだと入力が反映されるまでにラグができてしまうので、入力を先読みしてシミュレーションを勝手に進めちゃう事でラグを無くす機能みたいです。

なかなか素晴らしそうなPhoton Quantumですが、Unity標準の物理演算などを全て専用のものに置き換える必要があるので、既存のゲームをネットワーク対応させる時などは作り直しになってしまいそうです。

さらに、どんだけ凄い決定論的ライブラリとは言え、所詮はP2P+リレーサーバ構成なのは変わりません。むしろ各端末がそれぞれ全員分のシミュレーションを実行するハメになるので、負荷が高くてせいぜい32人が限界という感じみたいです。

Unity NetCode

最後に紹介するのが例の、未完成のUnity NetCodeです。

UnityNetCodeの事は、ぶっちゃけよく分かってません。何と言ってもまだできてないので。
しかし、色々と断片的な情報があります。
まず最初に分かってるのは、UnityNetCodeはDOTSしかサポートしてないという事です。DOTSによるパフォーマンス向上がUnityNetCodeの肝みたいです。

UnityNetCodeでは、Photon Quantumのような決定論的ロックステップという機能が実装されており、入力だけを送信するだけで同期できるらしいです。

「え、Unityの物理は決定論的じゃないから無理じゃなかったっけ?」という話ですが、実はUnityはUnity Physicsという新しいDOTS専用物理エンジンを準備しており、UnityNetCodeでそれを利用するようです。Unity Physicsは決定論的です。

UnityNetCodeが決定論的なのは素晴らしい事ですが、「え、じゃあUnityNetCodeって今さらP2Pなの?」という疑問が湧いてきます。専用ゲームサーバ構成は用意されないのでしょうか?

Unite Tokyo 2019でのセッション「Unity Connected Gamesの現在と未来」の動画の3:47あたりからその点に触れられています。

つまり、専用ゲームサーバ構成は「用意したいね」くらいの温度感ぽいですね。現状(2019年10月時点)まだ何も着手してないっぽいです。

Unityのブログ記事によると、UnityNetCodeではいわゆる従来のヘッドレスモードビルドによるサーバービルドとは異なるDOTSサーバーランタイムというものが用意されるらしいです。

Image may be NSFW.
Clik here to view.

どうもこの辺から話が怪しくなってきます。そもそも、決定論的ロックステップなら入力だけやり取りすればよかったのに、専用サーバで演算するならサーバからシミュレート結果を返さないといけないから結局全キャラの座標の同期が必要になるのでは?

UnityNetCodeは元々DOTS限定にする事でハイパフォーマンスを実現するという触れ込みでしたが、最近になって従来のGameObjectもサポートするという話が飛び込んできました。

え?そうなるとUnity Physicsによる決定論的なネットワークという話は崩壊するのでは?

GameObjectでもUnity Physicsが使えるという話もあるから行けるのかな?

【Unity】GameObjectでもUnity Physicsを使う

う~ん、ひょっとしてUnityNetCode周りの話って結構迷走してるんじゃないかと不安になりますね。

Unityは「2021年Q2にUnityNetCodeがリリースされるからそれが使えるよ!」とか言ってますが、本当にそうなら今の時点で一般開発者が普通に使えるベータ版くらいのものが出てきてないと間に合うはずなくないですか?

というか、まだDOTSからプレビューが取れてないのにDOTSのNetCodeがリリースされるわけないですよね。

仮に2021年にUnityNetCodeがリリースされたとしても、最初は相当限定的な機能かつ、まだ不安定なものにならざるを得ないのではないでしょうか。しかも、UnityNetCodeの専用ゲームサーバ構成のサポートはまだ影も形も存在しない状態です。

つまるところ、UnityNetCodeが本当に普通に使えるようになるのは早くても2022年、いや2023年、下手すると2025年とかになってしまう可能性も普通に想像できます。

まあ、今はMLAPIかな…

私も仕事で選定する必要があったので色々とUnityのネットワークサービスを調べてみましたが、結論としてはとりあえず数年間はMLAPI使っとけばいいかな…という気分になりました。

Unite Tokyo 2019の「Unityだったら簡単!マルチプレイ用ゲームサーバ開発 ~実践編~」というセッションではUnityでのマルチプレイの問題が色々と語られていますが、結局この話で採用されてるのは何なのかハッキリ書かれてはいませんが多分MLAPIの事なんじゃないかなと思います。全部MLAPIにある機能についてだし。

ところで専用ゲームサーバってどうやってホストすればいいの?

PhotonCloudなどはクラウドなので何も考えなくて済みますが、UNetやMLAPIでヘッドレスモードでビルドしたサーバービルドは自前でホストしないといけません。

自前でホストするって言っても、どうしよう?
じゃあ、EC2インスタンスを10個建てて、そこにサーバービルドを置いて10個の部屋として運用しましょうか?
でも、全部の部屋が埋まって、もっと沢山のプレイヤーが押し寄せたらどうしよう?どうやってスケーリングさせればいいんだ?

実のところ、それを解決するサービスが存在します。

例えば、AWSのGameLiftです。
GameLiftを使ってサーバービルドをアップロードしておけば、プレイヤーが接続してきた時に空いてる部屋(サーバ)を案内したり、部屋が埋まってたら自動的にEC2インスタンスを生やして新しい部屋を建ててくれます。

上述したセッションでもサーバーのホストにはGameLiftを採用したそうです。

GameLift以外にも、PlayfabやGoogleにも同じようなサービスがありますし、Unityが買収したMultiplayerというサービスも同じ感じです。

ちなみに、FallGuysはサーバーホスティングにMultiplayerを使ってるらしいです。

Mediatonic のハチャメチャなマルチプレイヤーゲームで Unity が大人数プレイをサポート

これらのサービスを使えば専用ゲームサーバをいい感じにホストしてくれるというわけです。

ちなみにGameLiftとか使うとバリバリにAWS課金されまくります。本記事ではゲーム会社が自社開発したネットゲームのサーバを用意する的なユースケースで話を進めてますが、個人制作者が自作ゲームでGameLiftとか使うのはちょっと手に負えなさそうな気がします。

まとめ

Unityでのネットワークサービスの歴史と現状について、色々なサービスを紹介して概観してみました。

Unity公式のネットワークはちょうど今空白期間に突入しており、今「FallGuysみたいなゲーム作って」と言われたらとりあえずMLAPI使うしか無いんじゃないかという結論に至りました。

専用ゲームサーバはGameLiftのようなサービスでホスティングすれば良さそうという事も分かりました。

今後の展望についてですが、今私は実際に仕事でMLAPIで作ったサーバをGameLiftでホスティングしようとしてます。MLAPIは簡単に使えるんですが、GameLiftは結構厄介なうえにネット上にあまり情報がありません。(個人で使うようなサービスじゃないから仕方ない)

今からGameLift使おうとしてる人とかに需要があるかもしれないので、GameLiftを使う上でつまづいた話とかの記事を書こうかなという感じです。

MLAPIがUnity公式ネットワークソリューションに採用された!!

ビッグなニュースです。

前に書いた記事で、「Fall Guysみたいなゲーム作るならとりあえず今はMLAPI使っとけば良さそう」と結論付けた、そのMLAPIが、なんとUnityの公式ネットワークソリューションに採用された事が本日発表されました!

Accelerating Unity’s new GameObjects multiplayer networking framework

要するに、MLAPIはUnityに買収されたという事でしょう。

前回の記事で、「Unity NetCodeはDOTSだけじゃなくGameObjectにも対応するらしい?」と書きましたが、あれは正確にはこの事だったようです。

つまり、DOTS向けにはUnity NetCode、従来のGameObject向けにはMLAPIを使ってね。という二段構えの構成です。

この事は結構前から噂になってたらしく、私も数日前にはすでに情報をキャッチしていました。(たまたま見かけたフォーラムで書いてた)

噂というかそもそもMLAPIの作者がディスコード内で普通に言ってたみたいだから全然秘密とかでは無かったようです。

私はこの情報を知った時、まんまとUnityに嵌められた!と思いました。

私の前回の記事は、Unityのブログ記事の内容を鵜呑みにして書いてしまいました。Unityが一番推薦してるMLAPIを実際自分も採用する事にしましたし。

自分のゲームに適したネットコードを選ぼう

それは、Unityのブログが利害関係の無い他社のネットワークソリューションを公平に比較した記事だと思っていたからです。

しかし、時系列としては、7月時点でMLAPI作者はUnityに雇用されており、Unityブログ記事が出たのが9月ですから、Unityは完全に利害関係の真っ只中にいた事になります。自社の製品になったMLAPIにユーザーを誘導するために、PhotonCloudやMirrorをサゲて、MLAPIを不自然にアゲた提灯ブログを書いた。そういう絵図に違いないだろと思ってしまいますね。

とは言え、冷静に考えてみれば、UnityがわざわざMLAPIを買収するのは、MLAPIが”非常に優れているから”である事は間違いないでしょうし、多少嵌められたとはいえ、今MLAPIを使うという選択は正しかったことが裏付けられたとも言えるでしょう。

それで、ユーザーにとって何が嬉しいの?

ユーザーにとってはMLAPIが公式採用された事にはメリットしかありません

これまでMLAPIはほぼ一人で開発されてたようですが、当然メンバーは増えて開発は加速しますし、サポートも段違いに厚くなるでしょう。

イマイチ足りてなかったドキュメントサンプルも充実するでしょう。

今までは個人のOSSプロジェクトだったので、いつサポート終了してもおかしくありませんでしたが、Unity公式になれば、今後何年も安心して使用する事が出来ます。

一番喜ばしい事は、昨日まではUnityのネットワークソリューションは完全に宙に浮いた状態で、Unityユーザーは何を使えばいいのかサーパリわからなくて混乱状態だった(だから前回みたいな記事も書くハメになった)のが、たった一晩で埋められて解決した事です。

これからは、とりあえずMLAPI使っとけばOK。という事になりました。今までが異常だっただけですが、とにかく安心です。

引っかかる点もあるが

そもそもUnity NetCodeがなんでDOTSしか対応してねえんだよ!という疑問はユーザーの間で湧いていたわけですが、Unityは「DOTSが最高にすげえから。Unityの未来はコレ一択だから!」みたいな説明をしていました。

それが何で急にGameObject用のMLAPIを買収してサポートする事にしたわけ?

もしかするとUnityはDOTSに対してちょっと日和り始めてる気持ちがあるのかもしれませんね。そんな憶測をしてしまう理由は、DOTSがいつまで経ってもマトモにゲーム作れるレベルの機能が揃わないからです。もしかすると、Unity社内でもDOTSで書ける人が少なくて、手が足りないのかもしれませんね。

フォーラムでは、「UnityはIPOが終わったから今まで株価を吊り上げるために色々と話を盛ってたのを、修正し始めるかもしれない。DOTSもじきに撤回されるかも」なんて言ってる人もいました。まあそれは冗談でしょうが。

Image may be NSFW.
Clik here to view.

↑これは英語のUnityブログ記事にGoogle翻訳をかけただけなので、正確なニュアンスではないかもしれませんが、かなりUnity NetCodeについてトーンダウンしてる感じがお分かりいただけるでしょうか。

元々は

「DOTS最高!だからNetCodeもDOTS専用だぞ!Unityの未来に付いてこい!付いてこれないヤツはUNetに置いてけぼりやぞ!」

ぐらいのイケイケなトーンだったのが、

「従来のGameObjectでMLAPIが使えるよ。どうしても好みの問題とか、よっぽどパフォーマンス厨な人はまあUnity NetCodeを使う事も可能っちゃ可能だよ」

くらいまでトーンが落ちてる気がしますねえ。これは…

あと、MLAPIの発表記事について、昨日の深夜時点ではリポジトリのライセンスが「MITからApatch2.0に移行する」と書かれていましたが、今記事を見ると「MITのままです」って書き換えられていました。

Unity、そういうのこっそり書き換えるなよ。

今すぐMLAPIに飛びついていいの?

今すぐ使うネットワークソリューションを決めないといけない!という人は、とりあえず今のMLAPI使ってみていいんじゃないでしょうか。

ただし、Unityの記事によると、MLAPIは今のままだと都合の悪い箇所がいくつかあるので、今後数カ月かけて大改造が行われるという事が書かれています。

Unityブログに書かれてた今後の改造ポイント
1.トランスポート層にUnityご自慢の新しいTransportパッケージ(パフォーマンスが優れてる)が使えるようにする
2.RPCの改善
3.スナップショット生成機能(サーバー側で毎フレームゲーム全体の状態のスナップショットを生成、保持する事でデルタ圧縮やクライアントの未来予測機能が実装しやすくなる)
4.ネットワーク関連性モデル(よく分からんが、クライアントからはコントローラ入力だけを送信すれば済むようにするという意味っぽい)

つまり、破壊的変更が入るという事です。バージョンアップで互換性が失われ、メソッドやら使い方やらが変わってしまうかもしれません。

ですので待てるなら数カ月待ってから使い始める方が安牌かもしれませんね。その頃にはドキュメントやらも整備されてるでしょう。

続・Unityでのネットワークマルチプレイの話

[2020/12/06] MLAPIのSteamトランスポートが普通に存在した件を追記

前々回に書いた記事で、UnityでFall Guysみたいなゲームを作るなら、どのネットワークソリューションを使えばいいのか?という話をしました。

今、Unityでネットワークマルチプレイ作るのに何を使えばいいのか

この記事では、まず現在Unityの公式ネットワークソリューションが存在せず、宙に浮いていてユーザーが大困惑させられている事を問題視しました。

が、

その数日後に突如としてMLAPIが公式になったので、たちどころに問題は解決しました。

MLAPIがUnity公式ネットワークソリューションに採用された!!

それから、Unityで使えるネットワークソリューションを概観してみましたが、それは図らずも、ソリューションの進歩とそれに伴うネットワーク構成の変遷の歴史を追いかけるものになっていました。

つまり、最初は素のP2Pだったネットワークが、マスターサーバーが使われるようになり、リレーサーバが使われるようになり、最近では専用ゲームサーバ構成に移行する流れになっているというストーリーです。

記事は思ったより反響をいただきました。例えば「サーバーを自前で実装する選択肢は?」みたいな反応もありました。

というわけで、今回の記事では前回頂いた反応などに基づいて、補足するような内容を書いてみたいと思います。

自分でサーバー実装するって選択肢は?

たしかに、既存のネットワークソリューションを使わなくても、自分でサーバーのコード書くという選択肢はあると思います。リアルタイム性を考えるとnode.js+Websocketなどの構成が有力でしょうか。

私は前回の記事で、「Fall Guysみたいなゲームを作る」という要件で頭が一杯だったので、自作サーバ実装については考えてませんでした。

「Fall Guysみたいなゲーム」とは、具体的にはどういう要件か?と考えると、まず真っ先に①”60人の多人数マルチプレイ”が挙がりますが、もう一つ、②”相互作用する物理演算”の楽しさも重要な要素です。

①”60人マルチプレイ”だけなら自作サーバ実装で実現可能かもしれませんが、②”相互作用する物理演算”は自作サーバ実装では難しいです。

Fall Guysでは巨大なボールをサッカーみたいに相手側のゴールに入れ合う競技があります。自分もボールを押すし、反対側からは相手もボールを押すというようなシチュエーションはまさに物理演算の相互作用です。

サーバーあるいはホストが代表としてゲーム全体の物理演算を行ってくれれば、”一貫した物理演算”が実現できるので、問題は起きませんが、プレイヤーがそれぞれローカルで物理演算した結果を押し付け合えば、コンフリクトを起こしてボールの挙動がグチャグチャに破綻するハメになります。

ですので、ゲームの要件に”一貫した物理演算”が必要なら、自作サーバ実装だと難しそうですし、そうでないなら自作サーバ実装も選択肢に入ってくると思います。

Unityでの自作サーバ実装事例

例えば、凹さんが作ったUnityでWebsocketサーバを使ってUnityのオブジェクトを同期するシステムの事例があります。

Unity WebGL x WebSocket で複数クライアント間の大量のオブジェクトを簡単に同期できる仕組みを作ってみた

このシステムでは30~40人のマルチプレイで動作したそうです。

しかしやはり、”一貫した物理演算”は提供されていません。各プレイヤーがそれぞれローカルで動かしたプレイヤーキャラの座標を送信、同期する仕組みです。

各自のローカルで動かしているので、入力が即時反映されるというメリットがあります。”一貫した物理演算”では入力をサーバに送って演算結果をもらってようやく入力が反映するので、ラグが発生する問題があります。

他の事例で言えば、白猫プロジェクトのマルチプレイでもWebsocketサーバが使われています。

白猫プロジェクトの裏側! ~パフォーマンスチューニングとリアルタイム通信のすべて~

白猫のマルチにはホスト、ゲストの概念があり、ホストで一括して処理をしてゲストは同期だけする仕組みのようです。

このように、クライアントをホストとして扱う仕組みを用意すれば、自作のWebSocketサーバでも”一貫した物理演算”を実現する事は可能でしょう。

しかし、どうせホストを立ててそこでまとめて処理するならP2P+リレーサーバの構成でもいいんじゃないのって気がします。

TCPはUDPより遅い

ちなみにWebSocketではTCPプロトコルで通信が行われますが、TCPはUDPより遅いです。そもそもパケットが相手に到達するまでの遅延がUDPの2倍くらいかかるようです。

ネットワーク ゲームにおけるTCPとUDPの使い分け

遅延を小さくしたいゲームではTCPよりUDPを使いたいという事になりそうです。

Unity Physicsを自作サーバ実装で使う?

「Unityのヘッドレスビルドを自前でホストしてサーバとして使うなんて馬鹿げてる!」みたいな論調も見かけました。

まあその気持ちは分かります。試算した事は無いですが、Unityの専用サーバ構成でゲーム運営したら恐ろしいくらいサーバ代がかかるのは目に見えてます。

Fall GuysはSteamで2千円くらいで売ってるので、全てのプレイヤーが前払いしてる(PSPlusで無料で配られてたけど)わけですから、そこからサーバー費は捻出できるでしょう。FortNiteなどは基本無料で遊ばれまくられてしまって、採算がとれているというのが不思議なくらいですね。

「Unity Physicsを自作サーバ実装に乗っければ、ヘッドレスビルド使わなくても一貫した物理演算を提供できるやん」みたいな論もあった気がします。

たしかに、DOTSやUnity Physicsのパッケージはソースが公開されてます。しかし、Unity公式パッケージのソースは、Unity Companion Lisenceで提供されている場合がほとんどです。

つまり、Unityでビルドして組み込まないと利用できません
というのも、もしUnityを通さずに自作サーバにUnity Physicsを組み込めるなら、そもそもUnityを使う必要が無いし、Unityにお金払う必要もなくなります。それだとUnityにとっては困るからです。

ですので、Unityの規約が変わらない限りは、イヤでもヘッドレスビルドを使わざるを得ないでしょう。

ヘッドレスビルドは簡単

そもそも、Unityのヘッドレスビルドをサーバーに使うという事は、サーバサイドの実装が一切不要という事ですから、一番簡単です。Unityの一つのプロジェクトでクライアントとサーバが完結します。

専用ゲームサーバのサーバ代は高まりますが、サーバサイドを書くエンジニアを一人増やすコストと比べたらどっちがオトクか?という考え方もできます。

ヘッドレスビルドサーバならUnityの物理演算以外にも、AnimationやらNavMeshやら、Unityの全ての機能が使えます。当たり前ですが。

専用ゲームサーバ構成とチートの話

余談になりますが、MMOやソーシャル性のあるスマホゲームでは、チートをいかにして防ぐかが常に問題でした。

昔ながらの一人またはローカルマルチプレイで遊ぶ家庭用ゲームは、ソフトを買った上でチートをどれだけしたところで、ゲーム会社には特に不利益はありませんでした。

しかし、MMOなどでは、例えばチートで課金アイテムが取り放題なんて事になれば、真面目に課金して買ってるユーザはアホらしくなります。正しく遊んでいるユーザに不利益が発生しますし、チートが横行するゲームからはユーザーが去っていき、ゲーム会社にも打撃です。

MMOのチート対策は明快です。要するに、全てのゲームの処理をサーバ側で行います。クライアント側は単にサーバから送られてくる情報を表示してるだけです。これではチートしようがありません。クライアントからは操作の入力しか送れないからです。

それではスマホゲームではどうだったか?というと、例えば、スマホ以前のガラケーで遊べていたモバマスなどは、モバゲーのWebサイト上で動いているブラウザゲームだったので、そもそもゲーム処理はサーバ側で全て行うしかありませんでした。チートの余地も無いという事です。

それからスマホのネイティブアプリのゲームが出現し始めると、全てをサーバ側で処理するというわけにはいかなくなりました。家庭用のアクションゲームと遜色ないような、白猫プロジェクト崩壊3rdFGOなどなど、このようなゲームはサーバ側で処理できるわけありません。という事は、クエスト部分はクライアントで処理して、クエスト成功、失敗などの結果だけをサーバに送信する形になりました。

クライアントで処理する=チートされるという事です。
実際、白猫プロジェクトではキャラ無敵化などのチートが存在するようです。

じゃあユーザへの不利益になるじゃないか!と思われるかもしれませんが、これらのゲームはチートされても致命的な不利益にはならないように仕様を工夫してます。

つまり、クエストを不正にクリアされたところで、大した問題ではないです。重要なのは、ガチャで不正されない事です。クエスト部分はクライアント処理でも、その他のアイテムや課金石周りなどは当然サーバ処理されているので、チートの余地はありません。

チート可能な部分に大きな価値を置かない事でユーザーの不利益を防いでる感じです。(もちろんクエスト部分でもできる範囲で間接的にチート対策はしているはず…例えば通常プレイでは有り得ないほどの短時間でのクエストクリアを検出したらバンするとか)
白猫プロジェクトはネットワークマルチがありますが、協力プレイのみで、対戦ではないので、まあ最悪チートされても致命傷にはなりません。

一番避けたいのは、対人での対戦プレイでのチートです。
対戦プレイなんて、スマホゲームではあまり実装されません。危険だからです。対戦プレイで相手がチートしたせいで負けたら、当然腹が立ちます。

しかし、FortNiteやFall Guysが流行ってしまっている現状を見ると、いよいよ対戦プレイでのチート対策に本腰を入れざるを得なくなるでしょう。

専用ゲームサーバ構成に移行しようという流れはそういうチート対策からの観点でも有効です。モバゲー時代から一周してきて、専用ゲームサーバ構成ではまたサーバ側で全ての処理を行えるからです。

ちなみに、クライアントと同じロジックを自作サーバーに持たせて、対戦時だけサーバー処理すればいんじゃね?という論もあるかもしれません。
それはまあ…そうなんですが…

ヒーローズチャージというゲームでは、アリーナという疑似的なPvP対戦機能がありましたが、チート防止のためその時だけサーバ側でバトル判定を行う仕様でした。一応クライアント側でもバトルするのですが、勝敗は最初からサーバ側で判定されているという事です。

しかし、そのせいで、自分の画面では勝ったはずなのに、リザルト画面を見ると負けになってる事がたまにありました。サーバ側でのロジックとクライアント側でのロジックが微妙に食い違ってるせいでしょう。

ヘッドレスビルドサーバーを使えばクライアント側とサーバ側で同じバイナリを使ってるので簡単に処理を一致させることができます。

Steamのリレーサーバの話

これは単なるオトク情報の話です。

前回の記事では、PhotonCloudやモノビットクラウドを使えばリレーサーバをホストしてもらえるけど、利用料金がかさんでしまうという話をしました。

例えば、PhotonCloudの場合、100CCUまでなら100ドルくらいを一度だけ払えば済みますが、500CCUになると毎月1万7千円ほどを払うハメになります。

「趣味で作ったマルチプレイヤーゲームをリリースしたいけど、万が一流行ったらサーバ維持費で破産してしまうよ…」

そんなあなたに朗報です!

実はSteamは、無料かつ無制限で利用できるリレーサーバを提供しています!

Steam ネットワーキング

Steamにゲームを登録するには最初に1万円くらい登録料を払う必要がありますが、その後は完全に無料(というか、ゲームの売り上げからSteamに払われる手数料で賄ってる)なので、どれだけゲームが大ヒットしても心配ありません。

例えば、クラフトピアというゲームでも、マルチプレイにSteamのリレーサーバを使っています。

Steamのリレーサーバ、余りにもコスパが良すぎます。もうこれ一択じゃん!って感じですが、気になる所もあります。
多分、対応してるのはPCだけで、スマホとかは非対応でしょう。Steamはスマホゲームとか扱ってませんから。そして、コンシューマプラットフォームも非対応と思われます。コンシューマはSteamじゃないので。つまり、クロスプラットフォームのマルチプレイを実現したければSteamのリレーサーバは選択肢から外れるかもしれません。

実際にUnityのゲームにSteamのリレーサーバ対応したい!という話もちょっと書いてみます。自分もいつかやるかもしれないので。

まず、Steamworks SDKをC#でラップした、Steamworks.NETというものがあります。とりあえずこれだけでUnityから触れます。

「もっと簡単に触りたいんだが?」という場合は、Mirrorに統合されたFizzyFacepunchトランスポートというものがあるので、Mirrorから簡単に使えそうです。

あるいはこちらのUnityアセットでもSteamリレーサーバ機能がMirrorに統合されています。

実際にSteamリレーサーバを実装してみた話では、Chiepommeさんの記事が参考になりそうです。

https://chiepomme.gitbook.io/chiepomme/happy-oshare-time/assets-libraries

Steamworks.NET で P2P 通信してみた

ちなみにMLAPIへのSteamリレーサーバ統合は無いんですか?というと、

公式でSteamP2PTransportが用意されてます。

Unity NetCodeの補足

前の記事では、「Unity NetCodeはよく分からん」みたいな話をしましたが、実際にUnity NetCodeを使い込んでる人から情報をいただきました。

まず、大前提として、Unity NetCodeには現在P2P構成は影も形も存在してないそうで、専用ゲームサーバー&クライアント構成しか無いようです。

Unityのブログ記事にはあたかもP2Pで決定論的ロックステップが実装されてるかのように書かれてましたが、あれは妄想…あるいは将来的にはこうなったらいいな…みたいな気分が書かれていたようです。

もうUnityのブログ記事をソースにして書くのイヤになってきたな。

現在のUnity NetCodeの構成は、ヘッドレスビルドされた専用ゲームサーバとクライアントの組み合わせらしいです。
クライアントからサーバへは入力情報だけが送信されます。サーバはゲーム全体の物理演算を行って、結果をクライアントに送って同期します。
クライアントはサーバのシミュレート結果を待ってる間ラグが発生してしまうので、自キャラの動きだけローカルで物理演算して先読みして動きます。他のキャラからの干渉などで予測に誤差が発生したら決定論的ロールバックで巻き戻します。

どうせサーバで演算して結果を同期するだけなら決定論的かどうかはあんま関係ないだろと思いますが、一応予測の役には立つようです。

将来的にはP2Pモードも実装されるかもしれませんし、その時は決定論的実装が本領を発揮するかも…?

UE4の話

こういう話もあります。

UE4は詳しくないですが、元々エンジンに専用ゲームサーバ構成のネットワーク機能があるようです。

いくら強調しても足りないですが、Fortniteを作ったのはUE4を作ったEpicです。

というか、EpicはUE4を使ってFortniteを作りました
つまり、Fortniteを作るためのノウハウ最適化は全部UE4にフィードバックされてます。

https://www.unrealengine.com/ja/tech-blog/unreal-engine-improvements-for-fortnite-battle-royale?sessionInvalidated=true

つまり「UE4ならFortniteみたいなゲームが作れる」という事は確実に言えます。

それに対して、「UnityでもFortniteみたいなゲームが作れる」かどうかは相当に怪しい話です。

Epicが頑張ってゲームを作るたびにUE4にそのノウハウが蓄積して「実際に凄いゲーム作れるエンジン」として磨きがかかっていくのに対して、Mediatonicが必死こいてUnityでFall Guysを作るために行った最適化は、決してUnityエンジンには反映されません。

Unityフォーラムで見かけた意見ですが、「Unityで本格マルチプレイゲームを作ろうとした会社は、最終的に別のゲームエンジンへの移行を余儀なくされる場合がほとんど。逆にUE4で成功したゲームは大抵UE4組み込みのネットワーク機能をそのまま使っている」という話がありました。

諸々考えると、”本気で”バトルロイヤルライクなゲームを作って成功を狙うなら、UE4を使うべきなんだろうなと思ってしまいます。

UnityからUE4への移行は当然コストがかかりますが、Unityでネットワークソリューションをどうしようか?とか選定や最適化に手間取るコストに比べたら、箱から取り出してすぐに最適化されたネットワークが使えるUE4を使う方が手っ取り早そうです。

ちなみに、UE4にはSteamリレーサーバ統合も公式で用意されてます。

Steam Socket を使用する

所感

色々書きましたが、結論としてはUnity捨ててUE4に移行しよう!って事ですかね…

専用ゲームサーバ構成について長々と話してますが、専用ゲームサーバ構成は個人制作のゲームだとコストがかかりすぎて選択肢から外れます。

個人で低コストにマルチプレイゲームを作るなら、やはりSteamリレーサーバが良さそうです。しかし、P2P+リレーサーバはチートに対して脆弱です。将来的に、Unity NetCodeが決定論的P2Pに対応して、それをSteamネットワークに統合すれば、コストゼロかつチートも効かない鉄板構成になりそうですね。
PhotonQuantumがあるじゃない?って話ですが、あれはそもそも利用料金が高いですから。

ParrelSyncを使ってUnityのネットワークマルチゲーム開発を倍速で進めよう

Unityでネットワークマルチ要素のあるゲームを開発していて、一番面倒なのは、ビルドしないと複数のゲームを開けないので、マルチプレイのテストをするたびにイチイチビルドするハメになる事です。

ちょっとした調整を入れるたびにビルド待ち。うんざりですね。ビルドの待ち時間というのはすなわち人生をドブに捨ててる時間です。

ちょっとしたプロトタイプならすぐにビルド完了するのでそこまで苦痛ではありませんが、開発が進むにつれ、ゲームのビルドには信じられないくらい時間がかかるようになっていきます。

つまり、段々と開発のイテレーション速度が低下していき、開発終盤には開発速度が限りなくゼロに近づいていって、全く進まなくなるという不思議現象が起きます。

もしも、一つのプロジェクトを複数のUnityエディタで開ければ、ビルドしなくてもマルチプレイのテストができるのに…

そこで活躍するのがこちらのParrelSyncです!

https://github.com/VeriorPies/ParrelSync

こちらのアセットを使えば、一つのプロジェクトを複数のUnityエディタで開けます!

もうイチイチビルドしなくてもマルチプレイのテストが可能です!

原理

実はParrelSyncが出る以前から一つのプロジェクトを複数のUnityエディタで開く方法は存在しました。

それは、UnityプロジェクトのAssetsとProjectSettingとPackagesのフォルダのシンボリックリンクを張る方法です。Assetsの中のファイルを変更したら当然シンボリックリンク側にも反映されます。実質一つのUnityプロジェクトを複数のエディタで開ける事になります。

ParrelSyncも実は同じ手法を使ってます。

ParrelSyncのいいところは、エディタ拡張から簡単にシンボリックリンクを生成してクローンプロジェクトを作って管理できることです。あとWindows以外にMacにも対応してます。

インストール

Githubでunitypackageが配布されてるのでそれを入れればOKです。

upmパッケージもサポートされており、パッケージマネージャからGit URLを入れるだけでインストール可能です。

使い方

インストールするとUnityエディタのメニューにParrelSyncという項目ができてます。その中にクローンマネージャという項目があります。

クローンマネージャからクローンプロジェクトを生成したり削除したりできます。クローンプロジェクトを新しいUnityエディタで簡単に開くこともできます。

高度な使い方

クローンプロジェクトにはオリジナルのプロジェクトの変更が自動的に反映されますが、逆に言うとクローンそれぞれに固有の処理をさせたくてもできないという事ですが、APIを使えば固有処理が可能になります。

こちらのページにAPIの説明があります。

1.ClonesManager.IsClone()で自分が今クローンプロジェクトかどうかが取得できるので、処理を出し分けできます。

2.クローンマネージャでそれぞれのクローンプロジェクトに固有の引数を渡すことができます。ClonesManager.GetArgument()で渡した引数が取得できます。

例えばクローンプロジェクトでプレイした時はAI操作に切り替わるみたいなテスト用処理を書けます。

別PCから開く

これは裏技的なテクですが、工夫すればLAN内の別PCからクローンプロジェクトを開く事もできます。

\\192.168.0.1\UnityProject…的な感じで直接IPアドレスからパスを指定してクローンプロジェクトを開こうとしても失敗します。

しかし、ネットワークドライブの割り当てを行って、G:\UnityProject…的な感じでドライブレターからクローンプロジェクトを開く形にすれば行けました。(こんな方法がサポートされてるわけじゃないので、いまはできるけど、いつできなくなってもおかしくない点に注意)Windowsでは行けましたが他のOSだと行けるか分かりません。

この時、できればネットワークドライブのドライブレターは元PCのドライブ名と一致させとく方のがオススメです。(つまり、元PCがGドライブならネットワークドライブもGドライブにする)何故なら、元PCのプロジェクトで、もしローカルのパッケージをインストールしていた場合、別PCから開いた時にローカルパッケージのパスがネットワークドライブのパスと一致してないと開けないからです。他にも、プログラム内などからローカルパスの参照などがあった場合にパスが一致してないとトラブルの元です。

おわり

ParrelSyncを使えばイチイチビルドしなくてもネットワークマルチのテストができて、非常に便利です。

簡単なテクですが、このテクを使うのと使わないのでは、開発速度が倍くらい違ってくるかもしれません。

是非試してみてください。

ちなみにParrelSyncを使ってると”気に入ったらGitHubでスターを付けてね!”みたいなダイアログが出てくる事があります。こんなもん仕込むなよ…。ここだけはイラっとさせられますが、多分一度きりなので我慢です。一度きりとは言え、色んなPCでプロジェクトを使ってるとそれぞれのPCで一度ずつ表示されるので結構イラッとするかもしれません。ソース内のAskFeedbackDialog.csってのを消せば出なくなると思います。


UnityでGameLiftを完全攻略 その1 概要編

[2020/12/30 追記] Playfabのマルチプレイヤーサーバー2.0は無料プランからでも使える旨を修正

前置きの前置き

この前、仕事でUnityでMLAPIGameLiftを統合して接続するという事をやりました。

GameLiftは個人で使うようなサービスではないからか、ネット上にあまり情報が無く、調べるのが大変でした。公式のドキュメントはありますが、UnityとかAWSのドキュメントってなんだか分からん専門用語が飛び交って、意味不明過ぎるといつも思うんですが、どうでしょうか。

だから、いつもはとりあえずサンプル動かしてみて、はあはあなるほどね。って動きを見て理解するしかないのですが、GameLiftはUnityのサンプルはあるっちゃるのですが、かなり微妙なシロモノなので見てもよく分かりませんでした。

「Amazonはこんな訳分らんドキュメントとサンプルしか用意しないで、ホントにサービスを使わせる気があるのかよ!」と何度も思いました。

そういうわけで、せっかく苦労してGameLiftの使い方を理解できたので、記事に書いておけば他の人の参考になるかなと考えました。

話が長くなりそうなので、いくつかの章に分けるつもりですが、GameLiftの概要の説明から初めて、最終的にはMLAPIにGameLiftを統合するとこの解説まで書けたらいいなと思ってます。

GameLiftとは

この記事を読んでる時点でGameLiftが何なのかは分かってる人が多いと思いますが、一応書きます。

GameLiftはゲームを運用するのに専用サーバをホスティングするためのサービスです。

GameLiftに適しているゲームは、FortniteFall Guysなどの、短時間の試合単位でマルチプレイを行うタイプのゲームです。マイクラARKのような、サーバが建ちっぱなしで遊ぶタイプのゲームは向いてません。

GameLiftを使う理由

なんでGameLiftとか使わなアカンの?という事を説明するために、もしGameLiftみたいなサービスが無かったらどうなるか?を考えてみます。

例えば、あなたがFall Guysのような60人バトルロイヤルゲームを作ったとしましょう。このようなゲームはマルチプレイでしか遊べず、プレイヤーは常にゲーム会社がホストしてるサーバに入って試合を楽しみます。サーバはUnityのヘッドレスサーバービルドによる専用サーバを使用します。

ゲームのピーク時には6000人が同時にアクセスしてくるので、あなたはEC2インスタンスを100台立てて、それぞれのインスタンスに60人がアクセスして試合を行うようにセットアップしました。

それはいいですが、ピーク時以外は数百人しかアクセスしなかったりするので、ほとんどの時間は無駄なサーバ代を払ってる事になります。

逆に、有名vTuberが実況プレイした影響で、数万人のユーザーが一度に押し寄せたらどうしましょう?サーバーがパンクして、繋がらないユーザーから苦情が殺到してしまいます。

これは問題ですね。

GameLiftを使えば解決します。

サーバーをホストしてるEC2インスタンスをオートスケールしてくれるので、ユーザーが増えたらインスタンスを増やして、ユーザーが少ないときはインスタンスを減らしてくれます。

結果的に、かかる費用を最小限に抑えて、ユーザーが殺到しても問題なく動作するサーバ環境を簡単に構築できます。

バトルロイヤルとサンドボックスの違い

FortniteやFall Guysのようなバトルロイヤルゲームでは、サーバーに接続してマルチプレイで遊ぶことが前提になってます。そもそもシングルプレイで遊ぶという選択肢はありません。

さらに、競技性のあるゲームなので、ゲーム会社自らがホストしている専用サーバを使う選択肢しか用意されてません。公式専用サーバならチートは不可能だからです。(まあサーバ側でのチートを防止したとしても、クライアントだけでできちゃうチートもありますが。例えば壁を透けさせて敵の位置を丸見えにしちゃうようなチートです。クライアント側のチートを防ぐには、クライアントPCに常駐するタイプのアンチチートソフトが使われます。原神でスパイウェア疑惑で炎上したヤツや、FortniteではEasy Anti-Cheat、ArkではBattleEyeというソフトが使われてます)

ですので、バトルロイヤルゲームでは、GameLiftのような専用サーバをオートスケールしてくれるシステムを用意しないと、公式サーバに入れないユーザはそのゲームで遊ぶこと自体が不可能になってしまいます。

それに対して、ARKのようなサンドボックスゲームでは、必ずしもマルチプレイで遊ばなくても、シングルプレイでも遊べます。

公式の専用サーバも用意されていますが、競技性が強いゲームではないので、ユーザが独自に建てた非公式の専用サーバも利用できます。

Image may be NSFW.
Clik here to view.

Arkでは公式専用サーバが1175部屋も建ってます!

また、P2P(リッスンサーバ)でも遊べます。

非公式の専用サーバやP2Pではサーバ管理者やホストがチートし放題に思えますが、そういうのって内輪で遊んでるわけなので、そこでチートしたら次から仲間外れにされてるだけなので、特に問題は無いでしょう。

公式専用サーバでチートして暴れたらそれは荒らしなので問題になります。サーバ側のチートはそもそも専用サーバなので起きませんが、クライアント側のチートはBattleEyeで防ぎます。(非公式サーバを建てる時はBattleEyeのインストールが必須かどうかを選択できます)

ARKのようなサンドボックスゲームではマルチプレイはオプションなので、GameLiftを使ってまでマルチプレイを保証する必要は無いかもしれません。

GameLiftのコスト

AWSの料金ってややこしすぎて意味不明なので私は個人的にはAWS使いたくないなという気にさせられます。

Amazonが言うにはGameLiftの料金は簡単、分かりやすいとの事ですが、実際いくらかかるのか調べるのに苦労しました。

まあ要するに、初期費用とか基本料金とかは一切かかりませんし、使ったEC2インスタンス分の料金だけ払えばいいという事です。

料金表はこちら

ややこしいのは、まずGameLift or FleetIQという2択があり、Linux or Windowという2択があり、スポットインスタンスとオンデマンドインスタンスという2択があり、どれを見ればええねん?っていう。

とりあえず見とけばいいのはGameLiftのLinuxのオンデマンドの奴です。

リージョンが米国東部で、c5.largeというインスタンスの場合の料金は、毎時0.109ドルと書かれています。一か月連続稼働した場合は78.5ドルです。

つまりこれがGameLift使用時の料金です。

ただし、一見するとGameLiftを使うフィーはタダで、EC2インスタンスの料金だけ払えば良さそうに見えますが、実はインスタンス料金自体にすでにフィーが乗ってます。GameLiftを使わずに普通にEC2でc5.largeを使った時の料金は、毎時0.085ドルで、一か月あたり61.2ドル。GameLiftの方が2割ほどフィーが上積みされてます。

ただ、GameLiftのインスタンスは固定でEBSのストレージが50GB積まれていて、それもコミコミの料金です。それでも普通にEC2使うよりはちょっとGameLiftの方が高いという事です。

あと、データの転送料金は別途かかります。米国東部リージョンで、1GBあたり0.09ドルです。

それと、ゲームサーバをGameLiftにアップしますが、これは実際にはS3に上がるようなので、S3のストレージ代がかかるようです。まあこれは些細な金額でしょう。

GameLiftにはFleetIQやFlexMatchといった機能がありますが、こうした機能はGameLiftの一部なので、使用しても別料金とかはかかりません。

ゲームサーバの転送料金っていくら?

サーバの転送料って実際いくらくらいかかるんでしょうか?そんなにちゃんとゲームサーバの運営をやった事無いので分かりませんが、ざっくり試算する事はできます。

100人のプレイヤーが同じ部屋に入ってて、全員が30日間ぶっ通しでプレイしてる状況を想定してみます。かなり極端な例ですが、ARKのようなゲームでは普通に100人サーバとかありますし、あり得なくは無いかも?

秒間20回、自キャラの座標と回転(vector3とQuaternionでfloat7個で28バイト)を同期するとします。

28バイト×秒間20回×100人が送信×100人に送信×60秒×60分×24時間×30日=14.5TB

GameLiftの転送料が0.09ドル/GBなので、毎月1305ドルもかかる事になります!

たけえ!

なんでこんなに高くなるんだろうと考えてみましたが、やはり同じ部屋に100人入れるというのが多すぎますね。

ゲームの通信量って、プレイヤーの数に対して理論上O(n²)で増えてしまいます。何故なら、部屋に100人いる場合は100人のデータを100人に対して送信する必要があるからです。

例えば、同じ100人だとしても、50人の部屋2つに分割すれば、通信量は半分に減ります。

Fortniteは100人が同じ部屋に入れますが、プレイヤーから見えているオブジェクトだけを優先して同期するなどの最適化を行っているので、通信量を節約しています。フィールドが広いので、同じ画面に同時に映るのはせいぜい数人です。

Fall Guysは全員が同じ画面に映っちゃったりしますが、最大でも60人なので、ギリギリ何とかなってます。それに、60人なのは最初だけで、どんどん減っていきますしね。

もしもあなたが、100人が同じ画面に映り続けるようなゲームを考えている場合は、通信量の観点から言えば、仕様を見直した方がいいかもしれないですね。どっちみち、画面内に100人もいたらゴチャゴチャしすぎてゲームとして成立しない可能性があります。

ARKのようなタイプのゲームでは、同じ部屋に100人入れたりしますし、何時間でも遊べちゃうので、通信量的にしんどそうですね。

でも、上述したように、ARKはGameLift使う必要は無さそうですし、別にEC2にこだわる必要もありません。

通信料がぼったくりみたいに高いのは、AWSを使ってるからで、VPSを使えば通信料は基本的に無料です。ARKならVPSを借りまくってサーバーホストする形もアリかもしれません。

ただし、VPSは通信料がかからない分、通信品質が保証されてるわけではありません。家のネット回線と同じように、速かったり遅かったりします。AWSは高いだけあって、どんだけ通信量が立て込んでも、それなりにスケールする仕組みになってそうです。

あまり実際のサーバー運用経験が無いのでハッキリした事は言えませんが、通信料を惜しんでVPSにしたけど、回線速度でトラブって、かえって損をした。という事もあり得るかもしれません。

AWS公式によるバトルロイヤルゲームのサーバ費用の試算

Image may be NSFW.
Clik here to view.

AWS公式が、もしバトロワ的なゲームをAWSとGameLiftを使って運営したら、毎月いくらくらいかかるのかを試算してくれてます。

その額、13,951ドル!毎月150万円ほどかかるという事です!

別の記事でも、GameLiftは個人開発ゲームで使うには荷が重いという話をしましたが、もし個人開発でバトロワ作ってそれがバズッたりしたら、サーバ代が大変な事になるのがお分かりいただけますでしょうか。

会社の偉い人が軽いノリで「バトロワ作りたい」とか言い出したらこれを見せて、こんだけサーバ代を払う覚悟があるのか確認しましょう。

DAU2万人で月150万円のサーバ代って事は、DAUが2500万人のFortniteは単純計算で年間225億円のサーバ代がかかる事になります!ヒエ~。でもFortniteの年間売り上げは2000億円だから全然払えるんですね。

GameLiftとPlayfab比較

MicrosoftのPlayfabにもAWSのGameLiftと同じような専用サーバホスティングサービスがあります。

どっちがオトクなのか、ざっくり料金比較してみたいと思います。

初期費用

GameLiftは初期費用、基本料金などは一切かかりません

Playfabは、専用サーバをホストするためには、有料プランに加入する必要があります。一番安いスタンダードプランで月額99ドルです。さらに、タイトル毎にプランがあるので、タイトルが分かれるごとに99ドル払うハメになるのが厄介です。

[2020/12/30 追記] Playfabのマルチプレイヤーサーバー2.0が有料プランじゃないと使えないのは、パブリックプレビューの時の話で、2020年4月に正式リリースされてからは無料プランからでも使えるようになってました。(クレカ情報登録が必須)

無料枠

GameLiftには、AWS会員登録後、1年間は無料枠が付いてます。c5.largeインスタンスが月125時間まで無料。通信料は月15GBまで無料(AWS全体で)です。

Playfabも有料プランに加入すれば、無料枠があります。Av2インスタンスが月750時間、Fv2インスタンスが月750時間まで無料です。ただし米国東部リージョンのみ。月750時間あれば、1台だけなら無料枠で起動しっぱなしにできます。通信料は月10GBまで無料です。

インスタンス費用(米国東部リージョン)

GameLiftでc5.largeというインスタンスを例に取ると、1時間当たり0.109ドルです。1カ月連続稼働で78.5ドルほど。ただし、スポットインスタンスなら、料金は常に変動してるものの、この記事を書いてる時の料金で、1時間当たり0.03888ドル、1カ月連続稼働で28ドルほどです。

Playfabで同じくらいのスペックのA2v2というインスタンスを例に取ると、1時間当たり0.09ドルです。1カ月連続稼働で64.8ドル

つまり、GameLiftよりPlayfabの方が少し安そうです。ただし、世の中良く出来てると思いますが、スポットインスタンスを使えばGameLiftの方が安くなります。

スポットインスタンスって何じゃ?という話は後述します。

通信費用(米国東部リージョン)

GameLiftは1GBあたり0.09ドルです。(10TBまでの場合)

Playfabは1GBあたり0.05ドルです。

その他の懸念

費用以外の比較ポイントとして、GameLiftはそれ単体で使えますが、Playfabの専用サーバホスティングは、Playfabサービスの一部として提供されているという点があります。

これにはメリットとデメリットが考えられます。

メリットは、Playfabのユーザ認証などと連携して簡単に使えそうなところです。ただし、それはゲームのバックエンドにPlayfabを使用する場合に限られるでしょう。

デメリットは、バックエンドがPlayfabに縛られてしまいそうなところです。GameLiftなら、バックエンドをPlayfabからやっぱりFirebaseに乗り換えよう。みたいな事もできると思います。

ですから、むしろゲームのバックエンドはPlayfabを使うけど、全部をplayfabに依存はしたくないから、専用サーバホスティングだけはGameLiftを使うという選択肢さえ考えられるかもしれません。

スポットインスタンスとFleetIQ

EC2のインスタンスにはオンデマンドインスタンスとスポットインスタンスの2種類があります。

オンデマンドインスタンスというのは普通のインスタンスです、じゃあスポットインスタンスとは何か?

スポットインスタンス=空き部屋の間借り

例えば、あなたが今、引っ越し先を探してるとします。親戚に賃貸マンションのオーナーがいて、「今ちょうど空き部屋があるから、入居者が決まるまで激安家賃で住んでていいよ」と言ってくれました。

安く住める代わりに、入居者が決まったらすぐさま立ち退きするハメになります。

要するにこれがスポットインスタンスです。

EC2インスタンスの在庫には限りがあります。とは言え、十分な在庫が用意されているので、基本的には在庫が尽きる事はありません。

しかし、Amazonからすると、余ってる在庫を遊ばせているのは勿体ないです。せっかくなので、安く間借りさせよう。そう考えたAmazonが用意したのがスポットインスタンスです。

つまり、スポットインスタンスはオンデマンドより安く使える代わりに、もし在庫が埋まっちゃったときは、すぐさま立ち退きさせられるハメになります。

ですので、Webページをホストしてるような、ずっと起動してないとこまるような使い方には向いてませんが、ちょっと短時間の計算処理を行いたいみたいな使い方にはスポットインスタンスは最適です。

つまり、数分間の試合につかうだけのGameLiftサーバはスポットインスタンスの使い道として、もってこいという事になります。

また、スポットインスタンスの料金は常に変動しています。在庫が余ってるインスタンスタイプほど安くなるというわけです。

めっちゃ賢いFleetIQ

でも、いくらゲームサーバがスポットインスタンスに向いていると言っても、プレイ中のゲームがいい所で立ち退き要求が来てゲームが中断されたらユーザーはイラッとします。

スポットインスタンスの立ち退き要求が来たら、シャットダウンまで2分間の猶予しかありません。そんな短時間で都合よく試合終了できません。

ですので、できる限り立ち退きは避けたいところです。そこでAmazonが作ったのがFleetIQという仕組みです。

FleetIQは、インスタンスを建てる時に、なるべく安くてなるべく立ち退きしないで済みそうなインスタンスタイプを自動的に選ぶことで、安く、中断しづらいスポットインスタンスでのサーバ運用を実現します。

FleetIQを使うためには、キューというものを使って、キューに色んなインスタンスタイプのスポットインスタンスのフリートを突っ込んでおきます。(フリートが何なのかは後述)

そうすることで、FleetIQはサーバのスケールアウトで新しくインスタンスを建てる時に、キュー内のフリートから一番コスパが高そうでかつ一番在庫が余ってて安全そうなインスタンスタイプを選択します。

さらに、すでに建ってるインスタンスについても、なんかもうすぐ立ち退き要求来そうだな…というのを察知したら、今やってる試合が終わり次第、インスタンスを閉じてくれたりもします。

このように、適切にキューを設定しておけば、FleetIQが頑張ってくれるので、実際のとあるゲームでは立ち退き要求があったのは全体のたった0.004%だったそうです。こちらの記事によれば。

GameLiftの仕組み

さて、いよいよ実際にUnityで作ったゲームをGameLiftで動かすために、実際のサーバーとクライアントの動きを説明します。

GameLift公式ドキュメントから引用しましたが、サーバーとクライアントの相互作用を説明した図がこれです。

Image may be NSFW.
Clik here to view.
ゲームクライアント/サーバーの相互作用

正直言って、最初にこの図を見た時は、まったく意味不明でした。サンプルを動かして、コードを見て、動作を理解してからあらためてこの図を見直して、ようやく意味が分かりました。

今の時点でこれだけ理解して欲しいのは、GameLiftの動作はクライアントゲームサーバーGameLiftサービスの3者のやり取りで行われるという事です。

Unityで作ったゲームで言えば、クライアントというのは要するにゲームアプリを指します。ゲームサーバーというのはゲームアプリと同じプロジェクトからビルドしたヘッドレスサーバービルドです。GameLiftサービスというのはまあそのままの意味で、GameLiftを管理しているサービスです。

この際なのでついでに説明すると、クライアントにはGameLiftサービスとやり取りするために、AWSSDKを組み込む必要があり、同様にゲームサーバーにはServerSDKを組み込む必要があります。まあUnityだとクライアントもサーバーも同じプロジェクトなので、そこに両方入れます。

さて、この図を説明するのに、ホテルの例え話をしてみます。

クライアントというのは、ホテルに泊まりたいお客様です。ゲームサーバーというのは、ホテルの部屋です。GameLiftサービスというのは、ホテルのフロントです。

まずはじめに、ホテルにやって来たクライアントは、GameLiftサービスに、「今日泊まりたいんだけど、空いてる部屋無い?」と訊きます。これが、SearchGameSession()です。ゲームセッションって何じゃ?というと、部屋の事です。さっき、ゲームサーバーも部屋の事だって言ってたじゃねえか!と思うかもしれませんが、1つのゲームサーバーの中に複数のゲームセッションがあったりするので、厳密に言えばゲームサーバーはホテルの棟で、ゲームセッションがホテルの部屋と例えた方が正しいかも。

空いてる部屋があればいいですが、無い場合もあります。無いと言われたら、クライアントは「無いなら今作れや!」と言います。無茶な話ですが、これはGameLiftという魔法のホテルなので、部屋が無くなってもいくらでも新しく作れます。これがCreateGameSession()です。

とにかく部屋が見つかったら、GameLiftサービスは、GameSessionオブジェクトをクライアントに渡してくれます。これはまあ部屋の番号みたいなもんです。

クライアントはここで忘れずにGameLiftサービスにプレイヤーセッションも作ってもらいます。プレイヤーセッションって何じゃ?というと、ホテルの話で言えば、ベッドの番号みたいなもんです。このホテルは相部屋前提なので、あらかじめベッドも予約しておかないと後で揉めます。これがCreatePlayerSession()です。

ベッドの予約ができたら、GameLiftサービスは、サーバーのIPアドレスポート番号、それとプレイヤーセッションIDをクライアントに渡してくれます。IPとポート番号は部屋の鍵みたいなもんです。プレイヤーセッションIDはベッドの予約番号みたいなもんです。

ここまで来れば、後はクライアントは部屋に行って入るだけです。IPとポート番号を使ってゲームサーバーに接続します。そしてプレイヤーセッションIDを渡して認証します。

これでようやく部屋に入れました。マルチプレイゲームが始まったという事です。

めでたしめでたし。

FlexMatch

私も使った事がないので、今回の記事では触れませんが、GameLiftにはFlexMatchというマッチメイキング機能があります。

FlexMatchを使うと、色々な条件が設定できて、同じくらいの腕前の人とか、同じくらいのレイテンシーの人同士でマッチングするようにできます。

あと、Amazonはチーターを隔離してチーター同士で争わせるやばい蠱毒の特許も取っているので、そういうのもFlexMatchで実現できるかも?

ちなみにFlexMatchを使わない場合はどうなるかというと、単に参加プレイヤーは空いてる部屋に適当にどんどん案内されるだけです。

それと、FlexMatchは元々GameLiftの機能の一部でしたが、これだけを切り出して単体でのサービス提供も始まりました。

GameLiftのマッチング機能であるFlexMatchが単体での機能提供を開始するアップデートが発表されました!

GameLiftとGameLift FleetIQ

ただでさえややこしい話を、これ以上ややこしくしたくないのですが、一応説明しておきます。

先ほどGameLiftの機能の一部であるFleetIQについて説明しましたが、最近になって、GameLiftからFleetIQだけを切り出した別サービスのGameLift FleetIQというものが始まりました。クソややこしいですね。

元々GameLiftはフルマネージドサービスと言って、面倒くさい事は全部やってくれるサービスです。その代わりに、ユーザーの自由度は低くなってます。

GameLift FleetIQではゲームサーバの管理部分を自前でやる事になります。手間がかかりますが、その分自由度が高いです。具体的に何が嬉しいのか?というと、例えばDockerのコンテナをゲームサーバに使えたりします。Unityのゲームサーバは単に実行すればいいだけですが、色々事前に環境構築が必要なゲームサーバもあります。そういう場合はDockerコンテナを使える方が便利です。

GameLift FleetIQはわれわれの何を解決してくれるものなのか?

Agones

ややこしいついでにAgonesの話もします。もはやGameLiftとは関係ない話なので読み飛ばしてもいいです。

Agonesというのはgoogleが開発しているOSSで、これを使えばGameLiftと同じような事が出来ます。

とは言えどうせ動かす環境はAWSとかなので、じゃあGameLift使えばいいじゃねえかと思われるかもしれませんが、Agonesのメリットは、自由度が高い事です。GameLift FleetIQも自由度が高いという事でしたが、Agonesはさらに自由度が高いです。というかソースが全部あるわけなので、ソースを弄れば細かい挙動まですべて制御できます。

しかし、その分使うのは相当面倒というわけです。

つまり、GameLift→GameLift FleetIQ→Agonesという順番で自由度が高くなっていきます。そして使う手間や難易度も高くなります。使い分けしましょう。

AgonesはKubernetesのプラグインなのでKubernetesと一緒に使います。Kubernetesって何じゃ?というと、Dockerとかを管理するものです。

つまり、Kubernetesを使えばDockerコンテナをオートスケールさせる事ができます。しかし、Kubernetesだけだとゲームサーバが今プレイ中かどうか判断できないので、スケールインでインスタンスを閉じる判断ができません。ですのでプレイ中のゲームサーバを保護するのがAgonesというわけです。

リアルタイムサーバーとカスタムサーバー

私としてはこれ以上話をややこしくするのはまったく心外なのですが、一応これについても説明する必要があるでしょう。

GameLiftのゲームサーバーにはリアルタイムサーバーとカスタムサーバーの2種類があります。

Unityでヘッドレスサーバービルドで用意したゲームサーバーは”カスタムサーバー”です。今回の記事で扱うのはこちらです。

じゃあ”リアルタイムサーバー”って何?というと、なんかGameLift側で用意された、javascriptで書けるサーバーです。

リアルタイムサーバー の仕組み

カスタムサーバーとリアルタイムサーバーの話は相当紛らわしいので気を付けましょう。リアルタイムサーバーなんて私的にはまったく眼中にありませんが、ググって出てきた記事をよく読むとこっちの話をしてたりするので厄介です。

例えばこの記事で触れられてる「Mega Frog Race」というサンプルは、たしかにUnityでGameLiftを使ってるのですが、リアルタイムサーバーを使ってるので、カスタムサーバーとは話が違います。

GameLift RealtimeServer SampleGame「MegaFrogRace」を動かしてみた ~ローカル対戦編~

つづく

今回の記事では、GameLiftの概要、用語説明、大まかな動作の説明などを行いました。

また続きの記事を書くつもりですが、次回の記事ではGameLiftのUnityサンプルを動かしてみる記事にする予定です。

ためになるリンク

公式ドキュメントはチンプンカンプンですが、それとは別に、GameLiftの無料学習コースが用意されてるので、見ておくと役に立つかもです。これもかなり良く分からんですが、ドキュメントよりはマシな気がします。このページの下の方から見れます。

【レポート】Unity+AWSによるマネージドなゲームサーバ運用

Agones 超入門

ゲーム開発者向けサービス「Amazon GameLift」の基礎知識

Unityで作成したビルドをGameLiftで起動してみる

Unity multiplayer game on GameLift #1

Unity multiplayer game on GameLift #2

Unity multiplayer game on GameLift #3

振り返り 2019年秋(10月~12月)

2020年も終わりですね。

今年は何か色々な事がありました。

twitterのログや書いたブログ記事を追いながら、今年一年間を振り返ってみたいと思います。

そう思ったのですが、せっかくなので欲張って去年の秋クールから振り返ってみようかな。

なんか書いてたら分量が大きくなりそうな気配なので、1クールごとに分割する事にしました。

2019年秋クール

今思うと感慨深いのが、2019年はまだコロナが影も形も無かったころなので、平和な日常を送っていた事です。

やった事と考えた事

この頃は、ArtstageというVRモデリングソフトをバリバリ開発中でした。

私はそもそも、「Blenderでマウスをポチポチしながら3Dキャラモデルをモデリングするのがしんどいなあ。VRならもっと直感的に簡単にできるかも」という着想からArtstageを作り始めたので、もちろん自分で使ってモデリングする気満々でした。

3Dモデルの用途としてはゲームや映像制作を考えていましたが、クオリティラインや世界観をどうするか、試行錯誤していたのが伺えます。

あとこの頃は日記漫画的なのをtwitterに描いてました。

無印のリュックはメチャメチャ使ってます。買ってよかったです。

こちらの漫画を見て買いました。

「今までずっとまどマギの二次創作ばっかり描いてたけど、そろそろ二次創作を脱却して一次創作を始めなきゃ」

「一次創作なら二次創作と違って寄せなきゃいけない原作が無いから、どんだけ適当な絵柄でもいいだろ」

みたいな事を考えてた気がしますが、何の思い入れも無いオリキャラを描くのはしんどいという事が判明してきました。

あとこの頃スマホのGalaxyS6を落として画面を割っちゃったので、アプリ開発用に買ってたiPhoneXにSIMを差し替えました。

何で買ってすぐiPhoneXを常用しなかったのか?というと、私の感覚では12万円もするワレモノをポケットに入れて持ち歩くなんて無理だったからです。最初は丁重に扱ってましたが、段々見慣れると大丈夫になって持ち歩けるようになりました。

GalaxyS6は裸で持ってましたが、iPhoneXはケースに入れて、画面保護ガラスも貼って、落下防止の指通すリングも付けました。

書いたブログ記事

この時期に書いたブログはこれだけです。

当時はSDF(符号付距離フィールド)という技術にハマっていました。何故なら、OculusのMediumで使われている技術だから気になってました。

すでにUnityでSDFを扱う記事も書いていました。

次はSDFについて解説する記事を書こう→じゃあその前にマーチンキューブの解説記事も書いた方がいいな→どうせならSPHの解説記事から書こう。

という感じでSPHの記事を書いたものの、そこで飽きて続きは書いてません。

観た、読んだ

2019年秋クールのアニメは、FGOの絶対魔獣戦線バビロニアのヤツを8話くらいまで観てました。

あと、前クールのDr.STONEと彼方のアストラを観てました。たしか、散歩しながらアニメ消化できたらいいな~って発想で、iPadのアマプラで散歩しながら観てました。

この時期にメチャメチャバズッてたのが「搾精病棟」です。

「搾精病棟」とは、サークル「搾精研究所」が制作している、エロCG集のフォーマットで描かれた成人向け漫画です。

主人公は、3時間おきに射精しないと玉が痛くなるという奇病を患っており、その彼が両手骨折で入院して自分で自慰できなくなり、看護婦さんはしょうがないから仕事としてイヤイヤ搾精するという、画期的な設定でした。

バズった理由は「アマミヤ先生」というキャラの、”とにかく声がデカい”という設定が面白くてウケたからです。

ちょうど最終話がリリースされるタイミングだったというのもあります。

私も読んでみましたが、相当面白いです。マゾヒスト男性向けの実用的作品として大真面目に制作されていますが、かえって耐えられないくらいの面白さになっています。

作者の方がブログで「ダウジングでストーリーを決めてる」とか書いてて、やっぱ天才なんだなとか思いました。

搾精病棟はその後、ブイカツからトレスして描いているという問題が発覚して、公開が差し止めになってしまいました。ブイカツは利用規約で「個人での商用利用は可能」としてますが、エロ表現にクレームが入ったようです。利用規約にはエロ禁止とは書いてないものの、「公序良俗に反する行為及び表現・誹謗中傷。」は禁止とされています。

代わりに、小説が出版され、アニメ化も発表され、コミカライズもされることになりました。また、実写化(AV)もされました。

現在では、次回作の「搾精学級」が続々とリリースされてます。

『搾精病棟』と同人CG集の新時代

年末には、「100日後に死ぬワニ」の連載が始まり、早くもtwitterで注目を浴びてました。

それから、ゲームオブスローンズを一気に全部観たのもこの時期でした。
会社で「ゲームオブスローンズ超面白い」という情報を教えてもらい、ちょうど完結したところらしく、アマプラで観れるので、観始めました。

タイトルだけは聞いた事あったものの、まったく事前知識が無かったので、タイトルの語感から、「資産家がマネーゲームする話かな?」とか思ってましたが、全然違いました。中世ファンタジーでした。

メチャクチャ面白かったです。

ゲームオブスローンズで一番すごかったシーンは、サーセイという王女様が色々やらかして、民衆の前で全裸で引き回しの刑を受けるところです。マジに全裸で引き回されます。さらに怒れる民衆からウンコとか投げつけられます。露出塗糞罵倒恥辱プレイとか上級者向け過ぎんか?

いくらこれがドラマの撮影だとしても、俳優が受ける恥辱は現実だと思うんですが。このシーンを筆頭に、ゲームオブスローンズでは結構ムチャクチャなシーンも多いです。もちろん、エログロだけじゃなくて、普通にドラマとして超面白いんですが、まあ下心だけで見ても満足できるっちゃできるでしょう。あまりネタバレするとアレですが、登場する女性キャラほぼ全員にセックスシーンがあります。

年末はずっとスティーブンユニバースを観て過ごしましたね。

スティーブンユニバースというのはカートゥーンネットワークのカートゥーンアニメです。

たとえば、ニャロメロンさんも推してます。

ニャロメロンが語る!アニメ『スティーブン・ユニバース』の魅力

このアニメ、ずっと気になってましたが、カートゥーンネットワークのアニメってとにかく観る手段が限られてて、観れなかったのですが、ちょうど年末にアマプラに入ったので観る事にしました。
序盤は主人公のスティーブンのキャラがウザくてイラついて中々視聴が進まなかったものの、段々と面白くなってきて、最終的には死ぬほど面白くなりました。

面白すぎてYoutubeで感想を語ってしまいました。

この頃、「マクニールの世界史」という本を読みました。読んだ理由はド嬢という漫画の中で紹介されてたからです。

内容で感銘を受けたのは、世界史の中で、蛮族が文明国家を侵略する事がよくありますが、侵略者が相手の国の文化に感化されて取り込まれちゃうケースが結構あったそうです。武力で負けても文化で勝つといったところでしょうか。日本もアニメや漫画で積極的に文化侵略していこう!

「1日江戸人」という本も読みました。江戸の人達って、大店の奉公人みたいなエリートサラリーマンを除いては、みんな相当適当に暮らしてたらしいですね。月に8日くらい日雇いで働けば、十分家族を養えるくらいチョロく稼げたそうですが、それさえやらないグータラばかりだったそうな。正直私も労働なんてそんなもんで十分だと思います。

買ったもの

この時期に買ってよかったものは、TESCOMの3000円くらいのフードプロセッサーです。

主に鶏の胸肉をミンチにするために使ってます。私はだいたい毎日鶏の胸肉を100gずつ食べてます。タンパク質とイミダペプチドを摂取するためですが、その話は長くなりそうなのでまた別の記事に書こうかなと思います。

他にも、いつも家でカレーを作る時は、ココイチ再現カレーというレシピを参考に作ってますが、その中で肉、玉ねぎ、人参をドロドロにするためにミキサー代わりに使ってます。ちなみにココイチ再現カレーとは言うものの、私が作ると別にココイチっぽくなりません。似ては無いけど普通に美味しいのでこのレシピで作ってます。

もう一つ、買ってよかったものは、IKEAの3000円くらいのスーツケースです。

今までずっと、旅行するときはスポーツバッグを使っていましたが、まずスポーツバッグを背負って歩くのがしんどいです。そして、空港にスポーツバッグを預ける時、「いい歳してこれはねーだろ」みたいな空気になります。スーツケースは頑丈ですが、スポーツバッグはふにゃふにゃなので、中の物が壊れるリスクがあるしです。

地元の友人の結婚式に出席する必要があったので、このスーツケースを買ってみました。これのいい所は、何と言っても折りたためる所です。普通のスーツケースは、あんなもん普段置く場所無いよ。って感じですが、これは折りたためるので収納できました。折りたためると言っても中に金属板が入ってるので、それなりに頑丈です。実際使ってみましたが、期待通りの働きをしてくれました。

そういえば、「KREISのカフェインレスコーヒー」もこの頃買ってよかったな~と思った商品で、今でも常飲してます。カフェインレスのインスタントコーヒーです。私はコーヒーを2杯以上飲むと夜寝つきが悪くなるので、それまで朝の1杯だけで我慢してましたが、もっとコーヒー飲みたい!と思ってて、このカフェインレスコーヒーなら何倍飲んでも大丈夫だし、それなりに美味しいし、ポリフェノールも摂れるし、QOLが爆上がりました。

他に買ったのは、ナイキのエアマックスの一番安いヤツくらいです。それまで履いてたナイキのジョギングシューズの靴の裏が剥がれたので買い換えました。ナイキの靴は軽くて走りやすくて好きですが、壊れやすいです。なのでジョギングの時だけ履くようにしてます。

世間の出来事

この時期、一番悲しかった出来事は、はなまるうどんのかけうどんが130円という神の安さ(初めて値段見た時目を疑った)だったのが162円に値上がった事です。

消費税10%

2019年10月は消費税が10%に上がりました。食料品などは軽減税率が適用されて8%のままでした。

私は消費税なんて馬鹿げた税金だと思ってました。何故なら、本当に生活が苦しい人からも一律で税金を巻き上げる仕組みだからです。
しかし、引退して年金生活している高齢者から税金をもらうには消費税しか方法が無いという意見のツイートも見かけました。
まあ、例えば消費税で払った税金が全て子育て支援に使われるとかなら、子供がいる人は消費税で払うよりも多く支援金をもらえる訳なので、少子化対策になって良いかもですね。

香港デモ

この頃、香港のデモが激化して大変な事になってました。

その後、2020年に入って、中国が香港デモに直接干渉するようになり、香港国家安全維持法というやばい法律が作られました。
今までは一国二制度の下で香港は中国の一部になったとはいえ、それなりに独立した自治国家みたいな扱いを受けてましたが、このやばい法律ができたせいで、こりゃもう完全に香港は中国化したな。と見なされて、アメリカや欧州は香港を特別扱いしてたのをやめたりしました。

そんなこんなでこの時期、中国当局はピリピリしていていました。
サウスパークで中国を揶揄する内容が流されると速攻で中国で放送禁止になりました。
さらに、twitterでサウスパーク関係のツイートをいいねしただけで中国からバンされるといった、過剰反応しすぎやろな事態になってました。

ハースストーンの大会で香港デモを支持した選手やチームをBlizzardが処分するみたいな事もありました。

台風19号

10月12日の台風で、どえらい量の雨が降って、多摩川が氾濫しました。

台風の前日くらいに、今回の台風はヤバいから、防災の準備しとけ!みたいな情報が流れてました。
それを聞いて、一応水を確保しておこうかなと買いに行ったら、すでにドラッグストアにもスーパーにもハナマサにも水売ってなくて、365円の日田天領水ってクソ高いヤツしか無くて、買いませんでした。

当時は二子玉川のタワマンでトイレが逆流したなどの怪情報が流れました。川崎市市民ミュージアムの倉庫が水没して収蔵していた漫画などがやられました。

私の家も確認したら、もし荒川が溢れたら絶対沈む場所だと分かったので相当焦りましたが、ギリギリ溢れずに済みました。
ビビりすぎて、日田天領水買わなかったのを後悔しつつ、バスタブに水を貯めて、最悪これを飲もう…とか考えてました。
その後流れてきた情報によると、実は荒川は墨田区の側より江戸川区の側の方が堤防が低いらしく、沈むなら江戸川区側の方が先らしいです。

全国的にメチャクチャに河川の氾濫が起きて、宮城、福島、長野などで被害が大きかったみたいです。

隅田川が決壊しなかったのは、すでにスーパー堤防を整備してバキバキに固めてるおかげだそうです。荒川のスーパー堤防はまだ途中みたいです。

https://www.kensetsu.metro.tokyo.lg.jp/jimusho/chisui/jigyou/super/index.html

そういえば、北区花火大会で荒川の河川敷に行った時に思ったのですが、「河川敷の幅広すぎじゃね?」っていう。川幅の2~3倍の広さを取ってます。しかし、今思えば増水時のバッファとしてこんだけ広くとってるんだと分かります。

ちょうどこの年の夏、「天気の子」を観ており、劇中で東京が沈没してるのを観て、「そんな事あんのかな」とかのん気に思ってました。

実は台風の直前の9月28日に、たまたま北区花火大会に行った会場のそばにあった、荒川知水資料館という所に寄っており、そこで色々と治水について学んでいました。

この図を見てください。かなり衝撃的じゃないですか?荒川、江戸川、隅田川の周りの土地は、川の水位より低いのです!堤防が決壊したらえらい事になります。

これを見て、「天気の子」みたいに東京が沈む事って全然有り得そうだなあ。とか思ってました。
その後に来たのがあの台風19号。

次に引っ越すときは、もっとハザードマップとか気にして考えよう…そう決心しました。

東京の荒川周辺は昔は水害が相当ひどかったらしく、毎年のごとく家が沈んでたので、軒下に船を常備していたほどだったそうです。

江戸川区が配布したこのハザードマップも衝撃的でした。

「ここにいてはダメです」って…ぶん投げ過ぎというか、諦めがいいというか…江戸川区どころか、葛飾区、足立区、墨田区、江東区も沈んでますよ。もちろん私の家のあたりも沈んでます。

水害こわいですね。

東京オリンピックのマラソン開催地が札幌に

当時、IOCが独断でマラソンの開催地を札幌に変更すると言い出して、都知事とかと揉めてました。

都知事がぶーたれて、「涼しいのがいいならもう北方領土でマラソンすりゃいんじゃね」とか言ってました。

今はそもそもオリンピック自体が延期して、中止になるかもしれないという状況なので、当時はマラソンの開催地程度で大騒ぎしていたのが微笑ましいというかなんというか。

異常にクソ暑い真夏の東京でマラソンなんて無茶だろ!って話はずっと議論されてましたが、朝顔を植えるだの、打ち水するだの、頭ん中お花畑みたいな案しか出せずに、業を煮やしたIOCが自らなんとかしたって感じでしょうか。

何でこんな時期に今さら変更を?というと、9月にカタールのドーハで世界陸上のマラソンが行われていて、余りのクソ暑さに棄権する選手が続出、主催側に批判が浴びせられた事が背景にあったみたいですね。

ディズニーtwitter漫画ステマ事件

なんか、一斉にtwitter漫画家たちがアナ雪2の宣伝漫画上げてて、それがステマだったらしく、ディズニーがステマ!みたいな感じで騒がれてました。

私は、もうtwitterは遊びじゃねえんだな。仕事なんだよ。というような事を思いました。

お出かけ

10/3はSEIKOのミュージアムに行きました

10/5は生田緑地に行って、多摩川花火大会に行きました

2020年は一切花火大会が開催されなかったのに、去年は普通にバンバン花火やってたので、世界の急転直下の落差に驚きます。

10/20は生田緑地のばら苑に行って、藤子F不二雄ミュージアムに行きました。

ばら苑は1年に1カ月くらいの間しか開いてません。無料で入れますが、タダというのも気が引けると思って募金箱に300円入れたら花の種をくれました。

藤子F不二雄ミュージアムはメッチャ良かったです。原稿の原画が一杯見れます。音声ガイドも貸してくれます。ショップのグッズも素敵でした。中で上映してるここだけの限定アニメもクオリティ高くて凄いです。予約しないと入れないですが、当日とかでもローソンのロッピーでチケット買えたので、結構気軽に行けます。

夕食は丸源ラーメン

その後、湯けむりの庄っていうスーパー銭湯に行きました。入浴料1500円で相当高いです。高いだけあって、客層がリッチそうな人達でした。

10/22はすみだ北斎美術館と江戸東京博物館に行きました。

絵を描く北斎

11/1は松戸駅からの戸定が丘歴史公園へ、そして千葉大学の庭園を見て、水元公園、ワークマン、三郷のIKEA、湯けむり横丁というスパ銭に行きました。

この頃ワークマンのイージスって防寒着がコスパいいらしいという噂を聞きつけてワークマンでイージス360リフレクトとかいうジャケットを買いました。たしかにメッチャ温かいのでいい買い物でした。

IKEAはクソ安い値段でホットドッグが食えるので好き。立川のIKEAでは、最後の最後の出口の手前でようやくホットドッグ売ってるので、ホットドッグ食うための代償としてクッソ広いIKEAを一周するハメになる仕組みかと思ってましたが、三郷のIKEAでは入り口入ってすぐ横でホットドッグ食えちゃうので衝撃でした。折りたためるスーツケースを買った。

湯けむり横丁は、レトロな街並み再現してて凝っててすごい。

11/15~18は、地元の友人の結婚式に呼ばれてたので、帰省しました。
実家は大分なんですが、湯布院に行ったことが無かったので、せっかくなのでこの機会に行ってみました。親は「湯布院なんて何も無い」と言ってましたが、実際行ってみたらたしかに何も無いなって感じでした。

この時、帰りの飛行機の時間を完全に勘違いしていて、飛行機が飛んでった後に空港に行ってしまいました。というかもう最終便だったので、チケットが取れず、またすごすごと実家まで戻って、翌日チケット取り直して帰りました。完全にすっぽかしたチケットは半額払い戻してくれました。

12/4は大嘗宮一般公開に行きました。

大嘗宮とは大嘗祭のために建てられて、終わったら取り壊される建物です。

こうして見ると、コロナの前でも結構マスクしてる人多いですね。そういえば私も冬は電車では必ずマスクしてた覚えがあります。風邪やインフルエンザが流行りますからね。

12/8は高尾山に登りました。紅葉を見に行こうといったところでしょう。

ほっともっとで唐揚げ弁当を調達していたようです。

何度も高尾山には登ってますが、この時初めて洞窟の奥の福徳弁財天があるのに気付きました。

12/26は目黒をぶらぶらして、目黒不動尊からの林試の森公園、清水湯に行きました。

ライクしたツイート

イラスト

おもしろ

豆知識、ニュース

技術情報

UnityでGameLiftを完全攻略 その2 公式サンプル編

前回の記事の続きです。

今回は、公式で用意されている、UnityにGameLiftを組み込んでる(カスタムサーバー使用)サンプルを動かしてみたいと思います。

↓こちらです。

https://github.com/aws-samples/amazon-gamelift-unity

正直言って色々と微妙なサンプルなんですが、これ以外サンプルは無いので贅沢は言えません。

前の記事でも書きましたが、AmazonはGameLift使わせる気あるんか?Playfabに行っちゃうぞゴラァ!とか思いますが、どうやらこれには事情があるっぽいです。

実は、GameLiftは元々、Amazon製ゲームエンジンのLumberYardの機能の一部でした。ですのでLumberYardとGameLiftの統合には力が入ってて、簡単に使えますが、残念ながらLumberYardはまだベータ版で完成度が低く、利用者が少ない状況です。

このままだとせっかくのGameLiftが使ってもらえないので、しぶしぶUnityやUE4もサポートした、というのが経緯のようです。

Image may be NSFW.
Clik here to view.
https://www.slideshare.net/AmazonWebServicesJapan/amazon-gamelift-flexmatch

ですのでUnity対応がやる気ないのは、さもありなんと言ったところでしょう。

サンプルを動かす

バッチファイルでアプリを自動ビルド

さておき、サンプルのREADMEを見ながら実際にサンプルを動作させてみましょう。

サンプル動かすだけの事を、わざわざブログで説明する事あんの?と言うと、GameLiftは当然ながらAWSの操作がちょっと絡むので、ちょっとややこしいので、一応説明します。

まず大前提として、OSはWindowsを使う必要があります。どこにも説明されてないですが、そうなんです。

事前準備として、UnityVisual Studio(2013か2017、2019でも行けるかも)が必要です。Unityはなにげにバージョンが指定されていますが、「このバージョンでテストした事があるよ」程度の話で、まあ他のバージョンでも動くと思います。

それと、AWSのCLIツールのインストールも必要です。(PowerShellとかからawsコマンドを叩けるようにするツール)

では、リポジトリをzipダウンロードまたはクローンします。

次に、クローンしたフォルダの中のBuildフォルダにPowerShellで入って、その中のbuild.batを叩きます。(PowerShellから叩かないと、直接batファイルを実行すると、終わり次第ウインドウが即閉じするので結果が成功したのか失敗したのか分かりません)

このバッチファイルを実行するだけで、アラ不思議。自動的にビルドされてクライアントアプリとサーバーアプリが出来上がってOutputフォルダの中に入ってます。

え、何じゃそりゃ?そりゃあ、自動ビルドで魔法みたいにアプリをビルドしてくれるのは嬉しいですが、でもそれじゃサンプルになんないでしょ!何が起きたのかサッパリ分かんないんだから!

まあ、一応バッチファイルの中身を見れば、どういう手順の処理が実行されたのか大体分かります。

1.どこからかAWSSDKのDLLをダウンロードする。
2.ServerSDKをビルドしてDLLを生成する。
3.GameLiftにサーバーを自動でデプロイするためのデプロイツールをビルドする
4.Unityをバッチモードで起動して、クライアントアプリをビルドする
5.同じく、サーバーアプリをビルドする

こんな感じです。

何か途中でエラーが出てコケる場合がありますが、その時はバッチファイルを何とかしていい感じに修正しましょう。(そんな無茶な)

ゲームサーバーをGameLiftにデプロイする

AWSでGameLiftを操作するためのIAMユーザーを作成します。すでにIAMユーザーを作成済みの場合はこの手順をスキップできます。IAMユーザーのポリシーでIAMS3GameLiftの権限を付けておく必要があります。

IAMユーザーを作成した時の画面でCSV形式の資格情報ファイルがダウンロードできるので、忘れずにダウンロードしておきます。

Image may be NSFW.
Clik here to view.
IAMユーザーの作成ステップ4

aws CLIを使用して、”deploy“という名前で名前付きプロファイルを生成します。

aws configure --profile = deploy

プロファイルの生成時に、アクセスキーIDシークレットアクセスキーの入力を求められるので、さっきダウンロードしたCSVの中を見て入力します。

プロファイルが生成されると、そのPCにIAMユーザーの”資格情報”がインストールされたことになります。

どこにインストールされたの?というと、C:\Users\ユーザー名\.awsというフォルダの中の、credentialsというファイルを見ると、資格情報が保存されてるのが確認できます。

プロファイルを作成したら、以下のコマンドで環境変数を設定して、一時的に自分のプロファイルを”deploy”プロファイルに切り替えます。

set AWS_PROFILE=deploy

次は、Buildフォルダの中のdeploy.batを叩きます。引数で1.0みたいな数字を付けてください。付けないと怒られます。この数字はビルドとフリートのバージョン名となります。ちなみにもう一つの引数でビルド名&フリート名を設定できます。

./deploy.bat 1.0

このバッチファイルの実行に成功すると、内部でデプロイツールを使用して、サーバーアプリを勝手にGameLiftにアップしてくれます。

ちゃんとアップされたか確認するために、ブラウザからIAMユーザーのアカウントでAWSにログインしてGameLiftのダッシュボードを見てみましょう。

Image may be NSFW.
Clik here to view.

こんな感じでビルド、フリート、エイリアスがそれぞれ一つずつ作られてるはずです。無いよ!って人は右上のとこから選択中のリージョンがバージニア北部になってる事を確認して下さい。勝手にこのリージョンにアップされます。

さて、ここまで読まれた方は、「ビルド、フリート、エイリアスって何じゃ?」と思われてるでしょう。私もこの時なんのこっちゃ分かりませんでした。簡単に説明します。

まず、”ビルド”というのはゲームサーバーの事です。ビルドとして上がってるって事は、GameLiftにアップされてます。が、まだこれだけではEC2にはアップされてません。

フリート”というのは実際のEC2インスタンスです。オートスケールされた、複数のEC2インスタンスが中に含まれてます。フリートがアクティブになってないと、ゲームクライアントからゲームサーバーにアクセスできません。

エイリアス”というのはフリートへのリンクみたいなもんです。ゲームクライアントのプログラムからはエイリアスを指定してフリートへ接続します。なんで直接フリートを指定せずに、エイリアスを挟んでワンクッション置くのか?というと、エイリアスを挟むことで、ゲームクライアントのコードをわざわざ変更しなくてもアクセス先のフリートを差し替えられるようにできるからです。

ビルド、フリート、エイリアスがそれぞれ作成されてるのが確認出来たら、フリートの状態を確認してください。フリートの状態は「検証中」とか「アクティブ化中」だったりしますが、準備が終わると「アクティブ」になります。アクティブじゃないとクライアントから接続できないので、アクティブになるまで待ちます。数分でアクティブになります。

クライアントアプリを実行する

フリートがアクティブになれば、クライアントから接続できますが、クライアントを実行する前に、もう一つ手順が必要です。

PCに”demo-gamelift-unity“という名前のプロファイルの資格情報もインストールする必要があります。何故なら、サンプルコードでこのプロファイル名がベタ書きで指定されてるからです。

READMEではここの手順は意味不明な説明が書かれてますが、要するにこうすればいいという手順を書きます。

C:\Users\ユーザー名\.aws ってディレクトリを開いて、credentialsファイルを開きます。

[deploy]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

↑なんかこういう感じになってるので、これをコピーしてその下にペーストします。そんでプロファイル名の所を”demo-gamelift-unity”に書き換えればOKです。

[deploy]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
[demo-gamelift-unity]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

ではクライアントアプリを実行してみましょう。Buildフォルダ内のrc.batを実行します。引数にエイリアスIDが必要なので、GameLiftダッシュボードのエイリアスのところでIDを確認してそれを使ってください。

./rc.bat --alias alias-0c67a845-bc6e-4885-a3f6-40f1d2268234

これでクライアントが起動します。

Image may be NSFW.
Clik here to view.

クライアントが起動すると、こういうなんか意味分からん画面になってます。

とりあえず確認して欲しいのは、一番上の文字のとこです。CLIENT | GAMELIFT | CONNECTEDって書いてますが、これは今クライアントモードで、繋ぐ先はGAMELIFTで、現在正常に接続中。という意味で、正常だとこうなります。

さて、正常に起動したのはいいですが、これってどういうゲーム?すげえつまんなそう。どうやって遊ぶの?私の時はそう思いました。

遊び方ですが、まずエンターキーを叩くとゲームが開始されます。

マーブルチョコみたいなのが9個並んでますが、これがテンキーの1~9に対応してます。上のスクショの例だと、黄色いチョコが2つありますよね?だから、テンキーの5と6を同時に押してからキーを離すと、2点です。は?青いチョコは4つあるので、3と4と8と9を押して離すと4点です。何じゃこりゃ。

いくらサンプルだからゲームの内容はどうでもいいとは言え、もうちょっとこう…おもしろげにしてくれないと、こちらもやる気が出ないでしょう。

それはさておき、このクライアントを起動したまま、さっきのクライアント起動コマンドをもう一度叩くと、2つめのクライアントが起動します。

盤面が同期してて、対戦相手のスコアも表示されるので、ちゃんとマルチプレイができてる事が確認できると思います。

サンプルの動作確認はこれで終わりです。READMEにはGAMELIFTモード以外にも、LOCALモードとかDISCONNECTモードとかあるよ!みたいな説明が書いてますが、どうでもいいのでここでは説明しません。

サンプルの構成はベストプラクティスじゃない

さて、ここまで試してみて、「これなんかおかしくね?」と思った人もいるかもしれません。

クライアントアプリを実行するには”demo-gamelift-unity”ってプロファイルの資格情報がPCにインストールされてる必要がありましたね。

じゃあ、これでゲーム作って配布しても、ユーザーのPCには資格情報が入ってないから実行できないんじゃね?

そうなんです。

実はこのサンプルは、このままの構成ではゲームに使う事ができません!開発者向けに、便宜上こういう構成にしてるだけで、本番のリリースされたゲームでは別の構成にする必要があります!なんてこった

そもそも、AWSSDKというのはIAMユーザで認証しないと使用できないものです。アクセスキーIDとシークレットアクセスキーをソースコードにべた書きすれば、配布して動く形にできるようですが、いずれにせよゲームクライアントから直接GameLiftサービスを叩くのはベストプラクティスではありません。

Image may be NSFW.
Clik here to view.

READMEにもこういう風に注意書きがされてます。

これ、何を言ってるか分かりますか?私は最初サーパリ分かりませんでした。

つまるところ、AWSのAPI Gateway、Lambda、Cognitoと連携させるのがベストプラクティスだよって事です。

クライアントから直でGameLiftサービスを叩かなくていいように、CreateGameSession()とかCreatePlayerSession()とかのメソッドをそれぞれAPI Gatewayを使ってREST API化します。ゲームクライアントからはそのREST APIを叩きます。

というかこうしないと、どっちみちAWS SDKはdllだからスマホのクライアントアプリから実行できないですよね。

そのREST APIの中身はLambdaで実装します。まあ単に内部でCreateGameSession()とかのメソッド叩いて結果を返すだけです。

単にREST APIにするだけだと、誰でも叩けるようになってマズいので、Cognitoを使って認証されたクライアントからのみAPI呼び出しを受け付けるようにします。

残念ながら私はこの辺りの事まではまだやれてないので、またいずれ理解出来たら別途記事を書きたいと思います。

サンプルコードの中身を見てみよう

サンプルは実行できたものの、みなさんこれでGameLiftの組み込み方が理解できましたか?私はサッパリ分かりませんでした。

何しろ全部自動化されちゃってたので、中身がどういう構造になってたのかまったく分かりません。このサンプル、こういう所が良くないですね。

とにかく、Unityで手動でプロジェクトを開いてみましょう。

プロジェクトの中はこんな構成になってます。

Image may be NSFW.
Clik here to view.

シーンは1つだけ、スクリプトは3つだけで、シンプルな構成ですね。

Pluginsフォルダには色々なDLLが入ってます。AWSSDKServerSDKのDLLです。自前のプロジェクトにGameLiftを統合する時は、これをコピーすればいいでしょう。

シーンファイルを開くと、さっき実行したサンプルと同じ画面です。

ただし、実行ボタンを押す前に、プレイヤーセッティングのScripting Define Symbolsの設定を確認しましょう。

Image may be NSFW.
Clik here to view.

ソースを見ると分かりますが、”SERVER“という定義がある場合は、サーバー側のコードが有効になります。”CLIENT“という定義がある場合は、クライアント側が有効になります。

ですので、クライアントの実行を試したい時は、ここで”CLIENT”を定義しておきます。

そして、実行ボタンを押すとクライアントが起動しますが、このままだとGameLiftで接続できなくて、LOCALモードで起動してしまいます。

コードでベタ書きされてるエイリアスIDを自分のものに書き直す必要があります。GameLift.csの365行目です。

// default alias - command line overrides, use --alias alias-0c67a845-bc6e-4885-a3f6-40f1d2268234
// or change the default below and rebuild the client (case sensitive command line)
//    buildconfig Client
public string aliasId = "alias-0c67a845-bc6e-4885-a3f6-40f1d2268234";

あらためて実行するとGameLiftに正常に接続できます。

動作確認出来たところで、ソースを見ていきましょう。

まず、Credentials.csですが、これは資格情報の操作関係のコードで、まああんま気にしなくていいでしょう。

次に、GameLift.csです。これがGameLift統合の中核のコードです。

ソースの中に3つのクラスが定義されてます。GameLiftクラスはMonobehaviourで、シーンに置かれています。

“CLIENT”が定義されてる場合は、GameLiftClientクラスが有効化されて、GameLiftクラスから使用されます。同じく”SERVER”が定義されてる場合は、GameLiftServerクラスが有効化して、GameLiftクラスから使用されます。

ではGameLiftClientクラスを見てみましょう。
このクラスの役割は、AWSSDKを直接叩いて、GameLiftサービスとやり取りしてゲームセッションやプレイヤーセッションを生成する事です。
このクラスで重要なのは、GetConnectionInfoメソッドです。この中で諸々をやって、最終的には返り値としてサーバーのIPアドレス、ポート番号、プレイヤーセッションIDを返してくれます。

サーバーのIPとポートで接続するのはUNETでもMirrorでもMLAPIでも同じなので、このクラスの処理はどのネットワークライブラリでも使い回せます。

ただし、先ほども説明した通り、直接AWSSDKを叩くのはベストプラクティスでは無いので、最終的にはREST APIを叩く形に置き換わるハズです。

ちなみに、サーバーの部屋当たりの最大人数は、CreateGameSession()の中で設定します。486行目です。

cgsreq.MaximumPlayerSessionCount = 4;

また、もしフリートのリージョンを変更している場合は、CreateGameLiftClient()の中で設定します。372行目です。

config.RegionEndpoint = Amazon.RegionEndpoint.USEast1;

次に、GameLiftServerクラスを見てみましょう。Scripting Define Symbolsで”SERVER”定義に切り替えるとコードが見やすくなります。
このクラスの役割は、ServerSDKを叩いて、ゲームサーバーとGameLift間のやり取りを行います。
重要なのはProcessReadyメソッドです。この中でProcessParametersを生成してGameLiftサービスに渡してます。

ProcessParametersでは、ゲームセッションを開始した時のコールバック処理や、サーバをシャットダウンする時の処理、ゲームサーバーの状態を通知する処理、通信するポート番号の設定、ログ出力設定などを設定します。

そして、最後のソース、GameLogic.csですが、これはゲームの実装が書かれてます。あんま面白く無いゲームですし、特に重要な所ではないです。

手動でアプリをビルドする

一応手動でビルドする方法も書いておきます。

クライアントアプリをビルドするには、Scripting Define Symbolsで”CLIENT”を定義した状態で、普通にビルドすればOKです。

サーバーアプリをビルドするには、同じくScripting Define Symbolsで”SERVER”を定義した状態で、ビルドセッティングでServer Buildにもチェックを入れます。あとTarget Platformも普通はLinuxを選びます。(まあGameLiftではWindowsのEC2インスタンスも使えるのでその時はWindowsです) それでビルドすればOKです。

それで、手動でビルドをGameLiftにアップする方法は?それは次回の記事で書きます。

GameLiftLocal?

READMEでは、GameLiftLocalというものの使い方が書かれてます。GameLiftLocalを使うとイチイチゲームサーバーをGameLiftにアップしなくてもサーバーの動作をチェックできるようです。

素晴らしそうですね!

GameLiftLocalを使って、ローカルでゲームサーバー側のテスト方法は書かれてます。しかし、肝心のクライアント側のマルチプレイをテストする方法が書いてません。「TODO」って書かれてて、実際の内容が書かれないまま放置されてます。だから、どうやるか分かりません。

イチイチゲームサーバーをアップしないで動作テストできると便利そうなので、誰か方法をご存じの方はむしろ教えてください。

つづく

今回の記事では、公式のUnity+GameLiftサンプルの説明を行いました。私は最初サンプル見た時マジに意味不明でしたが、これを読めば多少理解しやすくなるかもしれません。

このサンプル、アプリのビルドもGameLiftへのアップロードも全部自動化されてて、たしかに上級者には便利でしょうけど、初心者にとってはまったく内容が理解できないので参考にならなくて良くないですよね。

次回の記事では、実際にMLAPIアプリにGameLiftを統合してみたものを用意して、それについて解説してみたいと思います。

自分の一次創作キャラが好きになれない時に、どうすればいいのか

前置き

今まで誰にも言ってませんでしたが、実は私は今まで数年間、いや、ある意味では子供の頃からずっと深い悩みを抱えて生きていました。

それは、一次創作が上手くできないという悩みです。

別に秘密ではないんですが、なぜ誰にも言わなかったかというと、こんな悩みを言ったところで普通は理解できないだろうからです。

というか、「まったく現実の生活と無関係な悩みを抱えている余裕があるだけ幸せな野郎だ」とさえ思われるかもしれません。しかし、人からするとしょーもない事だとしても、私にとっては真剣な悩みなのです。

あるいは真剣に漫画家を志すトキワ荘みたいなコミュニティに自分が属していれば、こういう悩みを真剣に聞いてもらえる友達もいたのかもしれません。しかし、自分は実際、真剣に漫画家になろうなんて思ってないし、そういう友達もいません。

さて、一次創作が上手くできないと言うのは、具体的にはどういう事なのか?という話ですが、典型的なパターンとしてはこうです。

①散歩しながらぼんやりしてたら天才的なストーリーのアイデアを閃く

②興奮しながら家に帰ってキャラクターのデザインを考える

③とりあえず漫画を1~2ページ描き始める

何故か分からないが続きが描けなくなる。キャラクターを描くのがしんどい。潮が引くように意欲が減退し始める。理由は分からない

挫折する

私はこのパターンで今まで数えきれない回数挫折してきました。「アンタそりゃ漫画描くの向いてないだけだよ」と思われますか?私も自分でそう思ったことが何度もありますが、一方で何かを描いてみたいという気持ちが自分の中から湧いてくるのも事実なのです。

私が今思うのは、漫画を描ける、描けないというのは、その人が漫画家に向いている、向いていないで片付けられるものではなく、単に漫画を描く方法論を知ってるか知らないかの問題だけなんじゃないかと考えています。

さて、どうして挫折してしまうのか、何が問題だったのかを洗い出してみましょう。
①~③までは調子が良かったのに、④の”何故か分からないが続きが描けなくなる”というところでコケています。

何故筆が止まってしまったのか、自分を見つめ直してよ~く考えてみますと、”自分で考えたキャラをどういう風に動かせばいいのかまったく分からなかった”からだという事に思い至ります。

じゃあ何故動かし方が分からないのか?というと、自分がそのキャラの事を何も知らないからです。

何故そう言えるか?と言うと、一次創作と二次創作の違いを考えると分かります。
私はまどマギにハマっている間、ずっとtwitterで二次創作マンガを描いてましたが、二次創作ならスラスラと描けます。
それは、まどマギのキャラはアニメ本編を観て、どんなキャラクターなのかよく知ってるからです。

今書いてて気付きましたが、この理論で行けば一次創作でも自分の知り合いとかよく知ってる人間を描けば、スラスラ描けそうですね。まあ私には漫画にしてみたいと思うような知人はあんまいませんが。

さておき、具体的に何が問題なのか、ハッキリしてきましたね。

一次創作が上手く行かないのは、”自分のオリキャラの事を作者が何も知らないから”という事です。(あくまで私のケースで、他の人にはそれぞれの他の理由があるかもしれません)

では、どうすればオリキャラの事を知れるのか?

「キャラ設定を決めて羅列すればいいじゃん」と思うかもですが、私もやった事がありますが、設定があっても知らないもんは知らなくて上手く行きませんでした。

お話を構成する4パート

そこまで考えて行き詰ってた私ですが、放送していた「天気の子」を観ていて気付きました。

それは、アニメのお話は、大抵4つのパートに分かれてる気がするという事です。

漫才、茶番パート→ 主要キャラが登場して、日常の中でいくつか出来事が起きる。コミカルな漫才、茶番でそれぞれのキャラの性格とかを示す。

出会い、仲良しパート→ 主人公とヒロインが出会って、仲良くなっていく。このお話の目的、ゴールが何なのかを示す。

苦しみパート→ 主人公とヒロインがくっ付くのを妨害するような、ありとあらゆる苦しみが二人に降りかかる。

解決パート→ 全ての問題が完全に解決して、主人公とヒロインがくっ付いて終わり。(でも天気の子の場合は問題を解決しない代わりに主人公とヒロインがくっ付くという特殊パターンで、だから万人受けではなかった)

何故こういう構成になるのか?というのは、画面の前でアニメを見ている視聴者の気持ちを考えると分かります。

アニメが開始した時は、視聴者は当然登場人物を誰も知らない状態で始まります。視聴者は「誰だよオメーら?」と思ってます。だから漫才、茶番でキャラの事を知ってもらって、好きになってもらう必要があります。

次に、話を展開させる必要があります。主人公とヒロインが出会って仲良くなっていく事で、視聴者は「この二人がくっ付く話なんだな」と理解してくれます。そういうストーリー展開への期待感を持たせないと飽きられます。

そして、苦しみパートです。①と②のパートを上手くこなしていれば、ここで視聴者は主人公達を応援したくなる気持ちになって熱が入ります。

最後に解決パートで、視聴者は「あー、よかったよかった」と完全に満足してくれて、めでたしめでたしです。視聴者を満足させる事が商業作品の目的ですから。

「で、この話が何だっていうの?」という話ですが、私が「天才的なストーリーを思いついた!」って言う時は、大体③のパートを思いついただけで、それでいきなり③から描き始めちゃうからアカンかったというわけです。

キャラの事を知るのに重要なパートは①ですよね。

キャラクターの魅力を伝えるために、最初に漫才、茶番をさせるわけですが、逆に言えば、漫才、茶番をさせてみればキャラの魅力を知れるという事です!

視聴者や読者が、という意味じゃないですよ。作者自身でさえ、漫才をさせてみないとオリキャラの魅力を知る事はできないと私は考えました。

アニメの漫才、茶番を拒絶していた自分

私は昔から、大抵のアニメや漫画に茶番パートがある事は知ってはいたものの、それが重要だなんて思ってなくて、むしろ邪魔だとさえ思ってました。

私は作品のシリアスなところが気に入ってるんであって、漫才や茶番は悪い意味で漫画っぽくて、カッコ悪い、クールじゃない。とさえ思ってました。

しかし、実際は茶番こそが一番大事だったわけです。仮に全然知らないキャラがひたすらシリアスやってる作品があったとして、多分実際見たら全然つまらない、興味が沸かないものになると思われます。

私は今まで、茶番なんて普通過ぎてヤダ!とか言ってひねくれて間違った事にこだわっていたせいで、こんな簡単な事に気付かなかったわけです。

例えばですが、Fateや月姫では、シリアスなバトルパートとハーレム系ラブコメみたいな茶番パートが交互に展開されます。

ひぐらしでも、延々と日常茶番パートが続いた後に、一転してホラーパートが展開します。

なるたるでさえ、最初はいかにも普通のジュブナイル作品みたいな茶番で始まります。

ついでに言えばまどマギも、1話の時点ではいかにも普通の日常コメディだったわけで、最初はさやかさんもたわ言みたいな事ばっか言ってました。まあそれはハートフルアニメと勘違いさせて視聴者を騙すためのものだったと後で分かるものの、とはいえキャラを知るためには必須のパートだったのも事実。もし仮にまどマギが3話からスタートだったら好きになれていたかどうかは分かりません。

こういった、名だたる名作が、どれも決まって茶番から始まるのは、それが必須のパートだからに決まってます。

二次創作の罠

私は今までずっと二次創作ばっかやってきた人間ですが、大体、二次創作と言えば③の苦しみパートとか④の解決パートを膨らませて遊ぶものです。

①の茶番パートはまったく描きません。何故ならすでに原作アニメを観てキャラの事はよ~く分かりきってるからです。というかキャラがメッチャ好きになっちゃったから二次創作描いてるわけです。二次創作を読ませる相手も原作を観ている事が前提ですからね。

逆に二次創作で①をやって、変な方向に勝手にキャラを広げちゃうと、解釈違い!とか言って怒られる可能性さえあるのが二次創作です。

ですから、二次創作ばっかりやってる自分みたいな人が一次創作に転換しようとしても、①の素養が無いので上手い事行かないパターンが多そうです。

ただ、原作キャラがガワしか無くて正体不明なので、二次創作だけど①をやってキャラを広げるパターンもあります。例えば、初音ミクにネギを持たせたりするやつです。

ヒロユキ先生による漫画本質情報

さて、ここまでで、一次創作キャラを知るには①の茶番パートをやればいいと分かりました。

しかし、茶番パートって具体的にどうやって作ればいいんでしょうか?

それを考えていた私に、天啓を与えてくれたのがこの本、ヒロユキ先生の「マンガでわかる 本気で売れるためのヒロユキ流マンガ術」です。

こちらのtogetterまとめから最初の方が読めます。
[追記 2021/1/11] ニコニコ静画で本編の大部分が無料で読めてしまう事に気付きました!

この本は同人誌ですが、今は30ページの描きおろしが追加されて商業出版された「マンガで夢を叶えるための おもしろい の伝え方」が出ているのでそちらをオススメします。

↑この本のAmazonレビューを見たら、内容が薄いとか言って低評価が多いですね。う~む。私も今まで色んなマンガ入門書とかを読んできましたが、そういうのって些末なテクニックとかはもっともらしく色々と描いてますが、具体的にどうやって漫画を描けばいいのか?という本質的な話は全然書いてません。自分的には漫画を描くにあたっての本質的な事が描かれてると思ったのはこの本だけです。

この本は結構前に買って読んでいたんですが、あらためて読み返した時に、ちょうど今考えている、茶番パートはどうやって作ればいいのか?が全て描かれている事に気付きました。

この本の内容を簡単にまとめるとこのような感じです。

①漫画にはテーマが必要。テーマがあれば、テーマが読者に伝わったかどうかで次の改善につながる。

②テーマとは、読者にどんな感想を持ってもらいたいかである。

③そして漫画のテーマは「キャラの魅力」にした方がいい。漫画の全てのページはテーマを伝えるために使うべきだが、全ページで伝えられるようなテーマは「キャラの魅力」以外に無いから。例えば「サッカーのかっこよさ」をテーマにしても、全ページでサッカーのカッコよさを延々と伝えるのは無理。サッカー漫画も実は「キャラの魅力」をテーマにしてる。魅力あるキャラにサッカーさせるからサッカーが魅力的に見えるだけ

④「キャラの魅力」を伝える漫画は、4コマ漫画が適している。1~2コマ目にシチュエーションがある。3コマ目にキャラAが”アクション”する。4コマ目はそれに対してキャラBが”リアクション”する。この”アクション”と”リアクション”で、読者にキャラを印象付けられる。全ページでこれを繰り返すことでテーマが完全に達成される。

いや~、素晴らしい本質情報だ。これをたった千円そこらで教えてもらえるなんて…10万円払っても惜しくない…皆さん是非実際に買って読む事をおススメします。

「キャラの設定やプロフィールを作りこんでもしゃーない。キャラを印象付けるのはあくまでアクションとリアクション」という話もあります。なるほどな~、だから設定だけ決めても描けなかったんだね。

キャラクターを錬成したければ、日常系4コマを描け!

ヒロユキ先生のおっしゃる”アクション”と”リアクション”、漫才で言えば”ボケ”と”ツッコミ”って事になりそうですが、それだと漫才のイメージに引っ張られ過ぎちゃいますからね。

そこまでハッキリオチが付かない4コマ漫画…なんかそういうの、見覚えがありますね…

そう、日常系4コマ漫画です!

今では間違いだったと反省していますが、以前の私は、ああいう日常系萌え4コマ漫画って、あんまり内容が無い気がするし、そもそも1コマ目が一つ前の4コマ目の続きだったりするし、4コマ漫画として成立してねーじゃん!とか例によってひねくれた態度を取って敬遠していました。

しかし、ヒロユキ先生の漫画術を知った今、あらためて読んでみると、あれらは完全にキャラの魅力を伝えるという方法論に則って描かれている事がわかります!人類の叡智がそこに隠されていた!

日常系4コマは、4コマと言っても実は全部話が繋がってますよね。じゃあ4コマ漫画じゃなくていいじゃん!と思うかもですが、4コマ形式にすることで、必ず1ページに2回ずつ、キャラのアクションとリアクションを見せるチャンスが生まれます!あの日常系4コマ特有の作品フォーマット自体にキャラの魅力を伝えるための、最大限の工夫が仕込まれていた!これに則って描けば、誰でも機械的にキャラの魅力を伝えられる漫画が描けるというわけです!

云わんとすることがお分かりいただけますでしょうか。

ヒロユキ先生の漫画術は、本気で売れる漫画を描くための方法です。

ですが、私の抱えていた問題は、”一次創作をしたいけど自分のキャラの事が自分でも分からない”事で、結局のところ、その解決策は、”日常系4コマを描いてみる”という事です。自分で自分のキャラを好きになる事が目的で、漫画は手段という事になります。

”何を描けばいいか分からない”のが問題だったのに、日常系4コマなんて描けるのか?と言う話は、ヒロユキ先生の4コマメソッドに従えば描けるはずです。

では実際に試してみましょう。

Image may be NSFW.
Clik here to view.

超適当に二人のキャラをデザインしてみました。デザインは1分で終わりましたが、設定をどうしようか丸一日以上悩んでました。まあ一次創作についてはド素人ですから、そんくらいかかっても仕方ないでしょう。

「キャラ設定なんて、要するに何かが極端なら何でもいいんでしょ。たとえば極端に声がでかいとか、極端に大食いとかね。」

そう思ってましたが、主人公の設定だけは、ちゃんと考えないとそれが作品の方向性を決めてしまいます。

ヒロユキ流マンガ術では「漫画は自分に正直に描け!」と書かれてます。

そこで、私も自分の内なる声に耳を傾けてみました。
辛抱強く待っていると、内なる自分がこんな事を言い出しました。

顔がいい女子同士の絡みが描きてえ…
ラッキースケベとかエロコメ描きたいけど男は描きたくねえ

なるほど。
そういうわけで、主人公は「性別は女、性欲は男」という設定にしてみました。考えるのが疲れたのでもう一人の子は適当に、見た目通りクールっぽい感じってだけにしました。

ここまで決まれば、4コマ漫画に取り掛かれます。1~2コマ目にシチュエーションを置いて、3コマ目にアクション、4コマ目がリアクションでしたね。

Image may be NSFW.
Clik here to view.

はい、これはすぐ描けました。

自分自身に正直に描いたので、要するに自分がやりたいような事を主人公にやらせればいいだけなので、それさえわかれば簡単にネタが思いつきますね。

3コマ目のアクションの部分は、”主人公がエロおやじみたいに気持ち悪い感じで乳を揉もうとしてしまう

4コマ目のリアクションは”キモすぎて殴られる”です。

リアクションってどういう風に描くのがいいんだろう?とちょっと悩みましたが、ヒロユキ先生の漫画を実際読んでみると、とりあえず殴って終わるケースが多いようです。私は今まで、ギャグとは言え漫画で安易に暴力を振るうのってどうなの?とか思ってましたが、キャラクターを強く印象付けるためのリアクションとしてはたしかに有効だと感じました。

どうですか?この4コマを読んで、キャラクターの印象が付いたでしょうか。
自分では、たしかにこれだけで結構印象付いたかもなと思ってます。

今回はキャラのデザインが適当過ぎましたが、もっとリアルに可愛いデザインにすれば、美人なのに中身がおっさんって感じで、ギャップが面白くなりそうです。

こうやって4コマ漫画をどんどん描く事で、作者自身も知らなかったキャラクターの魅力が勝手に錬成されていくわけです!

作品を見るだけでは作者の意図が分からない

世の中、色々な漫画がありますが、それぞれの作品にそれぞれの作者の意図があり、出力された作品を読んだだけで意図を読み解くのは困難です。

ですから、誰よりも沢山漫画を読んでる人が、誰よりも漫画を描くのが上手いという事にはなりません。

ゲームで言えば、ゲームを遊ぶだけでそのプログラムのソースコードを想像で推測するようなもので、まあ無理です。

だから人を感動させるような漫画を描けるのってまるで魔法みたいに見えて、憧れてしまうのはありそうですね。

ヒロユキ流マンガ術は、ヒロユキ先生の漫画の作り方をロジカルかつ簡単に説明してくれます。ソースコードを開示してくれてるようなものです。ヒロユキ先生の漫画と付き合わせれば、その意図が読み解けます。

ヒロユキ先生は、自分のマンガ術を見付けるまで6年間もくすぶりつづけていたとの事です。その間ずっと、何度も漫画を描き直しながらあーでもこーでもないと試行錯誤したおかげでこの素晴らしいロジックを構築できたわけです。そして、それを実践して実際にヒット作をドシドシ生み出されました。さらに、その素晴らしいマンガ術のロジックを、こうして分かりやすい本に書いて出してくれるとは、こんなにありがたい話は無いといったところでしょう。

ヒロユキ流マンガ術では、「キャラの魅力というのはキャラ設定で決まるのではない。アクション、リアクション、それから受ける印象を積み重ねて育てていくもの」と書かれています。これは重要な気付きを与えてくれます。

つまり、キャラクターにソースコードのようなものが存在するとして、それは4コマ漫画(の中のアクションとリアクション)でのみ記述されうるという事を見事に喝破してます。(ヒロユキ先生の場合)

逆に、私もやってしまっていた事ですが、そうやって苦労して積み上げられたキャラクターを、敢えて壊して面白がるタイプの二次創作も存在します。

例えば、いわゆる筋肉ムキムキのドラえもんとかです。

キャラクターを積み上げる時は、キャラの事を真剣に考えて、たった一つの正解のアクション、リアクションを導き出す必要があるのに対して、二次創作でキャラが絶対しないような言動をさせて遊ぶのは、何も考えずにできてしまいます。

別に、一次創作の方が二次創作より偉いとか言うのではないですが、そういう安易な手法の二次創作に安んじてた自分が、その延長として一次創作に手を出そうとしても上手く行かないのは当然の事だったと今は分かります。

ちなみに、商業マンガでも、連載の末期になると、作者自らがキャラを壊してギャグにしちゃうケースも見られます。他にも、スピンオフ作品で原作を揶揄して笑いを取るヤツとかあったりします。

私はキャラの魅力を積み上げるのは価値の積み上げですが、キャラを壊すのは価値の切り売りだと思います。

私がキャラを生み出したい理由

すでに書いたとおり、私は別に漫画家になる事を目指している訳ではありません。

昔、東方とかマクロスFの同人誌を集中的に描いていた時期がありましたが、その時つくづく実感したのが、「漫画を描くのって大変すぎる」という事です。こんな苦行を永遠に続けないといけない漫画家という職業は、自分には無理と感じました。あと、同人誌を数冊描いたら自分の中で燻ぶってた”漫画描きたい欲”は十分満足して発散されちゃったという事もあります。

ちなみに、漫画描くのが大変なのって、最近の漫画は高度な画力が求められすぎるという問題もあると思います。メッチャ高度な絵を描かされる分だけ、単価が上がってるかと言うとそうでもないので、しんどさだけが上がってます。もはや、漫画家は長い間続けられる仕事では無いとさえ思います。

さておき、私は漫画家になるわけでも無いのに、自身で魅力的なキャラを生み出したいと思っているのは何故なのか?

二次創作のリスク

私はずっと二次創作ばかりしてきましたが、最近、二次創作には色々とリスクがあるように思えてきました。

まず、ネタ切れリスクです。私はまどマギの二次創作をやってましたが、正直ずっと前から完全にネタ切れしており、いくら描きたいと思っても描くネタがありません。いつまで経っても続編が作られないので、燃料も投下されません。かと言って、「じゃあさっさと他の作品にジャンル移動すれば?」と言われても、人間、そう都合よくドハマりできる作品に次々出会えるものでもありません。

それから、どうしてもいつかは原作に飽きてしまうリスクもあります。自分が飽きなくても、みんなが飽きて、描いても反応が得られなくなる事もあるでしょう。結局のところ、飽きずにずーっと好きなだけ続けられるのは、一次創作だけなんじゃないかという気付きがありました。

さらに、公式でトラブルが発生するリスクがあります。一番衝撃だったのは、けもフレのたつき監督降板トラブルです。けもフレのアニメはメチャメチャハマって動物園とかにまで行くようになってただけに、問題が起きた時の衝撃は大きく、相当なトラウマになりました。「二次創作するにも公式が安全そうな作品を選ぶ必要がある」という風に感じました。正直今でもカドカワが関わってる作品ってだけで構えてしまいます。

似たような話で、最近エヴァンゲリオンの二次創作ガイドラインが発表され、「エロ表現は控えて」という旨が通達されました。エヴァ公式はエロ二次創作して欲しくないという事です。”禁止”と言ってるわけではないとの事ですが、こう言われてしまっては、エロ二次創作描いたら賊軍になっちゃいますから描けません。このような、好きで描いてたものが突然描けなくなるリスクも二次創作にはあるっちゃあります。

ですので、できれば二次創作より一次創作メインに移行したい気持ちがあります。

イラスト、CGアニメ、ゲーム

漫画家にはならないにしろ、ちょっとしたラクガキをしたい時とかに、描けるオリキャラがあると便利でしょう。

いや、描けるというより、描きたくなるオリキャラです。

あわよくば今後はUnityを使ってCGアニメゲームの制作も行えればと思っているので、そこで登場させられるキャラクターのストックも用意できれば御の字です。

そのために、4コマ漫画を描いて積み上げてキャラクターを構築する必要があるわけです。

魅力あるキャラを生み出せた後は?

日常4コマを描いていけば、キャラの魅力を積み上げる事ができるのはわかりましたが、その後は?魅力あるキャラを作った後はどうしますか?

日常4コマ漫画では、永遠に日常4コマが続きます。

私の場合は4コマは目的じゃ無くて手段なので、魅力あるキャラができた後はそこから別展開にしちゃうのもアリだと思います。

日常4コマはアニメ構成の茶番パートに相当する部分なので、その後の苦しみパートを持って来るとかです。

作者自身、そして読者に一旦キャラを好きになってもらった後は、あとは「なるたる」みたいな展開にしようが、「ひぐらし」みたいな展開にしようが、ぶっちゃけキャラが立ってれば後は何させても自由みたいなとこあります。

世紀末リーダー伝たけし」とかは最初はギャグマンガでしたが、途中からシリアスバトル展開とギャグを行き来してましたよね。

画力に囚われない

絶対に自分に言い聞かせておいた方がいい事ですが、絵は上手くなくていいという事です。

ただでさえ挫折して困ってるのに、これ以上ハードルを増やしてはいけません。

大体、考えてみれば分かりますが、漫画の画力とその売り上げって、統計を取ってみれば多分全然無関係です。

私も昔は、超画力の漫画家達に憧れていましたが、それらの漫画家は今となっては現役の人はほとんど居なくなりました。

画力なんか無くてもぜ~んぜん問題ないですよ~。とりあえずそう自分に言い聞かせましょう。

キャラの見分けが付いて、そのキャラが何をしているのか、何が描かれてるのかさえ見て分かれば、それでOKです。

ただし、絵の見やすさは大事だと思います。見づらいのはいけません。
丁寧に描いた方がいいと思います。

漫画は一番スモールスタートしやすいコンテンツ

世の中色々なコンテンツがありますが、その中でも漫画は相当スモールスタートしやすいコンテンツだと思います。

例えば、ジャンプでは毎週読者からアンケートを取っており、人気の無い作品は打ち切られます。10週で打ち切られる作品もあります。

とりあえず連載してみて、ダメならすぐ撤回する。この方法なら、損失はほとんど発生しません。少しずつ描いては掲載して、読者の反応を見てテコ入れするチャンスも沢山あります。

逆に、いきなり大きな予算をかけてオリジナルのアニメ映画を作ったり、大作ゲームを出しちゃう場合は、それでコケたら大きな損失をこうむります。映画やゲームは全部完成させないと出せないものですから、反応見て途中でテコ入れもできません。

映画やゲームより、漫画の方がスモールスタートできるので便利という話です。

アニメ映画は上映と同時にコミカライズをやったりしますが、どうせなら、コミカライズの方を先にやって、反応を見ながらテコ入れして、それから映画にした方がリスクが少なそうだと思いますね。

まあ、漫画原作のアニメ、実写映画もありますから、すでにスモールスタートで成功した漫画を映画にする、というのはよいリスク回避ですね。

twitter漫画なんかは最小のスモールスタートだと思います。描いてみて、ウケなかったら撤回して別のを考える。それを当たるまでやればいいだけです。損失は何もありません。まあ代わりに原稿代ももらえませんが。

私は、どんな作品がヒットするかは、ぶっちゃけランダムだと思ってます。人知を超えているという意味で。

鬼滅がヒットした理由を分析してるWeb記事とかありますが、べつにそれを書いてる人がヒットを予言できた訳ではありません。後からなら何とでも言えるって話です。

AmongUsなんて、1年以上鳴かず飛ばずだったのが、今ではMAU5億です。じゃあヒットするまでは何だったの?

何がヒットするかがランダムだとすると、重要なのは、沢山の数打席に立つこと。それだけという事になります。

スモールスタートであるほど打席に立てる回数は増えます。

つまり、漫画はアツいって事です。

まとめ

まず、一次創作が上手くできないという私の悩みがありました。

その原因は、自分のキャラの事を作者自身分からない事でした。

キャラの魅力を構築するには、日常系4コマを描いて、”アクション”と”リアクション”と”印象”を積み上げる必要があると分かりました。

そうしてキャラを構築してしまえば、その後は自由に好き勝手展開させることができるでしょう。それで初めて自由な創作が可能になるのかもしれません。

と言うわけで、長年の悩みを解決する道しるべができました。
今回の記事は割とプライベートな悩みの話でしたが、もし誰かの参考になれば幸いです。

UnityでGameLiftを完全攻略 その3 MLAPI統合編

前回の記事の続きです。

前回はややこしいサンプルを動作させるだけで終わりましたが、今回はもう少し実践的な内容として、MLAPIアプリにGameLiftを統合してみたいと思います。
GameLift統合の要点さえわかれば、UNETやMirrorでも大体同じ要領でできると思います。

記事のシリーズとしては一旦この記事で終わりです。ここまでやれたら後はどうとでもなると思うので。
記事の続きを書きたくても、とくにまだこの記事以上の事を自分でやれてないので、もっと色々やってネタが出来たら続きを書くかもしれません。

さて、MLAPIにはまだ有用なサンプルプロジェクトがほとんど存在しません。今回はUnityテクノロジーズジャパンの黒河さんがUnityステーションの動画用に用意してくださっている、ユニティちゃんをプレイヤーキャラとして操作できるマルチプレイヤーゲームサンプルを使用させていただきたいと思います。

↓サンプルのGitHubリポジトリはこちらです。

https://github.com/wotakuro/MLAPI_UnitychanSample

こちらのサンプルを改造して、GameLiftを統合していきます。
サンプルの説明についてはGitHubのREADMEを参照してください。
今回の記事ではGameLiftの統合に焦点を当てるため、MLAPI自体についての説明はしません。MLAPIについては上にリンクを張ったUnityステーションの動画の説明が参考になると思います。

GameLift統合サンプルを動かしてみる

私の方で、すでにMLAPIサンプルをフォークしてGameLiftを統合したプロジェクトを用意しました。

https://github.com/umiyuki/MLAPI_UnitychanSample

元のサンプルでは普通のネットワーク接続またはリレーサーバ接続だけが可能であり、”Hostとして起動”と”Clientとして起動”の2つのボタンが用意されていましたが、私が改造したサンプルでは”GameLift接続”ボタンが追加されています。このボタンを押せばGameLiftのサーバに接続できます。

Image may be NSFW.
Clik here to view.

統合を実現した具体的なコードの説明は後に回すとして、ひとまずこの統合サンプルの実行方法を説明します。

サンプルの実行環境としては、前回の記事で書いた、GameLiftのUnityサンプルが実行できる環境であることが前提です。
つまり、AWSCLIがインストールされていて、deployプロファイルやdemo-gamelift-unityプロファイルの資格情報がPCにインストールされている必要があります。

では、上記リンク先のリポジトリをクローンして、Unity(2019.4.11を使ってますが、2019.4以降なら多分動く)で開いてください。

ゲームサーバーをビルド

GameLiftにアップロードする、ゲームサーバーをビルドします。

PlayerSettingsのScripting Define Symbolsで”SERVER“を設定します。

Image may be NSFW.
Clik here to view.

Build SettingsからターゲットプラットフォームをLinuxにして、Server Buildにチェックを入れます。

Image may be NSFW.
Clik here to view.

ビルド先のフォルダは、Unityプロジェクトのディレクトリに”build_server_linux”というフォルダを作ってそこにMLAPITest.x86_64という名前でビルドします。(他のフォルダや実行ファイル名にしても構いませんが、その場合はこの後の説明を適宜読み替えてください)

ゲームサーバーをGameLiftにアップロード

ビルドしたゲームサーバーをGameLiftにアップロードして、クライアントから接続できるように設定しましょう。

手動でゲームサーバーをアップロードする場合、残念ながらブラウザのダッシュボードからはできません。AWS CLIから行う必要があります。
プロジェクトフォルダに”upload_gamelift_linux.bat“というバッチファイルを入れておいたので、これを実行すればアップロードできます。

バッチファイルの中身は、

aws gamelift upload-build --operating-system AMAZON_LINUX --build-root .\build_server_linux --name "MLAPI Test" --build-version "build 2" --region ap-northeast-1 --profile deploy

これは、意味としては「GameLiftにゲームサーバーをアップロードしてください。OSはLinux、アップロードするフォルダは”build_server_linux”、ビルド名は”MLAPI Test”、バージョン名は”build 2″、リージョンは”ap-northeast-1″(東京)、使用するプロファイル名は”deploy”」みたいな感じです。必要に応じて引数は変更してください。

アップロードに成功したら、ブラウザからawsのGameLiftのダッシュボードを開いてください(リージョンは東京)。ビルドがアップロードされてる事が確認できると思います。

Image may be NSFW.
Clik here to view.

ビルドがアップされていても、フリートとエイリアスが無いとクライアントから接続できないので、作成する必要があります。

フリートから作成しましょう。

ビルドを選択して、”アクション”→”ビルドからフリートを作成”をクリックします。

Image may be NSFW.
Clik here to view.

”フリートの詳細”の”名前”の欄に、分かりやすい名前を設定します。
”プロセス管理”の”起動パス”の欄には、アップロードしたフォルダ内のゲームサーバーの実行ファイル名を記入します。

Image may be NSFW.
Clik here to view.

”同時プロセス”の欄で一つのEC2インスタンスで最大何個までサーバーを起動するかを設定できますが、とりあえず1でいいです。

EC2 ポート設定“でポート開放設定を行います。今回のプロジェクトでは1935番のポートを使用しているので、”ポート範囲”は1935、プロトコルはUDP、IPアドレス範囲は0.0.0.0/0(全部有効)を設定します。

Image may be NSFW.
Clik here to view.

これで”フリートの初期化“をクリックすればフリートが作成されます。

Image may be NSFW.
Clik here to view.

フリートの状態ですが、”初期化中”とか”アクティブ化中”とかになって、最終的に準備完了すれば数分で”アクティブ”になります。サーバーがバグってると”エラー”とかになっちゃいます。

最後にエイリアスを作成しましょう。(フリートがアクティブになるのを待つ必要はありません)

”エイリアスの作成”をクリックして、適当にエイリアス名を付けて、”関連付けられたフリート”で先ほど作成したフリートを選択して、”エイリアスの設定”をクリックすればエイリアスが作成されます。

Image may be NSFW.
Clik here to view.

ビルドとフリートとエイリアスが作成出来たら、GameLiftの設定はOKです。クライアントから接続できる状態になります。

今回は手順を理解するために手動で設定しましたが、手作業だと面倒くさいしミスが起きたりするので、ゆくゆくは自動でアップロードからビルド、フリート、エイリアス作成まで行えるようにした方がいいでしょう。

前回の記事で使ったUnityサンプルに自動デプロイツールのVisualStudioプロジェクトが同梱されているので、あれを弄れば自動デプロイができると思われます。

エディタからGameLiftに接続してみる

とりあえずエディタからGameLiftに接続してみましょう。

ソースコードに接続先エイリアスIDを設定する必要があります。ダッシュボードから自分のエイリアスのIDを確認して、GameLift.csの392行目を書き換えてください。

// default alias - command line overrides, use --alias alias-0c67a845-bc6e-4885-a3f6-40f1d2268234
// or change the default below and rebuild the client (case sensitive command line)
//    buildconfig Client
public string aliasId = "alias-0c67a845-bc6e-4885-a3f6-40f1d2268234";

Scripting Define Symbolsで”SERVER”を消して、”CLIENT“を追加します。

Image may be NSFW.
Clik here to view.

この状態でプレイモードに入って”GameLift接続”ボタンを押すと、GameLiftサーバに接続できます。

Image may be NSFW.
Clik here to view.

無事にGameLiftサーバに接続できました!やったぜ。

このままだと、エディタ上では1つしかゲームを起動できないので、ビルドしないとマルチプレイのテストができません。ParrelSyncを使えば一つのUnityプロジェクトを複数のエディタで起動できるので、ビルドしなくてもマルチプレイのテストができます。

↓ParrelSyncの解説についてはこちら

ParrelSyncを使ってUnityのネットワークマルチゲーム開発を倍速で進めよう

クライアントをビルドする

クライアントのゲームアプリをビルドしてみましょう。

エディタからGameLiftに接続できる状態になってれば、あとはBuildSettingsでターゲットプラットフォームをWindowsにして、Server Buildのチェックを外してビルドすればOKです。

エディタの時と同様にGameLiftに接続できるはずです。
クライアントはいくつでも起動できるので、好きなだけの人数のマルチプレイをテストできます。

しかし、複数のクライアントを起動しても、操作できるのは自分ひとりなので、自分のキャラしか動かせなくて、マルチプレイしてる感が無いですよね。

そんな時はダミークライアント機能が使用できます。

ダミークライアントを実行する

MLAPIサンプルは、バッチモードで起動すると自動でランダム操作するダミークライアントとして立ち上がるという便利な機能があります。

私が改造したサンプルでは、ダミークライアントは強制的にGameLiftサーバに接続するようにしてます。

↓このような内容でバッチファイルを作成してクライアント実行ファイルと同じフォルダに保存して、実行してください。

MLAPITest.exe -batchmode

バッチファイルを実行する度にダミークライアントが立ち上がります。ダミーのユニティちゃんはランダムに歩き回ります。

ダミーと言えども入力をシミュレートしてサーバに送信しているので、サーバ負荷などは人間がプレイした時と同様の条件でテストができます。

大量のクライアントで接続してみる

MLAPIとGameLiftの組み合わせで、何人くらいまで接続できるもんなのでしょうか?

ダミークライアントを大量に起動してテストしてみました。
GameLiftのEC2インスタンスはデフォルトで設定されてるc5.largeを使用しました。

Image may be NSFW.
Clik here to view.

うじゃうじゃ…

大体これで70人です。
ちょっとだけカクカクし始めてます。
サーバー的にはまだ余力があるのかもしれませんが、見ての通り、1台のPCで大量のダミークライアントを立ち上げているため、クライアントPC側のCPU、メモリ、GPUの方が一杯いっぱいになってきたのでこのくらいで止めておきました。

まあ70人で同じ部屋に接続出来たら十分満足な気がしますね。

MLAPIサンプル改造の流れ

GameLift統合サンプルの中身を解説…というよりどのような流れで元のサンプルにGameLiftを統合していったのかを説明します。

流れが分かれば自身のプロジェクトへの統合方法やMirrorやUNETの場合での応用も理解できると思います。

GameLiftのUnityサンプルからコードとDLLをコピーしてくる

まず最初に、前回使ったGameLiftのUnityサンプルからソースをコピーしてMLAPIサンプルプロジェクトに持ってきます。

持って来るのはGameLift.csとCredentials.csの二つです。GameLogic.csは要りません。

そして、Pluginsフォルダの中にあるdllファイルも全部コピーしてきます。

GameLift.csはほぼこのままでも使えるのですが、いくつかエラーが出てしまってるので修正します。

GameLift.csの変更

GameLogicクラスに依存してる箇所がちょっとあるので、コメントアウトします。gl.gameliftStatusを参照してる箇所については、GameLiftクラスにgameliftStatus変数を追加してそっちを参照するように変更します。

また、サーバーをアップロードするリージョンを東京リージョンに変更していたので、参照するリージョン先も東京リージョンに変更します。399行目です。

config.RegionEndpoint = Amazon.RegionEndpoint.APNortheast1;

今の設定だと部屋に4人までしか入れないので、とりあえず100人まで入れるようにしてみます。513行目です。

cgsreq.MaximumPlayerSessionCount = 100;

そして、ひとつ重要な機能追加を行います。GameLiftにUnityログを収集させて後からログファイルを確認できるようにする機能です。GameLiftでは基本的にはEC2インスタンスは直接見れないので、サーバーで何が起こってるか確認するにはログを見るしかありません。地味ですがデバッグ的には最重要機能です。154行目あたりに追加してます。

public void Awake()
{
    //ログをGameLiftに出力
    mLogFilePath = System.IO.Path.Combine(Application.dataPath, Guid.NewGuid().ToString("N") + ".log");
    var stream = new System.IO.FileStream(mLogFilePath, System.IO.FileMode.CreateNew, System.IO.FileAccess.Write);

    mLogFileWriter = new StreamWriter(stream, System.Text.Encoding.UTF8);
    mLogFileWriter.AutoFlush = true;

    Application.logMessageReceived += LogCallback;
}

void LogCallback(string condition, string stackTrace, LogType type)
{
    mLogFileWriter.WriteLine($"{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")},{type.ToString()},{condition},\n{stackTrace}");
}

あとはこのAwake()を呼ぶようにしたり、LogParametersでこのログファイルを指定したりします。

ConfigureConnectionBehaviour.csの変更

GameLiftサンプル側の変更が終わったので、MLAPIサンプル側を変更してGameLift接続に対応できるようにします。

まず、ConfigureConnectionBehaviour.csをちょっと変更します。

ゲームサーバーの待ち受けポートを指定するために、serverPortフィールドを追加します。デフォルトで1935番にしているのは、GameLift.csでゲームサーバーとGameLiftサービス間の通信にも1935番が指定されてるので、どうせなのでゲームサーバーとクライアント間の通信も同じ1935番使っとくかという事です。

GameLift接続ボタンとGameLiftクラスの参照用フィールドも追加しときます。

GameLift接続ボタンを押したときのメソッドも実装します。

public void OnClickGameLiftConnect()
        {
#if CLIENT
            // try to connect to gamelift
            //ローカルサーバが無ければGameLiftに接続する
            if (gameLift.client!=null)
            {
                string ip = null;
                int port = -1;
                string auth = null;
                gameLift.GetConnectionInfo(ref ip, ref port, ref auth); // sets GameliftStatus

                if (gameLift.gameliftStatus)// TryConnect(ip, port, auth); //GameLiftからip、ポート、認証をゲットしたので接続
                {
                    Debug.Log("GameLiftからIP取得! ip:" + ip + " port:" + port + " auth:" + auth);
                    this.connectInfo.useRelay = false;
                    this.connectInfo.ipAddr = ip;
                    this.connectInfo.port = port;
                    this.connectInfo.playerName = this.playerNameInputFiled.text;

                    ApplyConnectInfoToNetworkManager();

                    MLAPI.NetworkingManager.Singleton.NetworkConfig.ConnectionData = System.Text.Encoding.ASCII.GetBytes(auth); //セッションIDをカスタムデータとして送信

                    // ClientManagerでMLAPIのコールバック等を設定
                    this.clientManager.Setup();
                    // MLAPIでクライアントとして起動
                    var tasks = MLAPI.NetworkingManager.Singleton.StartClient();
                    this.clientManager.SetSocketTasks(tasks);
                }
            }
#elif !GAMELIFT
            Debug.Log("GAMELIFTのプリプロセッサ定義がありません");
#endif
        }

GameLiftクラスのGetConnectionInfo()を呼んで、サーバのIPアドレスとポート番号を取得してそこに接続する感じです。

また、ダミークライアント起動時にもGameLiftへ接続するように変更します。

#elif ENABLE_AUTO_CLIENT
            if (NetworkUtility.IsBatchModeRun)
            {
                // バッチモードでは余計なシステム消します
                NetworkUtility.RemoveUpdateSystemForBatchBuild();
                //OnClickClient();
                OnClickGameLiftConnect();
            }
#endif

そして、NetworkUtility.GetLocalIP()を呼んでる箇所がありますが、このメソッドはGameLift上のゲームサーバーから呼ぶと何故かエラーが出るので、呼ばないように変更します。

#if CLIENT || SERVER
            localIPAddr = "HostName: " + Dns.GetHostName();            
#else
            localIPAddr = NetworkUtility.GetLocalIP(); //GameLift環境では動作しない
#endif

ServerManager.csの変更

最後に、ServerManager.csを変更します。

まず、GameLiftを参照するフィールドを追加します。

そして、クライアントの承認機能を追加します。
クライアントの承認ってなんだ?という話ですが、MLAPIもそうですが、デフォルトではクライアントは無条件でサーバーに接続できます。

つまり、サーバーのIPとポート番号さえ知ってればいくらでも不正に接続出来ちゃいます。

サーバーにクライアント承認機能があれば、接続してきたクライアントが正当な資格を持ってるか検証して、不正なクライアント接続は弾く事が出来ます。
MLAPIはクライアント承認機能を利用可能です。

https://mlapi.network/wiki/connection-approval/

どういう仕組みかと言うと、クライアントはサーバに接続要求を出すときに、任意のデータ(byte[])をサーバに渡せます。サーバ側はApprovalCheck()でそのデータを見て正しいクライアントかどうかをチェックできます。

何のデータを渡せばいいの?と言うと、GameLiftではクライアントがプレイヤーセッションを生成した時に、GameLiftサービスからプレイヤーセッションIDをもらえます。このIDを渡せばOKです。すでにConfigureConnectionBehaviour.csのOnClickGameLiftConnect()でそのように実装しています。

サーバ側ではGameLift.ConnectPlayer()を使って、受け取ったプレイヤーセッションIDが正当かどうかをGameLiftサービスに問い合わせができます。間違いなければ接続承認してあげます。89行目あたりから実装してます。

//クライアントの接続を承認する?
        private void ApprovalCheck(byte[] connectionData, ulong clientId, MLAPI.NetworkingManager.ConnectionApprovedDelegate callback)
        {
            Debug.Log("ApprovalCheck connectionData:" + System.Text.Encoding.ASCII.GetString(connectionData));
            //Your logic here
            // ここにあなたの論理
            bool approve = true;
            //bool createPlayerObject = true;


#if SERVER
            if (gameLift == null)
            {
                Debug.Log("GameLift object is null!");
            }
            else
            {
                //GameLiftにプレイヤーセッションを問い合わせる
                approve = gameLift.ConnectPlayer((int)clientId, System.Text.Encoding.ASCII.GetString(connectionData));
                if (!approve) { DisconnectPlayer(clientId); }
            }
#endif


            // The prefab hash. Use null to use the default player prefab
            // プレハブハッシュ。デフォルトのプレーヤープレハブを使用するには、nullを使用します
            // If using this hash, replace "MyPrefabHashGenerator" with the name of a prefab added to the NetworkedPrefabs field of your NetworkingManager object in the scene
            // このハッシュを使用する場合は、「MyPrefabHashGenerator」を、シーン内のNetworkingManagerオブジェ
            // クトのNetworkedPrefabsフィールドに追加されたプレハブの名前に置き換えます。
            //ulong? prefabHash = SpawnManager.GetPrefabHashFromGenerator("MyPrefabHashGenerator");

            //If approve is true, the connection gets added. If it's false. The client gets disconnected
            // 承認がtrueの場合、接続が追加されます。それが間違っている場合。クライアントが切断さ
            // れます
            //callback(createPlayerObject, prefabHash, approve, positionToSpawnAt, rotationToSpawnWith);
            callback(false, null, approve, null, null);
        }

接続時のプレイヤーセッションの追加が実装されたので、次は切断時にプレイヤーセッションの終了を通知する部分も作ります。136行目あたりからです。

// クライアントが切断した時の処理
        private void OnClientDisconnect(ulong clientId)
        {
            Debug.Log("Disconnect Client " + clientId);
            DisconnectPlayer(clientId);
        }

        //GameLiftからプレイヤーセッションを削除
        private void DisconnectPlayer(ulong clientId)
        {
#if SERVER
            gameLift.DisconnectPlayer((int)clientId);   //プレイヤーセッションを解放
#endif
        }

ところで、今の時点では、一旦始まったゲームセッションは永遠に終了しません。ゲームの終了条件を特に作ってないからです。一応、ゲームサーバーの切断ボタンが押されたらゲームセッションを終了するようにしておきます。まあ、ヘッドレスサーバーなのでボタンは押せませんが一応。

// 切断ボタンが呼び出された時の処理
        private void OnClickDisconnectButton()
        {
            MLAPI.NetworkingManager.Singleton.StopHost();

#if SERVER
            //GameLiftのゲームセッションを削除
            if (gameLift != null && gameLift.gameliftStatus)
            {
                Debug.Log("TerminateGameSession");
                gameLift.TerminateGameSession(true);
            }
#endif

            this.RemoveCallBack();

            this.configureObject.SetActive(true);
            this.stopButton.gameObject.SetActive(false);
            this.serverInfoRoot.SetActive(false);
        }

ソースの変更はこれでおしまいです。お疲れさまでした。

Unityシーンの変更

変更したソースが正常に動作するように、Unityエディタでシーンを調整します。

まず、空のゲームオブジェクトをシーンにおいて、GameLiftクラスをアタッチします。
そして、インスペクタからServerManagerとConfigureConnectionBehaviourのGameLiftフィールドにこのオブジェクトを突っ込みます。

次に、接続UI上にGameLift接続ボタンを作成して、ConfigureConnectionBehaviourのConnectGameLiftButton参照に突っ込みます。

そして、MLAPIのクライアント承認機能を有効化するために、NetworkManagerのConnection Approvalにチェックを入れます。

以上で完成です。細々としたところが抜けてるかもしれませんが、詳細は改造サンプルの方を参照してください。

オマケ その他のGameLift情報

MLAPI統合の説明は以上で終了ですが、せっかくなのでGameLift使ってて知ったTipsみたいなのも書いときます。

テストが済んだらフリートを消しておくべし!

実際、何よりも重要な話ですが、GameLiftのフリートを作りっぱなしで放置しておくと、EC2インスタンスが起動し続けて(デフォルトだと誰も接続しなくても最低1つのインスタンスが常時起動してる設定になってるハズ。そうじゃないとプレイヤーがいつ接続してくるか分からないので)どんどん課金が発生してしまいます。

テストなどが済んだらフリートを全部消すか、手動でフリート内のインスタンス数をゼロに設定しておく必要があります。

ちなみに”ビルド”があるだけでもS3料金がかかります。まあこちらは微々たる金額だと思いますが。

チュートリアルを途中まで進めただけで数万円の支払が発生したAWS

GameLiftの無料枠は月当たり150時間しかありません。

ゲームセッションを強制終了させる裏技

GameLiftでは、ゲームセッション単位でログをダウンロードできます。逆に言えば、ゲームセッションが終了しない限り、ログを見れません。そして、今回作成したサンプルではゲームセッション終了処理を入れてないので、永遠にゲームセッションは終了しません。つまり、ログが見れないので、ゲームサーバーのデバッグが不可能です。

これは困りましたね。

しかし、実はフリートのゲームセッションを強制終了させる裏技があります。
フリートを開いて”スケーリング”タブから”最大インスタンス数の設定”と”手動で目的のインスタンス数を調整する”の数値を両方ゼロに設定しましょう。すると、しばらくするとゲームセッションが強制終了されます。

Image may be NSFW.
Clik here to view.

ゲームセッションが終了してこれまたしばらく経つと、ログが収集されてログファイルがダウンロードできるようになります。(強制終了でなく、正常にゲームセッション終了した場合はすぐにログダウンロード可能になります)

Image may be NSFW.
Clik here to view.

ちなみに当然ですが前述したようにプログラム内でUnityログをGameLiftが収集するように設定してないとログは空です。

先ほどゼロにした二つの数値を1に戻せばフリートのインスタンスが復活します。ちなみにゼロにしておけばEC2インスタンスがゼロになるのでGameLiftの料金がかからない状態になるハズです。

どうしてもフリートのEC2インスタンスに直接アクセスしたい

「サーバーに繋がらない理由が分からない!ログを見ても分からない!どうしても直接EC2がどうなってるか見たい!」という時もあるでしょう。

そんな時は、手間ですが一応EC2にアクセスする方法はあります。

↓こちらに方法が書いてます。

https://docs.aws.amazon.com/ja_jp/gamelift/latest/developerguide/fleets-remote-access.html

まず、AWS CLIを使用して、describe-instancesコマンドでフリート内のインスタンスIDをゲットできます。

次に、get-instance-accessコマンドでインスタンスにアクセスするための秘密鍵をゲットできます。

その秘密鍵をpemファイルとして保存すれば、sshコマンドで秘密鍵を使って目的のEC2インスタンスに入れます。

また、フリートの設定からsshで使用するポートを解放しておく必要もあります。

手間がかかるので最後の手段として使いましょう。

エイリアスを駆使したサーバ運用

実際にGameLiftを使ってサーバを実運用する場合、どんな感じになるのでしょうか?

色々なパターンを想定して考えてみようと思います。

①ゲームが2種類になった時

GameLiftで別々の2種類のゲームを運用する事になった時は、まあそれぞれのゲームに対してビルド、フリート、インスタンスをそれぞれ用意してあげればいいと思います。

②クライアントとサーバを両方更新する時

Unityでヘッドレスサーバを使ってサーバ運用する場合、大抵はクライアントを更新したらサーバも更新するハメになると思います。

まず、新しいサーバビルドをGameLiftにアップロードしましょう。
次に、新しいビルドのフリートを作成します。新しいエイリアスも作ります。

そして、新しいクライアントからは、新しいエイリアスを参照するようにプログラムから設定します。そして、アプリストアのクライアントを更新しましょう。

これで更新完了ですが、古いフリートを建てておくのはサーバ代の無駄なので消したいです。
実はエイリアスには、フリートをリンクする代わりにメッセージを送信する機能もあります。ですので、古いエイリアスからフリートへのリンクを外して、「クライアントを更新してください」みたいなメッセージを設定しましょう。

こうすれば古いクライアントからはサーバに接続できなくなり、アプリ更新が促されます。

これで、しばらくしてプレイヤーが誰もいなくなった古いフリートを削除できます。

③クライアントだけを更新する場合

クライアントだけを更新したい場合は、GameLift側は特に何も更新する必要ないはずです。
しかし、別々のバージョンのクライアントが同じサーバに接続してマルチプレイするのってなんか問題起きそうで気持ち悪いです。

新しいクライアント用には新しいフリートとエイリアスを用意して、マルチプレイでクライアントが混ざらないようにした方がいいような気がします。

④サーバだけを更新する場合

クライアントは更新せずにサーバだけを更新する場合は、とりあえず新しいサーバビルドをGameLiftにアップして、新しいフリートも作成します。

それからエイリアスの向き先を古いフリートから新しいフリートに変更しちゃいます。
そうすれば、その後のゲーム試合は新しいフリートで始まりますし、現在すでに始まってる試合は引き続き古いフリートで続行されます。

しばらく経てば古いフリートのプレイヤーはいなくなるはずなので、古いフリートを削除できます。

こういう感じでGameLiftではダウンタイム無しのサーバ更新が可能です。

Viewing all 181 articles
Browse latest View live