問題作「MCバトルOnline」は如何にしてコケたか?@第11回Unity1week「つながる」

第11回Unity1weekに参加した

2019年03月11日(月)〜03月24日(日) に開催された第11回Unity1weekに参加しました。
今回制作したゲーム「MCバトルOnline」は「対戦相手とオンラインで、ラップのように韻をつないでいく」というゲームです。
「ほう、どれいっちょ遊んでみっか!」と思ってくださった菩薩のようなあなた。本当にありがとうございます。ですが、お気持ちだけで結構です。なぜかというとおそらく遊べません

だって対戦相手がいないから

今回制作したゲームは、完全オンラインの1対1、対戦相手がいないと成立しません。あなたがこの記事を読んでいる今この瞬間に他の誰かがあなたと同時にゲームをはじめていない限り、あなたはロビーで延々と対戦相手を待ち続けることになるでしょう。心優しいあなたの貴重な時間をそんなことで浪費させると思うと、僕はキーボードを濡らさずにはいられません。
さてどうしてそんなゲームを作ってしまったのか、それをこれから一緒に紐解いていきましょう。

お題発表

お題を確認し、アイデア出しを始めます。月曜中に企画が固まれば、前回の経験もあるし御の字だろうと考えてました。


これは企画のブレストメモ。いくつか面白そうな候補はありましたが、新しいこととしてオンラインもやってみたかったので「韻を踏んで言葉をつなげていく」というアイデアに決まりました。
逆につながらない「逆連想ゲーム」とか、「つながらない文学」とかは一発ネタとしてちょっと面白そうですね。「世代をつなぐ」系のネタも面白そうだと思いましたが、1週間ではまとまらないと判断してます。

順調に固まる企画

よさそうなアイデアが見つかったので、これを固めていきます。


さきほどのアイデアをもとに煮詰めていった企画メモ。

右上の「気になること」を見る限り、「もろもろ心配はあるものの作ってから考えろ!」というスタンスだったようです。じつに男らしい。ほかにも観戦や投票など、大きな夢を見ていることが窺えます。

コンセプトを整理している最中に頭に浮かんでいたのは、すけどんさん@stamina_techの「575オンライン」がヒットした事実でした。あのライブ感、ハプニング感に、即興の緊張感、韻を踏むこと自体のリズム感を乗せることができれば、間違いなく面白くなるだろうという確信がありました。

PUN完全に理解した

上記の企画をもとにさっそくPUNを使ってオブジェクトの実装に成功しているのが下記の動画。コンビニは特に関係ないんですが、手ごろな素材がなかったので。

そして次の時点で水曜日。企画も固まってるしオンラインも思ってたより簡単に動かせるし、この辺完全に調子乗ってます。

↓は調子乗ってて絶対面白いと思ったのに鬼ほどスベったツイート

プロトタイプが出来上がっていくのは早かったです。作っていても楽しいですね。
ただ、そのおかげで進捗が順調だと勘違いしています。

BGMも付きました。土曜日の夜。作業は進んでいると本人錯覚してますがさっきのツイートと比較すると見た目にはほとんど進んでないのがわかります。


ガンバローじゃねぇよ!おめえもがんばんだよ!

余裕のApexLegends

突然ですがみなさんはApexLegendsというゲームをご存知ですか?2019年2月4日に電撃リリースされて以来、新世代のバトロワFPSとして世界を席巻しているタイトルです。リリースされてからというもののその面白さに、家にいる時間はUnityを触っているかApexLegendsをやっているかという状態でした。さすがに1week期間中は自粛しようとDiscordでちゃんとフレンドたちに、イン率が下がることを宣言しています。えらいですね。

ちなみにこの後1時間だけプレイしました。チーターがはびこっていて全く面白くありませんでした。


次の日。風呂にも入らずしっかり誘ってプレイしてます。


夢の中でもプレイしていたようです。意識高いですね。


金曜の夜にはApex(あぺ)やりたくて禁断症状が出ています。進捗がでている(と錯覚している)ので余裕ですね。


土曜の夜です。かける言葉が見当たりませんね。

阿鼻と叫喚の週末

時間というのは不思議なもので、いつもそこにあるのに本当に必要な時に限って足りなくなるんです。「最後に余った時間をとってやろう」と思っていたことは落ちます。これは100パーです。

エモすぎるコミットログ


バグを巻き戻したいのに、うまくできなくてパニクってます。ブランチの名前とかコメントからそれが手に取るように伝わってきますね。作者の感情が強く表現されている、非常にエモいコミットログです。

罪悪感とロスタイム

日曜20時を迎え、リザルトへ遷移しないバグがあることを確認したままビルドをアップロード。


殊勝なこと抜かしてますがApexしなければもっと整ったと思います。


謝罪の気持ちを見せてますがApexしなければ直っていたバグと思います。

リアルタイムのオンラインゲームという性質上、自然流入で遊んでもらうのはむつかしいということは分かっていました。狙っていたのはぱふもどきさん@PafuOfDuck全ゲーム遊ぶ生放送。要するにここで取り上げられるタイミングまでに体裁を整えればいいわけです。大人って汚い。ご本人に確認したところ、オンラインゲームは木曜か土曜になるとのこと。

ここから、己のスパゲティコードと戦う地獄のロスタイムが始まりました。

心(蔵)震える実況生放送

幾度もの「PUNなんもわからん」夜を超えいよいよ迎えた放送当日。まだ多少バグは残っていたものの、最低限遊べるところまでは持っていくことができました。この時点では「面白くなるぞ」という自信と「理解してもらえるだろうか」という不安との間で針がゆらゆら揺れてました。

結果は惨敗。コメント欄やリアクションを眺める限り、そもそも「韻を踏む」ということが伝わっていなかった、伝わっていても非常に難しかった、という感じが窺えました。これが「肩ごしの視線」というやつですね。


放送終わってからなんだかもやもやしてました。


でもあそんでツイートまでしてくれたお二方、本当にありがとう!!

結果発表


放送のリアクションを見る限り全く期待していなかったのですが、どうにか斬新さ部門で4点、24位にランクインできました。
遊んでくださった方、評価をつけてくださった方、本当にありがとうございます。

斬新さ4点というのは絶妙で「(面白いかは分からんけど)ほかに見ないから4点、でも面白いか分からんし5点はつけられないかな」という評価だったのかなと解釈してます。そもそも遊べなかった人は点数つけられないでしょうし。
バグをとって「絵作り」「雰囲気」を整えて完成度を高めれば、結果的に「楽しさ」につながるし「斬新さ」のところにも評価が入りやすくなるだろうと思っています。

浮き彫りになった弱点

ひとつは実装スピード。作り方の引き出しといっていいかもしれません。「こういうことをしたいときは、こういうパターンがあるよ」というテンプレを習得し、なるべく頭と時間を浪費せずに実装していけるようになる必要があります。時間が余ればそれだけ、絵作りや全体的な統一感、バグ修正にパワーを割くことができます。
自分で一から実装するだけでなくアセットストアの活用も。今回DOTweenを使ってみましたが、動きのある絵が5分で作れて感動しました。
もう一つは世界観づくり。アート、サウンド、UI全てから受け取る印象ですね。今回は時間がなくてやれなかった、というのは確かに間違いありませんが、時間があったとてクオリティを出せたかというと、おそらくそんなことはなかったでしょう。普段からその練習してませんからね。

これからのUnity1weekへの挑み方

「ゼロから新しい技術、表現に挑戦する場」というよりも、「練習したものを披露する場」としてとらえていこうかなと。今回新たに挑戦したPUNは、非常に簡単で、かつ程よくハマりました。1week中はその復習をする時間が取れないのでハマったところをゴリ押しで突破して放置しがちというのもよくない。

次のunity1week(たぶん7月くらい?)でもこの形式が続くのであれば
* 評価100人
* 総合トップ10
を目指します。

トップ10きついかな?トップ30くらいがいいかな?表向きはトップ10にしといてそれは努力目標ということにしておこうかな?

まとめの中期目標

これから3か月間は、細かく作って出してのサイクルを加速させていきます。新しい技術や設計、思想、テーマの検証→3週間でそれをリリース、を繰り返していくイメージ。
並行してアートや3Dモデルの勉強も始めていきます。3Dでつくってみたいゲームがあるんですよね。その辺も、この検証期間を使ってゲームに落とし込んでみたいと思います。


これ以降めんどくさくなったのでやってません。

ご意見ツッコミあればお待ちしています。

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.20「弾切れ、リロード中、武器チェンジ中をわかりやすくする」

20.弾切れ、リロード中、武器チェンジ中をわかりやすくする

大きく分けて下記の三つをまとめて実装します
* 弾切れ中に左クリックしたらカチカチ鳴って弾切れしているとわかる
* リロード中、HUDにその情報を表示する
* 武器チェンジ中、HUDにその情報を表示する

弾切れ中にカチカチ鳴らす

サウンドファイルは適当なものを用意してきます。実装は下記の通り

うーんイケてない。「おしっぱで射撃できていい」という仕様と「おしっぱでカチカチならすと音がうるさい」という問題とがバッティングしてしまっているため、わざわざInput.GetButtonDownで判定を取り直しています。きれいにできそうな気もするんですけどまあええかまずは完成させたろの精神でスルー!

リロード中のHUDを表示

これも適当な画像を作ります。この画像を、リロード中の待ち時間の間表示します。

これはシンプルですね。リロードが始まったら表示してWaitForSecondsが終わったら消す。ちなみにこの画像はCanvas内に設置しています。次の武器チェン表示も要領は同じ。

武器チェンジ中のHUDを表示

こちらも適当な画像を用意。

おんなじですね。今回はこれで終わり!

次回はコチラ

公式チュートリアルSurvival Shooter WITH PK Chapter.21「敵の強さ、登場数、キャラクターの成長をデザインする」

前回はコチラ

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.19「照準を表示する」

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.19「照準を表示する」

19.照準を表示する

射撃がどこに飛んでいくかの目安となる照準(レティクル)を表示します。

画像を用意する


今回は32*32pixelで画像を書きました。これをCanvas上に設置し、マウスカーソルの位置を追うようにします。

Reticleクラスの実装

Reticleクラスを作成し中身を実装していきます。

超シンプルですが、ほぼ意図通りの挙動です。

バグ

射撃は、GunBarrelEndオブジェクトの正面に向かって真っすぐ飛んでいく実装になっています。
ただ、射撃の始点であるGunBarrelEndオブジェクトがPlayerの正中線よりやや右に設置されているため、レティクルの位置と実際に射撃が飛んでいく位置がずれてしまっています。
GunBarrelEndオブジェクトの位置を調整してみようと試行錯誤したのですがうまくいかず。このバグは仕様にしようそうしよう。

次回はコチラ

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.20「弾切れ、リロード中、武器チェンジ中をわかりやすくする」

前回はコチラ

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.18「カメラシェイク」

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.18「カメラシェイク」

18.カメラシェイク

カメラシェイクとは、カメラ=画面が小刻みにぶるっと震える演出のことです。ダメージを与えた、受けた、壁に激しくぶつかったなど視点が揺れるときの演出として使います。今回はダメージを与えた時に画面が揺れるようにしてみましょう。かなり臨場感が増しました!

CameraShakeクラスの実装

新しくCameraShakeクラスを作成し、MainCameraにアタッチします。
ShakeTimeの値が正の間カメラが揺れ続け、Update内でShakeTimeの値を減らしています。負の値になると揺れが止まります。
PlayerShootingクラスのShootメソッド内で、ダメージを与えるタイミングでShakeTimeに揺らしたい秒数を入れることでカメラシェイクを実行しています。

public class CameraShake : MonoBehaviour {

public float ShakeTime { get; set; }

private void Start()
{
ShakeTime = 0.0f;
}

private void Update()
{
if (ShakeTime > 0.0f)
{
ShakeTime -= Time.deltaTime;
ShakeCamera();
}
else if(ShakeTime <= 0.0f)
{
ShakeTime = 0.0f;
}
}

public void ShakeCamera()
{
//カメラの揺らし幅
float x = Random.Range(-0.1f, 0.1f);
float y = Random.Range(-0.1f, 0.1f);

//カメラを揺らす
transform.position += new Vector3(x, y, 0);
}
}

次回はコチラ(執筆中)

前回はコチラ

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.17.5「リファクタリング」

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.17.5「リファクタリング」

17.5 リファクタリング

幻の第17回でコードを引っ掻き回した結果、PlayerShootingクラスが鬼のように見づらくなりました。今回は、リロードと武器チェンジの処理を別クラスに引っぺがし、射撃処理自体も関数化することで可読性を高めるリファクタリングを行います。どちらかというと、「こうなりました」という報告。

PlayerReloadクラス

今回Interfaceを練習がてら使ってみました。ただ、武器種ごとにリロードを実装するつもりだったのが結果的にReload関係のクラスは1つで済んだので、Interfaceの用途としては正しくありません。

Interfaceの説明については、こちらの説明が簡潔で非常に理解しやすかったです。
https://qiita.com/Akira_Kido_N/items/7cd18944173cd4cd7229

イメージをつかんだらこちらを読んでより本質的な理解に進むとよいかと。
https://niconare.nicovideo.jp/watch/kn3404

PlayerChangeWeaponクラス

switchの中をもっと共通化できないか30秒くらい悩んでできなさそうだったのであきらめました。

PlayerShootingクラス

全部張ると長くなるので、UpdateとShootメソッドだけ。特にShootメソッドの可読性が上がってます。

リファクタリングはうまくはまるとパズルを解いたような快感がありますね。漫画やゲームの整理が昔から好きだったのでその楽しさにも似てるかも。

次回はコチラ

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.18「カメラシェイク」

前回はコチラ

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.16「調整:攻撃中の移動速度を遅くする」

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.17「調整:ノックバックを実装する」

17.調整:ノックバックを実装する

アクションゲームには欠かせないといってもいいノックバック演出。攻撃を当てた瞬間に、敵やプレイヤーの動きが止まってからリアクションが始まるというもの。

実装に当たって改めてノックバックについて調べてみると、様々なタイプがあるようです。ゲーム内の時間を丸ごと止めるもの、敵だけ、プレイヤーだけ止めるものなどなど。どのようなノックバックがあるかについては、下記の動画が大変参考になりました。

ゲーム開発でのヒットストップ調査

なんでもチャージショットで決めてしまうサムスが強すぎる【スマブラWiiU】

格闘でなく射撃であることを考慮すると「敵だけを止める」タイプのヒットストップが適しているかと思いました。以下、ヒットストップについての考え余談。

ヒットストップとはなんぞ

せっかくのアクションゲームだしヒットストップとか入れてみるか(開発延長)
剣とか格闘のゲームでは欠かせない演出だけど、銃とかシューティングではあんまり見ない気がする?サムスのチャージショットくらいしか例が浮かばない

射撃攻撃とヒットストップについて
仮説1:ヒットストップとは「吹っ飛ばし」の再現である
なので、ライフルとかサブマシンガン、レーザーみたいな貫通の攻撃とはあまり相性が良くない
逆に射撃であっても、ミサイルとか波動拳とかかめはめ波みたいな、衝撃の攻撃とは相性が良い

仮説2:ヒットストップとは「抵抗」の再現である
サンドバックを蹴れば、かならずサンドバックからの跳ね返りが存在し、無抵抗で振り抜くことはできない
その抵抗の感覚を再現するのがヒットストップであるため、自分の体から離れてしまった攻撃からは抵抗を受けないため、射撃とは相性が良くない

ここまで書いてて思ったけど、要するに現実世界に存在する「作用反作用」のフィードバックをいかにしてプレイヤーに与えるか、という問いに対する1つの答えってことかな
逆に言えば、ヒットストップを設けることで、射撃攻撃であっても「吹っ飛ばし」や「抵抗」のような作用反作用のフィードバックをプレイヤーに与えられる、ということだろうか

あとカメラシェイクか
こっちは実装したことあるからすぐいけるはず
ひとくちにヒットストップといってもさまざまなパターンがある模様
それらの挙動を比較してくれているこの動画がかなり参考になる。まずはこれを見て方向性を決めよう

やっぱり格闘と射撃とでは、適切なヒットストップの種類異なってくる気がするなぁ
射撃は自分に反作用のフィードバックがないわけで、自分が止まるタイプのヒットストップはおかしいよなあ
撃つ瞬間に自分だけ硬直⇒当たった時に相手だけ硬直して吹っ飛ぶ なら自然かな?

サムス:撃った瞬間反動でちょっと後ろに下がってる。ヒットストップというよりその反動で重量感を出しているもよう
ベヨネッタ:当たった瞬間その場で硬直してから吹っ飛んでる。硬直中は完全に動きが止まるわけじゃなくて、やられモーションのままぶるぶるしてる?それともエフェクトでそうみえるだけ?

こっちで見ると、食らったほうはその場で上下に細かく揺れたり震えたりしてるのがわかる
撃ったほうはストップしてるというか反動で後ろに下がるor硬直してるだけだな

ていうか格闘でも、攻撃したほうにはヒットストップ入れてないな
不利になっちゃうから当たり前か

ヌルっと止まると気持ちよくない、パキッとその場で止まって欲しいのでWaitForSecondsをつかうか。

WaitForSecondsの間に、別の変数やオブジェクトを格納してしまいNullReferenceエラー
LineRendererの終点
 WaitForSeconds後にLineの終点を更新していたため、更新される前にLineが描画されていた

ノックバックの時に操作するNavmeshAgent
 WaitForSeconds中に壁など敵以外のオブジェクトを打つと、shootHitの対象がエネミーからそのオブジェクトになってしまい、NavMeshAgentを見つけられるNullエラー

実装したけど削除しました!!!

一度実装してみたけど、思ったよりも爽快感に寄与せずゲームプレイがダラけただけだったので削除しました!
攻撃が当たった瞬間=ノックバック処理の実行直前に、NavMeshのVelocityを0にするStopMotionメソッドを事項してます。

がんばって作ったけど削除しました!!!
あと、これを実装するときにPlayerShootingクラスが超でぶになって見づらかったので、リファクタリングを一緒にしてます。これについては次回まとめます。

次回はコチラ

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.17.5「リファクタリング」

前回はコチラ

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.16「調整:攻撃中の移動速度を遅くする」

Unity公式チュートリアルSurvival Shooter WITH PK Chapter.16「調整:攻撃中の移動速度を遅くする」

16.調整:攻撃中の移動速度を遅くする

前回までで、主だった昨日の実装は一段落つきました。ここからは実際に遊んでみてのフィードバックをもとに、細かい部分の実装をしていきます。
気になったのは、逃げながら攻撃していればほぼ追いつめられることが無い点でした。敵の移動速度>プレイヤーの速度となるよう調整するのが一案ですが、例えばシールド象の移動速度を速くすると少々オーバーパワーのようです。そこで、「攻撃中だけプレイヤーの移動速度が遅くなる」ようにします。

PlayerMovementクラスにメソッドを追加

移動速度を遅くするメソッドと、遅くなった移動速度を回復させるメソッドを追記します。

このメソッドの実行は、PlayerShootingクラスから行います。

PlayerShootingクラスから実行

まずは遅くする処理。Shootingメソッドの中で実行します。
また、PlayerMovementの取得は、PublicでInspectorより行います。

次に移動速度を回復させる処理。こちらはUpdateメソッドから。

実装確認

撃ったら移動速度が遅くなる⇒チョットしたら戻る の挙動ができていればOK!

第17回がお蔵入りしたので次回はコチラ

※第17回ではノックバックの実装を行いましたが、イマイチだったので削除してます。それでも読みたい物好きはコチラ

前回はコチラ

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

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

15.特殊な敵を実装する

前回の記事で書いたように、今回のゲームでは敵と武器とは対になります。

(断続的に登場するオーソドックスな敵)

これはすでに実装しているZonbunnyちゃんで良いでしょう。

(一斉に大量登場するが、HPが低い敵)

Zonbearちゃんのパラメータを調整すれば実現できそうです。

(盾orバリアを持っておりかつ、ダメージを食らわないでいると盾の耐久が回復する敵)

実装が必要ですね。今回はHellephantちゃんをこのシールド持ちにしましょう。

そうしてできた完成図がコチラ。

実装の段取りはこのようになります。

  • Unity上でShieldとなるObjectを用意する
  • Shieldに射撃RayがぶつかったらShieldのHPを減らす
  • ShieldのHPがゼロになったらShieldを破壊する
  • Shieldがダメージを受けずに一定時間経過したら、ShieldのHPを回復させる
  • スナイパーライフルで射撃した時はShieldと本体の両方にダメージを与える
  • Shieldにダメージが入った時、シールドの色を変えたり、大きさを小さくしたり、ヒットのエフェクトを表示する

Unity上でShieldとなるObjectを用意する

Hellephantの子Objectとして、3D Object -> cubeを作成し、ShpereColliderをアタッチします。シールドに衝突判定は設けないため、isTriggerにチェックを入れておきます。また、LayerをShootableにしておくことをお忘れなく。後の工程でこれに気づかず、2時間くらいハマりました。

Shieldの色を半透明にしたいため、専用のMaterialを用意します。Projectビューで右クリック -> Materialを作成し、Albedoから半透明の赤に調整し、ShieldObjectのMeshRendererにあるMaterialに設定します。

設定はこんな感じ。

ShieldHealthManagerの実装

Shieldの管理を行うクラスとしてShieldHealthManagerを用意します。もちろんShieldObjectにアタッチ。
ついでに、ヒット時に大きさを変えたり、エフェクトを表示する処理も一緒に書いてしまいます。色を変える処理はUpdateメソッドもいじる必要があるので事項で説明します。

Shieldにダメージを与える & その際に大きさを変えたりエフェクトを表示する

まずは基本の部分として、TakeShieldDamage()メソッドを実装します。

EnemyHealthクラスのTakeDamage()メソッドをひな型に、変数の名前を書いたりShieldだけの処理を入れたりしてます。
次に、このメソッドの実行元として、PlayerShootingクラスのShoot()メソッドを修正します。

EnemyHealthの判定を行う前にEnemyShieldの判定を差し込んでいます。
isTriggerにチェックを入れたColliderでもRayが衝突判定を返してくれるようにUnity側の設定を変更します。
Edit>ProjectSetting>PhysicsよりQuerriesHitTriggersにチェックを入れればOKです。

Shieldを回復させる & ヒット時にシールドの色を変える

一定時間Shieldへのダメージがなかったら、ShieldのHPを回復させます。これにより、スナイパーライフル以外の武器で倒すには集中砲火が必要となり、ほかの敵と合わせて出現した時のいやらしさが倍増します。

回復の処理は非常にシンプルですね。HPの値と一緒にShieldの大きさも戻してあげます。
シールドの大きさの変化率は数値を直で入れてしまってますが、本当はShieldのHPと、Colliderの大きさとの関係から計算式にすべきです。が、ややこしくなりそうなので今の段階では先送ってます。

また、ヒット時、Shieldの色にアルファ値を足してあげることで透明度を変更しています。
その直後からだんだんと色味を戻すため、Lerp関数を使っています。これはぜひ引き出しとして持っておきたい手法。

これにてShieldの実装は完了~~!!動かしてみて、攻撃を当てるたびに色が変わって小さくなること、HPがゼロになったら消滅すること、スナイパーライフルでは中身ごと攻撃できることを確認したらおしまいです。

次回はコチラ

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

前回はコチラ

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

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「射撃にリロードを設ける」