おもちゃラボ

Unityで遊びを作ってます

【Unity Tutorial 】How to make a shooter game

In this article, I'd like to introduce how to use Unity by making a simple shooter game. This article consists of 3 part.

  1. move the rocket and fire bullets.
  2. drop meteorites and collision detection
  3. make UI and game over

We are making the shooter game and scripts according to the book "Unity's textbook" written by me, so please refer to this book as well.

Overview of this shooting game

The game we are going to make will look like this.

f:id:nn_hokuson:20160702231742g:plain

Move your ship with the left and right keys, and shoot the bullet with the space key. Meteorites falls from the top of the screen, you should move ship and shoot the bullet and destroy it. If the meteorite goes beyond the bottom edge of the screen, the game will be over.

Create a Unity project

Let's create a Unity project. On the Unity startup screen, input the project name "Sample Shooting" and select the game type "2D".

f:id:nn_hokuson:20160703084730p:plain:w500

Next, select the screen aspect. Our game use a portrait screen layout, so click the Game tab and select the aspect ratio. Unity does not have a vertical aspect ratio , so click on the bottom "+ button" and select "Aspect Ratio" for a Type field and input "9: 16" for Width & Height field.

f:id:nn_hokuson:20160703085223p:plain:w500

Drag and drop the assets used in this game to Unity's project view. Assets for our game can be downloaded from the following URL.

www.dropbox.com

Let's add a rocket image to a scene view

At first, we gonna add rocket image(In Unity2D, image is called "sprite") on your scene view. Drag and drop the rocket sprite from the project window into the scene view.

f:id:nn_hokuson:20160703090750p:plain:w500

The rocket will be displayed on the screen.

The rocket sprite added in the scene view is also listed in the hierarchy view. Remember that the sprites on the scene view are correspond to thd list in the hierarchy window .

f:id:nn_hokuson:20160703091057p:plain:w500

You can change the position of the rocket from the inspector. When you select "rocket" in the hierarchy view, the rocket details are displayed in the inspector on the right side of the Unity editor.

In this example, change the rocket position to (0, -4, 0).

f:id:nn_hokuson:20160703093231p:plain:w500

Move the rocket

Next, Create a C# script to move the rocket with the left/right key. In Unity, you can use programming languages ​​such as C# or Javascript. Here we gonna develop our game using C#.

Right click on a project window and select "Create" → "C# Script", and
then change the file name to "RocketController.cs".

f:id:nn_hokuson:20160703093649p:plain:w500

Double click on RocketController.cs and open the code editor(Mono develop or Visual Studio) and enter the following script.

using UnityEngine;
using System.Collections;

public class RocketController : MonoBehaviour {
	void Update () {
		if (Input.GetKey (KeyCode.LeftArrow)) {
			transform.Translate (-0.1f, 0, 0);
		}
		if (Input.GetKey (KeyCode.RightArrow)) {
			transform.Translate ( 0.1f, 0, 0);
		}
	}
}

This script checks whether the keys(LertArrow and RightArrow) are pressed by using the Input.GetKey() method. When these keys are pressed, use the Translate() method to move the rocket in the direction of the arrow key. Translate () is a method that moves the object in the direction and distance of the argument. Note that the argument is not the absolute coordinate of the destination.

Next, we attach the RocketController script to the rocket object. In order to move an object as written in a script, you need to attach a script to the object.

Drag and drop "RocketController.cs" from the project view to "rocket" object in hierarchy view.

f:id:nn_hokuson:20160703093927p:plain:w500

Press the play button at the top of the Unity editor. You can move the rocket with the right/left key.

f:id:nn_hokuson:20160703094256g:plain

Let's add bullet sprite

The flow of firing a bullet from a rocket is as follows.

  1. Place a bullet sprite and move it upwards.
  2. Make a "bulletPrefab" based on the bullet you created.
  3. Write a bullet generator script. In this script, make an instance of a bullet from Prefab when you press the Space key.

At first, add the bullet's sprite on the scene view. Drag and drop "bullet" object from the project window to the scene view. Since the position of the bullet is specified by the script, you can place your bullet anywhere.

f:id:nn_hokuson:20160703131017p:plain:w500

After the bullet is added, you should make a script to move the bullet upwards. Right click in the project window and create a script with "Create" → "C# Script" and change the file name to "BulletController.cs".

f:id:nn_hokuson:20160703131228p:plain:w500

Open the "BulletController.cs" and write the following script.

using UnityEngine;
using System.Collections;

public class BulletController : MonoBehaviour {
	void Update () {
		transform.Translate (0, 0.2f, 0);

		if (transform.position.y > 5) {
			Destroy (gameObject);
		}
	}
}

We use the Translate() to move bullets upward (y-axis direction) by 0.2f every frame. This is the very similar way we used to move the rocket.

Even if bullets are out of the screen, bullets will continue to keep moving. Since this is a waste of CPU power, let's destroy the bullets when bullets go beyond the top of the screen (y = 5).

Save the script and attach it to the bullet just as you did with the rocketController.cs. Drag and drop "BulletController.cs" in the project window to the "bullet" in the hierarchy view.

f:id:nn_hokuson:20160703131433p:plain:w500

You attach the script, press the play button and run the game. The bullet moves upwards.

f:id:nn_hokuson:20160703131736g:plain

Make bullet Prefab

Next, we will make a Prefab of the bullet. Prefab is like a blueprint, and you can easily duplicate the same object using Prefab.

Select "bullet" in the hierarchy view to create bullet Prefab and drag & drop it to the project window. Then change the created file name to "bulletPrefab".

f:id:nn_hokuson:20160703131918p:plain:w500

After you create the bullet Prefab, the bullet on the scene view are not necessary. This is because you can create bullets from the Prefab anytime if you have blueprint. So right click in a hierarchy window and select "Delete".

f:id:nn_hokuson:20160703132034p:plain:w500

Create an instance from Prefab

Next, create a script to generate an instance (duplicate) of bullet from bullet Prefab when the space key is pressed.

Open the "RocketController.cs" and modify the script as follows.

using UnityEngine;
using System.Collections;

public class RocketController : MonoBehaviour {

	public GameObject bulletPrefab;

	void Update () {
		if (Input.GetKey (KeyCode.LeftArrow)) {
			transform.Translate (-0.1f, 0, 0);
		}
		if (Input.GetKey (KeyCode.RightArrow)) {
			transform.Translate ( 0.1f, 0, 0);
		}
		if (Input.GetKeyDown (KeyCode.Space)) {
			Instantiate (bulletPrefab, transform.position, Quaternion.identity);
		}
	}
}

In this script, we use the GetKeyDown() to detect that the space key is pressed. GetKey() returns true while the key is pressed, whereas GetKeyDown() return true only once when the key is pressed . When space key is pressed, make bullet instances from bullet Prefab. To create a bullet instance, we use Instantiate(). The Instantiate method requires three arguments:

  • Prefab
  • the position at which the instance
  • the rotation angle of the instance

Since transform.position is specified as the second argument, bullets are generated at the position of the rocket.

Finally, set the bulletPrefab to the "bulletPrefab" variable in RocketController script . Select rocket from the hierarchy window, and find the item "RocketController script" from the inspector, drag and drop "bulletPrefab" from the project window into the "bullet Prefab" field.

f:id:nn_hokuson:20160703152733p:plain:w500

Then bullets are fired each time when you press the space key.

f:id:nn_hokuson:20160703153002g:plain

The project file created this time can be downloaded following URL.

www.dropbox.com

Next article is as follow, please click here! (still Japanese)

nn-hokuson.hatenablog.com

【Unity】地形作りで学ぶShader Forge超入門

シェーダをグラフィカルに作れるツール「Shader Forge」を使って、ノイズ画像から立体的な地形を作ったり、シェーダで色をつけたりする方法を紹介します。作成する地形は次のような感じになります。

f:id:nn_hokuson:20170921195508j:plain:w600

Shader Forgeを使うことで、難しいシェーダ言語を覚えなくてもノードを繋ぐだけで簡単にシェーダを作ることができます。画面を見ながら試行錯誤できるので、実験的なシェーダを作るのにも最適です。Shader Forgeはアセットストアから入手できます。

今回の記事の内容は次のとおりです。

プロジェクトを作る

今回はハイトマップに使うノイズ画像と、高さごとの色を指定するランプ画像、スムーズな地形を作るためのハイポリゴンなPlaneを用意します。

今回使用するサンプルは↓からダウンロード出来ます。

www.dropbox.com

ダウンロードしたら、必要な素材をプロジェクトウインドウにドラッグ&ドロップし、mapをシーンビューに配置しておきましょう。

f:id:nn_hokuson:20170920193738j:plain

メニューバーからWindow -> Shader Forgeを選択してShader Forgeのウインドウを起動します。起動したらNew Shaderを選択して下さい。

f:id:nn_hokuson:20170920194144j:plain:w400

今回はライトの影響を考慮した影付きのモデルを表示したいので「Lit(PBR)」を選択します。

f:id:nn_hokuson:20170920200206j:plain

起動直後は次のような画面になります。一旦不要なノードは削除しておきましょう。

f:id:nn_hokuson:20170920200315j:plain

ノードを削除するには、ノードを選択して⌘+Xを押します。複数のノードを選択したいときはAltキーを押したまま左ボタンでドラッグします。また、接続した線を切りたい場合は、Altキーを押した状態でマウス右ボタンをドラッグします(ちょっとヤヤコシイですね・・・)

f:id:nn_hokuson:20170920194645j:plain

テクスチャを表示する

まずはPlaneにテクスチャを貼り付けるところから始めましょう。右クリックしてGeometory Data -> UV Coordinatesを選択(または「uキー」で表示されるメニューから選択)してUV Coordノードを追加します。同様にProperties -> Texture 2Dを選択し、Texture2Dノードを追加します。

f:id:nn_hokuson:20170920200549j:plain

これらのノードが追加できたらUVノードからTexture2DノードのUVへ、Texture2DのRGBからMainのBase Colorへ接続します。

f:id:nn_hokuson:20170920200738g:plain

Texture2Dノードの名前をbaseに変更し、Texture2Dノード内のSelectボタンを押してノイズ画像を設定してみましょう。

f:id:nn_hokuson:20170920200956j:plain

また、PBRではMainノードのMetallicに値を指定する必要があります。ここではConstant Vectors -> Valueを選択し、作成したValueノードをMainノードのMetalicに接続して下さい。

f:id:nn_hokuson:20170920202220j:plain

これで、テクスチャを貼り付けるだけのシェーダが完成しました。Unityエディタに戻りmapシェーダを見てみるとシェーダプログラムが自動的に記述されていることがわかります。このmapシェーダは通常のシェーダファイルと同じように扱えます。

シェーダに対応するマテリアルを作成する

mapシェーダを選択した状態で右クリックし、Create -> Materialを選択して新しくマテリアルを作成してください。作成したMaterialをシーンビューのmapにドラッグ&ドロップしてください。マテリアルがアタッチできたらmapのインスペクタに表示されるMaterialの欄のbaseにノイズ画像を設定してください。シーンビューのPlaneに、いま選択したノイズ画像が表示されます。Shader Forgeで設定したテクスチャはMaterialには反映されないので注意してください!

f:id:nn_hokuson:20170920202734j:plain

これで、①Shader Forgeでシェーダを作成、②マテリアルの作成とセットアップ、③シーンビューで表示という一連の流れが完成しました。次からは立体的な地形になるようにシェーダを作っていきましょう。

高さをつける

続いて地形に高低差をつけましょう。「どれくらい高くするか」はノイズ画像の明度によって決めます。ここでは画像が白いところは高く、画像が黒いところは低くなるように高さを調節していきましょう。

f:id:nn_hokuson:20170921191449p:plain:w400

シェーダで頂点の座標を操作するにはMainの「Vertex Offset」を使います。Vertex Offsetには「どの方向にどの程度移動させるか」のベクトルを指定します。

今回作るベクトルは、頂点の法線方向にノイズ画像の明度を掛けたものになります。数式にすると次のようになります。最後のKは頂点の移動量を調節するための係数です。

Vertex Offset = N(法線ベクトル)✕ ノイズ画像の明度(0.0〜1.0)✕ K

まず、法線の方向に関してはNormal Dirノードが用意されているので、これを配置しましょう。Geometry Data -> Normal Dirを選択してノードを配置します。続いて法線ベクトルとノイズ画像の明度を掛け合わせるため、Multiplyノードを配置します。MultiplyノードはArithmatic->Multiplyを選択して配置して、次のように接続して下さい。

f:id:nn_hokuson:20170920224640j:plain

頂点の移動量を調節する係数(K)にはSliderノードを使います。SilderノードはProperies ->Sliderを選択してノードを追加ください。Siderの範囲を0〜3、Sliderの名前をheightに変更しておきましょう。

f:id:nn_hokuson:20170920225138j:plain

これでノイズ画像の明度によって法線方向に頂点を移動させるシェーダが完成しました。Unityエディタに戻って、インスペクタからSliderの値を調節してみてください。テクスチャと同様、Shader Forgeで設定したSliderの値は保存されないので注意してください!初期状態ではSliderの値は0になるため、スライダを動かすまでは地形の高さは変化しません。

f:id:nn_hokuson:20170920225742j:plain

地形に色を付ける

地形が真っ白では味気ないので、色を付けていきます。色をつける方法も先程と同様、ノイズテクスチャの明度に沿って色分けします。具体的には次のような感じにしてみましょう。

明度
0~0.4
0.4~0.5
0.5~0.7
0.7~0.9
0.7~1.0

テクスチャの明度値から色をつくるためには、Rampテクスチャと呼ばれる仕組みを使います。Rampテクスチャとは次のように、一方向に色合いの変化があるテクスチャのことで、UV座標のU値に応じた色を取り出すことが出来ます。

f:id:nn_hokuson:20170921192540j:plain:w550

ノイズ画像の明度値をランプテクスチャののU値として扱うと、明度が0.2(u=0.2)なら青色、明度が0.8(u=0.8)なら茶色を取り出すことができます。これで、上に書いた表どおりの色が取り出せますね。

今回はノイズ画像の明度をU値としましたが、物体表面の明度をU値とすればトゥーンシェーダのような表現にも使うことができます。

nn-hokuson.hatenablog.com

この流れを作るため、Appendノード(Vector Operation -> Append)と、Texture2Dノードを追加して次のように接続してください。Texture2DノードにはRampという名前をつけて、Selectボタンでランプテクスチャを選択します。

f:id:nn_hokuson:20170920231441j:plain

ここでは、Appedノードを使ってUV座標を作っています。U値にはノイズ画像の明度値、V座標には0を入れています。作成したU座標を使ってランプテクスチャから色を取り出し、最後にその色をMainノードのDiffuseに設定しています。Unityエディタに戻って、インスペクタからRampの欄にランプテクスチャを設定して実行してみてください。

f:id:nn_hokuson:20170920231725j:plain

地形に陰影を付ける

実行してみると地形の高さによって色合いが変化しているのがわかります。でも、まだ全体的にのっぺりして陰影がついていません。これは頂点の座標を変化させたのは良いけれども、法線の方向を再計算していないため、すべての頂点が上を向いてしまっていることが原因です。

これでは陰影がつかずにのっぺりして見えても仕方がありません。実際の地形に沿った法線の再計算を行いましょう。

f:id:nn_hokuson:20170921200354p:plain

と・・・ここまで書きましたが、法線を再計算するのはやっぱり結構大変です。なので、ここではなんちゃってのライティングを考えてみましょう。

山があって、光が横から当たっていれば当然ですが明暗がつくられますね。この明暗は次の図のようにノイズテクスチャの位相を45度ずらしたものと考えることができます(ちょっと無理矢理ですが・・・)。

f:id:nn_hokuson:20170926195902p:plain:w550

要するに、ノイズテクスチャは「高いところを白、低い所を黒」としているので位相を45度回せば高いところの頂点を中心として「半分は白、半分は黒」となります(何度も書きますが、この計算はなんちゃって、英語ではpseudoです。笑)

ということで、ここではノイズのテクスチャを少しだけ移動させたものを明度として、最終的なテクスチャに掛け合わせてみましょう。次のようにノードを配置してください。

f:id:nn_hokuson:20170926202107j:plain

ここではUVの値に(0.02, 0.02)のベクトルを足すことで、U方向とV方向のテクスチャを左上の方向に移動させたテクスチャを作っています(ここでは分かりやすいようにTexture2Dのノードを配置して、base2という名前にしています)。

最後に作成したテクスチャと、色分けしたテクスチャをMultiplyノードでかけ合わせたものをMainノードのBase Colorに接続して出力しています。また、テクスチャどおしを掛け合わせると暗くなるので、Sliderノードを使って少し明るくしています。

実行すると次のようになります。

f:id:nn_hokuson:20170926204951j:plain

実行する際はインスペクタからbase2にノイズテクスチャを設定するのを忘れないようにしてください。

f:id:nn_hokuson:20170926204358j:plain:w300

Texture2Dノードをまとめる

先程、Texture2Dノードを追加してbase2と名前をつけましたが、インスペクタから設定する箇所が増えて不便なので、一箇所にまとめておきましょう。

次のようにもう一つTexture Assetノード(Properties->Texture Asset)を追加しbaseという名前にしましょう。続けてTexture AssetノードのTexから、Texture2DノードのTexに接続してください。Texture2DのTexに接続するとこで、インスペクタからは入力できないノードになります。

f:id:nn_hokuson:20170926202304j:plain

インスペクタを確認すると、テクスチャを入力する欄がbaseとrampの2つに減っていることが確認できますね。

f:id:nn_hokuson:20170926204041p:plain:w240

UVスクロールして地形を動かす

最後にUVスクロールを使って地形を動かす方法を紹介します。UVスクロールは2Dゲームの背景スクロールや、水面、滝の表現など、様々な場面で使える技術です。

nn-hokuson.hatenablog.com

ここではShader Forgeを使ってUVスクロールする方法を紹介します。Shader Forgeで「時間の変化に合わせてhogehogeしたい」というときにはTimeノード(External Data->Time)を使います。

Timeノードはゲーム開始からの時間を扱うノードです。4つの出力がありますが、それぞれ時間をスケーリングしてるだけなので、使う場面に合わせたものを選びましょう。

ここでは、時間とともにUV座標のうちU座標を変化させたいので、時間変化と移動速度(u方向に0.02)をMultiplyノードで掛け合わせたものをUV座標に足しています。

次のようにノードを配置してください。

f:id:nn_hokuson:20170926203059j:plain

実行すると、次のように地形がu方向にスクロールしていくのがわかります。移動速度のベクトルを変化させることでUV方向にスクロールさせたり、逆方向にスクロールすることもできますよ!

真面目に法線の再計算をして影をつける

真面目に法線の再計算をする方法を最後にサラっと紹介しておきます。法線は隣の頂点との傾きを見ることで計算できます。でも、シェーダは並列で計算されるため「隣の頂点」を見るのがとても苦手です。なので、ノイズテクスチャから仮想的に地形の傾きを計算して、その傾きから法線ベクトルを算出します。

現在注目しているテクスチャの座標値と、少し左にずれたテクスチャの明度値の差が、X方向の地形の傾きになります。同様に、現在注目しているテクスチャの座標値と、少し上にずれたテクスチャの明度値の差が、Y方向の地形の傾きになります。

f:id:nn_hokuson:20170921193358p:plain:w240

この2つのベクトルとZ方向のベクトルをあわせた3次元の傾きから、法線の方向を再計算します。すこし複雑になりますが、次のようにノードを配置してください。

f:id:nn_hokuson:20170921194335j:plain

急に複雑になってしまいましたね(笑)でも、やっていることは通常のテクスチャを少しだけx方向に移動させたテクスチャと、少しだけy方向に移動させたテクスチャを作り、そのテクスチャと通常のテクスチャの差分をとって法線ベクトルを作成しているだけです(赤枠内)。オレンジ色で囲った部分は、次の数式のように法線の大きさが1になるようにZ方向のベクトルの大きさを決めています。


{ \displaystyle
dz = \sqrt{1-dx^2 - dy^2}
}


保存できたらUnityエディタで実行してみて下さい。ちゃんと陰影が反映されて立体的な地形に見えると思います。流石になんちゃっての陰影よりも遥かに綺麗ですね!

f:id:nn_hokuson:20170921195508j:plain

まとめと参考資料

Shader Forgeを使って、ノイズ画像から立体的な地形を作ったり、シェーダで色をつけたりする方法を紹介しました。Shader Forgeは簡単にシェーダが作れて試行錯誤できるのでオススメです!

Shader Forge公式サイト

Shader Forgeのサイトでは各ノードの働きを確認できます。どんな種類のノードがあるのかを一通り眺めて置けるのがGoodです!

Shader Forge

小林信行さんの資料

Shader Forgeの使い方から、テクスチャブレンド、ライティング、トゥーンシェーダまでとってもわかり易く説明されている資料です。もはや小林さんの資料を読めば、このページはいらんのちゃうかと思わなくもないぐらい・・・笑

www.slideshare.net

Unityの教科書もよろしくおねがいしまーす!(Shaderには触れていませんが・・・笑)

【Unity】Androidの実機上でDebug.Logの内容を確認する2つの方法

Unity EditorではDebug.Logはコンソールウインドウに表示されますが、Androidの実機に転送した場合、コンソールウインドウでDebug.Logの表示は確認できません。

そこで、Androidの実機で実行しているアプリのDebug.Logを見る方法を2つ紹介します。

Debug.Logをフックする

Debug.Logの内容をフックして、uGUIのTextで表示させる方法です。結構手軽で気に入ってますが、こだわりだすとツールを作るのが苦痛になるので、機能はそこそこで(笑)

Debug.Logのメッセージをフックする

まずはログをフックするスクリプトを作成します。プロジェクトビューで右クリックしCreate -> Script -> C# Scriptを選択して、LogDisplayという名前で保存します。

スクリプトができたら、次のプログラムを入力してください。

using UnityEngine;
using UnityEngine.UI;

public class LogDisplay : MonoBehaviour
{
    public Text message = null;

    private void Awake()
    {
        Application.logMessageReceived  += HandleLog;
    }

    private void OnDestroy()
    {
        Application.logMessageReceived  += HandleLog;
    }

    private void HandleLog( string logText, string stackTrace, LogType type )
    {
        message.text = logText;
    }
} 

このスクリプトではlogMessageReceivedイベントにOnLogMessageイベントハンドラを追加しています。イベント?イベントハンドラ?という方は、拙書「」を参考にしてください(Unityに特価した本ではありませんが、ひととおりのC#の文法は解説しています)

[asin:4797390263:detail]

OnLogMessageイベントハンドラではフックしたログの内容をuGUIのTextに表示しています。

スクリプトをアタッチしてTextを設定する

ヒエラルキーウインドウでCreate->Create Emptyを選択し、空のオブジェクトを作成してください。そのオブジェクトにLogDisplayスクリプトをドラッグ&ドロップしてアタッチします。

f:id:nn_hokuson:20170915132136j:plain

また、ヒエラルキーウインドウでCreate-> UI -> Textを選択し、作成したTextオブジェクトをLogDisplayスクリプトのMessage欄にドラッグ&ドロップしてください。

f:id:nn_hokuson:20170915132241j:plain

あとは、実機に転送して実行すれば、ログの内容がTextに表示されます。

Android Device Monitorを使う

いや、わざわざ実機上でログを確認しなくても、ツール上で確認できれば十分だよ!という人(というか、普通はこっちですね。笑)はAndroid StudioについてくるMonitorアプリを使いましょう。

MonitorアプリはWindowsなら「C:\Users\ユーザー名\AppData\Local\Android\sdk\」、Macなら「/Users/ユーザ名/Library/Android/sdk/tools/monitor」にあります。ターミナルから次のように打ってMonitorアプリを起動しましょう。

$ /Users/ユーザ名/Library/Android/sdk/tools/monitor

起動すると次のような画面が表示されます。

f:id:nn_hokuson:20170915132609j:plain

続いてUnityで作ったアプリのログだけが表示されるよう、フィルタを作成します。画面左下の「Saved Filter」と書かれた横の緑色のプラスボタンをクリックし、Filter NameとBy Log Tagの欄に「Unity」と入力してOKボタンを押してください。

f:id:nn_hokuson:20170915132653j:plain

あとは、実機でアプリを動かすと、Monitorのコンソール上にログが表示されます。こちらも便利ですね!