テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

配列を使わずシューティング、またの名を初心忘るべからず

Twitterのタイムラインで「配列を知らずにシューティングゲーム作る人もいた」というパワーワードを聞いてから頭から抜けなかったので、作ろうとしてみました。
テーマは初診わするべからず(始めた頃のダメダメっぷりを忘れるべからず)

配列を使わずシューティング

作ろうとしてみました…というか、配列を使わずシューティングは自分も以前に作った記憶があります。 確か高校の展示で何となくパソコン使いたかったのでゲームを作ってみた的な。コンピューター部のPC借りてコッソリ作ってました。

最終的にはシューティングという名の別のなにか(回避ゲーム)になった事は覚えています。あと画像が用意出来なくて文字で全部代用したことも。

弾の定義

まず最初の前提として配列を使わず弾を動かします。今回使ったのはUnityですが昔の自分はコンポーネント指向なんて間違いなく理解してなかったので、今回はMain.csを用意してソコに全部書きます。最初の自分はそうしてました。

まず複数の動く弾が存在します。コレを解決する画期的な方法は、変数をたくさん用意することです。 ゲームを初めて作ったときには構造体とかクラスも知らなかったので(というか言語的になかった)座標だけです。

f:id:tsubaki_t1:20181003214506j:plain

おおっと名前が酷い? 最初の自分は確かにこう書いてました。それで変数がどれがどれかわからなくなった的な。HAHAHA

まぁ実際にはpppaとかppaとかppbそうのを合わせて100発分は作ったハズです。リネーム機能?知らない子ですね。
あとは記憶ではxとyが独立した変数として存在したので、その管理も割と大変なことになっていたという記憶ががが

弾を移動させる

次に弾を移動させます。まぁ移動方法は固定で下に移動するだけです。 そこで昔の自分は華麗に関数で移動処理を実装します。
自分の記憶での移動の関数名はコレだった気がします。日記には、なにか画期的な意味があったが思い出せんというコメントを書いたような、書かなかったような。

f:id:tsubaki_t1:20181003215334j:plain

しかし、この関数だけでたくさんの弾を移動する事は出来ません。どうするかって?こうするんだよ

f:id:tsubaki_t1:20181003215513j:plain

for文が使えないなら、その数だけ処理を繰り返せばいいじゃない。
ちなみに当たり判定も似たような感じです。

f:id:tsubaki_t1:20181003215711j:plain

戻り値が無いのは一発即死だからです。コードで言うとApplication.Quit()

感想

こんな感じでクッソ簡単なゲームを作ろうと思いましたが、流石に飽きたので終了。 恐るべきはこのノリでゲームを作りきってしまった昔の自分か

まぁ、あの時文化祭に展示して作る楽しさを知ったからこそ、今の自分があるわけで。今思うとアレだけど良い思い出です。作りきってなかったら多分いまごろ自分は別のことをしています。

勉強して効率的に作れる事も大切ですが、まず作ってみる…というのが自分にとって良い勉強になりました

f:id:tsubaki_t1:20181003220530g:plain

え?コード全文? 勘弁して下しあ

【Unity】指定のコードがGCを発生させるかどうかをテストする(AllocatingGCMemory)

GCガベージコレクション)はコードに紛れひっそりと忍び込みます。
今回はソレを見つけるのに便利なAPIが追加されていたので試してみました。

AllocatingGCMemoryでGCの発生を監視する

Unity 2018.3からAllocatingGCMemoryが新しく追加されました。
このコードとAssert.Thatを使用すると、実装の中でGCが発生しているかどうかをテストすることが出来ます。

Unity - Scripting API: AllocatingGCMemoryConstraint

例えば下のコードはマニュアルのコードです。int aを定義し代入する処理がGCを発生するかといった点をテストしています。 f:id:tsubaki_t1:20181002184258j:plain

ここで少し注意したいのが、IsNUnit.Framework.IsではなくUnityEngine.TestTools.Constraints.Isという点です。
何がどう違うのかは確認していませんが、サンプルコードではご丁寧にusing Is = UnityEngine.TestTools.Constraints.Is;でラッピングしてありました。

実際に使ってみる

実際に使ってみます。
当然テストコードなので、ユニットテストにて処理を実装…という感じのことをしています。一応Runtimeに属するAssertなのでDevelopmentBuildで動くんじゃないかな

コードは下のような感じです。

gist.github.com

結果は下のような感じです。
まぁ普通に配列を宣言したりLINQを使用すればGCが発生しますが、普通に足したりキャストしたりする程度ではGCが発生しません。 f:id:tsubaki_t1:20181002185207j:plain

そういえば昔は構造体や変数をキャストしたりボクシングしたりするとゴミが出てたような記憶があるんですが、今確認すると特に出ないですね。はて?

関連

GCを発生させない」というAPIも追加されました。流石に長時間放置するとゲームが死にますが、「アクションが激しくて絶対に止めたくない」という場合に有効かもしれません。

baba-s.hatenablog.com

【Unity】ECSの並列処理(IJobParallelForやIJobForEach系)でEntityCommandBufferを使う

今回はECSで並列処理した結果をEntityCommandBufferから削除する方法についてです。以前は出来なかったのですが、最近出来るようになりました。

 

 

EntityCommandBufferと非同期処理

使用中のEntity郡に対して、非同期(C# Job System)でアクセスする事は望ましくありません。そのためバッファを別途用意し一旦蓄積、後で一気に処理するというアプローチが望ましいです。

そういった事をしたい場合、EntityCommandBufferを使用して一旦バッファに指示を格納、後で一気に処理するといったを使用します。https://cdn-ak.f.st-hatena.com/images/fotolife/t/tsubaki_t1/20180902/20180902194448.png

tsubakit1.hateblo.jp

規模がでかい場合はExclusiveEntityTransactionを使用するのも良いかもしれませんが、細々としたものはEntityCommandBufferでやるべきです。

tsubakit1.hateblo.jp

このEntityCommandBuffer、以前はIJobでは使えてもIJobParallelForでは使えなかったのですが、気づいたら出来るようになっていました。

EntityCommandBufferと並列処理

EntityCommandBufferを使えると言っても直接は使えません。EntityCommandBuffer.Concurrentを経由してアクセスします。EntityCommandBufferSystem.CreateCommandBuffer().ToConcurrent()インスタンスを取得しジョブに流し込み、後はジョブ側でオブジェクトの追加や削除、Entityの設定等を行います。

なおEntityCommandBuffer.Concurrent経由でオブジェクトを操作する際にはユニークなIDが必要です。これはExecuteの引数のint indexを指定しておけばOKです。

下の例では、指定座標に対して当たり判定を行い、接触していたら削除する…といったものです。以前は一旦バッファに格納していましたが、それが無くても動作します。

 

実際に動かした所、ちゃんと当たり判定の計算は非同期で行いつつ、Entityの削除もちゃんと動作しています。

f:id:tsubaki_t1:20181001220311g:plainIJobForEachWithEntity が使えるようになったので、Entity関連に対してもIJobParallelForを使わずComponentDataとEntityが一緒に取れるようになったのは楽で良いです。

コード

gist.github.com

【Unity】"2D向けの簡単な開発環境"を提供する「Unity Playground」プロジェクト

f:id:tsubaki_t1:20181001000137j:plain

 

 

Unity Playgroundは組み合わせで作るプロジェクト

github.comUnity PlaygroundはUnityを学ぶという目的で少し面白いデモです。
これはプログラミング無しに、事前に用意されているコンポーネントの組み合わせで幾つかのゲーム的な表現を再現することが出来るプロジェクトです。
f:id:tsubaki_t1:20181001000926j:plain

面白いのは、提供しているコンポーネント郡が「○○○を作るための機能郡」ではなく組み合わせで様々なゲームのようなものを構築できる点です。

例えば操作方法や、動かすオブジェクトの役割、ゲームプレイの進行やオブジェクトのスポーンといったスクリプトが最初から用意されており、これらの組み合わせでゲームを作っていきます
スクリプトで記述するより遥かに大雑把な機能しか提供していませんが、色々動かしたり試したりというレベルで見ればアリかなという印象です。

f:id:tsubaki_t1:20181001002429j:plain

 

UIが2D向けに簡略化

PlaygroundプロジェクトではUI表示が幾つか簡略化します。

例えばエディターの幾つかのUIを2D向けに差し替え隠蔽(簡略化)されています。Transformは3D用にZ軸がありますが、Playgroundでは省略されます。またRotationがZ軸のみとなります。カメラに至っては背景色とサイズ以外は何もなくなります。

この辺り、学習するための物を出来るだけ少なくしようという意思が見え隠れしています。

f:id:tsubaki_t1:20181001000434j:plain

このUIはメニューからOFFに出来ます。

f:id:tsubaki_t1:20181001003936j:plain

 

インタラクティブな動作

ゲームを作る上で避けては通れないのがアクションと結果です。アイテムを取ったから障害物が排除される、接触したからダメージ、その他諸々。こういったインタラクティブな要素はコンポーネントとして提供されています。
残念ながらフローを制御する機能は提供されておらず、一次的な反応のみが作れます。

f:id:tsubaki_t1:20181001010349j:plain

動作のイベントに関しては幾つかの機能が提供されています。例えば「範囲内に入ったら」とか「キー入力」「一定間隔で」といった具合。

f:id:tsubaki_t1:20181001005413j:plain

このアクションが成立したとき、様々なアクションを起こします。オブジェクトを消したりダイアログを出したり、シーンをロードしたり。

もしくはUnityEventを呼び出すというオプションもあります。音を出したい場合等はそちらが手軽でしょう。

f:id:tsubaki_t1:20181001005604j:plain

その他、もう少し大雑把なレベルでは「オブジェクトの属性」や「ゲームプレイ」といったものがあります。

HPや接触するとダメージを受ける、アイテムや弾丸、倒したらスコアがもらえる、ボタンを押したら弾が出る、時間が立ったら死ぬ等。

f:id:tsubaki_t1:20181001010016j:plain

f:id:tsubaki_t1:20181001010025j:plain

感想

組み合わせで簡単なゲーム表現を作るプロジェクトでした。
この「組み合わせ」ってのが結構バカに出来なくて、一次機能では大した表現は出来なくても無限に組み合わせる事で結構面白い表現が出来たりします。オブジェクトのON/OFF等を組み合わせてフロー的な表現を実現したり。

 

関連

Playgroundプロジェクトの紹介

blogs.unity3d.comマニュアル(英語)Google翻訳様を通すヨロシ

github.com紹介ムービー

www.youtube.com