Unity 5で 2Dシューティングのチュートリアルを行う際の注意点(第11回)


Unity公式チュートリアル 2Dシューティング

第11回 エネミーのHP、弾の攻撃力、アニメーションの追加


上記チュートリアルで、私がつまずいたところ、初心者がつまずきそうなところをピックアップして解説します。

まとめへ戻る≪第10回へ第12回へ≫


注意:もし、この時点でゲームを実行時、Xで開始しても敵が流れてこなくなったら?


上記の現象が起きた場合、おそらく第10回のチュートリアル内のコラムにある「もし NullReferenceException が発生してしまったら?」の部分をやっていないことが原因です。
このコラムにある設定を行うことで、敵が流れてくるようになります。
私の第10回の解説にも追記を行ったので、よかったら読んでみてください。

11.1 HP(ヒットポイント)と攻撃力(power)の実装

まずはEnemy.csにヒットポイントを実装します。

Projectタブの Scripts配下にある Enemyをダブルクリックし、MonoDevelopで Enemy.csを編集します。
Enemy.cs のソースは、チュートリアルの内容でまるごと置き換えて問題ありません。
置換後、Ctrl+Sで保存して、Unity画面に戻りましょう。
ダイアログが表示されるので、「Go Ahead!」をクリックし、ソースを自動修正させましょう。


Enemy.cs の変更点は、以下の通りです。

・ヒットポイントを格納する変数 hpを追加

次にBullet.csに攻撃力を実装します。

Projectタブの Scripts配下にある Bulletをダブルクリックし、MonoDevelopで Bullet.csを編集します。
Bullet.cs のソースは、チュートリアルの内容でまるごと置き換えて問題ありません。
置換後、Ctrl+Sで保存して、Unity画面に戻りましょう。
ダイアログが表示されるので、「Go Ahead!」をクリックし、ソースを自動修正させましょう。


Bullet.cs の変更点は、以下の通りです。

・攻撃力を格納する変数 powerを追加

ヒットポイントが0になった時に爆発させる

Enemy.csのOnTriggerEnter2Dメソッド内にヒットポイントを減らしていく処理を実装していきます。
今回はたまの攻撃力の数値でヒットポイントを減らしていきます。

Projectタブの Scripts配下にある Enemyをダブルクリックし、MonoDevelopで Enemy.csを編集します。
Enemy.cs のソースは、チュートリアルの内容でまるごと置き換えて問題ありません。
置換後、Ctrl+Sで保存して、Unity画面に戻りましょう。
ダイアログが表示されるので、「Go Ahead!」をクリックし、ソースを自動修正させましょう。


Enemy.cs の変更点は、以下の通りです。

・OnTriggerEnter2D 関数内に、弾の攻撃力を取得してヒットポイントを減らす処理を追加
・ヒットポイントが0になったら爆発させる条件文を追加

WaveプレハブのEnemyを3つ選択し、HPの値を10にします。

Projectタブの Prefabs/Wave配下にある Enemyを3つ選択状態にします。
まず Enemyを一つクリックし、Ctrlを押しながら残りの2つをクリックします。
3つ選択状態にできたら、Inspectorの Enemy(Script)内にある HPを編集します。

ゲームを再生してみましょう。プレイヤーの弾に何発か当たらないとエネミーは爆発しなくなります。

うまくいきましたか?


もし、ここへきて「敵が落ちてくるのがなんか速い気がする」と思った方は、Projectタブの Prefabs/Wave配下にある Enemy の Inspectorで、Rigidbody 2D内の Gravity Scaleが 0になっているかどうか確認してみてください。
もし、Gravity Scaleが 1 になっていると、落ちてくるのが速くなるので、0に直してください。
#私はここを修正するのを忘れていて、ずっと敵が落ちてくるのが速い状態で進めてました。

11.2 ダメージを受けた時の表現

エネミーがダメージを受けたときに、わかりやすく機体の色を赤色にします。

アニメーター - レイヤーの作成

図11.1: 新しいレイヤーを作成し、ダメージを受けた時の表現を実装する(完成図)


エネミーには既にNormalという「スプライトを切り替えていく」アニメーションがあります。今回はそのNormalアニメーションに、色を変化させるアニメーションを「上書き」する形でダメージを表現します。

まず、Projectタブの Animations/Enemy配下の Enemy をダブルクリックします。
すると、図11.1のように、Sceneウィンドウのあったところに Animatorウィンドウが表示されます。

レイヤーの追加

レイヤーを追加します。追加した後は、「NameをDamage Layer、Weightを1にしてください。

Animatorウィンドウのタブ下の「Base Layer」の左にある「閉じたまぶた」みたいなアイコンをクリックします。
すると、レイヤー一覧ペインが表示されます。

レイヤー一覧ペインの右上にある「+」をクリックすると、レイヤーが追加できます。
レイヤー追加直後にリネームできるようになっているので、そのまま「Damage Layer」にリネームします。
もし、リネームできなくなってしまったら、レイヤー名のあたりをクリックするとリネームできるようになるので、そこでリネームします。
リネームできたら、名前の横の「設定」ぽい歯車のアイコンをクリックします。
すると、以下のようにレイヤーの設定パネルが表示されるので、Weightを 1 に修正します。

Damageアニメーションの作成

Enemyフォルダ上で右クリックし、Create → Animationを選択してアニメーションのアセットを作成します。名前はDamageとしてください。

Projectタブの Animations/Enemy フォルダで右クリックし、Create → Animationを選択します。
追加されたものを Damageにリネームします。

作成したらアニメーターに登録するためにDamageアニメーションをアニメーターのDamage Layer上にドラッグ&ドロップします。

Animatorウィンドウの Damage Layerが選択されていることを確認後、作成した Damage を、Animatorウィンドウにドラッグ&ドロップします。
ドロップすると、下図のように Entryから勝手に線が繋がりますが、気にしなくていいです。

次はアニメーションを作成していきます。一度Enemyのプレハブをシーン上へドラッグ&ドロップしてください。

まず、Sceneタブをクリックし、Sceneウィンドウへ切り替えます。
その後、Projectタブの Prefabs/Enemyをシーン上へドラッグ&ドロップします。

Enemyゲームオブジェクトを選択しながら、Window → Animationを選択し、Animationウィンドウを開きます。

Hierarchyタブの Enemyを選択し、メニューから Window -> Animation を選択して、
Animationウィンドウを開きます。
もし、このときウィンドウ内が空っぽで、「To begin Animating Enemy, create an Animator and Animation Clip」的なメッセージが出ていたら、「Create」ボタンを押します。すると、下図のようになると思います。

開いたらNormalアニメーションが選択されているので、Damageアニメーションへ変更します。

PLAYボタンみたいなのが並んでいる下の「Normal」をクリックし、「Damage」へ切り替えます。
この後、チュートリアルの説明にはありませんが、「Samples」の横の「12」を「60」に変更してください。
この画像を見るとわかるのですが、Samples が 12 -> 60 にいつの間にか変更されています。

アニメーションを行うプロパティを登録します。Add CurveボタンでSprite Renderer → Colorを追加してください。

Add Property ボタンをクリックし、Sprite Renderer → Colorを選択して追加します。
このとき、Colorの右にある「+」をクリックして追加するのですが、「+」が見えない時は、下のスクロールバーで少し右にスクロールしてみてください。すると「+」が出てきます。


するとデフォルトでKeyが2箇所、設定されているので右側のKeyを削除します。Keyを右クリックしてDelete Keysを選択してください。

まず下図のように「Enemy : Sprite Render Color」の左にある三角アイコンをクリックして、開きましょう。


それから、縦に2列ならんでいるKey(◆のこと)の右側の一番上をクリックして選択します(青くなります)。
その後、同じ◆を右クリックして、Delete Keysを選択します。
すると、縦一列が削除されます。

更に2つの操作を行います。


まずは、0フレーム目にあるKeyを5フレーム目に移動させます。一番上のKeyをドラッグして5フレームまで移動させてください。フレーム数の確認は左上で確認することが出来ます。


次に色の情報を変更します。Color.rを1、Color.gを0、Color.bを0.6、Color.aを1にしてください。

ここは説明の通りにできると思います。
色の情報は、数値をクリックすると、編集できます。

インスペクターのプレビューでエネミーが赤色になっているはずです。

たぶんこの時点では確認できなかった気がするので、あまり気にしなくて良いです。
色の情報さえきちんと編集できていれば、たぶん(きっと)赤くなります。←

トリガーの作成

ダメージを受けた時のみエネミーを赤色にするため、トリガーという機能を使います。


まずアニメーター上で空のステートを作成します。アニメーターウィンドウ上で右クリックをして、Create State → Emptyを選択してください。

メニューから、Window -> Animator を選択し、Animatorウィンドウを開きます。
LayersでDamage Layerをクリックします。
Animatorウィンドウの何もないところで右クリックし、Create State → Emptyを選択します。
New State という空のステートができます。

名前をDummyとします。ステートの名前を変更するにはインスペクター上で行います。ステートをクリックしてインスペクターを表示させましょう。

New Stateをクリックし、Inspectorで「Dummy」にリネームします。

次にDummyをデフォルトステートとします。Dummyステート上で右クリックしてSet As Defaultを選択してください。デフォルトステートはゲーム再生直後に再生されるステートのことを指します。こうすることによって、ゲーム再生時、Damage LayerではDummyステートが再生され、何もアニメーションを行わない状態になります。

Animatorウィンドウ上の Dummyを右クリックし、「Set As Layer Default State」を選択します。
Dummyがオレンジ色に変化します。

次は何も行わない状態からトリガーによってDamageアニメーションを再生 → 何も行わない状態 → Damageアニメーション...と繰り返し状態の遷移を行うようにします。


Dummy上で右クリックし、Make Transitionを選択します。
カーソルに矢印が追従するのでDamageステート上でクリックします。そうするとDummyステートからDamageステートへ何らかの条件で遷移する事ができるようになります。

説明通り、Dummy上で右クリックし、Make Transitionを選択します。
すると、マウスカーソルの位置までラインが伸びるので、Damageをクリックします。
Dummyから Damageへ遷移するラインが生成されます。

同じようにDamageステートからDummyステートへのTransitionも作成しましょう。

今度は Damageを右クリックし、Make Transitionを選択します。
そして Dummyをクリックして、遷移するラインを生成します。

次にトリガーを作成します。アニメーターウィンドウの左下にあるParametersの+ボタンを押してTriggerを選択してください。

現在、Animatorウィンドウにレイヤー一覧は見えていますか?
もし見えていなかったら、「閉じたまぶた」みたいなアイコンをクリックして表示させてください。
すると、「開いた目」のアイコンの左に「Parameters」というタブがあるのでクリックします。
すると、その下の検索窓みたいな枠の右に「+」ボタンがあるので、それをクリックします。
すると、ポップアップメニューが表示されるので、そこから「Trigger」を選択します。


名前をDamageとします。

生成された「New Trigger」を「Damage」にリネームします。


DummyステートからDamageステートへのTransitionをクリックし、表示されたインスペクターのConditionsをDamageへと変更します。DamageステートからDummyステートへのTransitionはそのままにしておきましょう。

下図のように、Dummyから Damageへのライン(Transition)を選択し、Inspectorの Conditionの右下の「+」をクリックします。

すると、下図のように勝手にDamageが追加されて入るはずです。

Damageから Dummyの方は特に何もしません。

スクリプトからトリガーのセット

ダメージを受けた時に「トリガーをセット」してダメージアニメーションを再生させます。


まずはSpaceship.csにAnimatorコンポーネントを取得するメソッドを追加します。

Projectタブの Scripts配下にあるSpaceship をダブルクリックし、MonoDevelopで Spaceship.csを編集します。
ソースの内容は、チュートリアルの通りにまるごと置き換えて問題ありません。
置換後、Ctrl+Sで保存して、Unity画面に戻りましょう。


Spaceship.cs の変更点は、以下の通りです。


・3行目の RequireComponentに、typeof(Animator)を追加
・アニメーターコンポーネントを格納する変数 animator を追加
・Start関数を追加、そこで animatorへオブジェクトを格納
・GetAnimator関数を追加

OnTriggerEnter2Dメソッド内にある、エネミーのHPをチェックしている部分を「HPが0以上であればDamageトリガーをセットする」ようにします。

Projectタブの Scripts配下にある Enemy をダブルクリックし、MonoDevelopで Enemy.csを編集します。
ソースの内容は、チュートリアルの通りにまるごと置き換えて問題ありません。
置換後、Ctrl+Sで保存して、Unity画面に戻りましょう。
ダイアログが表示されるので、「Go Ahead!」をクリックし、ソースを自動修正させましょう。


Enemy.cs の変更点は、以下の通りです。


・OnTriggerEnter2D関数内で、ヒットポイントが残っている場合は、AnimatorのDamageをトリガーする処理を追加

最後にEnemyゲームオブジェクトを削除して、ゲームを再生してみましょう。

Hierarchyタブの Enemyを選択し、Deleteキーを押して削除します。

弾が当たった時にエネミーが赤色になりました。ですが徐々に赤色になり、徐々に元の色に戻るアニメーション(フェード)になっています。

ここは正直良くわかりませんでした。
#当時私が敵のRigidbody2DのGravity Scaleを1にしていて敵の移動が速すぎて色の変化が良く見えなかったため
とりあえず、他の問題(赤くなるのが遅い)もあるので、ここはそのまま進めてください。

もう一度、アニメーターのTransitionのインスペクターを確認しましょう。


図11.7と図11.8のようにDummyステートからDamageステートへのTransitionのFadeのつまみを限りなく近づけてみましょう。

メニューから Window -> Animator を選択し、Damage Layerを選択後、Dummyから Damageへ伸びるラインを選択します。
すると、Inspectorでチュートリアルの図と同じように表示されるので、つまみを近づけます。

DamageステートからDummyステートへのTransitionも同じ設定を行います。ただし、Exit Timeを1へ設定してください。

Damageから Dummyへ伸びるラインを選択し、同じようにつまみを近づけます。
Exit Timeは、チュートリアルの図のようにConditionの中にはありません。
Inspector内の「Setting」の中に隠れていますので、Settingを開き、そこから編集してください。

ゲームを再生してみてください。ダメージを受けた時、瞬間的に赤色になるはずです。

私はチュートリアル通りやったつもりなのですが、瞬間的には赤色になりませんでした。
弾が当たってから、すこし間があり、その後赤くなります。
赤くなるタイミングが遅いのです。


そこで、チュートリアル11回の一番下にある「今回のプロジェクトファイルをダウンロード」でプロジェクト一式をダウンロードし、正しい状態がどうなっているのかを調べてみることにしました。
まず、一旦Unity画面でCtrl+Sを押して現在の状態を保存し、Unity画面を閉じてから開き直し、「OPEN OTHER」からダウンロードしたプロジェクトを開いて、まずはPLAYボタンを押して動きを確認してみました。
すると、ダウンロードしたプロジェクトでは、きちんと弾が当たった瞬間に赤くなります。


そこで、アニメーションファイル回りの設定を確認してみました。
すると、Dummy->DamageとDamage->DummyのそれぞれのTransitionの設定が、Inspectorで見る限り、わりと違っていました。
そこでこの設定をキャプチャし、自分のプロジェクトを開き直してから設定を合わせてみたところ、ちゃんと弾が当たった瞬間に赤くなるようになりました。
参考に、下にダウンロードしたファイルのTransitionの設定を載せておくので、もし私と同じように赤くなるタイミングが遅い人は、設定を合わせてみてください。

Dummy -> Damage   Damage -> Dummy
 

合わせるところは、Has Exit Timeのチェック状態、Setting内の各設定値(Exit Time、Fixed Duration、Transition Duration、Transition Offset)です。
合わせる時は、以下のように操作してTransitionのInspectorを表示させます。

  1. ProjectタブのAnimations/Enemy/Enemyをダブルクリック(Animatorウィンドウが開きます)
  2. AnimatorウィンドウのLayersをクリックし、Damage Layerをクリック
  3. Dummy -> Damageの Transition(矢印の線)をクリック
    これで、Dummy -> Damageの Transitionの Inspectorが表示されるので設定を合わせます
  4. Damage -> Dummyの Transition(矢印の線)をクリック
    これで、Damage -> Dummyの Transitionの Inspectorが表示されるので設定を合わせます

11.3 プレイヤーの無敵時間

ゲーム開始時にプレイヤーを点滅させ、無敵の状態を実装します。

実装方法はエネミーのダメージアニメーションの実装と同じです。

レイヤーの追加

PlayerアニメーターコントローラーをダブルクリックしてAnimrtorウィンドウを開きます。

Projectタブの Player配下にある Playerをダブルクリックして、Animrtorウィンドウを開きます。

Invincible Layerを追加します。Weightを1にするのを忘れないで下さい。

Animrtorウィンドウタブ下の列の左端の目のアイコンがもし閉じていたら開いてください。左のペインが開きます。
「Layers」タブを選択し、目のアイコンの下にある「+」をクリックしてレイヤーを追加します。
レイヤー名を「Invincible Layer」に変更します。
レイヤー名を変更するには、そのレイヤーをダブルクリックします。
その後、レイヤー名の右にある歯車アイコンをクリックし、表示されたパネルの中で、Weightスライダーを1に設定します(数値を入力してEnterを押すか、つまみを右端までずらします)。

アニメーションの作成

Playerプレハブをシーン上へドラッグ&ドロップしてください。

メニューから Window -> Scene で Sceneウィンドウを開きます。
Projectタブの Prefabs配下にある Playerを Scene の中にドラッグ&ドロップします。

次にアニメーションのアセットを作成します。Playerフォルダを選択し右クリックをして、Create → Animationを選択しください。

Projectタブの Animations配下にある Playerを右クリックし、Create -> Animation を選択します。
「New Animation」が追加されます。

作成されたアニメーションのアセット名はInvincibleとします。

New Animation を Invincible にリネームします。
リネームするには、クリックして選択後、もう一度クリックするか、F2キーを押します。

InvincibleアニメーションのLoop Timeにチェックを入れてください。

Invincibleを選択し、表示された Inspector内で、Loop Timeにチェックを入れます。

Invincible LayerにInvincibleアニメーションをドラッグ&ドロップし、Invincibleステートを作成します。

まず、Projectタブの Animations配下にある Playerをダブルクリックし、Animatiorウィンドウを開きます。
その後、Invincible Layerを選択します。
そして、Projectタブの Animations配下にある Invincibleを Animatiorウィンドウ内にドラッグ&ドロップします。
すると、緑色の「Empty」から勝手に「Invincible」へと矢印が伸びますが、気にしなくて良いです。


Create State → EmptyでDummyステートを作成し、InvincibleステートからDummyステートへのTransitionを作成します。

下図のようにAnimatorウィンドウの何もないところで右クリックし、Create State -> Emptyを選択します。

生成された New State を選択し、Inspector上で「Dummy」にリネームします。
その後、Animatorウィンドウの Invincible を右クリックし、Make Transition を選択します。
すると、マウスカーソルに直線矢印が付いてくるので、そのまま Dummyをクリックし、矢印をDummyへ接続します。
これで、Invincible ステートから Dummy ステートへの Transition が作成できました。

TransitionのExit Timeは3にしてください。これは3回Invincibleアニメーションをループさせる処理になります。

Invincible ステートから Dummy ステートへ伸びている線をクリックし、Inspector内で Settingをクリックして開きます。
下図のように「Exit Time」を 3 に編集します。

次にアニメーションを作成していきます。Playerゲームオブジェクトを選択しながらAnimationウィンドウを開き、Invincibleアニメーションを選択してください。

Hierarchyタブの Playerを選択後、Window -> Animation で Animationウィンドウを開きます(注意:Animatorではありません。画面下段の方にある Animationです)。
Animationタブ下の赤い丸アイコンの下にある「Normal」をクリックし、「Invincible」を選択します。
すると表示される「Player : Sprite」は不要なので、右クリック後「Remove Property」で削除します。

Add CurveボタンでSprite Renderer → EnabledとBox Collider 2D → Enabledの2つを追加してください

Add Curveボタンはありません。
Add Propertyボタンで、Sprite Renderer → EnabledとBox Collider 2D → Enabledの2つを追加します。
項目が見あたらない場合は、名前の左の三角をクリックして開いてみてください。出てくるはずです。
追加するための「+」アイコンが見えない場合は、メニューの下部のスクロールバーを右にドラッグしてください。隠れている「+」が見えると思います。

0フレーム目はオフに、60フレーム目はオンにします。ただし、Box Collider 2Dのキーは削除してください。Invincibleアニメーション再生中にコライダーを無効化し、当たり判定を発生させないことで無敵を実現させます。

ここはものすごくわかりづらいところです。
説明には書いてありませんが、まずは「Samples」を 60に変更します。
これで1秒間60フレームの設定になります(たぶん。筆者は良くわかってません)。

0フレーム目はオフに、

これは、「0:00」の位置にある一番上の「◆」をクリックした後、「Player : Box Box Collider 2D Enabled」と「Player : Sprite Renderer Enabled」の横にあるチェックボックスを、それぞれオフにします。

60フレーム目はオンにします。

まず、「0:10」の位置にある一番上の「◆」を「1:00」までドラッグします。これで、このキー(◆のこと)が60フレーム目となります。
その後、Player : Box Box Collider 2D Enabled」と「Player : Sprite Renderer Enabled」の横にあるチェックボックスを、それぞれオンにします(たぶん最初からオンのはずです)。

ただし、Box Collider 2Dのキーは削除してください。

まず、「1:00」の下に並んでいる「◆」3つより下の何もないところをクリックして、「◆」3つをグレー(非選択状態)にします。
その後、「1:00」の下の「Box Box Collider 2D Enabled」の行の「◆」をクリックします。
すると、一番上と「Box Box Collider 2D Enabled」の行の「◆」だけが青くなったはずです。
この状態で、もう一度「Box Box Collider 2D Enabled」の行の「◆」を右クリックし、「Delete Keys」を選択してキーを削除します。


#このチュートリアル、動画で作るべきだよね……

これを交互に60フレームまで「オフ、オン、オフ、オン...」というようにキーを打ち込んでください。この作業を楽にする方法として、キーのコピー&ペーストがあります。キーを選択し⌘(Ctrl)+Cでコピーしたら0:10の文字があるところをマウスでクリックし⌘(Ctrl)+Vでペーストしてください。

まず、「1:00」の一番上の「◆」をクリックします。すると、同時に「Sprite Renderer Enabled」の「◆」も青くなるはずです。
この状態で、Ctrl+C キーを押すことにより、この時間軸のキー(◆)がコピーできます。
そして5フレーム目(0:00と0:10の中間地点、薄いグレーの数字の書いてある横位置のところ)をクリックし、赤い線を移動させます。
その後、Ctrl+V でキーをペーストします。
そして「Box Box Collider 2D Enabled」横のチェックを外します(オフにします)。
以下の図のようになるはずです。

この後、5フレームずつ右にずらしつつペーストを繰り返し、「Box Box Collider 2D Enabled」横のチェックを2つ目ごとにオフにします。
つまり、

  1. 「0:10」をクリックし、赤い線を移動
  2. Ctrl+V でペースト(チェックはオンのまま)
  3. 「0:15」をクリックし、赤い線を移動
  4. Ctrl+V でペースト後、チェックをオフにする
  5. 「0:20」をクリックし、赤い線を移動
  6. Ctrl+V でペースト(チェックはオンのまま)
  7. 「0:25」をクリックし、赤い線を移動
  8. Ctrl+V でペースト後、チェックをオフにする

これを「1:00」につながるまで繰り返します。

最後にPlayerゲームオブジェクトを削除して、ゲームを再生してみてください。ゲームを開始すると点滅の無敵状態が3秒間続きます。

Hierarchyタブの Playerを選択し、Deleteキーで削除します。
ゲーム開始後、3秒間自機が点滅して無敵状態になれば、成功です。




今回はこれにて終了です。
うまくいきましたか?


まとめへ戻る≪第10回へ第12回へ≫