Unityでは、2Dゲームも作成できます。
昔ながらのシューティングゲームをUnityで作ることは、楽しいだけでなく色々とUnityやプログラミングへの知見が得られるのではないかと思います。
こんなゲームを作ります。
このゲームは、あくまで試作品です。(プロトタイプともいいます)
タイトル画面もないですし、敵も1種類しか出てきません。ただしUnity 2Dでのゲーム作成における根本的なことを学ぶためこの記事を書きました。
実際の動作確認は以下サイトで可能です。
操作はキーボードとゲームパッドの両方に対応させています。
【キーボード】 移動/十字キー ショット/z
【ゲームパッド】 移動/左アナログスティック ショット/Aボタン Xモードで使用
※スコア表示が見えない場合、ブラウザ画面を最大化して実行してください。
※スマホでは動作非推奨のようですが、一応動きます。ショットしか出来ませんが…
プロジェクトの準備
Unityを起動し、テンプレートから2Dを選択し、プロジェクト名「PocketShooting_trial」としてプロジェクトを新規作成します。

最終的にブラウザで実行可能なWebGLで書き出しを行いたい方は、プロジェクト名には日本語などの全角文字を使わないようにしてください。
プロジェクト起動直後の画面

シーンの保存
Unityの場合、ゲーム画面をシーンという単位で保存します。
プロジェクト起動直後はScenesフォルダにあるSampleSceneというファイルがデフォルトで開いている状態になっています。
このまま作成を進めても問題はないですが、名前をつけてシーンを保存した方がゲームを自分で作っている意識が出てきます。
File > Save As… を選択します。

Assets > Scenes に移動し、GameSceneという名前で現在のシーンを保存します。

ProjectタブのAssets > Scenes にGameSceneが作成されていればシーンの保存は完了です。
SampleSceneはもう必要ないので、deleteキーで削除してしまいましょう。

実行画面の設定
今回作成するシューティングゲームは縦長です。
Unityデフォルトの比率は、横長に設定されているため、縦長の設定を新たに追加します。
ちなみにシーンウインドウに表示されている白枠が実行時に表示される部分です。横長ですね。

Gameタブをクリックします。
先ほどの白枠部分がGameタブでは少し濃い青で表示されています。

GameタブのDisplay1の右隣りの項目をクリックするといくつかの縦横比が表示されます。
ただし、いずれも横長のため、ゲーム実行時の画面サイズを新規作成します。
リスト表示された一番下にある + をクリックします。

Labelに「Mobile」、Typeを「Aspect Ratio」、Width &Heightをそれぞれ「9」「16」としてOKボタンをクリックします。

新しい縦横比が作成されました。

実行画面の設定は以上です。
スプライトをAssetsに追加する
ゲームで使用する元画像は Assets > Sprites に保存することにします。
今回、スプライト(といってもわたしがMicrosoftのペイントで作った画像ですが)としてPNG形式のゲーム画像を用意しました。

こちらからダウンロードできます。
今回作るゲームではダウンロードした画像のうちの3つの画像しか使っていません。
使っていない画像が多数ありますが気にしないでください。ダウンロードしたファイルはZIP形式になっています。展開するとSpritesフォルダに画像が保存されますので、SpritesフォルダごとAssetsにドラッグ&ドロップして追加してください。
スプライトを追加した状態

ご自分でキャラクタを作りたい方は64×64ピクセルまたは128×128ピクセルくらいの大きさで背景を透過処理したPNG形式の画像を準備してください。(大きさは目安ですので、自由で構いません)
ゲームで利用する画像はAssetsにSpritesというフォルダを作ってまとめておくと管理が楽です。
なお、以降の解説にはこのスプライトを使わせて頂きます。
プレイヤーを作成する
まずはゲームパッドまたはキーボードで操作できるプレイヤーを作成します。
Spritesフォルダにあるplayerをシーンにドラッグ&ドロップします。

player画像は64×64ピクセルでつくってあるのですが、わたしとしてはゲーム画面に対してプレイヤーが小さ過ぎる気がしたので、InspectorウインドウからScaleのx,y,zを全て2(2倍)としました。
気になる方は適当に変えてみてください。

とりあえず実行するとこんな感じとなります。

プレイヤーのスクリプト
次にプレイヤーを操作できるようにします。
今回のゲームは、スクリプトが複数必要になりますので、他のスクリプトも保存できるように AssetsフォルダにScriptsフォルダを作成してください。

Assets > Scriptsフォルダ内で、
C# Script を作成し、スクリプト名を「PlayerController」とします。

PlayerControllerをダブルクリックしてVisual Studioを起動し、以下を入力してください。
PlayerContrller
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
// プレイヤーの移動速度
public float Speed;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
// 方向キーで入力された横軸の値を取得
float x = Input.GetAxis("Horizontal");
float y = Input.GetAxis("Vertical");
// 現在位置にx,y の値を加算する
transform.position += new Vector3(x, y, 0) * Time.deltaTime * Speed;
}
}
PlayerControllerスクリプトをシーン上のplayerにアタッチします。

プレイヤーの移動速度は、Inspectorウインドウから設定できます。
playerを選択して、InspectorウインドウのSpeed項目に適当な数値を入力してください。

実行確認してみます。
キーボードの十字キーまたはゲームパッドの左アナログスティックでプレイヤーの移動が出来るようになりました。

少しだけ解説
プレイヤーの移動速度などのように、public宣言するとInspectorウインドウで手軽に変更できるので便利です。
public float Speed;
Input.GetAxisを使うとキーボードとゲームパッドの両方への対応が出来ます。
引数のHorizontalは水平方向(左右)、Verticalは垂直方向(上下)となります。
float x = Input.GetAxis("Horizontal"); float y = Input.GetAxis("Vertical");
プレイヤーがショットを打てるようにする
zキーまたはゲームパッドのAボタンを押した時、プレイヤーがショットを打つようにします。
プレイヤーのショットはオブジェクトが上方向に移動するプレハブを作ります。
ショットプレハブの作成
Spritesフォルダのtamaをシーンにドラッグ&ドロップします。

サイズが小さいのでScaleのX, Y, Zを全て2(2倍)にしておきます。

次にスクリプトで動きをつけます。
Assets > Scriptsフォルダに
「BulletController」という名前のC# Scriptを作成します。

BulletContrllerをダブルクリックして以下を記述します。
BulletController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletController : MonoBehaviour
{
// 弾の発射スピード
public float Speed;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
// 下から上に弾を移動
transform.position += new Vector3(0, Speed, 0) * Time.deltaTime;
// 画面上方に消えたら弾を消去
if (transform.position.y >= 5.5f)
{
Destroy(gameObject);
}
}
}
BulletControllerをシーン上のtamaにアタッチします。

InspectorウインドウのSpeed項目に15と入力します。(ショットの移動速度なので適当に変更してみてください)

実行して上方向にtamaが移動したらOKです。

シーンから見えなくなったオブジェクトはDestroyする
ショットは上方に消えて見えなくなるので、見えなくなってからも同じ処理を続けることはCPUに余計な負担を掛けることになります。
このスクリプトでは、見えなくなったあたりでDestroy関数を使ってシーンからオブジェクトを破棄しています。
// 画面上方に消えたら弾を消去
if (transform.position.y >= 5.5f)
{
Destroy(gameObject);
}
スクリプトではショットのY座標が5.5以上になったらオブジェクトを破棄していますが、シーンの上辺のY値がだいたい5でしたので、少し余裕をもたせて5.5としているだけです。(ゲームはあくまでそれっぽく見えればいいのです)
ちなみに今回のゲーム画面の座標軸イメージはこんな感じです。
画面中央が(X, Y) = (0, 0)と考えてください。Y座標が5.0を越えるとシーンから見えなくなります。

試しに上記スクリプトを
// 画面上方に消えたら弾を消去
if (transform.position.y >= 3.0f)
{
Destroy(gameObject);
}
などとすればショットがシーンで見えているうちに消えるのでスクリプトの挙動がよく理解できると思います。
ショットをプレハブ化する
ショットの動きが出来たので、この状態でショットをプレハブ化しておきます。
シーン上のtamaをAssetsにドラッグ&ドロップします。

プレハブ化したtamaの名前をBulletに変更しておきます。

シーン上のtamaはもう必要ないので削除してください。
プレイヤーがショットを打てるようにスクリプトを変更する
現時点ではプレイヤーは移動操作しかできません。
zキーまたはゲームパッドのAボタンでショットが打てるようにスクリプトを変更します。
PlayerControllerを開き、以下のハイライト部分を追加してください。
PlayerController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
// プレイヤーの移動速度
public float Speed;
// 弾のプレハブ
public GameObject bulletPrefab;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
// 方向キーで入力された横軸の値を取得
float x = Input.GetAxis("Horizontal");
float y = Input.GetAxis("Vertical");
// 現在位置にx,y の値を加算する
transform.position += new Vector3(x, y, 0) * Time.deltaTime * Speed;
// ジョイパッドのAボタン または zキーが押されたら弾を発射
if (Input.GetButtonDown("Fire1") || Input.GetKeyDown("z"))
{
Instantiate(bulletPrefab, transform.position, Quaternion.identity);
}
}
}
PlayerControllerを上書き保存後、Playerを選択してInspectorウインドウを表示します。
BulletプレハブをPlayer ControllerコンポーネントのBullet Prefab項目にドラッグ&ドロップします。

実行してzキーまたはゲームパッドのAボタンでショットが打てるようになれば成功です。

敵を出現させる
まずはプレイヤーに向かってくる敵をプレハブとして作成してみます。
Spritesにあるtekiをシーンにドラッグ&ドロップします。

シーン上のtekiもサイズが小さいのでScaleのX, Y, Zを全て2(2倍)にしておきます。

敵のスクリプト
敵は登場したときは真っすぐ下方向に降りてきて、ある位置(ランダムで決定)からプレイヤーに向かってくる動きにします。
こんなイメージです。

Assets > Scriptsフォルダに
「EnemyController」という名前のC# Scriptを作成します。

EnemyControllerをダブルクリックして以下を記述します。
EnemyController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyController : MonoBehaviour
{
public float Speed; // 速度
private float pointY; // プレイヤーに向かってくるY軸の位置
private float vx; // X軸の移動量
private GameObject player; // プレイヤーオブジェクト取得用
// Start is called before the first frame update
void Start()
{
// プレイヤーに向かってくるY軸の位置
pointY = Random.Range(2.0f, 3.0f);
// 敵の初期位置とプレイヤーの位置によってX軸の移動方向を決定する(プレイヤーに向かってくるような設定)
vx = 1.0f;
player = GameObject.Find("player");
if(player.transform.position.x < transform.position.x)
{
vx = -vx;
}
}
// Update is called once per frame
void Update()
{
// 下に向かって移動する
transform.position += new Vector3(0, -Speed, 0) * Time.deltaTime;
// 一定の位置になるとプレイヤーに向かって移動する
if(transform.position.y < pointY)
{
transform.position += new Vector3(vx, 0, 0) * Time.deltaTime;
}
// 画面の下に消えたらオブジェクト消去
if(transform.position.y < -5.5f)
{
Destroy(gameObject);
}
}
}
EnemyControllerをシーン上のtekiにアタッチします。

tekiのInspectorウインドウを確認してください。
Enemy Controller(Script)にあるSpeedの項目が敵の降下スピードです。適当な数値を入力してください。

実行の際は、敵の動きを確認するため、シーン上の敵のY座標をなるべく上方にして、X座標はプレイヤーの右側か左側にはっきりと分かる配置としてください。

こんな風に敵が途中からプレイヤーに向かってくればOKです。

敵の動きが確認できたらAssetsにドラッグ&ドロップしてプレハブ化します。

プレハブ化した敵の名前をEnemyと変更しておきます。

次に敵をランダムで出現させるようにします。
シーン上のtekiはもう必要ないので削除しておいてください。
敵をランダムで出現させる
スクリプトを使って、プレハブ化した敵(Enemy)をシーン上にランダムで出現させます。
まずはスクリプトの準備です。
Assets > Scriptsフォルダに
「EnemyGenerator」という名前のC# Scriptを作成します。

EnemyGeneratorをダブルクリックして、以下を記述します。
EnemyGenerator
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyGenerator : MonoBehaviour
{
// 敵のプレハブ
public GameObject enemyPrefab;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
// 敵をランダムに生成
if(Random.Range(0, 300) == 1)
{
Vector3 pos = new Vector3(Random.Range(-2.8f, 2.8f), 5.5f, 0); // 画面上方に生成
Instantiate(enemyPrefab, pos, Quaternion.identity);
}
}
}
EnemyGeneratorをアタッチするため、空のオブジェクトをシーンに作ります。
Hierarchyウインドウから + > Create Empty を選択します。

作成されたオブジェクトの名前 GameObject を GameMain に変更してください。

EnemyGeneratorをシーン上のGameMainにアタッチします。

GameMainを選択し、InspectorウインドウのEnemy Generator(Script)の項目を表示しておきます。
プレハブEnemyをInspectorウインドウのEnemy Prefabの項目にドラッグ&ドロップしてください。

これでEnemyGeneratorに生成させる敵のプレハブが決定されました。
実行して敵がランダムに出現すれば成功です。

敵の出現頻度は、スクリプトの300の数値を減らせば上がりますし、数値を増やせば出現頻度は下がります。適当に変更してみてください。
// 敵をランダムに生成
if(Random.Range(0, 300) == 1)
{
Vector3 pos = new Vector3(Random.Range(-2.8f, 2.8f), 5.5f, 0); // 画面上方に生成
Instantiate(enemyPrefab, pos, Quaternion.identity);
}
ショットと敵の当たり判定をする
敵が出現したので、ショットで倒したいですよね。
でも現時点ではプレイヤーのショットは敵を通り抜けてしまいます。

ショットと敵との当たり判定が必要です。
当たり判定には、当たり判定するオブジェクト双方にColliderコンポーネントが必要です。また、どちらか一方にはRigidbodyコンポーネントが必要となります。
今回は以下のようにコンポーネントを追加していきます。
オブジェクト | 追加コンポーネント |
---|---|
ショット(Bulletプレハブ) | CircleCollider |
敵(Enemyプレハブ) | CircleCollider Rigidbody |
ショットにColliderを追加する
英語でCollider(コライダー)とは衝突装置のような意味を持ちます。
UnityではColliderはコンポーネントの1つとして提供されていまして主に当たり判定に利用します。
UnityのColliderには、その形状から沢山種類がありますが、今回は2Dゲーム用のCircle Collider 2Dを使います。
Circle Collider 2D は名前の通り円状範囲を持つ当たり判定コンポーネントです。
Colliderの形状の種類を知りたい方は以下を参照してください。

Bulletプレハブをダブルクリック(または選択してOpen Prefabボタン)して、InspectorウインドウからAdd Componentボタンをクリックします。

Phisics 2D > Circle Collider 2D を選択して追加します。

Sceneタブに緑色の線で表示されている領域が Circel Collider 2D の当たり判定の境界となります。

今回は自動で選択された範囲で問題なさそうですが、微調整も可能です。
当たり判定の境界を調整する場合は、InspectorウインドウにあるCircle Collider 2DのEdit ColliderボタンまたはRadius項目の数値を変更することで円状の範囲の微調整ができます。

ショットと敵がぶつかった時の跳ね返りを防ぐため、Is Triggerにチェックを入れます。

Is Triggerのチェックを外すとオブジェクト同士がぶつかった際、物理挙動が発生して跳ね返ったりします。今回のゲームでは物理挙動が必要ない為、チェックを入れています。
敵にColliderを追加する
敵(Enemyプレハブ)にもColliderを追加します。
Bulletプレハブに追加した時と同じように、Enemyプレハブをダブルクリック。

Add Componentボタンから Phisics 2D > Circle Collider 2D を選択して追加します。

自動選択範囲で問題なかったため、わたしはColliderの範囲をこのままにしました。
気になる方は Circle Collider 2D のRadius項目等で調整してください。

ショットと同様に衝突した時の跳ね返りを防止するためIs Triggerにチェックを入れます。

敵にはColliderに加え、Rigidbodyコンポーネントも追加します。
Add Componentボタンから Phisics 2D > Rigidbody 2D を選択して追加します。

Rigidbody 2DにあるBody TypeをKinematicに変更します。

Rigidbody 2DのBody Typeは変更しなくても問題はありませんが、デフォルトの Dynamic に設定されている場合、重力と力の物理演算をします。
Kinematicにすると、物理演算を伴わないため処理が軽くなるので今回は変更しています。
当たり判定用にスクリプトを修正する
今回はショットと敵との当たり判定となります。
この場合、BulletControllerとEnemyControllerのどちらか一方に当たり判定用のスクリプトを記述すれば良い事になります。
今後、敵の種類が増えることも考慮するならショット側(BulletController)に記述する方が良いでしょう。
BulletControllerスクリプトに以下のハイライト部分を追加します。
BulletController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletController : MonoBehaviour
{
// 弾の発射スピード
public float Speed;
// Start is called before the first frame update
void Start()
{
}
// シーン上のオブジェクトと接触したときの処理
private void OnTriggerEnter2D(Collider2D col)
{
// 敵だったら
if (col.gameObject.tag == "Enemy")
{
// ぶつかった相手を破壊
Destroy(col.gameObject);
// 弾を破壊
Destroy(gameObject);
}
}
// Update is called once per frame
void Update()
{
// 下から上に弾を移動
transform.position += new Vector3(0, Speed, 0) * Time.deltaTime;
// 画面上方に消えたら弾を消去
if (transform.position.y >= 5.5f)
{
Destroy(gameObject);
}
}
}
こままま実行してもエラーは出ませんが当たり判定が実行されません。
上記スクリプトでは、タグによる当たり判定をしています。
EnemyプレハブにEnemyというタグ名をつけることでこの当たり判定が有効となります。
Enemyプレハブにタグ名をつける
シーン上のオブジェクト(プレハブ含む)にはタグといってTwitterのハッシュタグのように特定のカテゴリ分けした名前をつける事ができます。
例えば敵のプレハブとしてがEnemy1とEnemy2の2種類のプレハブを作ったとします。Enemy1とEnemy2のタグ名を同じEnemyとしてしまえば、プレイヤーとの当たり判定ではタグ名を使って同じ《敵》として判定できるわけです。
先ほどのスクリプトの以下の部分です。
// 敵だったら
if (col.gameObject.tag == "Enemy")
{
// 処理
}
今回敵が1種類しかありませんので、メリットは少ないですが、こうした作りはゲームを拡張していったときに威力を発揮します。
前置きが長くなりましたが、Enemyプレハブにタグ名としてEnemyをつけていきます。
Enemyプレハブをダブルクリックします。
InspectorウインドウのTag項目のUntaggedとなっている部分をクリックして、Add Tag… を選択します。(ちなみにリストアップされたPlayerやMainCameraなどは最初から存在するタグ名です)

+ をクリックするとテキストボックスが表示されます。
Enemy と入力してSaveボタンをクリックします。
これでタグ名Enemyが新規作成されました。
再度EnemyプレハブをダブルクリックしてTag項目を表示させ、Enemyタグを選択してください。

プレハブEnemyにEnemyタグを設定した状態

これでタグ名による当たり判定が出来るようになりました。
実行確認して敵がショットに当たったら消えることを確認してください。

敵を倒したときの効果音とエフェクトを設定する
敵をショットで倒せるようになりましたが、爽快感が足りません。
敵を倒したときの効果音と効果エフェクトを設定します。
素材の準備
効果音は、魔王魂から爆破したときの音を利用しました。(フリーのMP3形式等であれば何でも良いです)
以下からMP3形式のファイルをダウンロードします。

ダウンロードした音源ファイルは、あらかじめ作成しておいたSoundsフォルダにドラッグ&ドロップして取り込んでおきます。

爆破エフェクトとして、Asset StoreからUnity公式アセットのUnity Particle Pack 5.xをインポートします。

Unity Particle Pack 5.xインポート後は、EffectExamplesというフォルダが作成されます。

Unity Particle Pack 5.xインポート後に以下のエラーが表示される場合があります。
Library\PackageCache\com.unity.postprocessing@2.0.3-preview\PostProcessing\Runtime\PostProcessManager.cs(425,66): error CS0117: 'EditorSceneManager' does not contain a definition for 'IsGameObjectInMainScenes'
以下を参考にUnityパッケージをアップデートして下さい。
効果音と爆破エフェクト用にスクリプトを修正
BulletControllerスクリプトを修正します。
以下ハイライト部分を追加してください。
BulletController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletController : MonoBehaviour
{
// 弾の発射スピード
public float Speed;
// 爆破エフェクト(プレハブ)
public GameObject ExplosionEffect;
// 効果音
public AudioClip se;
// Start is called before the first frame update
void Start()
{
}
// シーン上のオブジェクトと接触したときの処理
private void OnTriggerEnter2D(Collider2D col)
{
// 敵だったら
if (col.gameObject.tag == "Enemy")
{
// 爆破エフェクト
Instantiate(ExplosionEffect, transform.position, Quaternion.identity);
// 効果音再生
AudioSource.PlayClipAtPoint(se, transform.position);
// ぶつかった相手を破壊
Destroy(col.gameObject);
// 弾を破壊
Destroy(gameObject);
}
}
// Update is called once per frame
void Update()
{
// 下から上に弾を移動
transform.position += new Vector3(0, Speed, 0) * Time.deltaTime;
// 画面上方に消えたら弾を消去
if (transform.position.y >= 5.5f)
{
Destroy(gameObject);
}
}
}
Bulletプレハブに効果音とエフェクトを設定する
修正したスクリプトではInspectorウインドウから効果音と爆破エフェクトが設定できるようになっています。
BulletプレハブをクリックしてBullet Controller(Script)項目を表示します。
Seには、効果音ファイルを、Explosion Effectには爆破エフェクト用のオブジェクトを設定します。

ヒント
Assetsフォルダの素材が増えてきましたので、ドラッグ&ドロップで設定するよりは、各項目の選択ボタン(◎ボタン)でファイル選択した方が今後は楽です。

Se項目にSoundsフォルダに保存した効果音を設定します。
◎をクリックします。

設定したい効果音をダブルクリックします。

Se項目設定後のイメージ

次にExplosion Effectに爆破エフェクトを設定します。
今回エフェクトに利用するアセットUnity Particle Pack 5.xは、インポート後EffectExamplesというフォルダ名でAssetsに保存されています。

今回利用する爆破エフェクトは
Assets > EffectExamples > FireExplosionEffects > Prefabsにある SmallExplosionEffectを使います。(ファイル名が長いと欠けてみえないのでスライドを左端にすると見やすいです)

ただしこのプレハブのデフォルト設定が、ずっと同じ位置でループ再生する(爆破エフェクトを繰り返す)設定になっているため使い勝手が少々悪いです。1回のみ爆発するように SmallExplosionEffect プレハブの設定を変更します。
SmallExplosionEffect をダブルクリックします。
Hierarchyウインドウに表示されているSmallExplosionEffect、Light、Embers、Fireの4項目すべてを選択します。(Shiftキーを押しながら選択)

InspectorウインドウのLooping項目のチェックを外します。

次にHierarchyウインドウの SmallExplosionEffect のみを選択し、InspectorウインドウのStop Action項目をNoneからDestoryに変更します。

SmallExplosionEffectプレハブの設定変更は以上です。
Bulletプレハブを選択し、Explosion Effect項目の◎ボタンをクリックしてオブジェクト選択ウインドウを表示します。

SmallExplosionEffect をダブルクリックします。

爆破エフェクト設定後のイメージ

以上で効果音と爆破エフェクトの設定は完了です。
実行して敵を倒した時に音とエフェクトが再生されたら成功です!
音量が小さく感じるとき
ちょっと効果音の音量が小さくない?と感じた方は正解です。
効果音を再生しているスクリプト部分に問題があります。
以下のようにBulletControllerの効果音再生のスクリプト部分を修正してみてください。
// 効果音再生
AudioSource.PlayClipAtPoint(se, new Vector3(0.0f, 0.0f, -10.0f) );
これで元の音量で効果音が再生できるはずです。
修正後のイメージ
PlayClipAtPointの最初の状態
AudioSource.PlayClipAtPoint(se, transform.position);
では、transform.positionで設定しているため、爆発した位置で音が鳴っている状態でした。
変更後の new Vector3(0.0f, 0.0f, -10.0f) は、シーン上のMain Cameraの場所を指しています。
なぜMain Cameraの場所にすると音が大きくなるかと言うとMain CameraにAudio ListenerというUnityでいうところの耳があるからです。
詳しくは以下を参考にどうぞ。
スコアを表示する
敵を倒した時スコアを表示するようにします。
Unity 2Dでスコア等を表示するには3Dゲーム制作と同様にUI Textを使います。
スコアはゲーム画面右上に表示するようにします。

UI Textを作成する
Hierarchyウインドウから + > UI > Text を選択します。

Canvasオブジェクトの中にTextが作成されます。

Textの名前を分かりやすいようにScoreと変更します。

端末サイズに応じてフォントサイズを変える
HierarchyウインドウのCanvasを選択してInspectorウインドウを表示してください。
Canvas Scaler項目の以下の箇所を修正します。
UI Scale Mode | Scale With Screen Size |
Reference Resolution | Xを720, Yを1280 |
Screen Match Mode | Expand |

これは端末のサイズに応じてスコア表示の位置と大きさを同じにするための設定です。
特にUI Scale Modeの項目は大事です。
UI Scale ModeがConstant Pixel Sizeになっていると端末サイズが変わってもフォントサイズが小さく見えたり大きく見えたりして違和感のある表示となってしまいます。
ゲームっぽいフォントをインポートする
Unityの最初の状態ではフォントはほとんど入っていません。
Asset Storeからゲームっぽい見た目の「Free Pixel Font – Thaleah」をダウンロード&インポートしてください。

インポート後にAssetsに「Thaleah_PixelFont」というフォルダが作成されていればフォントインストール完了です。

UI Textの見た目を整える
GameタブでないとUI Textの配置イメージがつかみにくいのでGameタブをクリックします。

UI Textのデフォルトで表示される文字はNew Textです。
Gameタブにこの文字が表示されてはいますが、小さすぎて見えません。(New Textの文字が見える方は余程目の良い方です)
まずはUI Textのフォントサイズを大きくする前にUI Textの枠を広げておきます。
Scoreを選択してInspectorウインドウのWidthとHeightを以下のようにしてください。
Width | 500 |
Height | 100 |

次にText項目のフォントやフォントサイズ等の4項目を変更して見やすくします。
Text | Score: 0000 |
Font | ThaleahFat_TTF を選択 |
Font Size | 90 |
Color | 白 ※カラーピッカーのRGB項目全てを255にすれば白くなる |

この時点でScoreの表示文字が見えない方は次の項目で見えるようになります。
スコア表示の位置を右上にする
UI Textの表示位置を右上に設定します。
ScoreのRect Transform項目にあるアンカーボタンをAltキーを押しながらクリックし、右上の項目を選択します。

ParagraphにあるAlignment項目の左右揃えを右端、上下揃えを中央に設定します。

これである程度右上となります。
微調整は右上の位置からの相対距離でPosXとPosYを使って指定します。
わたしはPosXを-280、PosYを-70としましたが、ここはお好みで変更してみてください。

スコア加算と表示を行うスクリプトの作成
UI関連は別のスクリプトにまとめた方が分かりやすいです。
Assets > Scripts にUIControllerという名前でC#スクリプトを作成します。

UIControllerに以下を記述します。
UIController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class UIController : MonoBehaviour
{
public GameObject scoreText; // 点数表示のUI Text
int score; // 得点保存用
// 得点アップ用メソッド
public void AddScore()
{
score += 10;
}
// Start is called before the first frame update
void Start()
{
// 得点の0クリアとシーン上のUI Text(得点用)を取得
score = 0;
scoreText = GameObject.Find("Score");
}
// Update is called once per frame
void Update()
{
// 0埋め4桁表示で得点を表示
scoreText.GetComponent<Text>().text = "Score: " + score.ToString("D4");
}
}
UIControllerはシーン上のCanvasにアタッチします。

アタッチ後、CanvasのInspectorウインドウを表示します。
UI Controller(Script)項目が新たに出来ています。HierarchyウインドウのScoreをScore Text項目にドラッグ&ドロップしてください。

これはUI Controllerスクリプトでの表示処理をシーン上のどのUI Textにまかせるかの設定となります。
UIControllerスクリプトでは、スコア加算のためAddScoreという関数を作っています。
public void AddScore() { score += 10; }
ただしこの関数は外部から呼び出しがないと実行されません。
このAddScore(加算処理)を呼び出す部分は、ショットと敵の当たり判定を行っているBulletControllerに記述します。
BulletControllerに以下のハイライト部分を追加してください。
BulletController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletController : MonoBehaviour
{
// 弾の発射スピード
public float Speed;
// 爆破エフェクト(プレハブ)
public GameObject ExplosionEffect;
// 効果音
public AudioClip se;
// Start is called before the first frame update
void Start()
{
}
// シーン上のオブジェクトと接触したときの処理
private void OnTriggerEnter2D(Collider2D col)
{
// 敵だったら
if (col.gameObject.tag == "Enemy")
{
// 得点アップ
GameObject.Find("Canvas").GetComponent<UIController>().AddScore();
// 爆破エフェクト
Instantiate(ExplosionEffect, transform.position, Quaternion.identity);
// 効果音再生
AudioSource.PlayClipAtPoint(se, transform.position);
// ぶつかった相手を破壊
Destroy(col.gameObject);
// 弾を破壊
Destroy(gameObject);
}
}
// Update is called once per frame
void Update()
{
// 下から上に弾を移動
transform.position += new Vector3(0, Speed, 0) * Time.deltaTime;
// 画面上方に消えたら弾を消去
if (transform.position.y >= 5.5f)
{
Destroy(gameObject);
}
}
}
実行して敵を倒した時、スコアが加算されていれば成功です!
ゲームを実行形式に書き出す
ここまでのゲームの状態はあくまで開発と開発環境での実行確認です。
他の端末でも利用できるようにゲームを実行形式に書き出しが必要です。
もしレンタルサーバをお持ちでしたらWebGL形式で書き出してサーバにアップロードすれば以下のリンク先のように自分のサイトで公開出来ます。
実行形式への書き出し方法は以下を参考にしてください。
パソコンのアプリケーションとしてゲームを書き出したい方
パソコンの通常のアプリとして書き出す場合はこちらです。
Windowsでは~.exeの拡張子のファイルとなります。
Player Settings…の項目では、以下のように設定するとベストかと思います。

ブラウザ実行可能なWebGLでゲームを書き出したい方
レンタルサーバをお持ちでしたらWebGLで書き出して自分のサイトに表示させてみてください。
WebGLで書き出す場合、Player Settings… の項目は以下のようにするとベストかと思います。

さいごに
長々と説明しましたが、Unity2Dをシューティングゲーム試作品を作って学ぶを終わりにします。
ここまで作って何か物足りないなあと感じた方はその先を目指してみてください。
実はこの記事本来の目的はそこにあります。
このゲームある意味無敵モードですよね。
まずはプレイヤーと敵が当たったらゲームオーバーとしたいところです。
タイトル画面も欲しいです。敵ももっと種類を増やしたいですし、ボスキャラも欲しいところです。
あるいは全く別の方向に進んで行くのもありかと。
BGMないじゃん!とか思いませんでした?
…好きなように改良して楽しんでください。
【追記 2023-02-20】試作品を元にタイトル画面、ボス戦までを作る
敵2の出現、ボス戦、タイトル画面からゲーム画面への遷移などゲームとして完成までのメモ書きを追加しました。
12章からなります。ただしメモ書き程度ですので詳細な説明はありませんが、スクリプトや設定等は全て網羅したつもりです。
WebGLビルドした完成版が以下リンクにあります。
操作:EnterキーまたはBボタンでスタート、矢印キーまたはアナログスティックで移動、ショットはzキーまたはAボタン
コメント