はじめに
RPG以外のジャンルでもそうですが、重要な部分から手を付けていくと制作を進めやすいです。
今回制作するMiniRpgで最も重要なのは、戦闘システムです。
その中でも特にプレイヤーが重要なので、プレイヤー周りから制作していきます。
このパートでは、まずはプレイヤーの移動を実装します。
なお、コードはどんな風に実装しても良いということと、本題はRPGという”ゲーム”を制作することなので、コードの説明は基本省きます。
プレイヤーを作成する
プレイヤーのモデルを配置する
Projectビューから「Assets > FightingUnityChan_FreeAsset > FightingUnityChan_FreeAsset > Models > unitychan」を選択し、シーンに配置します。
そして、名前を「Player」に変更しておきます。
プレイヤーの中心を決める
ヒエラルキから、たった今配置した「Player」オブジェクトを右クリックし、CreateEmptyを選択します。更に、新しいGameObjectの名前を「Center」とリネームし、目分量でプレイヤーの中心に移動させます。
このようにプレイヤーの中心となる位置を予め決めておくと、後々良いことがあります。
こんな感じになります。
CharacterControllerをアタッチする
物理演算を適用するために、「Player」オブジェクトにCharacterControllerをアタッチします。
少し細めの方が良いので、これくらいの値で。
プレイヤーの移動を実装する
スクリプトを作成する
フォルダの準備
Projectビューの「Assets > MiniRpg > Scripts」の下に、「Actor」フォルダを作成します。更に、「Actor」フォルダの下に「Behaviour」フォルダを作成します。
Actorは、プレイヤーやモンスター、村人など、ゲームの登場人物を指すこととします。
Moveスクリプトを作成する
作成したBehaviourフォルダの下に、「Move」という名前でスクリプトを作成し、次のコードをコピーして貼り付けて下さい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
using UnityEngine; namespace MiniRpg.Actor.Behaviour { public class Move : MonoBehaviour { [Header("Callback")] [SerializeField] UnityEngine.Events.UnityEvent m_OnEnable = new UnityEngine.Events.UnityEvent(); [SerializeField] UnityEngine.Events.UnityEvent m_OnDisable = new UnityEngine.Events.UnityEvent(); protected virtual void OnEnable() { if (m_OnEnable != null) m_OnEnable.Invoke(); } protected virtual void OnDisable() { if (m_OnDisable != null) m_OnDisable.Invoke(); } } } |
名前の通り移動を表すクラスですが、まだ特に中身はありません。
Moveスクリプトを作成したら、一旦先に進みます。
WayPointMoveスクリプトを作成する
作成したBehaviourフォルダの下に、「WayPointMove」という名前でスクリプトを作成し、次のコードをコピーして貼り付けて下さい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
using UnityEngine; using System.Collections.Generic; namespace MiniRpg.Actor.Behaviour { public class WayPointMove : Move { #region enum STATE { Idling, Walking, Running } enum RAYCAST_TRIGGER { LeftMouseButton, LeftMouseButtonDown, RightMouseButton, RightMouseButtonDown } #endregion [Header("Required")] [SerializeField] CharacterController m_CharacterController; [Header("Settings")] [SerializeField] float m_StoppingDistance = 1f; [SerializeField] List<KeyCode> m_WalkingTriggers = new List<KeyCode> { KeyCode.LeftShift, KeyCode.RightShift }; [SerializeField] float m_WalkingSpeed = 0.1f; [SerializeField] float m_RunningSpeed = 0.3f; [Header("Animation")] [SerializeField] Animator m_Animator; [SerializeField] string m_RunningAnimationName; [SerializeField] string m_WalkingAnimationName; [Header("Raycast")] [SerializeField] Camera m_RaycastingCamera; [SerializeField] RAYCAST_TRIGGER m_RaycastTrigger = RAYCAST_TRIGGER.LeftMouseButton; [SerializeField] List<string> m_IgnoreTags = new List<string>(); Vector3? m_HitPosition; [Header("Info")] [SerializeField] STATE m_State; #region functions Vector3 Destination() { return m_HitPosition == null ? m_CharacterController.transform.position : (Vector3)m_HitPosition; } Vector3 MovingDirection() { var direction = Destination() - m_CharacterController.transform.position; direction.y = 0f; return direction.normalized; } float HorizontalDistance(Vector3 arg1, Vector3 arg2) { arg1.y = 0f; arg2.y = 0f; return Vector3.Distance(arg1, arg2); } bool HasReachedDestination() { return HorizontalDistance(Destination(), m_CharacterController.transform.position) <= m_StoppingDistance; } #endregion void RayCast() { RaycastHit hit; Ray ray = m_RaycastingCamera.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out hit)) { foreach (string tag in m_IgnoreTags) { if (hit.transform.gameObject.tag == tag) return; } m_HitPosition = hit.point; } } void LookAtDestination() { var lookedAt = Destination(); lookedAt.y = m_CharacterController.transform.position.y; m_CharacterController.transform.LookAt(lookedAt); } protected override void OnEnable() { base.OnEnable(); } protected override void OnDisable() { base.OnDisable(); } private void FixedUpdate() { switch (m_State) { case STATE.Idling: if (m_Animator == null) break; m_Animator.SetBool(m_WalkingAnimationName, false); m_Animator.SetBool(m_RunningAnimationName, false); break; case STATE.Walking: LookAtDestination(); m_CharacterController.Move(MovingDirection() * m_WalkingSpeed); if (m_Animator == null) break; m_Animator.SetBool(m_WalkingAnimationName, true); m_Animator.SetBool(m_RunningAnimationName, false); break; case STATE.Running: LookAtDestination(); m_CharacterController.Move(MovingDirection() * m_RunningSpeed); if (m_Animator == null) break; m_Animator.SetBool(m_WalkingAnimationName, false); m_Animator.SetBool(m_RunningAnimationName, true); break; } } private void Update() { switch (m_RaycastTrigger) { case RAYCAST_TRIGGER.LeftMouseButton: if (Input.GetMouseButton(0)) RayCast(); break; case RAYCAST_TRIGGER.LeftMouseButtonDown: if (Input.GetMouseButtonDown(0)) RayCast(); break; case RAYCAST_TRIGGER.RightMouseButton: if (Input.GetMouseButton(1)) RayCast(); break; case RAYCAST_TRIGGER.RightMouseButtonDown: if (Input.GetMouseButtonDown(1)) RayCast(); break; } if (HasReachedDestination()) { m_State = STATE.Idling; } else { m_State = STATE.Running; m_WalkingTriggers.ForEach(trigger => { if (Input.GetKey(trigger)) m_State = STATE.Walking; }); } } } } |
WayPointMoveオブジェクトを作成する
画像のようにPlayerオブジェクトの下に空の「Way Point Move」オブジェクトを作成し、先ほど作成したWayPointMoveスクリプトをアタッチします。
アタッチしたら、画像上側の赤枠部分にPlayerのCharacterControllerを、画像下側の赤枠部分にMain Cameraを設定します。
動作確認
カメラを調整
動作確認のため、カメラをプレイヤーが映る位置まで移動しておきます。
動作確認
現時点でゲームをプレイすると、こうなります。
この状態ではまだアニメーションが付いていません。
次のパートで移動にアニメーションを付けていきます。
なお、WayPointMoveのRunningSpeedやWalkingSpeedをいじると、移動スピードを変更することができます。必要に応じてパラメータを調整して下さい。
コメント