超初心者のゲーム開発記~Unity~

超初心者がUnityでゲーム(目標はAndroidアプリ )を開発していくブログです!

【Unity公式チュートリアル】 サバイバルシューター part.11 敵の自動生成機能を作る!

こんにちは!ヤギです!

Unity公式チュートリアルのサバイバルシューターをやってみるpart.11になります。

記事概要

今回の記事では、敵の自動生成機能の作り方についてご説明していきます。
時間経過で自動で敵が作成されるようにしていきます。
※part.11に対応する公式チュートリアルは、
Spawning Enemies - Unityとなります。
※公式チュートリアルでは、複数の敵を生成していますが、簡略化のため1種類の敵でご説明いたします。
※前回の記事はこちら
www.yagigame.com

敵を自動生成するスクリプトの作成

1. Hierarchy > Create > Create Emptyを選択し、名前をEnemyManagerとします。
f:id:yagigame:20181119200647p:plain
2. Project > Assets > Scripts > Manager > EnemyManager.csをEnemt Managerにドラッグし適用します。
3. EnemyManager.csに敵を自動生成する処理を書いていきます。
※ソース内の解説をご確認ください。

using UnityEngine;

public class EnemyManager : MonoBehaviour
{
    public PlayerHealth playerHealth; //プレイヤーのHP
    public GameObject enemy; //敵のオブジェクト
    public float spawnTime = 3f; //敵の生成間隔
    public Transform[] spawnPoints; //敵を生成する場所

    void Start ()
    {
        //敵を生成する間隔で、敵を生成する処理を呼ぶ
        InvokeRepeating ("Spawn", spawnTime, spawnTime);
    }

    //敵を生成する処理
    void Spawn ()
    {
        //プレイヤーのHPが0以下の場合
        if(playerHealth.currentHealth <= 0f)
        {
            return;
        }

        //敵を生成する場所をランダムに決める
        int spawnPointIndex = Random.Range (0, spawnPoints.Length);

        //敵を生成する
        Instantiate (enemy, spawnPoints[spawnPointIndex].position, spawnPoints[spawnPointIndex].rotation);
    }
}

敵を生成する場所(SpawnPoints)の設定

1. Hierarchy > Create > Create Emptyを選択し、名前をZombunnySpawnPointとします。
2. ZombunnySpawnPoint > Inspector > 四角マークを押し、青丸を選択します。
※これでZombunnySpawnPointが、Scene viewに表示されます。
f:id:yagigame:20181119202624p:plain
3. ZombunnySpawnPoint > Inspector を以下の内容に修正します。
・Position > (-20.5,0,12.5)
・Rotation > (0,130,0)
4. Hierarchy > EnemyManager > Inspectorを以下の内容修正します。
・Player Health > Player ※Hierarchy > Playerをドラッグ
・Enemy > Zomunny ※Hierarchy > Zombunnyは削除し、Prefabs > Zomnunnyをドラッグ
・Spawn Points > ZombunnySpawnPoint ※Hierarchy > ZombunnySpawnPointをドラッグ
f:id:yagigame:20181119204228p:plain
5. ZombunnySpawnPointと同様のオブジェクトを作成し、Spawn Pointsに追加します
※これで、ランダムな場所から敵が作成されるようになります。
f:id:yagigame:20181119204443p:plain

実行してみましょう!

ランダムな場所に敵が自動生成されていれば、大大成功です!!
https://yagigameblog.tumblr.com/post/180271614805/unity公式チュートリアル-サバイバルシューター-part11-敵の自動生成機能を作る

次回予告

次回は、ゲームオーバーの機能を作成していきます!
次回に対応する公式チュートリアルは、「Game Over」です!

読んでいただきありがとうございました!

【Unity公式チュートリアル】 サバイバルシューター part.10 スコア機能を作る!

こんにちは!ヤギです!

Unity公式チュートリアルのサバイバルシューターをやってみるpart.10になります。

記事概要

今回の記事では、スコア機能の作り方についてご説明していきます。
敵を倒した時に、画像のようなスコアが表示されるUIを作っていきます。
f:id:yagigame:20181118203102p:plain
※part.10に対応する公式チュートリアルは、
Scoring points - Unityとなります。
※前回の記事はこちら
www.yagigame.com

スコア表示用UIの作成

まず初めに、スコアを表示するUIを作ります。
1. Canvasを右クリックし、Create > UI > Textを選択し、名前をScoreTextとしてCanvasの子に作成します。
f:id:yagigame:20181118173622p:plain
2. ScoreText > Inspector > Anchorをクリックし、真ん中上を選択します。
f:id:yagigame:20181118173819p:plain
3. ScoreTextのInspectorを以下の内容で設定していきます。
・PosY > -55
・Width > 300
・Height > 50
・Text > Score: 0
・Font > LuckiestGuy
・Font Size > 50
・Alignment > 真ん中
・Color > 白
f:id:yagigame:20181118202556p:plain
4. ScoreText > Inspector > Add ComponentでShadowコンポーネントを追加します。
5. ShadowのInspectorを以下の内容で設定していきます。
・Effect Distance x > 2
・Effect Distance y> 2
f:id:yagigame:20181118202943p:plain
※これでスコアを表示するUIが完成しました!

スコアを表示するスクリプトの作成

スコアを表示するスクリプトを作成していきます。
1. Project > Scripts > Manager > ScoreManagerをHierarchy > ScoreTextにドラッグし適用します。
2. ScoreManager.csを作成していきます。
※ソース内に解説を記載いたしました。

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class ScoreManager : MonoBehaviour
{
    //スコア
    public static int score;

    //スコア表示用のテキスト
    Text text;

    void Awake ()
    {
        //テキストコンポーネントのとの取得
        text = GetComponent <Text> ();
        //スコアの初期化
        score = 0;
    }

    void Update ()
    {
        //テキストコンポーネントのテキストに表示する文字列を設定
        text.text = "Score: " + score;
    }
}

EnemyHealth.csの修正

EnemyHealth.csのStartSinking関数に、敵を倒した時にスコアを加算する処理を追加します。

using UnityEngine;

public class EnemyHealth : MonoBehaviour
{
    public int startingHealth = 100; //敵のHPの初期値
    public int currentHealth; //敵の最新のHP
    public float sinkSpeed = 2.5f; //敵の消滅時間
    public int scoreValue = 10; //敵を倒した時のスコア
    public AudioClip deathClip; 

    Animator anim; //アニメータ
    AudioSource enemyAudio; //敵の効果音
    ParticleSystem hitParticles; //攻撃された時のエフェクト
    CapsuleCollider capsuleCollider; //Collider
    bool isDead; //敵が倒されたかフラグ
    bool isSinking; //敵の消滅フラグ

    void Awake ()
    {
        //コンポーネントの設定
        anim = GetComponent <Animator> ();
        enemyAudio = GetComponent <AudioSource> ();
        hitParticles = GetComponentInChildren <ParticleSystem> ();
        capsuleCollider = GetComponent <CapsuleCollider> ();

        //最新のHPを初期化
        currentHealth = startingHealth;
    }

    void Update ()
    {
        //消滅フラグがオンの場合
        if(isSinking)
        {
            //敵が沈んでいく
            transform.Translate (-Vector3.up * sinkSpeed * Time.deltaTime);
        }
    }

    //攻撃を受けた時の処理
    public void TakeDamage (int amount, Vector3 hitPoint)
    {
        //倒されたフラグがオンの場合
        if(isDead)
            return;
        //攻撃を受けた時の音を鳴らす
        enemyAudio.Play ();
        //HPを減らす
        currentHealth -= amount;
        //攻撃を受けた時のエフェクトを表示する
        hitParticles.transform.position = hitPoint;
        hitParticles.Play();
        //敵のHPが0以下になった場合
        if(currentHealth <= 0)
        {
            //敵が倒される
            Death ();
        }
    }

    //敵が倒された場合の処理
    void Death ()
    {
        //敵が倒されたかフラグをオンにする
        isDead = true;

        capsuleCollider.isTrigger = true;
        //倒された時のアニメーショントリガーをオンにする
        anim.SetTrigger ("Dead");
        //倒された時の効果音を設定する
        enemyAudio.clip = deathClip;
        //敵が倒された時の効果音を鳴らす
        enemyAudio.Play ();
    }

    //敵を消滅させる処理
    //Zombunnyのアニメーション(Death)の中から呼び出されます
    //この呼び出す設定は既に完了しています
    public void StartSinking ()
    {
        //NavMesh Agentコンポーネントをオフにする
        GetComponent <UnityEngine.AI.NavMeshAgent> ().enabled = false;
        //RigidbodyコンポーネントのKinematicをオンにする(重力の効果を受けない)
        GetComponent <Rigidbody> ().isKinematic = true;
        //消滅フラグをオンにする
        isSinking = true;
        //スコアを加算する
        ScoreManager.score += scoreValue;
        //敵のオブジェクトを破壊する
        Destroy (gameObject, 2f);
    }
}

※これで敵を倒した時に、スコアが加算されます。
2. Zombunnyも完成したため、Hierarchy > ZombunnyをProject > Prefabsフォルダにドラックし、Prefab化しておきます。
f:id:yagigame:20181118204720p:plain

実行してみましょう!

敵を倒した時に、スコアが加算されて表示されていれば大成功です!
https://yagigameblog.tumblr.com/post/180236183932/unity公式チュートリアル-サバイバルシューター-part10-スコア機能を作る

次回予告

次回は、敵の自動生成機能(敵のスポーン機能)を作成していきます!
※次回の記事はこちら
www.yagigame.com
次回に対応する公式チュートリアルは、「Spawning Enemies」です!

読んでいただきありがとうございました!

【Unity公式チュートリアル】 サバイバルシューター part.9 敵を攻撃する!

こんにちは!ヤギです!

Unity公式チュートリアルのサバイバルシューターをやってみるpart.9になります。

記事概要

今回の記事では、敵を攻撃する方法についてご説明していきます。
プレイヤーの銃から弾が発射されるようにしていきます!
f:id:yagigame:20181118150717p:plain
※part.9に対応する公式チュートリアルは、
Harming Enemies - Unityとなります。
※前回の記事はこちら
www.yagigame.com

銃を撃つエフェクトの作成

まず初めに、銃を撃つエフェクトを作っていきます。
1. Project > Assets > Prefabs > GunParticles > Inspector > Particle System > ギアマークをクリックし、Copy Componentを選択します。
f:id:yagigame:20181118111451p:plain
2. Hierarchy > Player > GunBulletEnd > Inspector > Transform > ギアマークをクリックし、Paste Component As Newを選択します。
f:id:yagigame:20181118111748p:plain
3. Hierarchy > Player > GunBulletEnd > Inspector > Add Componentを選択し、Line Rendererコンポーネントを追加します。
※Line Rendererコンポーネントを利用して、レーザーのような射線を描写していきます!
4. Line Rendererコンポーネントを以下の内容に修正します。
・Materials > Element0 > LineRenderMaterial
・Width > 0.05
・Line Renderer > すぐ左のチェックをオフにします。※デフォルトでは描写せず、銃を撃った時のみ描写するようにします。
f:id:yagigame:20181118113419p:plain
5. Hierarchy > Player > GunBulletEnd > Inspector > Add Componentを選択し、Lightコンポーネントを追加します。
※銃を光らせるエフェクトを追加します。
6. Lightコンポーネントを以下の内容に修正します。
・Color > 黄色
・Ligh > すぐ左のチェックをオフにします。※デフォルトでは光らせず、銃を撃った時のみ光るようにします。
f:id:yagigame:20181118113819p:plain
7. Hierarchy > Player > GunBulletEnd > Inspector > Add Componentを選択し、Audio Sourceコンポーネントを追加します。
※銃の効果音を追加します。
8. Audio Sourceコンポーネントを以下の内容に修正します。
・Audio Clip > Player GunShot
・Play On Awake > チェックをオフにします。※ゲーム開始と共に音を鳴らさず、銃を撃った時のみ鳴るようにします。
f:id:yagigame:20181118113950p:plain
※これで銃を発射するエフェクトが完成しました。

弾を撃つスクリプトを作成

1. Project > Assets > Scripts > Player > PlayerShootingをHierarchy > GunBarrelEndにドラッグし適用します。
2. PlayerShooting.csを弾を撃つためのスクリプトとして作成していきます。Rayという機能を使用しています。
※スクリプト内に解説を記載しています。

using UnityEngine;

public class PlayerShooting : MonoBehaviour
{
    public int damagePerShot = 20; //弾のダメージ
    public float timeBetweenBullets = 0.15f; //弾を撃つ間隔
    public float range = 100f; //弾の飛距離

    float timer; //経過時間
    Ray shootRay = new Ray(); //rayを、弾の攻撃範囲とする
    RaycastHit shootHit; //弾が当たった物体
    int shootableMask; //撃てるもののみ識別する
    //弾を打った時のエフェクト
    ParticleSystem gunParticles;
    LineRenderer gunLine;
    AudioSource gunAudio;
    Light gunLight;
    float effectsDisplayTime = 0.2f;

    void Awake ()
    {
        //Shootable Layerを取得
        shootableMask = LayerMask.GetMask ("Shootable");
        //コンポーネントを取得
        gunParticles = GetComponent<ParticleSystem> ();
        gunLine = GetComponent <LineRenderer> ();
        gunAudio = GetComponent<AudioSource> ();
        gunLight = GetComponent<Light> ();
    }

    void Update ()
    {
        //経過時間を計測
        timer += Time.deltaTime;

        //弾を打つボタンを押した時、かつ経過時間が弾を打つ間隔よりも大きい場合
		if(Input.GetButton ("Fire1") && timer >= timeBetweenBullets && Time.timeScale != 0)
        {
            //弾を打つ
            Shoot ();
        }

        //経過時間がエフェクトの表示時間よりも大きくなった場合
        if(timer >= timeBetweenBullets * effectsDisplayTime)
        {
            //エフェクトを非表示にする
            DisableEffects ();
        }
    }

    //銃を撃つエフェクトをオフにする処理
    public void DisableEffects ()
    {
        gunLine.enabled = false;
        gunLight.enabled = false;
    }

    //弾を撃つ処理
    void Shoot ()
    {
        //経過時間を初期化
        timer = 0f;

        //弾を撃つエフェクトをオンにする
        gunAudio.Play ();
        gunLight.enabled = true;

        //弾を連写することを想定して、オフにしてからオンにする
        gunParticles.Stop ();
        gunParticles.Play ();

        //射線のスタート位置を設定する
        gunLine.enabled = true;
        gunLine.SetPosition (0, transform.position);

        //弾の攻撃範囲のスタート位置を設定する
        shootRay.origin = transform.position;
        //弾の飛んでいく方向を設定する
        shootRay.direction = transform.forward;

        //弾を飛ばし、(Rayを飛ばし、障害物に当たった場合
        if(Physics.Raycast (shootRay, out shootHit, range, shootableMask))
        {
            //弾が当たった障害物のEnemyHealthスクリプトコンポーネントを取得する
            EnemyHealth enemyHealth = shootHit.collider.GetComponent <EnemyHealth> ();

            //EnemyHealthスクリプトコンポーネントがnullではない場合(敵に弾が当たった場合)
            if(enemyHealth != null)
            {
                //敵にダメージを与える
                enemyHealth.TakeDamage (damagePerShot, shootHit.point);
            }
            //射線を障害物で当たった場所で止める
            gunLine.SetPosition (1, shootHit.point);
        }
        //障害物に当たらなかった場合
        else
        {
            //射線を弾の飛距離分表示する
            gunLine.SetPosition (1, shootRay.origin + shootRay.direction * range);
        }
    }
}

3. Hierarchy > Player > Inspector > Applyをクリックし、変更内容をPlayer Prefabに反映します。
f:id:yagigame:20181118142308p:plain
※これで弾を撃つスクリプトが完成しました。

EnemyMovement.csを修正

1. EnemyMovement.csを修正します。
※敵とプレイヤーが生きている場合のみ、敵を移動させるようにします。

using UnityEngine;
using System.Collections;

public class EnemyMovement : MonoBehaviour
{
    Transform player;
    PlayerHealth playerHealth; //プレイヤーのHP
    EnemyHealth enemyHealth; //敵のHP
    UnityEngine.AI.NavMeshAgent nav; //NavMesh Agent(敵)

    void Awake ()
    {
        //プレイヤータグのゲームオブジェクトを探し、場所を取得する
        player = GameObject.FindGameObjectWithTag ("Player").transform;
        playerHealth = player.GetComponent <PlayerHealth> (); //プレイヤーのHPを取得する
        enemyHealth = GetComponent <EnemyHealth> (); //敵のHPを取得
        //NavMeshAgentコンポーネントを取得する
        nav = GetComponent <UnityEngine.AI.NavMeshAgent> ();
    }

    void Update ()
    {
        //敵とプレイヤーが生きている場合
        if(enemyHealth.currentHealth > 0 && playerHealth.currentHealth > 0)
        {
            //NavMesh Agent(敵)をプレイヤーに向かって動かす
            nav.SetDestination (player.position);
        }
        //敵もしくは、プレイヤーが倒されている場合
        else
        {
            nav.enabled = false;
        }
    }
}

※これで、敵とプレイヤーが生きている場合のみ、敵が移動するようになりました。

PlayerHealth.csの修正

1. PlayerHealth.csを修正します。
※プレイヤーが倒された場合、弾を撃てなくします。

using UnityEngine;
using UnityEngine.UI; //UIを使うために必要
using System.Collections;
using UnityEngine.SceneManagement;

public class PlayerHealth : MonoBehaviour
{
    public int startingHealth = 100; //スタート時点のHP
    public int currentHealth; //最新のHP
    public Slider healthSlider; //HPバー
    public Image damageImage; //攻撃された時の画像
    public AudioClip deathClip; //倒された時の効果音
    public float flashSpeed = 5f; //攻撃された時の画像の表示速度
    public Color flashColour = new Color(1f, 0f, 0f, 0.1f); //攻撃された時の画像の色

    Animator anim; //アニメーション
    AudioSource playerAudio; //音楽
    PlayerMovement playerMovement; //PlayerMovementスクリプト
    PlayerShooting playerShooting; //PlayerShootingスクリプト
    bool isDead; //プレイヤーが倒されているかのフラグ
    bool damaged; //プレイヤーがダメージを受けているかのフラグ

    void Awake ()
    {
        //コンポーネントを設定
        anim = GetComponent <Animator> ();
        playerAudio = GetComponent <AudioSource> ();
        playerMovement = GetComponent <PlayerMovement> ();
        playerShooting = GetComponentInChildren <PlayerShooting> ();

        //体力を初期化
        currentHealth = startingHealth;
    }

    void Update ()
    {
        //プレイヤーがダメージを受けた場合
        if(damaged)
        {
            //攻撃された時の画像の色を設定する
            damageImage.color = flashColour;
        }
        //ダメージを受けていない場合
        else
        {
            //攻撃された時の画像の色をクリアする
            damageImage.color = Color.Lerp (damageImage.color, Color.clear, flashSpeed * Time.deltaTime);
        }
        //ダメージを受けているかのフラグをオフにする
        damaged = false;
    }

    //プレイヤーが攻撃された時の処理
    public void TakeDamage (int amount)
    {
        //ダメージを受けているかのフラグをオンにする
        damaged = true;

        //プレイヤーのHPを減らす
        currentHealth -= amount;

        //HPバーを減らす
        healthSlider.value = currentHealth;

        //攻撃を受けた時の効果音を鳴らす
        playerAudio.Play ();

        //HPが0以下になった場合、かつ既にたい押されていない場合、倒される
        if(currentHealth <= 0 && !isDead)
        {
            Death ();
        }
    }

    //プレイヤーが倒された場合の処理
    void Death ()
    {
        //プレイヤーが倒されているかのフラグをオンにする
        isDead = true;

        //弾を撃つエフェクトをオフにする
        playerShooting.DisableEffects ();

        //倒された時のアニメーションのフラグをオンにする
        anim.SetTrigger ("Die");

        //倒された時の効果音を設定する
        playerAudio.clip = deathClip;
        //倒された時の効果音を鳴らす
        playerAudio.Play ();

        //プレイヤーを動けなくする
        playerMovement.enabled = false;
        //弾を撃てなくする
        playerShooting.enabled = false;
    }

    public void RestartLevel ()
    {
        SceneManager.LoadScene (0);
    }
}

※これでプレイヤーが倒された場合、弾が撃てなくなります。

実行してみましょう!

マウスを左クリックすると弾が発射され、敵を倒すことができれば大成功です!
https://yagigameblog.tumblr.com/post/180229468357/unity公式チュートリアル-サバイバルシューター-part9-敵を攻撃する

次回予告

次回は、敵を倒した時に加算されるスコア機能を作成していきます!
次回に対応する公式チュートリアルは、「Scoring points」です!

読んでいただきありがとうございました!

【Unity公式チュートリアル】 サバイバルシューター part.8 敵の体力を管理する!

こんにちは!ヤギです!

Unity公式チュートリアルのサバイバルシューターをやってみるpart.8になります。

記事概要

今回の記事では、敵の体力を管理する方法についてご説明していきます。
※part.8に対応する公式チュートリアルは、
Harming Enemies - Unityとなります。
※前回の記事はこちら
www.yagigame.com

敵の体力管理用スクリプトの作成

敵の体力を管理するためのスクリプトを作っていきます。
1. Project > Assets > Scripts > Enemy > EnemyHealthを、Hierarchy > Zombunnyにドラッグし適用します。
f:id:yagigame:20181117202507p:plain
2. Hierarchy > Zombunny > Inspector > Enemy Health(Script) > Death ClipにZombunny Deathを設定します。
f:id:yagigame:20181117202710p:plain
3. EnemyHealth.csに敵の体力を管理するための処理を書いていきます。
※ソース内に解説を記載しています。ご確認ください。

using UnityEngine;

public class EnemyHealth : MonoBehaviour
{
    public int startingHealth = 100; //敵のHPの初期値
    public int currentHealth; //敵の最新のHP
    public float sinkSpeed = 2.5f; //敵の消滅時間
    public int scoreValue = 10; //敵を倒した時のスコア
    public AudioClip deathClip; 

    Animator anim; //アニメータ
    AudioSource enemyAudio; //敵の効果音
    ParticleSystem hitParticles; //攻撃された時のエフェクト
    CapsuleCollider capsuleCollider; //Collider
    bool isDead; //敵が倒されたかフラグ
    bool isSinking; //敵の消滅フラグ

    void Awake ()
    {
        //コンポーネントの設定
        anim = GetComponent <Animator> ();
        enemyAudio = GetComponent <AudioSource> ();
        hitParticles = GetComponentInChildren <ParticleSystem> ();
        capsuleCollider = GetComponent <CapsuleCollider> ();

        //最新のHPを初期化
        currentHealth = startingHealth;
    }

    void Update ()
    {
        //消滅フラグがオンの場合
        if(isSinking)
        {
            //敵が沈んでいく
            transform.Translate (-Vector3.up * sinkSpeed * Time.deltaTime);
        }
    }

    //攻撃を受けた時の処理
    public void TakeDamage (int amount, Vector3 hitPoint)
    {
        //倒されたフラグがオンの場合
        if(isDead)
            return;
        //攻撃を受けた時の音を鳴らす
        enemyAudio.Play ();
        //HPを減らす
        currentHealth -= amount;
        //攻撃を受けた時のエフェクトを表示する
        hitParticles.transform.position = hitPoint;
        hitParticles.Play();
        //敵のHPが0以下になった場合
        if(currentHealth <= 0)
        {
            //敵が倒される
            Death ();
        }
    }

    //敵が倒された場合の処理
    void Death ()
    {
        //敵が倒されたかフラグをオンにする
        isDead = true;

        capsuleCollider.isTrigger = true;
        //倒された時のアニメーショントリガーをオンにする
        anim.SetTrigger ("Dead");
        //倒された時の効果音を設定する
        enemyAudio.clip = deathClip;
        //敵が倒された時の効果音を鳴らす
        enemyAudio.Play ();
    }

    //敵を消滅させる処理
    //Zombunnyのアニメーション(Death)の中から呼び出されます
    //この呼び出す設定は既に完了しています
    public void StartSinking ()
    {
        //NavMesh Agentコンポーネントをオフにする
        GetComponent <UnityEngine.AI.NavMeshAgent> ().enabled = false;
        //RigidbodyコンポーネントのKinematicをオンにする(重力の効果を受けない)
        GetComponent <Rigidbody> ().isKinematic = true;
        //消滅フラグをオンにする
        isSinking = true;
        //ScoreManager.score += scoreValue;
        //敵のオブジェクトを破壊する
        Destroy (gameObject, 2f);
    }
}

4. EnemyAttack.csを修正していきます。
※Update関数内で、敵が生きている場合のみ攻撃するように条件を追加します。
※こちらもソース内に解説を記載しています。

using UnityEngine;
using System.Collections;

public class EnemyAttack : MonoBehaviour
{
    public float timeBetweenAttacks = 0.5f; //攻撃する時間間隔
    public int attackDamage = 10; //攻撃のダメージ量


    Animator anim; //アニメーション
    GameObject player; //プレイヤー
    PlayerHealth playerHealth; //PlayerHealthスクリプト
    EnemyHealth enemyHealth;  //EnemyHealthスクリプト
    bool playerInRange; //攻撃する範囲にプレイヤーが存在するかのフラグ
    float timer; //経過時間


    void Awake ()
    {
        //プレイヤーを取得
        player = GameObject.FindGameObjectWithTag ("Player");
        //プレイヤーのHPを取得
        playerHealth = player.GetComponent <PlayerHealth> ();
        //敵のHPを取得
        enemyHealth = GetComponent<EnemyHealth>();
        //アニメータコンポーネントを取得
        anim = GetComponent <Animator> ();
    }

    //物体と衝突した時の処理
    void OnTriggerEnter (Collider other)
    {
        //衝突した物体がプレイヤーの場合
        if(other.gameObject == player)
        {
            //攻撃する範囲にプレイヤーが存在するかのフラグをオンにする
            playerInRange = true;
        }
    }

    //衝突した物体が離れた時の処理
    void OnTriggerExit (Collider other)
    {
        //衝突した物体がプレイヤーの場合
        if(other.gameObject == player)
        {
            //攻撃する範囲にプレイヤーが存在するかのフラグをオフにする
            playerInRange = false;
        }
    }


    void Update ()
    {
        //経過時間を加算する
        timer += Time.deltaTime;

        //攻撃の時間間隔よりも経過時間が長い、かつプレイヤーが攻撃範囲に存在する場合、かつ敵のHPが0以上の場合
        if(timer >= timeBetweenAttacks && playerInRange && enemyHealth.currentHealth > 0)
        {
            //プレイヤーを攻撃する
            Attack ();
        }

        //プレイヤーのHPが0以下になった場合
        if(playerHealth.currentHealth <= 0)
        {
            //プレイヤーが倒された時のアニメーションフラグをオンにする
            anim.SetTrigger ("PlayerDead");
        }
    }

    //敵が攻撃する処理
    void Attack ()
    {
        //経過時間を0にする
        timer = 0f;

        //プレイヤーのHPが0よりも大きい場合
        if(playerHealth.currentHealth > 0)
        {
            //プレイヤーにダメージを与える
            playerHealth.TakeDamage (attackDamage);
        }
    }
}

※これで敵の体力の管理が出来るようになりました!

次回予告

次回は、遂にプレイヤーが敵を攻撃する(シューティングする)部分を作成していきます!
※次回の記事はこちら
www.yagigame.com
次回に対応する公式チュートリアルは引き続き、「Harming Enemies」です!

読んでいただきありがとうございました!

【Unity公式チュートリアル】 サバイバルシューター part.7 プレイヤーの体力を管理する!

こんにちは!ヤギです!

Unity公式チュートリアルのサバイバルシューターをやってみるpart.7になります。

記事概要

今回の記事では、プレイヤーの体力の管理方法についてご説明していきます。
敵に攻撃された場合、プレイヤーの体力を減らし、HPバーの表示にも反映できるようにしていきます!
※part.7に対応する公式チュートリアルは、
Player Health - Unityとなります。
※前回の記事はこちら
www.yagigame.com

プレイヤーの体力管理用スクリプトの作成

まず初めに、プレイヤーの体力を管理するためのスクリプトを作っていきます。
1. Project > Assets > Scripts > Player > PlayerHealthを、Hierarchy > Playerにドラッグし適用します。
f:id:yagigame:20181117170813p:plain
2. PlayerHealth.csのソースを書いていきます。
※ソース内に解説を記載していますので、ご確認ください!

using System.Collections;
using UnityEngine.SceneManagement;

public class PlayerHealth : MonoBehaviour
{
    public int startingHealth = 100; //スタート時点のHP
    public int currentHealth; //最新のHP
    public Slider healthSlider; //HPバー
    public Image damageImage; //攻撃された時の画像
    public AudioClip deathClip; //倒された時の効果音
    public float flashSpeed = 5f; //攻撃された時の画像の表示速度
    public Color flashColour = new Color(1f, 0f, 0f, 0.1f); //攻撃された時の画像の色

    Animator anim; //アニメーション
    AudioSource playerAudio; //音楽
    PlayerMovement playerMovement; //PlayerMovementスクリプト
    //PlayerShooting playerShooting;
    bool isDead; //プレイヤーが倒されているかのフラグ
    bool damaged; //プレイヤーがダメージを受けているかのフラグ

    void Awake ()
    {
        //コンポーネントを設定
        anim = GetComponent <Animator> ();
        playerAudio = GetComponent <AudioSource> ();
        playerMovement = GetComponent <PlayerMovement> ();
        //playerShooting = GetComponentInChildren <PlayerShooting> ();

        //体力を初期化
        currentHealth = startingHealth;
    }

    void Update ()
    {
        //プレイヤーがダメージを受けた場合
        if(damaged)
        {
            //攻撃された時の画像の色を設定する
            damageImage.color = flashColour;
        }
        //ダメージを受けていない場合
        else
        {
            //攻撃された時の画像の色をクリアする
            damageImage.color = Color.Lerp (damageImage.color, Color.clear, flashSpeed * Time.deltaTime);
        }
        //ダメージを受けているかのフラグをオフにする
        damaged = false;
    }

    //プレイヤーが攻撃された時の処理
    public void TakeDamage (int amount)
    {
        //ダメージを受けているかのフラグをオンにする
        damaged = true;

        //プレイヤーのHPを減らす
        currentHealth -= amount;

        //HPバーを減らす
        healthSlider.value = currentHealth;

        //攻撃を受けた時の効果音を鳴らす
        playerAudio.Play ();

        //HPが0以下になった場合、かつ既にたい押されていない場合、倒される
        if(currentHealth <= 0 && !isDead)
        {
            Death ();
        }
    }

    //プレイヤーが倒された場合の処理
    void Death ()
    {
        //プレイヤーが倒されているかのフラグをオンにする
        isDead = true;

        //playerShooting.DisableEffects ();

        //倒された時のアニメーションのフラグをオンにする
        anim.SetTrigger ("Die");

        //倒された時の効果音を設定する
        playerAudio.clip = deathClip;
        //倒された時の効果音を鳴らす
        playerAudio.Play ();

        //プレイヤーを動けなくする
        playerMovement.enabled = false;
        //playerShooting.enabled = false;
    }

    public void RestartLevel ()
    {
        SceneManager.LoadScene (0);
    }
}

3. Hieraechy > Player > Inspector > Player Health(Script)を以下の内容で設定します。
・Health Slider > HealthSlider
・Damage Image > DamageImage
・Death Clip > Player Death
f:id:yagigame:20181117172955p:plain
※これで、プレイヤーの体力を管理するスクリプトが完成しました。

敵の攻撃用スクリプトの作成

次に、敵がプレイヤーを攻撃するスクリプトの作成を行なっていきます。
1. Project > Assets > Scripts > Enemy > EnemyAttackを、Hierarchy > Zombunnyにドラッグし適用します。
f:id:yagigame:20181117173118p:plain
2. EnemyAttack.csのソースを書いていきます。
※ソース内に解説を記載していますので、ご確認ください!

using UnityEngine;
using System.Collections;

public class EnemyAttack : MonoBehaviour
{
    public float timeBetweenAttacks = 0.5f; //攻撃する時間間隔
    public int attackDamage = 10; //攻撃のダメージ量

    Animator anim; //アニメーション
    GameObject player; //プレイヤー
    PlayerHealth playerHealth; //PlayerHealthスクリプト
    //EnemyHealth enemyHealth; 
    bool playerInRange; //攻撃する範囲にプレイヤーが存在するかのフラグ
    float timer; //経過時間

    void Awake ()
    {
        //プレイヤーを取得
        player = GameObject.FindGameObjectWithTag ("Player");
        //プレイヤーのHPを取得
        playerHealth = player.GetComponent <PlayerHealth> ();
        //enemyHealth = GetComponent<EnemyHealth>();
        //アニメータコンポーネントを取得
        anim = GetComponent <Animator> ();
    }

    //物体と衝突した時の処理
    void OnTriggerEnter (Collider other)
    {
        //衝突した物体がプレイヤーの場合
        if(other.gameObject == player)
        {
            //攻撃する範囲にプレイヤーが存在するかのフラグをオンにする
            playerInRange = true;
        }
    }

    //衝突した物体が離れた時の処理
    void OnTriggerExit (Collider other)
    {
        //衝突した物体がプレイヤーの場合
        if(other.gameObject == player)
        {
            //攻撃する範囲にプレイヤーが存在するかのフラグをオフにする
            playerInRange = false;
        }
    }

    void Update ()
    {
        //経過時間を加算する
        timer += Time.deltaTime;

        //攻撃の時間間隔よりも経過時間が長い、かつプレイヤーが攻撃範囲に存在する場合
        if(timer >= timeBetweenAttacks && playerInRange/* && enemyHealth.currentHealth > 0*/)
        {
            //プレイヤーを攻撃する
            Attack ();
        }

        //プレイヤーのHPが0以下になった場合
        if(playerHealth.currentHealth <= 0)
        {
            //プレイヤーが倒された時のアニメーションフラグをオンにする
            anim.SetTrigger ("PlayerDead");
        }
    }

    //敵が攻撃する処理
    void Attack ()
    {
        //経過時間を0にする
        timer = 0f;

        //プレイヤーのHPが0よりも大きい場合
        if(playerHealth.currentHealth > 0)
        {
            //プレイヤーにダメージを与える
            playerHealth.TakeDamage (attackDamage);
        }
    }
}

※これで、敵がプレイヤーを攻撃するようになりました!

ゲームを実行してみましょう

プレイヤーと敵が接触した時、画面が赤く光る演出と共に、HPバーが減っていきます!
そして、HPが尽きた時、プレイヤーが倒されれば、大成功です!
https://yagigameblog.tumblr.com/post/180199281320/unity公式チュートリアル-サバイバルシューター-part7

次回予告

次回は、敵の体力を管理出来るようにしていきます!
※次回の記事はこちら
www.yagigame.com
次回に対応する公式チュートリアルは、「Harming Enemies」です!

読んでいただきありがとうございました!

【Unity公式チュートリアル】 サバイバルシューター part.6 UIを作成する!

こんにちは!ヤギです!

Unity公式チュートリアルのサバイバルシューターをやってみるpart.6になります。

記事概要

今回の記事では、画面上に常に表示されるUIの作成についてご説明していきます。
※part.6に対応する公式チュートリアルは、
Health HUD - Unityとなります。
※前回の記事はこちら
www.yagigame.com

UIの作成~ハート画像~

まず初めに、ゲーム画面左下にプレイヤーのHPを表すハートを表示します。
1. Hierarchy > Create > UI > Canvasをクリックします。
※Canvas上に他のUIを作成していきます!
f:id:yagigame:20181117032600p:plain
2. Canvas > Inspector > Add ComponentからCanvas Group追加します。
3. Canvas GroupのInteractiveとBlock Raycastsのチェックを外します。
※ボタンなど押したら反応するUIは作らない、またrayを妨げないために、このチェックを外します。
f:id:yagigame:20181117033506p:plain
4. Canvasを右クリックし、Create > UI > Textを選択し、名前をHealthUIとしてCanvasの子に作成します。
f:id:yagigame:20181117034032p:plain
5. HealthUI > Inspector > Anchorをクリックし、Anchor Presetを表示します。
6. shift+alt(or option)を押したまま、左下をクリックします。
※これで、UIの中心や表示される場所が左下になります。
f:id:yagigame:20181117050337p:plain
7. HealthUI > Inspector を以下の内容に修正します。
・Width > 75
・Height > 60
f:id:yagigame:20181117040215p:plain
8. HealthUIを右クリックし、Create > UI > Imageを選択し、名前をHeartとしてHealthUIの子に作成します。
f:id:yagigame:20181117040606p:plain
9. Heart > Inspector を以下の内容に修正します。
・Width > 30
・Height > 30
・Source Image > Heart
f:id:yagigame:20181117040920p:plain
※ここまでの設定で、ゲーム画面の左下に、ハートが表示されていれば成功です!
f:id:yagigame:20181117041038p:plain

UIの作成~HPバー~

ここからは、プレイヤーのHPバーを作っていきます。
1. HealthUIを右クリックし、Create > UI > Sliderを選択し、名前をHealthSliderとしてHealthUIの子に作成します。
f:id:yagigame:20181117041303p:plain
2. HealthSlider > Inspector を以下の内容に修正します。
・Pos X > 95
・Width > 130
・Slider(Script) > Transition > None
・Max Value > 100:プレイヤーのHPと連動させます
・Value > 100
f:id:yagigame:20181117044018p:plain
3. HealthSlider > Background > Inspector を以下の内容に修正します。
・Top > 0
・Bottom > 0
f:id:yagigame:20181117044145p:plain
4. HealthSlider > Fill Area > Inspector を以下の内容に修正します。
・Top > 5
・Bottom > 5
・Left > 10
・Right > 10
f:id:yagigame:20181117050508p:plain
5. HealthSliderの子オブジェクトの、Handle Slide Areaは不要なので削除します。
f:id:yagigame:20181117042953p:plain
※ここまで設定し、ゲーム画面左下にHPバーが表示されていれば成功です!
f:id:yagigame:20181117044525p:plain

UIの作成~ダメージを受けた時にゲーム画面全体を光らせる~

ここからは、ダメージを受けた時に、ゲーム画面全体を光らせるUIを作っていきます。
1. HealthUIを右クリックし、Create > UI > Imageを選択し、名前をDamageImageとしてHealthUIの子に作成します。
f:id:yagigame:20181117045003p:plain
2. DamageImageをCanvasの直下に一旦ドラッグし、Canvas直下の子オブジェクトとします。
3. DamageImage > Inspector > Anchorをクリックし、Anchor Presetを表示します。
4. alt(or option)を押したまま、右下をクリックします。
f:id:yagigame:20181117045609p:plain
※これで、DamageImageがCanvasの全体に広がります。
f:id:yagigame:20181117045638p:plain
5. DamageImage > Inspector > Colorをクリックし、Aを0にします。
※画像を透明にしています。
f:id:yagigame:20181117045853p:plain

※これでUIの作成が完了しました。

次回予告

次回は、プレイヤーの体力の管理のプログラム作成を行なっていきます!
※次回の記事はこちら
www.yagigame.com
次回に対応する公式チュートリアルは、「Player Health」です!

読んでいただきありがとうございました!

【Unity公式チュートリアル】 サバイバルシューター part.5 プレイヤーを追いかける敵を作成する!

こんにちは!ヤギです!

Unity公式チュートリアルのサバイバルシューターをやってみるpart.5になります。

記事概要

今回の記事では、プレイヤーを追いかける敵の作成についてご説明していきます。
※part.5に対応する公式チュートリアルは、
Creating Enemy #1 - Unityとなります。
※前回の記事はこちら
www.yagigame.com

敵のコンポーネントの設定

1. Project > Assets > Models > Characters > ZombunnyをHierarchy viewにドラッグします。
※これが1体目の敵となります。
2. Projects > Asssts > Prefabs > HitParticlesをHierarchy > Zombunnyにドラッグし適用します。
※敵が攻撃を受けた時のエフェクトを設定しています。
f:id:yagigame:20181116173504p:plain
3. Zombunny > Inspector > Layer > Shootableに変更します。
f:id:yagigame:20181116173915p:plain
4. Zombunny > Inspector > Add Componentをクリックし、Rigidbodyを選択します。
5. Rigidbodyを以下の内容に修正します。
・Drag > Infinity
・Angular Dragg > Infinity
・Freeze Position > Yにチェック
・Freeze Rotation > X,Zにチェック
f:id:yagigame:20181116175152p:plain
6. Zombunny > Inspector > Add Componentをクリックし、Capsule Colliderを選択します。
7. Capsule Colliderを以下の内容に修正します。
・Center > y > 0.8
・Height > 1.5
f:id:yagigame:20181116175357p:plain
8. Zombunny > Inspector > Add Componentをクリックし、Sphere Colliderを選択します。
※Playerとの接触検知に使うため、少し大きめにしています。
9. Sphere Colliderを以下の内容に修正します。
・Is Trigger > チェクする
・Center > y > 0.8
・Radius > 0.8
f:id:yagigame:20181116180804p:plain
10. Zombunny > Inspector > Add Componentをクリックし、Audio Sourceを選択します。
※敵が攻撃を受けた時の効果音を設定します。
11. Audio Sourceを以下の内容に修正します。
・Audio Clip > Zombunny Hurt
・Play On Awake > チェックを外す
f:id:yagigame:20181116181118p:plain

移動できる範囲の設定

敵が移動できる範囲の設定を行なっていきます。
※今回はUnityのNavMeshという機能を使っています!
1. Window > AI > Navigationをクリックします。
f:id:yagigame:20181116181942p:plain
2. Zombunny > Inspector > Add Componentをクリックし、Nav Mesh Agentを選択します。
f:id:yagigame:20181116182235p:plain
3. Nav Mesh Agentを以下の内容に修正します。
・Speed > 0.3
・Stopping Distance > 1.3
・Radius > 0.3
・Height > 1.1
f:id:yagigame:20181116183000p:plain
4. 手順1で開いたNavigationを以下の内容に修正します。
・Radius > 0.75
・Height > 1.2
・Step Height > 0.1
5. Navigation > Bakeをクリックし、移動できる範囲を作成します。
f:id:yagigame:20181116184058p:plain
※移動できる範囲が、青く表示されたら成功です!
f:id:yagigame:20181116184336p:plain

敵のアニメーションの作成

1. Projects > Assets > Animation > Animator Controllerを選択し、名前をEnemyACとします。
f:id:yagigame:20181116200939p:plain
2. EnemyACをHierarchy > Zombunnyにドラッグして適用します。
3. EnemyACをダブルクリックし、Animator viewを開きます。
4. Project > Asset > Models > Characters > Zombunnyの「Move」「Idle」「Death」をEnemyACのAnimator viewにドラッグします。
f:id:yagigame:20181116201258p:plain
※オレンジで表示されているのがデフォルトのアニメーションとなります。
5. Animator view > Parameters > +をクリックし、Triggerを選択して、名前を「PlayerDead」とします。
※プレイヤーが倒された場合使用するトリガー
6. Animator view > Parameters > +をクリックし、Triggerを選択して、名前を「Dead」とします。
※敵が倒された場合使用するトリガー
f:id:yagigame:20181116201754p:plain
7. Moveを右クリックし、Make Transitionを選択し、矢印をIdleに繋ぎます。
f:id:yagigame:20181116201858p:plain
8. 7で作成した矢印をクリックし表示されたInspector > Conditionsに 「PlayerDead」を設定します。
9. 7で作成した矢印をクリックし表示されたInspector > Has Exit Timeのチェックを外します。
※このチェックを外すことで、アニメーションが即座に切り替わるようになります。
f:id:yagigame:20181116202230p:plain
10. 同様にAny Stateを右クリックし、Make Transitionを選択し、矢印をDeathに繋ぎます。
11. 10で作成した矢印をクリックし表示されたInspector > Conditionsに 「Dead」を設定します。
12. 10で作成した矢印をクリックし表示されたInspector > Has Exit Timeのチェックを外します。
f:id:yagigame:20181116224840p:plain
※これで、敵のアニメーションの設定は完了です!

プレイヤーを追いかけるスクリプトの作成

1. Project > Assets > Scripts > Enemy > EnemyMovementをZombunnyにアタッチします。
2. Playerを追いかけるスクリプト(EnemyMovement.cs)を作成します。
※一部ソースはコメントアウトしています。今後のチュートリアルで使っていきます!
※今回関係するのは、NavMeshを使いプレイヤーを追いかけるようにするところです。

using UnityEngine;
using System.Collections;

public class EnemyMovement : MonoBehaviour
{
    Transform player;
    //PlayerHealth playerHealth;
    //EnemyHealth enemyHealth;
    UnityEngine.AI.NavMeshAgent nav; //NavMesh Agent(敵)


    void Awake ()
    {
        //プレイヤータグのゲームオブジェクトを探し、場所を取得する
        player = GameObject.FindGameObjectWithTag ("Player").transform;
        //playerHealth = player.GetComponent <PlayerHealth> ();
        //enemyHealth = GetComponent <EnemyHealth> ();
        //NavMeshAgentコンポーネントを取得する
        nav = GetComponent <UnityEngine.AI.NavMeshAgent> ();
    }


    void Update ()
    {
        //if(enemyHealth.currentHealth > 0 && playerHealth.currentHealth > 0)
        //{
            //NavMesh Agent(敵)をプレイヤーに向かって動かす
            nav.SetDestination (player.position);
        //}
        //else
        //{
        //    nav.enabled = false;
        //}
    }
}

※これで、敵がプレイヤーを追いかけるようになります!

実行してみましょう

プレイヤーが移動すると、敵が追いかけてくれば大成功です!
https://yagigameblog.tumblr.com/post/180172667043

次回予告

次回は、画面上に表示されるUIの作成を行なっていきます!
※次回の記事はこちら
www.yagigame.com
次回に対応する公式チュートリアルは、「Health HUD」です!

読んでいただきありがとうございました!

【Unity公式チュートリアル】 サバイバルシューター part.4 カメラの設定をする!

こんにちは!ヤギです!

Unity公式チュートリアルのサバイバルシューターをやってみるpart.4になります。

記事概要

今回の記事では、カメラの設定についてご説明していきます。
カメラがプレイヤーの後をついていくようにしていきます!
※part.4に対応する公式チュートリアルは、
Camera setup - Unityとなります。
※前回の記事はこちら
www.yagigame.com

カメラの設定

カメラがプレイヤーの後ろをついていくための設定を行なっていきます。
1. Main Camera > Inspector > をクリックし、以下の設定をします。
・Position > (X,Y,Z) = (1,15,-22)
・Rotation > (X,Y,Z) = (30,0,0)
・Projection > Orthographic:遠近感なしで画面を表示する設定
・Backgroud > 黒に設定
f:id:yagigame:20181116170330p:plain
2. カメラを操作するためのスクリプト「CameraFollow.cs」を作成します。
f:id:yagigame:20181116164248p:plain
※ソース内に解説を書いていますので、ご参照ください!

using UnityEngine;
using System.Collections;

public class CameraFollow : MonoBehaviour
{
    public Transform target; //カメラがついていくターゲットのポジション
    public float smoothing = 5f; //カメラのついていくスピード

    Vector3 offset; //カメラとターゲットの間の距離

    void Start()
    {
        //カメラとターゲットの間の距離を算出
        offset = transform.position - target.position;
    }

    //物体が動く毎に呼び出される
    void FixedUpdate()
    {
        //カメラの移動先
        Vector3 targetCamPos = target.position + offset;

        //カメラを移動する
        transform.position = Vector3.Lerp(transform.position, targetCamPos, smoothing * Time.deltaTime);
    }
}

3. CameraFollow.csをHiwrarchy view > Main Cameraにドッラグし適用します。
f:id:yagigame:20181116164828p:plain
4. Main Camera > Inspector > Camera Follow(Script) > TargetにHierarchy > Playerをドラッグし設定します。
f:id:yagigame:20181116165310p:plain
5. Hierarchy view > PlayerをProject > Assets > Prefabsにドラッグし、Prefab化します。
f:id:yagigame:20181116165527p:plain

※これで、プレイヤーの後をついていくカメラが完成しました!

実行してみましょう

ゲームを実行していきましょう!
プレイヤーの後を追いかけてカメラが動くようなっていれば大成功です!
https://yagigameblog.tumblr.com/post/180173034202/unity公式チュートリアル-サバイバルシューター-part4-カメラの設定をする

次回予告

次回は、ゲームに登場する敵の設定を行なっていきます!
NavMeshという機能を使って、プレイヤーを自動で追いかける敵を作っていきます!
※次回の記事はこちら
www.yagigame.com
次回に対応する公式チュートリアルは、「Creating Enemy #1」です!

読んでいただきありがとうございました!

【Unity公式チュートリアル】 サバイバルシューター part.3 プレイヤーを動かす設定をする!

こんにちは!ヤギです!

Unity公式チュートリアルのサバイバルシューターをやってみるpart.3になります。

記事概要

今回の記事では、プレイヤーを動かす設定についてご説明していきます。
※part.3に対応する公式チュートリアルは、
Player Character - Unityとなります。
※前回の記事はこちら
www.yagigame.com

Playerのコンポーネントの設定

1. Player > Inspector > Add Componentをクリックし、Rigidbodyを選択します。
※このコンポーネントで、重力を適用します。
f:id:yagigame:20181114144105p:plain
2. Rigidbodyを以下の内容に修正します。
・Drag > Infinity
・Angular Dragg > Infinity
・Freeze Position > Yにチェック
・Freeze Rotation > X,Zにチェック
f:id:yagigame:20181114144447p:plain
3. Player > Inspector > Add Componentをクリックし、Capsule Colliderを選択します。
※このコンポーネントで、衝突検知を可能にします。
4. Capsule Colliderを以下の内容に修正します。
・Center > x > 0.2
・Center > y > 0.6
・Height > 1.2
f:id:yagigame:20181114144948p:plain
5. Player > Inspector > Add Componentをクリックし、Audio Sourceを選択します。
※プレイヤーが攻撃を受けた時の効果音を設定します。
6. Audio Sourceを以下の内容に修正します。
・Audio Clip > Player Hurt
・Play On Awake > チェックを外す
f:id:yagigame:20181114145409p:plain

プレイヤを動かすスクリプトの作成

1. Project > Assets > Scripts > Player > PlayerMovementをPlayerにドラッグします。
f:id:yagigame:20181114145748p:plain
2. PlayerMovementスクリプトを作成していきます。
※ソースの中に解説を書いています!ご確認ください!

using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    public float speed = 6f;            //プレイヤの移動速度

    Vector3 movement;                   //プレイヤーの移動方向
    Animator anim;                      //アニメーションコンポーネント
    Rigidbody playerRigidbody;          //Rigidbodyコンポーネント
    int floorMask;                      //Floorとrayermaskを使う
    float camRayLength = 100f;          //カメラからのray

    void Awake()
    {
        //Floorのrayermaskを作成
        floorMask = LayerMask.GetMask("Floor");

        //コンポーネントを取得
        anim = GetComponent<Animator>();
        playerRigidbody = GetComponent<Rigidbody>();
    }

    //オブジェクトが動くたびに呼ばれる
    void FixedUpdate()
    {
        //インプットから左右上下の移動量を-1もしくは1で受け取る
        float h = Input.GetAxisRaw("Horizontal");
        float v = Input.GetAxisRaw("Vertical");

        //プレイヤーを動かすMove()を呼ぶ
        Move(h, v);

        //プレイヤーの方向を動かすTurning()を呼ぶ
        Turning();

        //プレイヤーのアニメーションを設定するAnimating()を呼ぶ
        Animating(h, v);
    }

    //プレイヤーを動かす処理
    void Move(float h, float v)
    {
        //移動量を設定
        movement.Set(h, 0f, v);

        //移動するベクトルを1にし、移動する距離を設定する
        movement = movement.normalized * speed * Time.deltaTime;

        //プレイターのポジションを動かす
        playerRigidbody.MovePosition(transform.position + movement);
    }


    void Turning()
    {
        //カメラから、マウスで指している方向のrayを取得する
        Ray camRay = Camera.main.ScreenPointToRay(Input.mousePosition);

        //rayが衝突した情報を取得する
        RaycastHit floorHit;

        //rayを飛ばして、床に衝突した場合の処理
        if (Physics.Raycast(camRay, out floorHit, camRayLength, floorMask))
        {
            //マウスで指している場所と、プレイヤーの場所の差分を取得
            Vector3 playerToMouse = floorHit.point - transform.position;

            //プレイヤはy座標には動かさない
            playerToMouse.y = 0f;

            //プレイヤーの場所から、マウスで指している場所への角度を取得
            Quaternion newRotation = Quaternion.LookRotation(playerToMouse);

            //プレイヤーの角度(プレイヤーの向き)を、新しく設定
            playerRigidbody.MoveRotation(newRotation);
        }
    }

    //アニメーションの処理
    void Animating(float h, float v)
    {
        //プレイヤーの移動量が0以外の場合、walkingをtrueにする
        bool walking = h != 0f || v != 0f;

        //アニメーションのパラメーターOsWalkingをwalkingの値で設定する
        anim.SetBool("IsWalking", walking);
    }
}

トラブルシューティング

実行すると、以下のエラーが出るかもしれません。
NullReferenceException: Object reference not set to an instance of an object
PlayerMovement.Turning () (at Assets/Scripts/Player/PlayerMovement.cs:58)
PlayerMovement.FixedUpdate () (at Assets/Scripts/Player/PlayerMovement.cs:35)

これは、Main CameraのTagが設定されていないことで発生している可能性があります!
Main CameraのTagをMain Cameraと設定しましょう。
f:id:yagigame:20181114161649p:plain

ゲームを実行する

実際にゲームを動かしてみましょう。
キーボードの矢印でプレイヤーの位置が動き、マウスを追ってプレイヤーが向きを変えれば大成功です!
f:id:yagigame:20181114162153p:plain

次回予告

次回は、カメラの設定を行なっていきます!
次回に対応する公式チュートリアルは、「Camera setup」です!

読んでいただきありがとうございました!

【Unity公式チュートリアル】 サバイバルシューター part.2 プレイヤーのアニメーションを設定する!

こんにちは!ヤギです!

Unity公式チュートリアルのサバイバルシューターをやってみるpart.2になります。

記事概要

今回の記事では、プレイヤーのアニメーションの設定についてご説明していきます。
※前回の記事(環境設定について)はこちら
www.yagigame.com

※part.2に対応する公式チュートリアルは、
Player Character - Unityとなります。

Playerのアニメーションの作成

1. Models > Characterフォルダ内のPlayerをHierarchy viewにドラッグします。
2. PlayerのInspector > TagをPlayerに変更します。
f:id:yagigame:20181114110032p:plain
3. Project > Create > Folderでファルダーを作成し、名前を「Animation」とします。
4. Animationファルダの中に、Create > Animator Controllerでアニメーションコントローラを作成します。
f:id:yagigame:20181114111003p:plain
※名前は「PlayerAC」としておきます。
f:id:yagigame:20181114111053p:plain
5. PlayerACをHierarchy > Playerにドラッグします。
※Player > Inspector にAnimatorコンポーネントが追加されます。
f:id:yagigame:20181114111252p:plain
6. PlayerACをダブルクリックし、Animator viewを開きます。
f:id:yagigame:20181114111350p:plain
7. Project > Asset > Models > Characters > Playerの「Idle」「Move」「Death」をAnimator viewにドラッグします。
※オレンジで表示されているのがデフォルトのアニメーションとなります。
f:id:yagigame:20181114111916p:plain
8. Animator view > Parameters > +をクリックし、Boolを選択して、名前を「IsWalking」とします。
※アニメーションを切り替える際に使用するパラメータとなります!
f:id:yagigame:20181114112313p:plain
9. Animator view > Parameters > +をクリックし、Triggerを選択して、名前を「Die」とします。
f:id:yagigame:20181114112445p:plain
10. Idleを右クリックし、Make Transitionを選択し、矢印をMoveに繋ぎます。
※矢印でアニメーションの遷移を設定していきます。
f:id:yagigame:20181114112827p:plain
11. 矢印をクリックし表示されたInspector > Conditions > + をクリックします。
※Has Exit Timeのチェックを外しておきます。
※IsWalkingが表示されない場合、リストから選択しておきましょう。
f:id:yagigame:20181114143937p:plain
12. Moveを右クリックし、Make Transitionを選択し、矢印をIdleに繋ぎます。
f:id:yagigame:20181114113310p:plain
13. 12で作成した矢印をクリックし表示されたInspector > Conditionsを「IsWalking」「false」とします。
※これで、IsWalkingがtrueの時はMoveが、falseの時はIdleが表示されます。
f:id:yagigame:20181114114237p:plain
14. Any Stateを右クリックし、Make Transitionを選択し、矢印をDeathに繋ぎます。
※Any Stateを選択することで、どのようなアニメーションの状態でもDeathに遷移することが出来ます。
f:id:yagigame:20181114114002p:plain
15. 14で作成した矢印をクリックし表示されたInspector > Conditionsを「Die」とします。
f:id:yagigame:20181114114130p:plain
※これで、Playerのアニメーションの設定は完了です!

次回予告

次回は、プレイヤーを動かすための設定などを行なっていきます!
プレイヤーをキーボードで動かしたり、マウスで指している方向を向かせられるようにしていきます!
※次回の記事はこちら
www.yagigame.com
次回に対応する公式チュートリアルは、引き続き「Player Character」です!

読んでいただきありがとうございました!

【Unity公式チュートリアル】 サバイバルシューター part.1 環境設定をする!

こんにちは!ヤギです!

Unity公式チュートリアルのサバイバルシューターをやってみるpart.1になります。

記事概要

この記事のシリーズでは、シューティングゲームの作り方についてご説明していきます。
今回の記事では、導入として環境のセットアップを行います。
※part.1に対応する公式チュートリアルは、
Environment setup - Unityとなります。

プロジェクトの作成

1. 新規プロジェクトを作成します。
※3Dのゲームのため、形式は3Dとしておきましょう。
f:id:yagigame:20181111213808p:plain
2. 画面右上のLayout > 2 by 3をクリックします。
※皆様の使いやすいレイアウトがあれば、そのままで大丈夫です。
f:id:yagigame:20181111213828p:plain
3. Project viewをHierarchy viewにドラッグアンドドロップします。
4. Project viewの下にあるスライドを一番左にします。
※スライドを動かすことで、表示されるフォルダの大きさが変わります!
f:id:yagigame:20181111214416p:plain
5. Window > General > Asset Storeをクリックし、Asset Storeを開きます。
f:id:yagigame:20181111214833p:plain
6. Survival Shooter Tutorialをダウンロードし、インポートします。
f:id:yagigame:20181111215037p:plain
7. File > Save scene asをクリックし、シーンの名前を「Level 01」として、Scenesフォルダに保存します。
f:id:yagigame:20181111215857p:plain
※これで、ゲーム開発を始めるための環境設定できました!

ステージの作成

Prefabを使って、ゲームのステージを作っていきます。
1. Project view > Prefabの中にある、EnvironmentをHierarchy viewにドラッグアンドドロップします。
※これで、ゲームのステージが表示されます。
f:id:yagigame:20181111220453p:plain
2. Project view > Prefabの中にある、LightsをHierarchy viewにドラッグアンドドロップします。
f:id:yagigame:20181111220823p:plain

床の作成

1. Hierarchy > Create >3D Object > Quadをクリックし、オブジェクトを追加します。
f:id:yagigame:20181111221322p:plain
2. Inspector > Transform > Position(X,Y,Z)=(0,0,0)とし、Rotation(X,Y,Z)=(90,0,0)、Scale(X,Y,Z)=(100,100,0)とします。
f:id:yagigame:20181111221840p:plain
3. 名前をFloorと変更します。
※この段階だと、ステージに変な床が刺さったように表示されてしまいます。
f:id:yagigame:20181111222010p:plain
4. Floor > Inspector viewからMesh RenderをRemove Componentで削除します。
f:id:yagigame:20181111222426p:plain
※これで、刺さったように表示されていた床が、表示されなくなります。
5. Layer > Floorを選択します。
f:id:yagigame:20181111222627p:plain
※これで、床の完成です!

BGMの作成

1. Hierarchy > Create > Create Emptyでオブジェクトを作成します。
※名前をBackgroundMusicとします。
f:id:yagigame:20181113215838p:plain
2. Inspector > Add Componet > Audio Sourceをクリックし、音を鳴らすためのコンポーネントを設定します。
f:id:yagigame:20181113220053p:plain
3. Audio Source > Audio Clipに、Background Musicを設定します。
※小さい丸を押すと、Select AudioClip画面に選択できる候補が表示されるのでその中から選択しましょう!
f:id:yagigame:20181113220540p:plain
4. シーン読み込み時に自動で音を鳴らす「Play On Awake」のチェックを外します。
5. BGMは音をループさせて鳴らすので、Loopにチェックをつけます。
6. Volumeを0.1とします。
f:id:yagigame:20181113221102p:plain

※これで、環境設定は完了です!

次回予告

次回は、プレイヤーの作成を行なっていきます!
※次回の記事はこちら
www.yagigame.com
次回に対応する公式チュートリアルは、「Player Character」です!

読んでいただきありがとうございました!

【超初心者】UnityからAsset Storeを開く方法!

こんばんは!ヤギです!

Unityでゲームを作りながら、Asset Storeが使いたい!
今回は、UnityからAsset Storeを開く方法をご紹介致します。

UnityからAsset Storeを開く方法

1. Unity画面上部に表示されている Window > General > Asset Storeをクリックします!
f:id:yagigame:20181113212827p:plain
※これで、Asset Storeが起動できます。
f:id:yagigame:20181113213035p:plain

今回も記事を読んでいただきありがとうございました!
今後も、今回の記事のように、基本的なことを記事としてご紹介していきたいと思います。

【超初心者】UnityのInspector viewを固定する方法

こんばんは!ヤギです!

今回は、Unityでゲーム開発がめちゃくちゃやりやすくなる方法をご紹介いたします!
※ものすごく、基本的なことですが、このテクニックを知った時感動したのでご連携いたします。

Inspector viewを固定する方法

1. 固定したいInspector viewを開きます。
f:id:yagigame:20181111200731p:plain

2. Inspector view右上のロックマーク(青枠部分)をクリックします。
f:id:yagigame:20181111200944p:plain

※これでInspector viewが固定されます!

今回も記事を読んでいただきありがとうございました!

【Unity 2Dローグライク】公式チュートリアルをやってみる 最終回~スマートフォンに対応する

こんにちは!ヤギです!

Unityの2Dローグライクの
公式チュートリアルをやってみる 遂に最終回になります!
※前回(part.14)の記事はこちら
www.yagigame.com

記事概要

今回の記事では、スマートフォンに対応する方法についてご説明していきます。
※最終回に対応する公式チュートリアルの章は、Adding Mobile Controlsです!
unity3d.com

※この記事は、ひよこのたまご様の記事をリスペクトしています。
hiyotama.hatenablog.com

タッチパネルで操作する~スワイプ操作~

まず初めに、スマートフォンに対応するためにビルド設定を変えます。
1. File > Build Settings > iOSもしくはAndroidを選択し、Switch Platformをクリックします。
f:id:yagigame:20181110025649p:plain
2. タッチパネルでスワイプすることでプレイヤーを操作できるように、Player.csを修正します。
※ソース内に解説を記載いたしました!ご参照くださいませ!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement; //シーンの読み込みに必要
using UnityEngine.UI; //part.13で追加

//MovingObjectクラスを継承する
public class Player : MovingObject
{
    //ここから最終回で追加
    //タッチ場所の初期化
    private Vector2 touchOrigin = -Vector2.one;
    //ここまで最終回で追加

    //ここからpart.14で追加
    //効果音
    public AudioClip moveSound1;
    public AudioClip moveSound2;
    public AudioClip eatSound1;
    public AudioClip eatSound2;
    public AudioClip drinkSound1;
    public AudioClip drinkSound2;
    public AudioClip gameoverSound;
    //ここまでpart.14で追加

    //ここからpart.13で追加
    public Text foodText; //食料を表示するテキスト
    //ここまでpart.13で追加

    public int wallDamage = 1; //壁へのダメージ量
    public int pointsPerFood = 10; //食べ物の回復量
    public int pointsPerSoda = 20; //ソーダの回復量
    public float restartLevelDeray = 1f; //ステージ移動時の時間

    private Animator animator; //アニメーション用変数
    private int food; //食料


    // Use this for initialization
    //MovingObjectクラスのStartを継承する
    protected override void Start()
    {
        //animatorのコンポーネントを設定
        animator = GetComponent<Animator>();
        //foodをステージ間で引き継げるように、GameManagerから設定
        food = GameManager.instance.playerFoodPoints;
        //ここからpart.13で追加
        //foodTextを初期化
        foodText.text = "Food: " + food;
        //ここまでpart.13で追加
        //GameObjectのStartを呼び出す
        base.Start();
    }

    //PlayerのfoodをGameManageに保存する
    public void OnDisable()
    {
        GameManager.instance.playerFoodPoints = food;
    }

    protected override void AttemptMove<T>(int xDir, int yDir)
    {
        //移動するたびに食料が減る
        food--;
        //ここからpart.13で追加
        //減らした食料をUIに表示する
        foodText.text = "Food: " + food;
        //ここまでpart.13で追加
        //MovingObjectのAttemptMoveを呼び出す
        base.AttemptMove<T>(xDir, yDir);

        RaycastHit2D hit;

        //ここからpart.14で追加
        //動いた時の効果音を鳴らす
        if (Move(xDir, yDir, out hit))
        {
            SoundManager.instance.RandomizeSFx(moveSound1, moveSound2);
        }
        //ここまでpart.14で追加

        //ゲームオーバーか確認
        CheckIfGameOver();
        //プレイヤーのターン終了
        GameManager.instance.playerTurn = false;
    }

    //プレイヤーが壁にぶつかった場合、壁をチョップする
    protected override void OnCantMove<T>(T component)
    {
        //Wallスクリプトを使えるように設定
        Wall hitWall = component as Wall;
        //壁にダメージを与える
        hitWall.DamageWall(wallDamage);
        //チョップするアニメーションを呼び出す
        animator.SetTrigger("PlayerChop");
    }

    //プレイヤーが、Exit、Food、Sodaと接触した場合に呼び出す
    private void OnTriggerEnter2D(Collider2D other)
    {
        //Exitと接触した場合
        if (other.tag == "Exit")
        {
            //ステージ移動の時間分待ってから、次のツテージに移動する
            Invoke("Restart", restartLevelDeray);
            enabled = false;
        }
        else if (other.tag == "Food")
        { //食料と接触した場合
            //食料を回復
            food += pointsPerFood;
            //ここからpart.13で追加
            //増えた食料をUIに表示する
            foodText.text = "+" + pointsPerFood + " Food: " + food;

            //ここからpart.14で追加
            //食べた時の効果音を鳴らす
            SoundManager.instance.RandomizeSFx(eatSound1, eatSound2);
            //ここまでpart.14で追加

            //ここまでpart.13で追加
            //食料を削除
            other.gameObject.SetActive(false);
        }
        else if (other.tag == "Soda")
        {
            //食料を回復
            food += pointsPerSoda;
            //ここからpart.13で追加
            //増えた食料をUIに表示する
            foodText.text = "+" + pointsPerFood + " Food: " + food;

            //ここからpart.14で追加
            //飲んだ時の効果音を鳴らす
            SoundManager.instance.RandomizeSFx(drinkSound1, drinkSound2);
            //ここまでpart.14で追加

            //ここまでpart.13で追加
            //ソーダを削除
            other.gameObject.SetActive(false);
        }
    }

    //プレイヤーがExitに到達した場合、次のステージを呼び出す
    private void Restart()
    {
        //シーンを呼び直す
        SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex, LoadSceneMode.Single);
    }

    //プレイヤーが敵に攻撃された場合、食料を減らす
    public void LoseFood(int loss)
    {
        //攻撃を受けたアニメーションを呼び出す
        animator.SetTrigger("PlayerHit");
        //食料を減らす
        food -= loss;
        //ここからpart.13で追加
        //減らした食料をUIに表示する
        foodText.text = "-" + loss + " Food: " + food;
        //ここまでpart.13で追加
        //ゲームオーバーか判定
        CheckIfGameOver();
    }

    // Update is called once per frame
    void Update()
    {
        //プレイヤーのターンではない場合、何も実行しない
        if (!GameManager.instance.playerTurn)
        {
            return;
        }

        //左右の移動
        int horizontal = 0;
        //上下の移動
        int vertical = 0;

        //ここから最終回で追加
        //プラットフォームを判定
#if UNITY_STANDALONE || UNITYWEB_PLAYER

        //左右の移動量を受け取る
        horizontal = (int)Input.GetAxisRaw("Horizontal");
        //上下の移動量を受け取る
        vertical = (int)Input.GetAxisRaw("Vertical");

        //上下左右のいずれかに移動を制限する
        if (horizontal != 0)
        {
            vertical = 0;
        }
#else
        //タッチされた場合
        if(Input.touchCount > 0){
            //最初にタッチされた情報を取得
            Touch myTouch = Input.touches[0];

            //タッチ開始時
            if(myTouch.phase == TouchPhase.Began){
                //タッチした場所を取得
                touchOrigin = myTouch.position;
            }

            //指を離した時かつ指の場所が0以上の場合
            if(myTouch.phase == TouchPhase.Ended && touchOrigin.x > 0){
                //指を離した場所を取得
                Vector2 touchEnd = myTouch.position;
                //横方向の移動量を取得
                float x = touchEnd.x - touchOrigin.x;
                //縦方向の移動量を取得
                float y = touchEnd.y - touchOrigin.y;
                //横と縦の移動量が大きい方に移動する
                if(Mathf.Abs(x) > Mathf.Abs(y)){
                    horizontal = x > 0 ? 1 : -1;
                }else{
                    vertical = y > 0 ? 1 : -1;
                }
            }
        }
#endif
        //ここまで最終回で追加
        //左右上下のいずれかに移動する場合
        if(horizontal != 0 || vertical != 0){
            //プレイヤーの侵攻方向に壁があるか確認
            AttemptMove<Wall>(horizontal, vertical);
        }
	}

    //食料が0いかになった場合、ゲームオーバーにする
    private void CheckIfGameOver(){
        if(food <= 0){

            //ここからpart.14で追加
            //ゲームオーバーの時の効果音を鳴らす
            SoundManager.instance.PlaySingle(gameoverSound);
            SoundManager.instance.musicSource.Stop();
            //ここまでpart.14で追加

            //GameManagerのGameOverを呼び出す
            GameManager.instance.GameOver();
        }
    }
}

スクリプトの補足説明

タッチパネルをタッチした情報は、以下の機能で取得していきます!

  • Input.TouchCount:タッチされた回数を取得
  • Input.touches[i]:i番目にタッチされた情報を取得
  • Input.touches[i].position:タッチされた場所を取得

ゲームを実行してみよう!

PCにUSBでスマートフォンを接続し、Build and Runで実行してみましょう!
スワイプ操作でプレイヤーを動かすことができると思います!
f:id:yagigame:20181110034308p:plain

感謝

今回の記事で、【Unity2Dローグライク】公式チュートリアルをやってみるは完結となります。
長い間読んでいただきありがとうございました!

これからも、当ブログをよろしくお願いいたします!

【Unity 2Dローグライク】公式チュートリアルをやってみる part.14~ゲームに音をつける

こんにちは!ヤギです!

Unityの2Dローグライクの
公式チュートリアルをやってみる part.14になります!
※前回(part.13)の記事はこちら
www.yagigame.com

記事概要

今回の記事では、ゲーム内の効果音やBGMについてご説明していきます。
※part.14に対応する公式チュートリアルの章は、Audio and Sound Managerです!
unity3d.com

※この記事は、ひよこのたまご様の記事をリスペクトしています。
hiyotama.hatenablog.com

BGMを鳴らす

まず初めに、音を鳴らすオブジェクトを作成します。
1. GameObject > Create Empty をクリックし、名前をSoundManagerとします。
f:id:yagigame:20181107224621p:plain
2. Inspector > Add ComponentからAudio Sourceコンポーネントを2つ追加します。
※効果音と、BGM用になります!
f:id:yagigame:20181107224946p:plain
3. 音を管理するスクリプト(SoundManager.cs)を作成します。
※ソースの中に解説を記載しております。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SoundManager : MonoBehaviour {
    public AudioSource efxSource; //効果音
    public AudioSource musicSource; //BGM
    public static SoundManager instance = null;

    //音の速さの範囲
    public float lowPitchRange = .95f;
    public float highPitchRange = 1.05f;

    // Use this for initialization
    void Awake () {
        //シングルトンにする
        if(instance == null){
            instance = this;
        }else if(instance != this){
            Destroy(gameObject);
        }
        //シーンロード時は破壊しない
        DontDestroyOnLoad(gameObject);
	}

    //BGMを鳴らす処理
    public void PlaySingle(AudioClip clip){
        efxSource.clip = clip;
        //音を再生する
        efxSource.Play();
    }

    //ランダムな音を、ランダムな長さで鳴らす ※効果音を鳴らす
    public void RandomizeSFx(params AudioClip [] clips){
        //音をランダムに選択
        int randomIndex = Random.Range(0, clips.Length);
        //長さをランダムに選択
        float randomPitch = Random.Range(lowPitchRange, highPitchRange);

        //音の長さを設定
        efxSource.pitch = randomPitch;
        //鳴らす音を設定
        efxSource.clip = clips[randomIndex];
        //音を鳴らす
        efxSource.Play();
    }
}

4. SoundManager.csをHierarchy viewのSoundManagerオブジェクトにドラッグし、アタッチします。
5. SoundManager > Inspector viewで、SoundManager.csのEfx SourceとMusic Sourceに、Audio Sourceをドラッグします。
f:id:yagigame:20181107230854p:plain
6. BGM用のAudio Source > AudioClipにscavenger_musicを設定します。
7. BGM用のAudio Souceは音を繰り返し流すために、Loopにチェックをつけます。
8. 効果音用のAudio Sourceは、ゲーム実行と同時に音を鳴らすわけではないので、Play On Awakeのチェックを外します。
f:id:yagigame:20181107231735p:plain
※ここで、一度ゲームを実行してみましょう!BGMが再生されます。

プレイヤーの効果音を鳴らす

1. プレイヤーの効果音を鳴らすために、Player.csを修正していきます。
※ソース内の解説をご確認ください。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement; //シーンの読み込みに必要
using UnityEngine.UI; //part.13で追加

//MovingObjectクラスを継承する
public class Player : MovingObject {
    //ここからpart.14で追加
    //効果音
    public AudioClip moveSound1;
    public AudioClip moveSound2;
    public AudioClip eatSound1;
    public AudioClip eatSound2;
    public AudioClip drinkSound1;
    public AudioClip drinkSound2;
    public AudioClip gameoverSound;
    //ここまでpart.14で追加

    //ここからpart.13で追加
    public Text foodText; //食料を表示するテキスト
    //ここまでpart.13で追加

    public int wallDamage = 1; //壁へのダメージ量
    public int pointsPerFood = 10; //食べ物の回復量
    public int pointsPerSoda = 20; //ソーダの回復量
    public float restartLevelDeray = 1f; //ステージ移動時の時間

    private Animator animator; //アニメーション用変数
    private int food; //食料


	// Use this for initialization
    //MovingObjectクラスのStartを継承する
    protected override void Start () {
        //animatorのコンポーネントを設定
        animator = GetComponent<Animator>();
        //foodをステージ間で引き継げるように、GameManagerから設定
        food = GameManager.instance.playerFoodPoints;
        //ここからpart.13で追加
        //foodTextを初期化
        foodText.text = "Food: " + food;
        //ここまでpart.13で追加
        //GameObjectのStartを呼び出す
        base.Start();
	}

    //PlayerのfoodをGameManageに保存する
    public void OnDisable()
    {
        GameManager.instance.playerFoodPoints = food;
    }

    protected override void AttemptMove<T>(int xDir, int yDir)
    {
        //移動するたびに食料が減る
        food--;
        //ここからpart.13で追加
        //減らした食料をUIに表示する
        foodText.text = "Food: " + food;
        //ここまでpart.13で追加
        //MovingObjectのAttemptMoveを呼び出す
        base.AttemptMove<T>(xDir, yDir);

        RaycastHit2D hit;

        //ここからpart.14で追加
        //動いた時の効果音を鳴らす
        if(Move(xDir,yDir,out hit)){
            SoundManager.instance.RandomizeSFx(moveSound1, moveSound2);
        }
        //ここまでpart.14で追加

        //ゲームオーバーか確認
        CheckIfGameOver();
        //プレイヤーのターン終了
        GameManager.instance.playerTurn = false;
    }

    //プレイヤーが壁にぶつかった場合、壁をチョップする
    protected override void OnCantMove<T>(T component)
    {
        //Wallスクリプトを使えるように設定
        Wall hitWall = component as Wall;
        //壁にダメージを与える
        hitWall.DamageWall(wallDamage);
        //チョップするアニメーションを呼び出す
        animator.SetTrigger("PlayerChop");
    }

    //プレイヤーが、Exit、Food、Sodaと接触した場合に呼び出す
    private void OnTriggerEnter2D(Collider2D other)
    {
        //Exitと接触した場合
        if(other.tag == "Exit"){
            //ステージ移動の時間分待ってから、次のツテージに移動する
            Invoke("Restart", restartLevelDeray);
            enabled = false;
        }else if(other.tag == "Food"){ //食料と接触した場合
            //食料を回復
            food += pointsPerFood;
            //ここからpart.13で追加
            //増えた食料をUIに表示する
            foodText.text = "+"+pointsPerFood+" Food: " + food;

            //ここからpart.14で追加
            //食べた時の効果音を鳴らす
            SoundManager.instance.RandomizeSFx(eatSound1, eatSound2);
            //ここまでpart.14で追加

            //ここまでpart.13で追加
            //食料を削除
            other.gameObject.SetActive(false);
        }else if(other.tag == "Soda"){
            //食料を回復
            food += pointsPerSoda;
            //ここからpart.13で追加
            //増えた食料をUIに表示する
            foodText.text = "+" + pointsPerFood + " Food: " + food;

            //ここからpart.14で追加
            //飲んだ時の効果音を鳴らす
            SoundManager.instance.RandomizeSFx(drinkSound1, drinkSound2);
            //ここまでpart.14で追加

            //ここまでpart.13で追加
            //ソーダを削除
            other.gameObject.SetActive(false);
        }
    }

    //プレイヤーがExitに到達した場合、次のステージを呼び出す
    private void Restart(){
        //シーンを呼び直す
        SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex,LoadSceneMode.Single);
    }

    //プレイヤーが敵に攻撃された場合、食料を減らす
    public void LoseFood(int loss){
        //攻撃を受けたアニメーションを呼び出す
        animator.SetTrigger("PlayerHit");
        //食料を減らす
        food -= loss;
        //ここからpart.13で追加
        //減らした食料をUIに表示する
        foodText.text = "-" + loss+ " Food: " + food;
        //ここまでpart.13で追加
        //ゲームオーバーか判定
        CheckIfGameOver();
    }

    // Update is called once per frame
    void Update () {
        //プレイヤーのターンではない場合、何も実行しない
        if (!GameManager.instance.playerTurn)
        {
            return;
        }
      
        //左右の移動
        int horizontal = 0;
        //上下の移動
        int vertical = 0;
        //左右の移動量を受け取る
        horizontal = (int)Input.GetAxisRaw("Horizontal");
        //上下の移動量を受け取る
        vertical = (int)Input.GetAxisRaw("Vertical");

        //上下左右のいずれかに移動を制限する
        if(horizontal != 0){
            vertical = 0;
        }

        //左右上下のいずれかに移動する場合
        if(horizontal != 0 || vertical != 0){
            //プレイヤーの侵攻方向に壁があるか確認
            AttemptMove<Wall>(horizontal, vertical);
        }
	}

    //食料が0いかになった場合、ゲームオーバーにする
    private void CheckIfGameOver(){
        if(food <= 0){

            //ここからpart.14で追加
            //ゲームオーバーの時の効果音を鳴らす
            SoundManager.instance.PlaySingle(gameoverSound);
            SoundManager.instance.musicSource.Stop();
            //ここまでpart.14で追加

            //GameManagerのGameOverを呼び出す
            GameManager.instance.GameOver();
        }
    }
}

2. Player > InspectorのAudio Clipを以下の画像の内容で設定します。
f:id:yagigame:20181108232637p:plain
※これで、プレイヤーの効果音が鳴るようになりました。

敵の効果音を鳴らす

1. 敵の効果音を鳴らすために、Enemy.csを修正していきます。
※ソース内の解説をご確認ください!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//MovingObjectを継承する
public class Enemy : MovingObject {

    //ここからpart.14で追加
    //敵の攻撃の効果音
    public AudioClip enemyAttack1;
    public AudioClip enemyAttack2;
    //ここまで、part.14で追加

    public int playerDamage; //プレイヤーへのダメージ

    private Animator animator;
    private Transform target; //プレイヤー場所
    private bool skipMove; //動くか判定


	// Use this for initialization
    //継承クラス
    protected override void Start () {

        //ここからpart.12で追加
        //敵をリストに加える
        GameManager.instance.AddEnemyList(this);
        //ここまでpart.12で追加

        //Animatorコンポーネント取得
        animator = GetComponent<Animator>();
        //プレイヤーの場所を取得する
        target = GameObject.FindGameObjectWithTag("Player").transform;
        //MovingObjectクラスのStartを呼び出す
        base.Start();
	}

    //敵のターンか判定、移動を試みる処理
    protected override void AttemptMove<T>(int xDir, int yDir)
    {
        //敵のターンではない場合
        if(skipMove){
            //敵のターンにする
            skipMove = false;
            return;
        }

        base.AttemptMove<T>(xDir, yDir);
        //敵のターンを終わる
        skipMove = true;
    }

    //敵を移動させる処理
    public void MoveEnemy(){
        int xDir = 0; //左右の移動量
        int yDir = 0; //上下の移動量

        //敵とプレイヤーの左右の距離がほぼ0の場合
        if(Mathf.Abs(target.position.x - transform.position.x) < float.Epsilon){
            //プレイヤーが上にいれば、1とし、下にいれば、-1とする
            yDir = target.position.y > transform.position.y ? 1 : -1;
        }else{
            //プレイヤーが右にいれば、1とし、左にいれば、-1とする
            xDir = target.transform.position.x > transform.position.x ? 1 : -1;
        }
        //移動する
        AttemptMove<Player>(xDir, yDir);
    }

    //敵が移動できない時の処理
    protected override void OnCantMove<T>(T component)
    {
        //衝突したプレイヤーを設定
        Player hitPlayer = component as Player;

        //ここからpart.12で追加
        //プレイヤーに攻撃するアニメーションを呼び出す
        animator.SetTrigger("EnemyAttack");
        //ここまでpart.12で追加

        //プレイヤーの食料を減らす
        hitPlayer.LoseFood(playerDamage);

        //ここからpart.14で追加
        //攻撃する効果音を鳴らす
        SoundManager.instance.RandomizeSFx(enemyAttack1, enemyAttack2);
        //ここまでpart.14で追加
    }
}

2. Enemy1とEnemy2 > InspectorのAudio Clipを以下の画像の内容で設定します。
f:id:yagigame:20181108233355p:plain
※これで、敵の効果音が鳴るようになりました。

壁が攻撃された時の効果音を鳴らす

1. 次に、壁が攻撃された時の効果音が鳴るようするために、Wall.csを修正していきます。
※ソース内の解説をご確認ください!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Wall : MonoBehaviour {
    //ここからpart.14で追加
    public AudioClip chopSound1;
    public AudioClip chopSound2;
    //ここまでpart.14で追加

    public Sprite dmgSprite;
    public int hp = 4;
    private SpriteRenderer spriteRenderer;

	// Use this for initialization
	void Awake () {
        spriteRenderer = GetComponent<SpriteRenderer>();
	}
	
    //壁が攻撃された場合の処理
    public void DamageWall(int loss){
        //ここからpart.14で追加
        SoundManager.instance.RandomizeSFx(chopSound1, chopSound2);
        //ここまでpart.14で追加

        spriteRenderer.sprite = dmgSprite;
        //壁のhpを減らす
        hp -= loss;
        //hpが0になった場合
        if(hp <= 0){
            //壁を破壊する
            gameObject.SetActive(false);
        }
    }
}

2. Wall1からWall8 > InspectorのAudio Clipを以下の画像の内容で設定します。
f:id:yagigame:20181108235249p:plain
※これで、壁が攻撃された時の効果音がなるようになりました。

ゲームを実行してみよう!

ゲームを実行してみましょう!
プレイヤーが移動した時や、敵が攻撃した時など、効果音がなるようになりました!

次回予告

次回の記事では、スマートフォンに対応させる方法について書いていきたいと思います。
※次回で最終回となります!!!
※Unityのチュートリアルの章としては、次回は(Adding Mobile Controls)となります!

読んでいただきありがとうございました!