Unityはまだ慣れていませんので、参考程度にしてください。
Character Controllerを用いて以下のように実装しました。 詳しくは以下のコード中に書いてあります。
using System.Collections; using UnityEngine; /* * 構成図 * root [このスクリプト、CharacterControll、Animator] * |- Camera * |- Initial Camera Transform [からのオブジェクト] * |- Rotate Body[主に カメラ基準にした時の回転方向。からのオブジェクト。しばしばモデルそのもののルート] * |- モデルの構造体 * * マウスの左右でカメラ視点切り替え * 十字キーでカメラ視点方向を基準に8方向に動く * character controllerを用いるため、超えられる段差の調整はそちらで行う * character controllerを用いるため、rigidbodyなどは基本使わない * 体がカメラ視点方向を基準とするタイミングはなんらかの十字キーを押したタイミング * カメラはキャラクターの上下移動に対し、画角の基準になるまでは動かない * ジャンプ中も移動が可能 * キックアクション中は地上にいる時移動が止まるが、ジャンプ中は移動できる(大技に改造できそう) * animationは各自自由に設定する * * 未実装など * カメラの上下回転移動 * カメラ基準にモデルが戻る時の回転のスムースと、モデルが180度方向が変わる時のスムース * カメラ移動のキャラクターに対するスムース */ public class PlayerController : MonoBehaviour { CharacterController controller; Animator animator; [SerializeField] float walkSpeed=2; [SerializeField] float runSpeed = 5; [SerializeField] float accel = 5; [SerializeField] float blake = 10; [SerializeField] float maxAngle = 45; [SerializeField] Transform rotateBody; [SerializeField] float cameraRotateSpeed=10; [SerializeField] Transform playerCamera; [SerializeField] Transform initialCameraPos; [SerializeField] [Tooltip("ジャンプの初速度")] float jumpVelocity = 13.5f; float rotateAngle = 0; float verticalVelocity = 0; float oldCameraY; bool canMove = true;//地面に触れている時、falseなら入力を受け付けない [SerializeField,Header("Not Changeable.For Debug")]float speed=0; void Awake() { controller = GetComponent<CharacterController>(); animator = GetComponent<Animator>(); oldCameraY = playerCamera.localPosition.y; } IEnumerator Kick() { canMove = false; animator.SetTrigger("Kick"); yield return new WaitForSeconds(0.5f); canMove = true; } void Update() { CameraMove(); Move(); CameraHeight(); if (Input.GetKeyDown(KeyCode.Mouse0)&&canMove) { StartCoroutine(Kick()); } } void CameraMove() { float h = Input.GetAxis("Mouse X"); playerCamera.RotateAround(transform.position, Vector3.up, h * cameraRotateSpeed); if (Input.GetKeyDown(KeyCode.Z)) { //キャラクターの前の方向にカメラの方向を合わせる // todo //transform.localRotation= } oldCameraY=playerCamera.position.y; } void CameraHeight() { //上下でプレイヤーが画伯から出そうになるまでカメラは動かない Vector3 pos = playerCamera.position; Vector3 oldPos = pos; pos.y = oldCameraY; playerCamera.position = pos; Vector3 p = Camera.main.WorldToViewportPoint(transform.position); if ( p.y<0 || 0.25f <p.y) { // 画伯からはみ出た、もしくは画伯に入ろうとしているとき //カメラの高さはプレイヤーの動きに付随する playerCamera.position = oldPos; } } private void Move() { float x = Input.GetAxis("Horizontal"); float z = Input.GetAxis("Vertical"); if (!canMove&&controller.isGrounded) { // ジャンプ中のキックは、移動しながらのアクションを認める x = 0;z = 0; } float magnitute = x * x + z * z; if (magnitute != 0) { //Debug.Log("move x:"+x+"z:"+z); //動いたら全体をカメラの方向に向け、カメラの位置をリセットする。 Vector3 bodyAngle = transform.localEulerAngles; bodyAngle.y += playerCamera.localEulerAngles.y; transform.localEulerAngles = bodyAngle; // yは回転に関与していないのでリセットしない。 Vector3 pos = playerCamera.position; pos.x = initialCameraPos.position.x; pos.z = initialCameraPos.position.z; playerCamera.position = pos; playerCamera.rotation = initialCameraPos.rotation; if (Input.GetKey(KeyCode.LeftShift)) { // シフトキーを押して加速する時 speed += accel * Time.deltaTime; speed = Mathf.Clamp(speed, 0, runSpeed); } else if (speed <= walkSpeed) { // 歩くスピードまで加速する時 speed += accel * Time.deltaTime; speed = Mathf.Clamp(speed, 0, walkSpeed); } else { //歩くスピードを超えて走っていて減速する時 speed -= blake * Time.deltaTime; speed = Mathf.Clamp(speed, 0, runSpeed); } rotateAngle = Mathf.Clamp(Mathf.Atan2(x, z), -maxAngle, maxAngle); } else if(speed>0) { // 何も押していない時 speed -= blake * Time.deltaTime; speed = Mathf.Clamp(speed, 0, runSpeed); } rotateBody.localEulerAngles = new Vector3(0, rotateAngle, 0) * Mathf.Rad2Deg; animator.SetFloat("Speed", speed); Vector3 move = transform.rotation * new Vector3(x, 0, z) * speed; if (controller.isGrounded) { verticalVelocity = 0; if (Input.GetKeyDown(KeyCode.Space)) { verticalVelocity += jumpVelocity; animator.SetTrigger("Jump"); } } else { animator.SetFloat("Speed", 0); //地面についていないときは加速を続ける verticalVelocity += Physics.gravity.y*Time.deltaTime; verticalVelocity = Mathf.Clamp(verticalVelocity, 0, jumpVelocity); } move.y = verticalVelocity; controller.Move((move+ Physics.gravity)* Time.deltaTime); } }