さて、Unityちゃんトゥーン化が中途半端に終わってしまいましたが、今日からはこれをやっていきましょう。

今まで僕がやって来たのは、やりたい事を実行するためにどんなコードを書けばいいのか?という形でした。
しかし、今回からは上のようなチュートリアルなどをベースに学習して、それを元にどんな機能を実装出来るか?という形でやっていきます。

まずは、チュートリアルを進めます。

Overview game what i will make

今回作るのは、クリック移動型のアドベンチャーゲーム。
街を歩いていろいろなアイテムを集めて変装して、警備員を騙して侵入できたらクリアという流れ。

最初は概要から説明がされます。
真偽を判定したり、マップ移動にLoad Sceneを使ったり…

8:33~
意外と僕の前作ったゲームでやったことが説明されています。
シーン読み込み時にリセットしてしまったらコインが無限にできちゃうからシーンの状態(Scene State)管理は重要だよねって話。
うん、僕もクエストウィンドウを保持したりするためにやりました。

その後も僕のとは比べ物にならないぐらい綺麗な設計図を元に説明がされていきます。
なるほど…中身がどういう風に動いているのかを設計図で書くとわかりやすいですね。

次ゲーム制作をするときは参考にしましょう。

When 1 (b) / 6 ends

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.EventSystems;


public class PlayerMovement : MonoBehaviour {

    public Animator animator;
    public NavMeshAgent agent;
    public float inputHoldDelay = 0.5f;
    public float turnSpeedThreshold = 0.5f;
    public float speedDampTime = 0.1f;
    public float slowingSpeed = 0.175f;
    public float turnSmoothing = 15f;

    private WaitForSeconds inputHoldWait;
    private Vector3 destinationPosition;
    private Interactable currentInteractable;
    private bool handleInput = true;

    private const float stopDistanceProportion = 0.1f;
    private const float navMeshSampleDistance = 4f;

    private readonly int hashSpeedPara = Animator.StringToHash("Speed");
    private readonly int hashLocomotionTag = Animator.StringToHash("Locomotion");

    private void Start()
    {
        agent.updateRotation = false;
        inputHoldWait = new WaitForSeconds(inputHoldDelay);
        destinationPosition = transform.position;
    }    

    private void OnAnimatorMove()
    {
        agent.velocity = animator.deltaPosition / Time.deltaTime;
    }

    private void Update()
    {
        if (agent.pathPending)
        {
            return;
        }

        float speed = agent.desiredVelocity.magnitude;

        if (agent.remainingDistance <= agent.stoppingDistance * stopDistanceProportion)
        {
            Stopping(out speed);

        }
        else if (agent.remainingDistance <= agent.stoppingDistance)
        {
            Slowing(out speed, agent.remainingDistance);
        }
        else if (speed > turnSpeedThreshold)
        {
            Moving();
        }

        animator.SetFloat(hashSpeedPara, speed, speedDampTime,Time.deltaTime);
        

    }

    private void Stopping (out float speed)
    {
        agent.Stop();
        transform.position = destinationPosition;
        speed = 0f;

        if (currentInteractable)
        {
            transform.rotation = currentInteractable.interactionLocation.rotation;
            currentInteractable.Interact();
            currentInteractable = null;
            StartCoroutine(WaitForInteraction());
        }
    }

    private void Slowing (out float speed,float distanceToDestination)
    {
        agent.Stop();
        transform.position = 
            Vector3.MoveTowards(transform.position,destinationPosition,slowingSpeed * Time.deltaTime);
        float proportionalDistance = 1f - distanceToDestination / agent.stoppingDistance;
        speed = Mathf.Lerp(slowingSpeed, 0f, proportionalDistance);

        Quaternion targetRotation = 
            currentInteractable ? currentInteractable.interactionLocation.rotation : transform.rotation;
        transform.rotation = Quaternion.Lerp(transform.rotation,targetRotation,proportionalDistance);
    }

    private void Moving()
    {
        Quaternion targetRotation = Quaternion.LookRotation(agent.desiredVelocity);
        transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, turnSmoothing * Time.deltaTime);
    }

    public void OnGroundClick(BaseEventData data)
    {
        if (!handleInput)
        {
            return;
        }

        currentInteractable = null;

        PointerEventData pData = (PointerEventData)data;
        NavMeshHit hit;
        if (NavMesh.SamplePosition(pData.pointerCurrentRaycast.worldPosition, out hit, navMeshSampleDistance, NavMesh.AllAreas))
        {
            destinationPosition = hit.position;
        }
        else
        {
                destinationPosition = pData.pointerCurrentRaycast.worldPosition;
        }
        agent.SetDestination(destinationPosition);
        agent.Resume();
    }

    public void OnInteractableClick (Interactable interactable)
    {
        if (!handleInput)
        {
            return;
        }

        currentInteractable = interactable;
        destinationPosition = currentInteractable.interactionLocation.position;

        agent.SetDestination(destinationPosition);
        agent.Resume();
    }

    private IEnumerator WaitForInteraction()
    {
        handleInput = false;

        yield return inputHoldWait;

        while (animator.GetCurrentAnimatorStateInfo(0).tagHash != hashLocomotionTag)
        {
            yield return null;
        }
            
        handleInput = true;
    }
}

こちらが、1(b)/6終了時点での「キャラクターをマウスクリックで動かす」コードです。

今日は、1(b)/6まで完成させたところで終わってしまったので、明日はこのコードの解読を進めていきます。
今日はここまで。