Unity公式チュートリアルSurvival Shooter WITH PK Chapter.14「武器変更を実装する」

14.武器変更を実装する

武器の変更システムに思ったよりも時間を食いましたですよ。強化のシステムはいったん延期して、最後に優先度を再検討しませふ。

クラスの構成について

武器変更はPlayerShootingクラスに実装していきます。本当は別クラスに武器の特性等を実装していくべきと思うのですが、やってみたらどの変数をどこに置いてどこから呼び出して……の切り分けに混乱しまったく実装が進まなかったので諦めました。問題意識としては持っているが能力が追い付かない、ってかんじでふ。かなC。

どんな武器を実装するか

今回は「どんな敵を実装するか」から考え、その敵への対抗手段として武器種を用意する、というアプローチをとります。例えば、「バリアを張っており一撃では倒せない敵」に対して、「バリアを貫通し一撃で倒すことのできる武器」を用意するといった具合に。
また、各武器にはデメリットを必ず用意します。ほかの武器の長所を裏返したデメリットを付与することで使えない武器(死に武器)が存在しにくくなります。
先の貫通武器であれば「ただし連射が効かない」といったように。

今回は以下の三つの武器(敵)を用意することにしました。
* サブマシンガン:連射が効き、攻撃力も並み(断続的に登場するオーソドックスな敵)
* ショットガン:広範囲の敵を一度に攻撃できるが、弾一発の攻撃力が低い(一斉に大量登場するが、HPが低い敵)
* スナイパーライフル:貫通し、攻撃力も高いが連射が効かない(盾orバリアを持っておりかつ、ダメージを食らわないでいると盾の耐久が回復する敵)

概要

武器切り替え機能の追加
武器ごとのステータスを設定:ShootメソッドとReloadメソッド

武器切り替え機能

三種類の武器を、キー1,2,3を押すことで切り替えられるようにします。また、切り替えには既定の時間がかかり即時の切り替えはできなくします。

  • enumで宣言した値を、playerWeapon変数に現在の装備として代入
  • Shootメソッド、Reloadメソッドを調整して、ダメージ値やリロード弾数の部分は引数を受けるように修正:引数の詳細は後ほど解説
  • playerWeapon変数を見て、Shootメソッドに渡す変数を切り替える

ChangeWeaponメソッドの追加

Invokeでは引数を渡すことができないのでcoroutineを使うことにしました。
HUDのアイコンを変えたり、残弾数表示の区切りを変えたり、発射レートの値を変えたりしています。

Shootメソッドの改修

めっちゃ長いですが、ショットガンの場合(isDiffuse == true)とスナイパーライフルの場合(isPierce == true)の場合分けを行い、それぞれ処理を追加してます。

拡散能力を付与する

Rayを配列化して、ランダムな前方に複数射出するようにしています。この時、射線の数だけLineRendererを付与したオブジェクトが必要となるため、gunLine変数も同様に配列として宣言し、GunBarrelEndオブジェクトにぶら下げた射線用のオブジェクトからLineRendererを取得しています。

貫通能力を付与する

Physics.Raycastはぶつかった最初のオブジェクトの情報しか取得しないため、スナイパーライフル装備時はPhysics.RaycastAllを使って、Rayがぶつかったすべてのオブジェクトの情報を取得しています。

この時、Enemy以外にもぶつかっているので、EnemyHealthを取得できずTakeDamageを実行しようとしてもNullエラーが出ることがありました。めんどくさがらずEnemyHealthがNullだった場合の分岐を設けなければいけませんでした。

Reloadメソッドの改修

Changeメソッドと同様の理由でcoroutineを使うことにしました。

クラス設計について

冒頭にも書きましたが勉強不足を実感してます。あまりにもメンテ性が悪すぎる……。この記事を書くためにコードを読み返すのが苦痛すぎました。雰囲気でここまでやってきましたが、体系的な勉強を始める必要がありそうです。

次回はコチラ

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.15「特殊な敵を実装する」

前回はコチラ

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.13「敵に射撃がヒットした時、ノックバックする」

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.13「敵に射撃がヒットした時、ノックバックする」

13.敵に射撃がヒットした時、ノックバックする

今回の実装は大きく2つ。本当は1つでもよいのだが、よりコンセプトをとがらせるため追加の実装を行う。
* 銃から発射しているRayが敵にヒットした時、Rayの方向に敵を移動させる
* ノックバックの距離と角度にすこしランダム性を持たせる
* 予定調和にせず緊張感を保たせたい

Rayが敵にヒットした時、Rayの方向に敵を移動させる

ヒットした時の処理に、Rigidbody.AddForce(shootRay.direction)を追加すれば実装できると思っていたが、試してみたところAddForceが効いている感じがない。

公式リファレンスを確認してみると、NavMeshAgentを付与したキャラクターを動かしたいときには、NavMeshAgent.velocityを使えとのこと。

ではそれを踏まえてもう一度。PlayerShootingクラスをいじっているが、EnemyMovementクラスに新たなメソッドを用意してもいいかもしれない。
武器種によってノックバック距離を変えるならPlayerShootingくらす、エネミーによるならEnemyMovementクラスに書くのがよいのだろうが、両方でやりたい場合はどうしたらいいだろうか。今は分からないので棚上げにして、実装を進めよう(EnemyMovementクラスに記述して、PlayerShootingクラスから調整用の引数を渡して実行、が正解な気がする)。

挙動はこんな感じ。

ノックバックの距離と角度にランダム性を持たせる

上まで出来ていればそう難しくない。
距離はnbPowerの取る値をランダム化させれば良いし、角度もshootRay.directionのxとzの値に少しランダム値を±させてやればよい。

これで実装できたのがコチラ。値の幅は調整の余地があるけども、ランダムでノックバックするようになりました。ただ、触ってみた感触もしかしたらランダムいらないかも。思ったより違和感がある。値の調整でも違和感が拭い去れなければ削除しよう。

次回はコチラ

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.14「武器変更を実装する」

前回はコチラ

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.12「射撃にリロードを設ける」

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.12「射撃にリロードを設ける」

12.射撃にリロードを設ける

必要なことは3つ
* 射撃可能回数に制限を設ける(1マガジンで撃てる数)
* ボタンを押すと射撃可能回数が最大まで回復する
 * マガジンの数は無限。資源の管理はこのゲームの面白さに据えないので。
 * オートリロードは設けない。俺のリロードは革命(レボリューション)なので。
 * リロード中射撃できない時間を設ける。マグチェンジではとうてい味わえない緊張感と高揚を戦闘にもたらすので。

完成形はこんな感じ

弾数制限&リロードの基本を実装

PlayerShooting.csをいじるよ。具体的にはこんな感じ
* 残弾数としてint変数currentAmmo、装填数としてint変数maxAmmoを用意
* Shoot()を実行するたびにcurrentAmmoを減らす
* Shoot()の実行条件にcurrentAmmoが0でないことを追加
* Rを押したらcurrentAmmoにmaxAmmoを代入するReload()メソッドを実行

ミスった点として、Shoot()実行前の残弾数をチェックするタイミングがあります。
最初、

という風に、最初に判定してreturnで抜けてしまったところ、残弾が0になった瞬間Update内のすべてのメソッドが効かなくなりました。
ifの一塊だけ抜けて、Update内の次の関数に行ってほしかったんですが、残弾数の判定⇒0なのでUpdateメソッド自体を抜ける⇒次フレームで再度Updateメソッド実行⇒…の無限ループしちゃいました。幸いすぐ気づいて直せました。

リロードタイムを設ける

リロードボタン(Rキー)を押してn秒後にReload()メソッドを実行するようにします。

これでリロード中は射撃ができないようになりました。リロードタイムがこんなにも息吹を……!!

[追記]嘘です。この実装だとリロード中も射撃できます。あとで直す。

残弾数のUI表示

3枚のスプライトを重ね、FillAmountを使って表現します。

実際に用意した画像ファイルは4枚、一番上の外枠と、内枠の区切りを示す一本の黒い線とで2枚に分けました。バランス調整や、別の武器の実装で装填数の異なるUIを作るとき、応用が利くようにしたかったためです。等間隔になるようなPosition設定がめんどいので、1枚で書いてもそんなに手間が変わらないかも。

HUDCanvas下にImageオブジェクトを4つ追加してそれぞれ画像ファイルを設置。
Projectビュー内の画像ファイルTextureTypeをSprite(2D and UI)にするのを忘れずに。

PlayerShootingスクリプトで制御する必要があるのは真ん中の黄色いスプライトのみです。

ついでに、武器変更機能を見越して、装備中の武器がわかるようなHUDも追加しました。

リロード中の表現

グラフィックでやろうと思ったんですが、AssetStoreに無料でいい感じのオーディオ素材があったのでそちらで実装してみます。

MentalDreams, Weapon Soldier Sounds Pack

リロードタイム3秒で丁度SEの長さとあってますが、今後のバランス調整を経てズレてきた場合は、SEの長さを調整する必要が出てきそうです。

これでリロード周りの実装は終わりです。次回はノックバックを実装しますよ~
それとタイトル名決めました。
SurvivalShooter Who In The Hell Punches or Kicks? -やさしい地獄へようこそ-
略してSurvivalShooter WITH PKです。どうぞよろしく。

次回はコチラ

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.13「敵に射撃がヒットした時、ノックバックする」

前回はコチラ

Unity公式チュートリアルSurvival Shooter応用Chapter.11.5「コンセプトを考える」

Unity公式チュートリアルSurvival Shooter応用Chapter.11.5「コンセプトを考える」

11.5.コンセプトを考える

前回の記事を書いた後、大事な手順を忘れていたことに気づいた。
「このゲームをどんなゲームにしたいか」というコンセプトの確認だ。危うく開発が迷走するところであった。
次の実装に入る前に、コンセプトの整理と先に挙げた5つの要素がそれに沿っているか、過不足はないか確認しよう。

このゲームの醍醐味をどこに置くか

このゲームは、何を面白いと感じてもらうものなのか
何をどうしてどうするためのゲームなのか
なぜこのゲームを作りたいと思ったのか、このゲームで何を伝えたいのか

コンセプトはワンピースにおけるログポースだ。桃鉄における目的地だ。母を訪ねて三千里における母だ。
このコンセプトがなければゲーム開発は迷走する。チームでの開発ならいわずもがな、たぶん個人でも規模が大きくなれば何が正解かわからなくなってくるはずだ。その時に立ち返るためのものである。

今回のSurvivalShooterでは、コンセプトを下記の通り定義する。

襲ってくるたくさんのゾンビを、命からがら全滅させるゲーム

なんてことないコンセプトだと思うかもしれない。だが、下記のようなコンセプトを立てた場合と比べてみてほしい。イメージできるゲームの完成図はだいぶ違うのではないだろうか。

  • 武器を持たない一般人がゾンビに見つからないように、朝が来るまで生き残るゲーム
  • 圧倒的な数のゾンビを、圧倒的な火力で蹂躙するゲーム
  • ゾンビがうろつくマップを、限られた資源だけで何日生き残れるか競うゲーム

コンセプトから実装項目を考える

コンセプトによって実装すべき機能、優先度が変わる。
今回のコンセプトでは、どんなゲームデザインをすべきだろうか。

  • 襲ってくるたくさんのゾンビ
    ゾンビは自分に向かって進んでこなければならない。
    ゾンビの同時出現数も多くなるだろう。

  • 命からがら全滅させるゲーム
    ライフは貴重なものになる。
    また、そもそもダメージを食らわないようなプレイングに対してメリットを設けるべきだろう。
    全滅させるための手段を用意する必要がある。
    ゲームクリアの条件になるのはゾンビの全滅だ。

今回順序が逆になってしまったが、前回の記事で挙げた項目とコンセプトとが一致しているかを確認しよう。

  • 11.敵の出現をWaveで管理する
    ゾンビの出現数を管理することは必須である。プレイ開始直後から100体のゾンビに襲われてはかなわない。
    難易度のデザイン、ゲームクリアに欠かせない機能であるため、(Waveという形にするかはさておき)これは最優先で実装すべきだ。

  • 12.射撃にリロードを設ける
    無制限に攻撃できる場合、(敵が一方的に強くならない限り)プレイヤーは命の危機を感じないし、ゲームプレイにも工夫を凝らさない。
    攻撃のあとに必ず「逃げなければいけない」フェーズが訪れることで、プレイヤーに「(生き残るために)今攻撃すべきかどうか」の駆け引きを強いることができる。これも欠かせない機能といえるだろう。

  • 13.敵に射撃がヒットした時、ノックバックする
    敵に攻撃を当てたことへの何よりの報酬は、敵が死ぬことだ。だが、一発で死んでしまっては面白くない。とはいえ、死ぬまで何の報酬がもたらされないのもストレスだ。中間の報酬として「逃げるのが有利になる」ノックバックを与えるのは悪くない。

  • 15.敵の個性を強くする
    たくさんのゾンビを撃ち殺しているうちに、プレイヤーは飽きてくるだろう。彼らに刺激を与えるために「5発撃っても死なないゾンビ」や「遠いところから攻撃してくるゾンビ」を追加しよう。油断していたプレイヤーたちは目を醒まし、再び対策に頭をひねるだろう。

  • 14.武器変更と武器強化アイテムを出現させる
    夢中になって意地悪なゾンビを追加しているうちに、プレイヤーの持つ武器では対処しきれないモンスターを作ってしまうかもしれない。これではプレイヤーはストレスや理不尽を感じてしまうだろう。フェアなゲームとするために、彼らにも新たな武器を与えよう。嬉々としてゾンビ狩りに精を出してくれることだろう。

さあ実装しよう

前回挙げた実装項目の中には、幸いアテを外しているものはなかった。自分の中でコンセプトは割としっかり固まっていたようだ。が、実装を進める中できっと「これも入れたら面白いだろうな」と思う機能が出てくるだろう。すでにいくつか新しいアイデアは生まれている。だがすべての機能を実装することは時間の面でも根気の面でも不可能だ、取捨選択をしなければならない。その時、ここでコンセプトを明文化していたことが役に立つであろう。

次回はコチラ

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.12「射撃にリロードを設ける」

前回はコチラ

Unity公式チュートリアルSurvival Shooter応用Chapter.11「敵の出現をWaveで管理する」

オフ会用の名刺をいますぐ120円で作る方法

あ!名刺つくらなきゃ!

急遽あるオフ会に参加することにしたので、名札代わりの名刺を作ることにしました。開催は明後日。業者に頼んでいては間に合わないので、コンビニのプリントサービスを利用したところ1時間でゼロから名刺がつくれました。費用は120円/10枚。
「すぐ作りたい」「名刺の新しいデザインを試したい」ような時にはオススメ。
一方、「大量に作りたい」「急がないからコスパ優先」みたいな時には素直にラクスルなどのサービスを利用したほうが良いでしょう。

必要なもの

スマホ
PC
コンビニ(ローソンorファミマ)
120円
カッター
定規

手順

  1. PCでデザインする
  2. 作ったデザインをpdf形式で保存しスマホに転送
  3. コンビニで印刷
  4. カッターで切断
    以上です。

PCでデザインする&pdfで保存

こちらのサービスを利用しました。

ラベル屋さん.com http://www.labelyasan.com/

インストール不要で使えるWeb版がラクチンです。
新規作成>名刺用>必要な用紙サイズ(僕は「品版51164」を使いました)>好みのデザインテンプレート
を選んだら、名前と必要な情報を追加するだけで名刺のデザインは完成です。

右上の「レイアウト」に進み、「選択面のコピー」は「全て」を選んだら

「印刷」に進み、「PDF出力」を行います。

出力されたファイルをご利用のオンラインストレージ等を経由してスマホに転送しておきましょう。
これでPCでの作業は終わりです。

コンビニで印刷

pdfファイルをコンビニのプリントサービスで印刷するには専用のアプリをインストールしておく必要があります。

PrintSmash http://www.sharp.co.jp/multicopy/prsm/
UIが親切なので、コンビニのプリンタの前で指示に従えばスムーズに進みます。
用紙は「A4光沢紙カラー」(\120)を使いましょう。一般的な名刺ほどではありませんが、コピー用紙よりもしっかりした紙です。

カット

おうちに帰ったらカッターやハサミを使ってきれいにカットしましょう。この工程が一番難しいかもしれませんw

完成!

できました。

調べる+デザインの時間も込みで1時間なので、それがサクッと終われば30分もかからないと思います。
ただ、普通の名刺の紙に比べたらペラいので、あくまで緊急用か、自分のように名札としての利用が良いと思います。

Unity公式チュートリアルSurvival Shooter応用Chapter.11「敵の出現をWaveで管理する」

今回からは、「こうやったらより面白くなるんじゃないかな」というポイントをいくつか挙げて、自分流にアレンジしていくよ。具体的には以下の5つを実装していこうと思う。

11.敵の出現をWaveで管理する
12.射撃にリロードを設ける
13.敵に射撃がヒットした時、ノックバックする
14.武器変更と武器強化アイテムを出現させる
15.敵の個性を強くする

それぞれを実装する理由は各記事で解説していくよ。さっそく始めよう!
[追記]コンセプトの整理を忘れていたので次回の記事で、各項目の実装理由を整理しまする。

11.敵の出現をWaveで管理する

面白いゲームプレイには、だんだん上昇していく難易度と目標が不可欠だ。現状では敵の出現は散漫かつやむことがなく、自身が力尽きるまで悪夢が終わることはない。
出現する敵の種類、数を一つのWaveとしてパッケージングし、この問題に対処しよう。

実装概要

EnemyManagerスクリプトの書き換え
* SpawnメソッドにエネミーのPrefabを引数として渡すことで、アタッチするスクリプト1つで完結させる

* 実際にはWaveのさらに細かい概念を用意(便宜上Levelと呼ぶ)、各レベルごとにメソッドSpawnWaveW_L()で、スポーンするエネミーの数、種類を指定する

* 各Waveの開始時には、Wave開始を告げるUIを表示する
* 最終Waveの最終レベルで出現するエネミーを全部倒したらクリア画面に移行する

Spawnメソッドを書き換え、出現する敵をスクリプトで指定できるようにする

ずばりこうじゃ!

これで、各GameObjectに設定したPrefabのエネミーをスポーンさせることができる。

Wave毎にメソッドを用意し出現する敵を決める

例えばWave1のLevel1で出現する敵を呼び出すメソッドはこうなる。

超シンプルですね。
では、このメソッドの実行はどこから呼び出そうか?
そのアプローチが次。

Waveクリアを判定し次のWaveへ進む

これには、EnemyManagerクラスのみならずEnemyHealthクラスにも手を加える必要がある。
ざっくり言うと「Levelの初めにスポーンした敵を倒して残りが0体になったら、次のレベルのSpawnWaveメソッドを実行する」という実装です。

ちなみに、Wave1-1はStartメソッドからInvoke関数で実行してます。

まずはEnemyManagerクラスがコチラ。
※Levelと命名すべきところもWaveと命名して実装してしまってます。
 実装時は”Wave1-1″でいいや~と思ってましたが、ブログにまとめる段になって”Wave1-1“を説明する言葉がないと不便なことに気づき急遽Levelと呼ぶことにしたためです。

そしてEnemyHealthクラスの調整がコチラ。

ここまでできれば機能の実装はほぼ終わったようなもの。
あとはWave開始を知らせるUIとクリア画面を作って表示するだけです。

Wave開始を知らせるUIのアニメ作成とその表示

チュートリアル内でゲームオーバー画面を作った時と同じ要領で、AnimationのClipを追加する。

完成形はこんな感じ

HUDCanvas下にWaveTextを追加し、見た目を整える。設定はこんな感じ。

HUDCanvasのアニメータにWaveClipを追加して、WaveTextが左から登場して右に消えていくようアニメを作る。設定はこんな感じ。

ここで一瞬詰まったのが、テキストの位置を動かすときにPosition(Z)でなくAnchoredPositionをプロパティにしなければならないということ。(下記Reddit参考)

Animation on Rect Transform I can’t see position X & Y. What is position(Z)? Can I get the X & Y position on position(Z)? from Unity3D


理由を考えるに、画面サイズが変わった時にPositionで指定していると意図しない挙動になりそうだから、とかかしら。

アニメータのNewStateからWaveClipへのTransitionを引き、Waveトリガーを作成しくっつける。

WaveClipからNewStateへ戻るTransitionも忘れずに。こちらのTransitionはHasExitTimeにチェックをつけておこう。

各Wave最初のLevelのエネミースポーンメソッドに、SetTriggerを追記したらOK!

クリア画面のアニメ作成とその表示

こちらもWave表示とやることは同じ。

クリア画面の完成形

HUDCanvas下にClearTextを追加。

設定はこう

ClearClipを作成。

Animatorを設定。

Transitionは一方通行でOK。

Levelクリア処理に、「最終Levelをクリアした時」の条件分岐を追記。ついでにスペースキーでリトライもできるようにしておく。

これで実装は終わり!次は武器の残弾とリロードをやっていくぞ!

[追記]コンセプトの整理を忘れていたので、次回はそれを挟む。実装はそのあとから。

次回はコチラ

Unity公式チュートリアルSurvival Shooter応用Chapter.11.5「コンセプトを考える」

前回はコチラ

Unity公式チュートリアルSurvival Shooter日本語実践Chapter.10

2019年がやって来たヤァ!ヤァ!ヤァ!

2019年明けましておめでとうございます。
正月休み最終日の夜。最高にテンションの上がらないこのタイミングで、2018年の振り返りと2019年の目標を整理しておこうと思い立ち。さっとまとめるつもりでしたが芋づる式に書きたいことが浮かんできてしまったので、なんのために働くのか、どんなゲームが作りたいのかについても一緒に整理しておこうと思います。長いポエムです。

2018年は、自分の将来のために時間を使う、ということを意識し始めることができた一年でした。その中でなにより大きいのは、Unityでのゲーム開発(&勉強)を改めて再始動させたこと。これは大きな前進だったと思っています。
17年の4月ころに、新卒から4年間勤めた会社を退職し、規模20人程度の現職へ転職。職種もプロジェクトマネージャから企画職へ転じ、要するに市場価値がほとんどない状態のチャレンジでした。
ただ残念ながらこのチャレンジは順調とは行かず、18年頭ころは再転職を視野に己の身の振り方を考え直さねばならなくなりました。これが非常に苦しかった―――。

―――僕がまだ小学生だったころ、”真・三國無双2”というゲームが発売されました。僕の母親はゲームそのものに対してあまり良い感情を持っていなかったようですが、このゲームをきっかけに三国志にハマる僕を見ていろいろ本を用意してくれました(逆に”グランドセフトオート3”をプレイしている時の僕を見る母はしかめっ面でした)。
この体験が大きく作用し、僕は中国文学の専攻を念頭に志望大学を決めました。

6年前(!)、僕も就職活動をする時期でした。無事に中国文学の研究室に潜り込むことはできていましたが、それに対する興味はかなり衰えていました。いま振り返るなら、幼い子供がウルトラマンや恐竜、電車の種類を覚えることに夢中になるような一過性のものだったのでしょう。とにかく進学という選択肢はありませんでした。起業ということは露ほども考えていませんでしたので、まあ無難に就職活動。それでも一本、軸は通さねばと建てたのが「好きなことを仕事にする」でした。なんとも曖昧ではありますが、今考えても悪くはなかったかなと思います。ラジオとマンガとゲームが好きでしたので、ラジオ局と出版社をつまみつつ、ゲーム会社をメインに就職活動していました。

「私は、幼いころからテレビゲームが好きです。テレビゲームをきっかけに、別の世界への扉を開くこともできる。なのに、世間のゲームに対する風は依然冷たいままです。私はこれが悔しい!古くは小説、20世紀に入ってからは映像がその文化的価値を上げてきたように、ゲームという文化の価値も上げていきたい。」

ゲーム会社への志望動機はこれをベースに固めました。当時の任天堂社長だった岩田聡も、こんなようなことを言っていました(と解釈してました)。テレビゲームがお母さんに受け入れてもらえる文化にならなければならない、と。(ちょっと古いですがこの辺

この気持ちを一本小脇に抱え、企業研究して向こうに合わせていくようなことはせず、「俺はこれがやりたいんだ、どうだ?」という攻め方でした。なんとも具体性を伴わない志望動機な上に図々しいやり方でしたが、一社だけ内定を出してくれたところがありました。任天堂は書類で落ちました。

ゲーム会社に内定をもらえたといっても、当時の僕は自分にゲームが作れるとは露ほども考えておりませんでしたから、非開発職です。プログラミングなんか文学部には無理無理。ざっくりいえば営業とか人事とか総務とか経理とかパブリシティとかライセンスとかです。そういう仕事で、この思いを実現したいと考えていました。
入社後の面談でもそういったことを伝えていきました。そして研修終了後、発表された配属は”プロジェクトマネージャ”でした。何ですかその仕事は?ワケが分かりません。
……ふむふむなるほど。まずは開発の現場を直で知らないとオハナシになりませんよと。確かに一理ある。プロマネというのはプロジェクトを俯瞰する立場で全体を見渡すので、非常に勉強になりますよと。なるほどね。なんか難しそうだけど大丈夫なのかしら―――?

えっちらおっちらプロマネをやっていた時のことを書くのはまた別の機会に譲るとして、4年経ったころに僕はこんなことを考え始めるわけです。

・プロマネだけ続けててもやりたいことできねえな
・ゲーム業界、偉くなれるのは実際に作れた奴だけだな
・ゲームを娯楽以外の目的に応用する”シリアスゲーム”って分野があるらしい

担当していたプロジェクトの切れ目が重なったこともあり、僕は本格的に転職活動を始めます。この時16年の末頃。最終的な転職タイミングでは間も悪く、当時の上長が図ってくれた異動の便宜もぶち壊すグダグダな退職になりました。本当に申し訳ない。

自分の本意に沿うという意味では転職活動は成功でしたが、上述の通り18年初に改めて自分を見つめなおす必要性に迫られます。

企画職としての経験は充分とは言えず、プロマネにも戻りたくない。自分のやりたいことも捨てたくない。こうなると転職先は非常に限られます。いや、限られるどころか自分の意志を曲げないで済むことはできないように思われました。

そんなときオフィスの本棚に”Unityの教科書”を見つけました。(急に胡散臭いブログっぽくなってきたな……)

Unityは、前職の末期にすこし勉強を始めていましたが、転職活動のバタバタでめっきりご無沙汰になっていました。一本自力でゲームを作り切ることができれば、企画職としてレベルアップできるだろうと一念発起、この窮状を打破すべく藁にも縋る思いで、Unityを使ってゲーム開発を始めました。プログラミングも始めてみれば全く歯が立たないなんてこともなく、勉強すればしただけ前に進める確かな実感がありました。

僕が2018年、Unityを使ってゲーム開発を始めたのはこんな経緯があったのでした。

さて2019年も幸運なことに、僕のやりたいことは新卒当時のまま変わりません。
本業の方はなかなか苦しいままですが、本業と個人開発とでうまく経験値稼ぎの両輪を回しつつやっていければとポジティブにとらえることができるようになっています。
2019年の目標を掲げておきましょう。

・個人で「これは面白い」と自分で思えるものをリリースする
・遊んだ人がフラットな評価で「面白い」と言ってくれるものをリリースする
・遊んだ人が「役に立った」と言ってくれるものをリリースする
・個人で1円以上のマネタイズに成功する

2019年が僕にとって、読んでくれた皆さんにとって良い年になりますよう。

Unity公式チュートリアルSurvival Shooter日本語実践Chapter.10

10.GameOver

とうとう最終章。今回はプレイヤーの体力が0になった時のゲームオーバー処理を実装してする。
画面UIをアニメーションさせる方法が今回のキモ。

ゲームオーバー画面の下準備

ゲームオーバー画面背景

HUDCanvas下にImageオブジェクトを作成、名前をScreenFaderとする。
Anchor:Altをクリックしながら一番右下を選択する。これによってCanvas領域全体に画像を引き延ばす。
Color;いい感じの水色に設定する。これがゲームオーバー画面の背景となる。

ゲームオーバー画面テキスト

HUDCanvas下にTextオブジェクトを作成、名前をGameOverTextとする。設定は下記の通り。
Anchor:中央
Width,Height:300,50
Text:Game Over!
Font:LuckiestGuy
FontSize:50
Allignment:中央真ん中
Color:白
Shadowコンポーネントを追加し、EffectDistance(2,-2)

HUDCanvas内の配置順整理

Scene内のオブジェクトは、Hierarchy画面で上にあるものから順に重ねて描画される。一番上のものが一番奥に、一番下のものが一番手前に描画されることになる。オブジェクト内の子オブジェクトも同様だ。HUDCanvas内には、ゲームオーバー画面に表示したいものとそうでないものがあるため、配置順を下記の通りに整理する。 
(上から)
HealthUI
DamageImange
-ここから下がゲームオーバー画面に表示したいもの-
ScreenFader
GameOverText
ScoreText

ゲームオーバー画面のアルファ値をゼロに

ゲームオーバー画面にかかわるパーツ(ScreenFaderとGameOverText)のColorからアルファ値をゼロにして透明にしておく。

ゲームオーバー画面のアニメーション作成

Animation作成

なんと!UnityのAnimationはキャラクターのモーションだけでなくUIその他なんでもアニメにできるのだ!今回はUIのアニメを作成するぞ。
HUDCanvasを選択した状態でメニューバーからWindow>Animation>Animationを選択する。このAnimationはGameビューの表示位置にドッキングさせておくと便利らしい。Unity2018ではAddCurveのボタンがAddPropertyになっているので注意。RecordModeをオンにしておくとSceneビューで直接動きをチェックしながら作れて便利っぽい、が今回は特に利用しないっぽい。

AddPropertyからアニメさせる要素を追加していく。今回は下記の4つ。
GameOverText.Text.Color:30フレーム目でアルファ値を1に設定
GameOverText.RectTransform.Scale:0フレーム目で(0,0,0)、20フレーム目で(1.2,1.2,1.2)、30フレーム目で(1,1,1)に設定
ScreenFader.Image.Color:30フレーム目でアルファ値を1に設定
ScoreText.RectTransform.Scale:30フレーム目で(0.8,0.8,0.8)に設定

ゲームオーバー画面表示処理に移行してから全体で30フレームですべてのアニメが終了するのは早すぎるので、アニメの開始タイミングを1秒と30フレーム後に変更。

Animationウィンドウの要素の意味は大体こんな感じ

なんてこった……!たったこれだけで、「90フレームかけて透明から水色の背景に遷移しつつ、白のゲームオーバーテキストを色・大きさ共にフェードインさせ、ついでにScoreTextの大きさもちょっぴり小さくして動きのメリハリをつける」アニメーションが完成しちまったぜ!あとはこのアニメを再生するタイミングを制御するだけだな!
オッといけない、このAnimationはLoop設定がOnになっているから、GameOverClipからLoopTimeのチェックを外すのを忘れないようにしないといけない。

AnimatorControlleのHUDCanvasをダブルクリックで開き、空のStateを作成したらそれがデフォルトStateとなるよう設定。そこからGameOverClipへのTransitionをつなぎ、遷移条件のParameterとしてTriggerのGameOverを作成、設定しておく。

GameOverManagerスクリプト

HUDCanvasオブジェクトに、GameOverManagerスクリプトをアタッチしたら実装はほぼおしまいだ!GameOverスクリプトの中身を確認するぜ!あ、あとBGMのPlayOnAwakeをオンに戻しておくのを忘れずにな!

実装確認

無事に動けばおめでとう!これでこのチュートリアルはおしまいだ!
ここでやめてしまってもいいんだが、少しいじってこのゲームをもっと面白くしたいと思う!のでもうちょっとだけ続くんじゃ!

第11回はコチラ

Unity公式チュートリアルSurvival Shooter応用Chapter.11「敵の出現をWaveで管理する」

第9回はコチラ

Unity公式チュートリアルSurvival Shooter日本語実践Chapter.9

Unity公式チュートリアルSurvival Shooter日本語実践Chapter.9

9.Spawning Enemies

Prefab化したEnemyを、プレイ中にスポーンさせる処理を実装する。チュートリアルや教本でよく見るオーソドックスな方法がベースになっているものの、スポーンする種類の増やし方や複数のスポーン地点の設定など、今後のために押さえておきたいポイントも含まれている。

なお筆者の環境(Unity2018 2.1f1)では、PrefabにZomBearとHellephantが存在しなかったため、Complete-Gameフォルダからその2つのPrefabをコピーしてきた。その際、ScriptはComplete-Gameフォルダ内のものを参照していたため一度リムーブし、MyProject内のScriptに付け替えた。

ZomBear,HellephantにAnimatorを設定

ZomBearの場合

ZomBunnyと同じアニメーション、ステート、パラメータを流用できるため、ZomBunnyと同じEnemyACをそのままAnimatorのControllerとして設定する。

Hellphantの場合

モデルの大きさや骨格、関節が異なるためEnemyACをそのまま流用することができない。このような、異なる骨格、アニメーションを持つモデルでも、同じステート、トランジションを流用したいときに登場するのがAnimation Override Controllerである。
Projectパネル内で新たにHellephantAOCを作成したら、InspectorのControllerに基となるAnimationControllerをD&Dで設定する。するとその下に、ステートの一覧と上書きするアニメーションを設定するカラムが表示される。今回は、Hellephantのモデル内にあるMove,Idle,Deathのアニメをそれぞれ上書きする。
最後にHellephantのAnimatorコンポーネントのControllerにHellephantAOCを設定して準備完了。

何が同じアニメーションで、何がそうでないのか、については一度3Dのモデリングを学んだほうが理解が深まるような気がする。今の時点では、BunnyとBearは大きさも骨格も同じだから表面のテクスチャだけ張り替えてアニメを流用してるんだろうな、というくらいの理解で流しておく。というかそうしないとドツボにはまりそう……。

EnemyManagerの準備

空のGameObjectを作成し、EnemyManagerとリネームする。スクリプトEnemyManagerが用意されているのでそれをアタッチし中身を確認しておく。

変数

Startメソッド

Spawnメソッド

EnemySpawnPointの準備

上記のpublic Transform[] spawnPointsに代入するため、EnemyごとにSpawnPointを準備する必要がある。まずはZomBunnyのSpawnPointを設定するため、空のGameObjectとしてZombunnySpawnPointを作成する。空のGameObjectを視覚化するため、Inspectorの名前の横から色を設定することができる。ZonbearSpawnPoint,HellephantSpawnPointも同様にコピーペーストして作成し、それぞれ既定のPositionへ置く。

EnemyManagerの設定

EnemyManagerのPublicな変数にInspectorから値を設定して行く。
PlayerHealthは、前述したようにPlayerオブジェクトをそのままD&D。
EnemyはまずZomBunnyのPrefabをD&D。(つまりEnemyの数だけEnemyManagerスクリプトをアタッチし設定する必要がある)
SpawnTimeは3のままでOK。
SpawnPointsは一見D&Dする場所が無いように見えるが、先ほど作成したEnemySpawnPointをD&Dすれば配列の1要素として設定することができる。二個目をD&Dすれば配列の二個目として、どんどん追加していける。

ZomBear,Hellephantの分もEnemyManagerスクリプトをアタッチ、設定したら今回の作業は完了だ。
おっと、HellephantのSpawnTimeをちょっと短くするのを忘れずに。

実装確認

いろんなところからいろんな敵が出てくるようになった。だんだんゲームの様相を呈してきたぞ。
ゾンビゲーらしくラッシュとかあってもいいなあ。

第10回はコチラ

Unity公式チュートリアルSurvival Shooter日本語実践Chapter.10

第8回はコチラ

Unity公式チュートリアルSurvival Shooter日本語実践Chapter.8

Unity公式チュートリアルSurvival Shooter日本語実践Chapter.8

8.Scoring points

今回は、Enemyを倒したときにスコアを獲得する処理を実装する。大きく分けて下記の段取りだ。

1.スコアを表示するUIを準備
2.Enemyを倒したとき、そのUIを書き換えるスクリプトを実装

スコアを表示するUIを準備

HUDCanvasの子オブジェクトとしてUIのTextをオブジェクトを作成。アンカーを中央上部に設置したら、Positionを(0、-55,0)に設定。Widthを300、Heightを50、textのColorを白、FontをLuckiestGuy、FontSizeを50に設定。Alignmentも真ん中中央に揃え、テキストの内容を”Score:0″に変更しておく。
文字に影をつけるためShadowComponentをアタッチしたら、EffectDistanceを(2,-2)に設定しておく。これは、文字の影を本体からどのくらいの場所に置くか、の設定であり、数字を大きくすればその分だけ影が文字から離れていく。

Enemyを倒したとき、そのUIを書き換えるスクリプトを実装

ScoreManagerをScoreTextにアタッチ。ScoreManagerの中身を確認しよう。

ScoreManager スクリプト

変数

public static int score:獲得したScoreを格納する。public staticの説明はちょっと適切にできる自信がないが、下記のように解釈している。

staticでない変数は、このスクリプト≒クラスがアタッチされたオブジェクト毎に生成されている(この生成すること、生成されたものがInstance)。オブジェクトAでは100という値をとっていても、オブジェクトBでは200という値をとっている、ということがあり得るわけだ。
一方staticな変数はクラスに紐づいて生成されている。複数のオブジェクトにスクリプトがアタッチされていようと、オブジェクトAで100という値を記録すれば、オブジェクトBでも100という値に書き換えられる。
また、そのため他クラスから参照する際にFindでオブジェクトを指定する必要がなく、クラスから直接呼び出すことができる。
あと、シーンが変わっても破棄されない。これも、オブジェクトでなくクラスに紐づいているから。

いままでStaticを使ってきた感じと、この動画の中での解説を統合して以上のように解釈してる。もし間違ってたらゴメンナサイ。

Text text:ScoreTextのtextコンポーネントを格納。

Awakeメソッド

text = GetComponent():ScoreTextのtextコンポーネントを格納。
score = 0:Scoreをリセット

Updateメソッド

text.text = “Score: ” + score:Textコンポーネントに文字列”Score: “と整数scoreを代入

EnemyHealthメソッドの修正

Enemy死亡時に実行されるメソッドStartSinkingの中にコメントアウトされていた下記一文をコメント解除。
ScoreManager.score += scoreValue:scoreに、scoreValueの値を代入

実装確認

Enemyを倒したときにScoreに10点加点されることを確認

ZonBunnyをPrefab化

次回、ZonBunnyのスポーンを実装する。それに備えてZonBunnyをPrefab化し、Hierarchyから削除しておく。

以上!前回に比べたらあっという間でしたね~

第9回はコチラ

Unity公式チュートリアルSurvival Shooter日本語実践Chapter.9

第7回はコチラ

Unity公式チュートリアルSurvival Shooter日本語実践Chapter.7