Unityはじめの第一歩

無限に登場するまるとらをクリックしたら、隣接する同種を巻き込んで消滅するツムツムクローンを製作中。ツムツムやってことないけどルールは多分同じ。クリックしても隣接虎が消えない時があるんだよね、再現性は無くランダム。隣接判定にミス?クリックしたら消える虎たちをマウスオーバー時に半透明処理を施すと…。謎の明滅を開始。わけが分からなくて解決できず困った。

原因はわかった。Unityから呼び出される関数の順番によるエラー。各オブジェクトのUpdateが呼び出される順序は原則ランダム。優先順位が付けられるが、クラス単位での順位。インスタンス同士の順序はどうやるんだろ。相互に依存していて情報をやり取りしているとまずい場合があるね。通常のUpdateと物理エンジンのUpdateは別物だったことも原因。文字で説明すると面倒なので省略。解決したからOK

虎消滅時に小さい虎を多数登場させて分裂消滅させようと思ってパーティクル機能のお勉強を開始。パーティクルにアニメーションを設定できるから、絵の切り替えなしアニメを設定したら想定の動作をするはず、っていうか動作成功。虎の種類によって絵を切り替えようとしたところで絶望。startframeの数値を変えればできるはずだが、設定が反映されない。コードからの変更は出来ないの?まったくわからないから放置。最悪、手間ひまかけて数十個のプレハブに個別設定すれば解決…。うわめどい。

パーティクルは無視して次へ。

虎消滅後即座に他の虎たちが落下するけど、消滅時はすべてを一時停止したいよね。物理エンジン止めると全部止まってあかん。個別に止める方法あるかな?

Time.timescaleを変更せずにRigidbodyの一時停止&再開処理【Unity】【拡張メソッド】 – (:3[kanのメモ帳]

あったわ。速度と回転量を保持して復帰かー。そりゃそうか。ついでにプロパティと拡張メソッドを覚えたぞ!

一時停止と再開が出来るようになった。コレを利用して、消滅時に演出を表示しつつスコア表示してからゲーム再開の処理を組み込んでみよう。switchや関数ポインタでゴリゴリ切り替えても良いが、C#ってコルーチン使えるよね?調べてみるべー

UnityのCoroutine(コルーチン)でできる事のメモ – テラシュールブログ

消えるときに一時停止させることに成功。効果音も鳴らせたし、最低限の機能は把握できたのかしら?シーン遷移時にデータの受け渡しはどうやるのだろう。

WebGL版ぽち潰し

フォントが無いらしく、スタード画面でタイトル文字が表示されない。設定どこ?

つむつむやったことない

他のチュートリアルも見ておこう。まずはInterface & Essentials。これ超基本だけど知らない操作もあるだろうから全部見た!見終わった!これで!私!うにちーますたー!!

チュートリアルでちゃんと学べたのか試すために、ゼロからゲームを作れるか試してみましょ。

数時間後

ごめんむり。すべてのオブジェクトをコードから生み出そうとしたけど、そんな方法わからんがな。諦めて別の方法を取ろう。すべてのオブジェクトはシーンに配置しましょう。動的生成なんて後回しだ。

まるとらずを配置して、重力の作用で、画面外へ落下。床を作るためにイカちゃん海の家を配置。当たり判定をどうやって作ろうかと思っていたら、線分配置も対応してんのな。輪郭をなぞってコリジョン完成。ゲームだから、まるとらずがどんどん増えていって欲しい。つーわけでプレハブ作って動的生成だー!

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-10-18-01-15-54

イカちゃんがまるとらずを投げる感じ?下にどんどん積み重なる。

クリックしたら消えて欲しい。マウス位置とクリック検知を仕込み、まるとらずとコリジョン取ってDestroy(this)を記述したらあら不思議、バグ!Destroy(gameObject)にしないとダメなんだってさ。thisだとC#コードだけ外れる。罠すぎるわ。

隣り合うとらも消えてほしいけど、隣り合ってるって判定どうすんの?判定時にコリジョンを大きくしたらいいのかしら。衝突時に相手のIDを保存させる方が楽かな?って、コリジョン判定してくれない。小一時間悩み抜いた末

void OnCollisionStay(Collision collision)

ではなくて

void OnCollisionStay2D(Collision2D collision)

このように2D指定しないとダメだってさ!気づかんわ!!

修正したけど永久ループでUnityフリーズ。あー、相互に呼びあって終わらんわコレ。

処理を修正して解決したけど別の問題が発覚。見た目では接触して隣り合ってるようにみえるけど、隙間があって接触してないから消えない。ゲームとして作り込むと、見た目との相違でプレイにストレス溜まる?コリジョン大きく取って判定したほうが良いのかな。コリジョンだけスケール変更できたら良いのに…。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-10-18-01-15-55

exe、apk、ブラウザ上の3つで動作確認OK。このサーバにUPしての動作もOKであった。

C#のコード量は50行程度なんだよね。それでも苦戦中

sceneLoadedで詰まる

アンドロでの動作確認をいちいち実機でやるの面倒だよね。エミュレータ使えば楽になったりする?ってことで調べて

英語とか Unityで作成したアプリをAndroid Studioのエミュレータで動かす

エミュ動かせるまでにはなったけどさ、Unityでビルド&ランを実行したらビルドは瞬時に終わるんだけど、エミュへのインストールに5分以上かかってまじうざい。実機へファイル転送してからのインストするほうが時間が短いってどういうことだよ。エミュの出番ないじゃん!複数解像度試せる利点はあるから良いのか。何か設定が悪いのかしら?

エミュは一旦我慢するとして、サンプルコードに以下の関数が有りましてね

//This is called each time a scene is loaded.
void OnLevelWasLoaded(int index)
{
   //Add one to our level number.
   level++;
   //Call InitGame to initialize our level.
   InitGame();
}

OnLevelWasLoadedが非推奨になって将来廃止予定だよって警告がでるの。代替案があるんだろ?って探したらSceneManager.sceneLoadedを使えば良いらしい。あまり深く考えずに書き換えてみよう。要点抜き出すと

void Awake()
{
    SceneManager.sceneLoaded += TestSceneLoaded; 
}

void TestSceneLoaded(Scene sceneName, LoadSceneMode sceneMode)
{
    level++;
}

これで解結すると思ったらバグ発生。ローグライクでlevel1(1階層目)から始まるはずが2でスタート。次のlevelへ移動したら数値が+1ではなく+2される。なんじゃこりゃー。Awakeが複数回呼ばれてsceneLoadedへ関数2回登録したとか?調べたけどそんなことはない。Loadedがゲーム開始時に1回呼び出され、レベル変更時には二回呼び出されてる。なんで?

そもそも、Levelは1で初期化してんだよね。シーン呼び出し時に+1されるのだから、2から始まるのは当然か。最初のサンプルコードでは何故+1されず1でスタートしてんの?OnLevelWasLoadedが呼び出されてないんじゃね?調べてみると

Awake
OnEnable
OnLevelWasLoaded
Start
の順番で呼び出される。
Awake,Startはひとつのオブジェクトについて、一度しか呼ばれない。
しかし、OnEnableは、Enableされるたびに呼ばれる。

で、OnLevelWasLoadedが呼び出されてないんだがどういうことだよ。よくよく調べてみると、最初のシーンロード時はOnLevelWasLoadedが呼び出されないんだってさ。

わ か る か よ

名前見たらロード後に呼び出すとしか思わんわ。2回目からのロード時に関数が呼び出されるのなら、OnLevelWasLoadedの話は解決。次はsceneLoadedの仕様を解かねばならぬ。解説ブログをぐぐり

  1. Awake
  2. SceneManager.sceneLoaded
  3. Start

の順番で呼び出しが発生すると判明。つまり

Startでメソッドを登録すると最初のシーンでは実行されず
Awakeでメソッドを登録すると最初のシーンでも実行されます

あーなるほど、そういうことか。

わ か ら ね ぇ Yo!

結論として

void Awake()
{
    //SceneManager.sceneLoaded += TestSceneLoaded; 
}

void Start()
{
    SceneManager.sceneLoaded += TestSceneLoaded;
}

void TestSceneLoaded(Scene sceneName, LoadSceneMode sceneMode)
{
    level++;
    InitGame();
}

こう書けば良いのでした。

【Unity】OnLevelWasLoadedとSceneManager – うら干物書き

Unityローグチュートリアル完了

2Dサンプルなローグゲームチュートリアルを無事に完遂。本当に基本だけのチュートリアルだから、色々いじって使い方を覚えていくのが妥当。何を変えようか。イカちゃんローグの絵を持ってきて貼り替えるところからやってみる?

それはともかく、Winデスクトップアプリ以外にAndroidなAPK出力にも成功。スマホとガラホに入れて動作確認もOK。WebGLが選べたのでやってみたけど、ビルドに30分近くかかったんだよ。この規模が小さいソフトでこれって…。なおかつブラウザで正常動作しないオチがついてきた。chromeとfirefoxどちらもアウト。こりゃどうにもならぬ?何か設定あるんかね

無料の3Dモデルが無いかと探していたら

ImagineGirls – ImagineGirls オフィシャルサイト

エロもOKらしいよ。

二択:英語orポルトガル語

Unityの書籍は手元に2冊あるけど、今作りたいゲームとは方向性が違うので封印。Unity入門や学習個人サイトがたくさんあるけど、ちょっと肌に合わぬ。公式サイトにあるチュートリアルで学んで全体を把握するのが最初は良いかしら?ってことで

1

全部英語でござる。すべての動画に字幕を付けてる人が居るらしく、聞き取れなくても安心。一時停止して英文読めば何とかなる程度のレベル。英語わからなくてもコードと操作方法を見ればわかるよ。んなわけで2Dの基礎とローグタイプを題材に簡単なものを模写なう。

日本語訳は無いけどポルトガル語はあるんだよ!何故ゆえに…

Unityの中の人はもうちょっと頑張っていただきたいであります。みんな書籍出してるからそれ買ってくれ、で済ませる姿勢はわからんでもない。