「Unity/3d/キャラクタ移動/上下左右」の版間の差分
提供: 初心者エンジニアの簡易メモ
(ページの作成:「unity/3d/キャラクタ移動/上下左右」) |
|||
| 行1: | 行1: | ||
| − | + | ==キャラクタ移動== | |
| + | 適当にUnityAssetsからキャラクタをDLする(例:Supercyan Character Pack Free Sample https://assetstore.unity.com/packages/3d/characters/humanoids/character-pack-free-sample-79870?locale=ja-JP) | ||
| + | |||
| + | ===サンプル=== | ||
| + | キーボードの上下左右で操作できるサンプル。 | ||
| + | |||
| + | CharacterControl.cs | ||
| + | <pre> | ||
| + | using System.Collections.Generic; | ||
| + | using UnityEngine; | ||
| + | |||
| + | public class CharacterControl : MonoBehaviour | ||
| + | { | ||
| + | [SerializeField] private float m_moveSpeed = 2; | ||
| + | [SerializeField] private float m_turnSpeed = 200; | ||
| + | [SerializeField] private float m_jumpForce = 4; | ||
| + | |||
| + | [SerializeField] private Animator m_animator = null; | ||
| + | [SerializeField] private Rigidbody m_rigidBody = null; | ||
| + | |||
| + | private float m_currentV = 0; | ||
| + | private float m_currentH = 0; | ||
| + | |||
| + | private readonly float m_interpolation = 10; | ||
| + | private readonly float m_runScale = 2f; | ||
| + | |||
| + | private Vector3 m_currentDirection = Vector3.zero; | ||
| + | |||
| + | private bool m_jumpInput = false; | ||
| + | |||
| + | private bool m_isGrounded; | ||
| + | private bool m_wasGrounded; | ||
| + | |||
| + | private List<Collider> m_collisions = new List<Collider>(); | ||
| + | |||
| + | private void Awake() | ||
| + | { | ||
| + | if (!m_animator) { gameObject.GetComponent<Animator>(); } | ||
| + | if (!m_rigidBody) { gameObject.GetComponent<Animator>(); } | ||
| + | } | ||
| + | |||
| + | private void OnCollisionEnter(Collision collision) | ||
| + | { | ||
| + | ContactPoint[] contactPoints = collision.contacts; | ||
| + | for (int i = 0; i < contactPoints.Length; i++) | ||
| + | { | ||
| + | if (Vector3.Dot(contactPoints[i].normal, Vector3.up) > 0.5f) | ||
| + | { | ||
| + | if (!m_collisions.Contains(collision.collider)) | ||
| + | { | ||
| + | m_collisions.Add(collision.collider); | ||
| + | } | ||
| + | m_isGrounded = true; | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | private void OnCollisionStay(Collision collision) | ||
| + | { | ||
| + | ContactPoint[] contactPoints = collision.contacts; | ||
| + | bool validSurfaceNormal = false; | ||
| + | for (int i = 0; i < contactPoints.Length; i++) | ||
| + | { | ||
| + | if (Vector3.Dot(contactPoints[i].normal, Vector3.up) > 0.5f) | ||
| + | { | ||
| + | validSurfaceNormal = true; break; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | if (validSurfaceNormal) | ||
| + | { | ||
| + | m_isGrounded = true; | ||
| + | if (!m_collisions.Contains(collision.collider)) | ||
| + | { | ||
| + | m_collisions.Add(collision.collider); | ||
| + | } | ||
| + | } | ||
| + | else | ||
| + | { | ||
| + | if (m_collisions.Contains(collision.collider)) | ||
| + | { | ||
| + | m_collisions.Remove(collision.collider); | ||
| + | } | ||
| + | if (m_collisions.Count == 0) { m_isGrounded = false; } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | private void OnCollisionExit(Collision collision) | ||
| + | { | ||
| + | if (m_collisions.Contains(collision.collider)) | ||
| + | { | ||
| + | m_collisions.Remove(collision.collider); | ||
| + | } | ||
| + | if (m_collisions.Count == 0) { m_isGrounded = false; } | ||
| + | } | ||
| + | |||
| + | private void Update() | ||
| + | { | ||
| + | if (!m_jumpInput && Input.GetKey(KeyCode.Space)) | ||
| + | { | ||
| + | m_jumpInput = true; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | private void FixedUpdate() | ||
| + | { | ||
| + | if (m_animator != null) | ||
| + | { | ||
| + | m_animator.SetBool("Grounded", m_isGrounded); | ||
| + | } | ||
| + | DirectUpdate(); | ||
| + | m_wasGrounded = m_isGrounded; | ||
| + | m_jumpInput = false; | ||
| + | } | ||
| + | |||
| + | private void DirectUpdate() | ||
| + | { | ||
| + | float vertical = Input.GetAxis("Vertical"); | ||
| + | float horizontal = Input.GetAxis("Horizontal"); | ||
| + | |||
| + | Transform camera = Camera.main.transform; | ||
| + | |||
| + | vertical *= m_runScale; | ||
| + | horizontal *= m_runScale; | ||
| + | |||
| + | m_currentV = Mathf.Lerp(m_currentV, vertical, Time.deltaTime * m_interpolation); | ||
| + | m_currentH = Mathf.Lerp(m_currentH, horizontal, Time.deltaTime * m_interpolation); | ||
| + | |||
| + | Vector3 direction = camera.forward * m_currentV + camera.right * m_currentH; | ||
| + | |||
| + | float directionLength = direction.magnitude; | ||
| + | direction.y = 0; | ||
| + | direction = direction.normalized * directionLength; | ||
| + | |||
| + | if (direction != Vector3.zero) | ||
| + | { | ||
| + | m_currentDirection = Vector3.Slerp(m_currentDirection, direction, Time.deltaTime * m_interpolation); | ||
| + | |||
| + | transform.rotation = Quaternion.LookRotation(m_currentDirection); | ||
| + | transform.position += m_currentDirection * m_moveSpeed * Time.deltaTime; | ||
| + | |||
| + | if (m_animator != null) | ||
| + | { | ||
| + | m_animator.SetFloat("MoveSpeed", direction.magnitude); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | </pre> | ||
| + | |||
| + | ==進むキャラクタの回転方向を固定== | ||
| + | 右にしか行かないようにとか。 | ||
| + | <pre> | ||
| + | // transform.rotation = Quaternion.LookRotation(m_currentDirection); | ||
| + | transform.rotation = Quaternion.Euler(0, 90f, 0f); | ||
| + | |||
| + | // カメラの方向を固定。 | ||
| + | // Vector3 direction = camera.forward * m_currentV + camera.right * m_currentH; | ||
| + | Vector3 direction = new Vector3(0.1f, -0.1f, 1f) * m_currentV + new Vector3(1f, 0f, -0.1f) * m_currentH; | ||
| + | </pre> | ||
2022年12月7日 (水) 23:41時点における版
キャラクタ移動
適当にUnityAssetsからキャラクタをDLする(例:Supercyan Character Pack Free Sample https://assetstore.unity.com/packages/3d/characters/humanoids/character-pack-free-sample-79870?locale=ja-JP)
サンプル
キーボードの上下左右で操作できるサンプル。
CharacterControl.cs
using System.Collections.Generic;
using UnityEngine;
public class CharacterControl : MonoBehaviour
{
[SerializeField] private float m_moveSpeed = 2;
[SerializeField] private float m_turnSpeed = 200;
[SerializeField] private float m_jumpForce = 4;
[SerializeField] private Animator m_animator = null;
[SerializeField] private Rigidbody m_rigidBody = null;
private float m_currentV = 0;
private float m_currentH = 0;
private readonly float m_interpolation = 10;
private readonly float m_runScale = 2f;
private Vector3 m_currentDirection = Vector3.zero;
private bool m_jumpInput = false;
private bool m_isGrounded;
private bool m_wasGrounded;
private List<Collider> m_collisions = new List<Collider>();
private void Awake()
{
if (!m_animator) { gameObject.GetComponent<Animator>(); }
if (!m_rigidBody) { gameObject.GetComponent<Animator>(); }
}
private void OnCollisionEnter(Collision collision)
{
ContactPoint[] contactPoints = collision.contacts;
for (int i = 0; i < contactPoints.Length; i++)
{
if (Vector3.Dot(contactPoints[i].normal, Vector3.up) > 0.5f)
{
if (!m_collisions.Contains(collision.collider))
{
m_collisions.Add(collision.collider);
}
m_isGrounded = true;
}
}
}
private void OnCollisionStay(Collision collision)
{
ContactPoint[] contactPoints = collision.contacts;
bool validSurfaceNormal = false;
for (int i = 0; i < contactPoints.Length; i++)
{
if (Vector3.Dot(contactPoints[i].normal, Vector3.up) > 0.5f)
{
validSurfaceNormal = true; break;
}
}
if (validSurfaceNormal)
{
m_isGrounded = true;
if (!m_collisions.Contains(collision.collider))
{
m_collisions.Add(collision.collider);
}
}
else
{
if (m_collisions.Contains(collision.collider))
{
m_collisions.Remove(collision.collider);
}
if (m_collisions.Count == 0) { m_isGrounded = false; }
}
}
private void OnCollisionExit(Collision collision)
{
if (m_collisions.Contains(collision.collider))
{
m_collisions.Remove(collision.collider);
}
if (m_collisions.Count == 0) { m_isGrounded = false; }
}
private void Update()
{
if (!m_jumpInput && Input.GetKey(KeyCode.Space))
{
m_jumpInput = true;
}
}
private void FixedUpdate()
{
if (m_animator != null)
{
m_animator.SetBool("Grounded", m_isGrounded);
}
DirectUpdate();
m_wasGrounded = m_isGrounded;
m_jumpInput = false;
}
private void DirectUpdate()
{
float vertical = Input.GetAxis("Vertical");
float horizontal = Input.GetAxis("Horizontal");
Transform camera = Camera.main.transform;
vertical *= m_runScale;
horizontal *= m_runScale;
m_currentV = Mathf.Lerp(m_currentV, vertical, Time.deltaTime * m_interpolation);
m_currentH = Mathf.Lerp(m_currentH, horizontal, Time.deltaTime * m_interpolation);
Vector3 direction = camera.forward * m_currentV + camera.right * m_currentH;
float directionLength = direction.magnitude;
direction.y = 0;
direction = direction.normalized * directionLength;
if (direction != Vector3.zero)
{
m_currentDirection = Vector3.Slerp(m_currentDirection, direction, Time.deltaTime * m_interpolation);
transform.rotation = Quaternion.LookRotation(m_currentDirection);
transform.position += m_currentDirection * m_moveSpeed * Time.deltaTime;
if (m_animator != null)
{
m_animator.SetFloat("MoveSpeed", direction.magnitude);
}
}
}
}
進むキャラクタの回転方向を固定
右にしか行かないようにとか。
// transform.rotation = Quaternion.LookRotation(m_currentDirection); transform.rotation = Quaternion.Euler(0, 90f, 0f); // カメラの方向を固定。 // Vector3 direction = camera.forward * m_currentV + camera.right * m_currentH; Vector3 direction = new Vector3(0.1f, -0.1f, 1f) * m_currentV + new Vector3(1f, 0f, -0.1f) * m_currentH;
