見出し画像

コウペンちゃんを歩かせよう コウペンちゃんランド#003

歩き回るコウペンちゃんを実装する

こんにちは、ふにいちごです🍓
建築を決めたコウペンちゃんランド🎡
かわいい建造物を作る前に、ゲームのシステムで優先度の高いものから作っていこうと思います。
(かわいい建造物が作れる自信がないのは内緒)

まずはコウペンちゃんが歩き回っている空間を三人称視点でお散歩できることを目指します。

手っ取り早く歩き回れるようにするため、Unityの「Starter Assets - Third Person Character Controller」を利用しました。
これでお散歩機能はOK。
(プレイヤーがゴツゴツ気味なのは気にしない)
あとはコウペンちゃん数人をランダムに歩き回らせます。

調べた結果、UnityではNavMeshAgentというものを利用することで自動でNPC(コウペンちゃん)が動き回ってくれることがわかりました。
早速下記のサイトさんを確認しながら設定

【Unity】巡回する敵AIをNavigationで作る方法

そもそもAIメニューがないんですけど……

さらっと書いてある、「Window→AI→Navigation」がそもそも見つかりませんでした。なんで。
調べているうちに、プロジェクトへのインポートが必要だということが分かったので、「Package Manager」で「AI Navigation」をインストールします。

今度はなんか、メニューが違うんですけど……

どうやら、前述した参考記事の時からメニューが変更になったようで、NavMeshのベイクボタンがなくなっていました。
廃止されていると書かれた方には同じボタンがあるのですが、廃止されたものを使うのもどうかと思い……
これら二つの課題はこちらのサイトさんで解決いたしました。
Unity、やっぱり情報たくさんあって助かる……

【Unity】NavMeshを使ってキャラクターを自動で移動させる

あとはNavMeshAgentをコウペンちゃんに設定し、最初に見つけたほうの参考サイト様のスクリプトを参考に(というかほぼコピペ……)してコウペンちゃんにアタッチします。

コウペンちゃん動いた!

可愛い❗️めっちゃ可愛い‼️
ただ水平移動を繰り返しているだけなのにニヤニヤが止まりません。
やっぱりコウペンちゃん天使すぎる……❗️

もっとコウペンちゃんらしくしたい

ここで更なる欲望が。
コウペンちゃんとコウペンちゃんが出会ったら、もにゃもにゃお話しすると可愛くない❓

ということで、よりコウペンちゃんらしさが出るよう以下の設定をスクリプトに追加してみることに

  • 歩きまわるだけでなく、時々ぼんやりとする

  • 他のコウペンちゃんに出会ったら、お話しする

  • プレイヤーに出会ったら、気が付く

これ絶対可愛いやつ‼️
と言ってもC#もUnityも初心者の私にはなかなかうまくいきません。
ChatGPT大先生に相談して骨子となるプログラムを作ってもらい、コードを読み解いて改変を重ねていきます。

できた……!

めちゃくちゃ可愛い!!!!(悶絶)
やったことは、スクリプトの修正、吹き出しや気づいたときのパーティクル作成、コウペンちゃんへのコリジョンやリジッドボディの設定、アニメーションコントローラーの追加などです。
以下に作成したコードを掲載しておきます♪
(バグが潜んでいる可能性があるのでご注意くださいね)

using System.Collections;
using UnityEngine;
using UnityEngine.AI;

public class RandomWalker : MonoBehaviour

    //コウペンちゃんの動き
    //ランダムに近めの目的地を設定(歩き始める)
    //目的地についたらランダムな秒数立ち止まる
    //立ち止まった後またランダムな目的地を設定
    //途中で別のコウペンちゃんにあったらお話する
    //途中でプレイヤーにあったら、君だ~をする
{
    
    //ゲームコンポーネント
    private NavMeshAgent agent;
    private Animator animator;

    //フラグ系
    private bool isWalking = false;
    private bool isMonyamonya = false;
    private bool isBonyari = false;
    private bool isKimida = false;
    private bool isParticleOn = false;

    //調整可能パラメータ
    public float minWalkTime = 5f;
    public float maxWalkTime = 15f;
    public float minConversationTime = 5f;
    public float maxConversationTime = 15f;
    public float wanderRange = 5f;

    //パーティクルシステム設定
    public ParticleSystem monyaParticle;
    public ParticleSystem kimiParticle;

    private void Start()
    {
        //必要コンポーネント取得
        agent = GetComponent<NavMeshAgent>();
        animator = GetComponent<Animator>();

        //最初の目的地決定
        RandomNavMeshPoint(transform.position, 3f);
        animator.SetBool("isWalking", true);
        isWalking = true;
    }

    
    private void Update()
    {
        //歩行・ぼんやり・もにゃもにゃ・きみだー! のいずれでもないとき
        if(!isWalking && !isBonyari && !isMonyamonya && !isKimida)
        {
            //新しい目的地を設定
            RandomNavMeshPoint(transform.position, 3f);
            animator.SetBool("isWalking", true);
            isWalking = true;
        }
        //目的地についたとき
        else if (agent.remainingDistance <= agent.stoppingDistance && !agent.pathPending)
        {
            //ぼんやりに移行
            agent.isStopped = true;
            animator.SetBool("isWalking", false);
            StartCoroutine(Bonyari());
            isWalking = false;
        }

    }

    //ランダムな目的地を決める
    private void RandomNavMeshPoint(Vector3 origin, float radius)
    {
        NavMeshHit hit;
        Vector3 randomPos = Random.insideUnitSphere * radius;
        randomPos += origin;
        //SamplePositionは設定した場所から5の範囲で最も近い距離のBakeされた場所を探す。
        NavMesh.SamplePosition(randomPos, out hit, 5, 1);
        agent.SetDestination(hit.position);
    }

    //コウペンちゃん同士が出会ったときの会話
    private IEnumerator MonyaMonya()
    {
        //吹き出しのパーティクルを表示
        if (!isParticleOn) {
            isParticleOn = true;
            ParticleSystem newParticle = Instantiate(monyaParticle);
            newParticle.transform.position = new Vector3(this.transform.position.x, this.transform.position.y + 0.5f, this.transform.position.z);
            newParticle.Play();
            Destroy(newParticle.gameObject, 5.0f);
        }

        //会話してる間ランダムな時間待つ
        yield return new WaitForSeconds(Random.Range(minConversationTime, maxConversationTime));
        
        //フラグ初期化
        agent.isStopped = false;
        isMonyamonya = false;
        isParticleOn = false;
        
    }

    //コウペンちゃんがぼんやりする
    private IEnumerator Bonyari()
    {
        isBonyari = true;
        yield return new WaitForSeconds(Random.Range(minConversationTime, maxConversationTime));
        agent.isStopped = false;
        isBonyari = false;
    }

    //コウペンちゃんがきみだ~!となる
    private IEnumerator Kimida()
    {
        //気づいた感じのパーティクル表示
        if (!isParticleOn)
        {
            isParticleOn = true;
            ParticleSystem newParticle = Instantiate(kimiParticle);
            newParticle.transform.position = new Vector3(this.transform.position.x, this.transform.position.y + 0.5f, this.transform.position.z);
            newParticle.Play();
            Destroy(newParticle.gameObject, 5.0f);
        }
        //ランダムな時間待つ
        yield return new WaitForSeconds(Random.Range(minConversationTime, maxConversationTime));

        //フラグ初期化
        agent.isStopped = false;
        isKimida = false;
        isParticleOn = false;
    }

    void OnCollisionEnter(Collision other)
    {
        //ぶつかった相手がきみ
        if (other.gameObject.CompareTag("Player"))
        {
            isKimida = true;
            agent.isStopped = true;
            agent.ResetPath();
            animator.SetBool("isWalking", false);
            StartCoroutine(Kimida());
            isWalking = false;
        }
        //ぶつかった相手がコウペンちゃん
        else if (other.gameObject.CompareTag("NPC"))
        {
            isMonyamonya = true;
            agent.isStopped = true;
            agent.ResetPath();
            animator.SetBool("isWalking", false);
            transform.LookAt(other.transform);
            StartCoroutine(MonyaMonya());
            isWalking = false;
        }
    }

}

というわけで、コウペンちゃんがワールドにいて、プレイヤーがお散歩できる仕組みを作りました。
カメラ外にいるコウペンちゃんにも処理が行われてしまい、動作が重くなる懸念や、パーティクルのズレ、なぜかプレイヤーは正面から触れないとコウペンちゃんに気付いてもらえない点、そもそも歩行アニメーションが微妙な点、などなど直さなければならない点は沢山あるのですがひとまずの区切りとしたいと思います。
何かの参考になれば嬉しいです☺️

それではまた!