๋น ์ค๋ธ์ ํธ ์์ฑ ๐ ํ์์ Capsule ์ฝ์ ๐ ํ์์ ๋ ๋ถ์ฌ์ฃผ๊ธฐ
- ๋น ์ค๋ธ์ ํธ(์ดํ ๋ถ๋ชจ ์ค๋ธ์ ํธ)์ Capsule Collider ์ปดํฌ๋ํธ ์ฝ์
- Capsule์ ์๋ Capsule Collider๋ ๋นํ์ฑํ/์ญ์
- ๋ถ๋ชจ ์ค๋ธ์ ํธ์ collider์ ์ค์ฌ์ (0,1,0)์ผ๋ก ๋ณ๊ฒฝํด์ค๋ค. ๐ ์บ๋ฆญํฐ์ ๋ฐ๋์ด ํญ์ ์์ ์ ํฅํ๋๋ก
- capusle์ transform-position๋ ์์ ํด์ค๋ค.
- ๋ถ๋ชจ ์ค๋ธ์ ํธ์ rigidbody ์ปดํฌ๋ํธ ์ถ๊ฐ
โจ Rigidbody
- mass : ์ง๋ ๊ณ์ฐ. ์ค๋ ฅ์๋ ์ํฅ์ ๋ฐ์ง ์์. ๊ฐ์ rigidbody ์ค๋ธ์ ํธ๋ผ๋ฆฌ ์ถฉ๋ํ์์ ๋ ๋ฐ์
- drag : ๊ณต๊ธฐ์ ํญ๊ฐ. ๊ฐ์ด ์์์๋ก ์ค๋ธ์ ํธ๊ฐ ๋ฌด๊ฑฐ์ ๋ณด์ด๊ณ , ๊ฐ์ด ํฌ๋ฉด ๊ฐ๋ฒผ์ ๋ณด์ธ๋ค. ํด์๋ก ์ค๋ ฅ์ด ๊ฐํด์ง์ง ์๋ ๊ฒ์ฒ๋ผ ๋ณด์ธ๋ค.
- angualr drag : ํ์ ํ ๋์ ๊ณต๊ธฐ์ ํญ๊ฐ.
- use gravity : ์ค๋ ฅ ์ํฅ ์ฌ๋ถ
- is kienematic : ๋ฌผ๋ฆฌ์์ง์ด ์๋ ๊ฒ์ ์ค๋ธ์ ํธ ๋ก์ง์ ๋ฐ๋ผ์ ๊ฒ์ ์ค๋ธ์ ํธ๋ฅผ ์ด๋ํ ๊ฒ์ธ์ง
- interpolate : ๋ฌผ๋ฆฌ์์ง์ ์ ๋๋ฉ์ด์ ์ด ์์ฐ์ค๋ฝ๊ฒ ๋ณด๊ฐ์ ํ ์ง ์ฌ๋ถ
- collision detection : ์ถฉ๋ ์ฒ๋ฆฌ๋ฅผ ์ฐ์์ ์ผ๋ก ํ ๊ฒ์ธ์ง, ํน์ ํ ๊ฒฝ์ฐ์๋ง ํ ๊ฒ์ธ
- freeze position/rotation : ๋ฌผ๋ฆฌ์์ง์์ ์ฒ๋ฆฌ๋๋(๋ณ๊ฒฝ๋๋) ๊ฐ๋ค์ ๋ณ๊ฒฝ๋๋๋ก ํ ์ง, ๋ง์ง ์ฌ๋ถ
๋์ ๋ถ์ฌ์ค์ผ๋ก์จ, ์ฌ์ฉ์๊ฐ ์ ๋ ฅํ ๋ฐฉํฅ์ผ๋ก ์บ๋ฆญํฐ๊ฐ ๋ฐ๋ผ๋ณด๋ ๊ฒ ํ์ธ ๊ฐ๋ฅ
(๋์ ๊ทธ๋ฅ cube๋ฅผ ๋ถ์ฌ์ฃผ๋ฉด ๋๋ค. transform๋ง ์ด์ง ์์ ํจ)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace FastCampus.Characters {
[RequireComponent(typeof(Rigidbody)), RequireComponent(typeof(CapsuleCollider))]
public class RigidBodyCharacter : MonoBehaviour {
#region Variables
[SerializeField] private float speed = 5f;
[SerializeField] private float jumpHeight = 2f;
[SerializeField] private float dashDistance = 5f;
[SerializeField] private float groundCheckDistance = 0.2f;
[SerializeField] private LayerMask groundLayerMask;
private Rigidbody rigidbody;
private Vector3 inputDirection = Vector3.zero;
private bool isGrounded = true;
#endregion
#region Unity Methods
private void Start() {
rigidbody = GetComponent<Rigidbody>();
}
private void Update() {
// Check grounded
CheckGroundStatus();
// Process move inputs
inputDirection = Vector3.zero;
inputDirection.x = Input.GetAxis("Horizontal");
inputDirection.z = Input.GetAxis("Vertical");
if (inputDirection != Vector3.zero) {
transform.forward = inputDirection;
}
// Process jump input
if (Input.GetButtonDown("Jump") && isGrounded) {
Vector3 jumpVelocity = Vector3.up * Mathf.Sqrt(jumpHeight * -2f * Physics.gravity.y);
rigidbody.AddForce(jumpVelocity, ForceMode.VelocityChange);
}
// Process dash input
if (Input.GetButtonDown("Dash")) {
Vector3 dashVelocity = Vector3.Scale(transform.forward, dashDistance * new Vector3((Mathf.Log(1f / (Time.deltaTime * rigidbody.drag + 1)) / -Time.deltaTime), 0, (Mathf.Log(1f / (Time.deltaTime * rigidbody.drag + 1)) / -Time.deltaTime)));
rigidbody.AddForce(dashVelocity, ForceMode.VelocityChange);
}
}
// FixedUpdate : ๋ฌผ๋ฆฌ์์ง ๋ฐ๋ก ์์ชฝ์์ ์งํ๋๋ ํจ์. ๊ฒ์์ ํ๋ ์๊ณผ ์๊ด์์ด ๊ณ ์ ์ ์ผ๋ก ํธ์ถ๋๋ update ํจ์
private void FixedUpdate() {
rigidbody.MovePosition(rigidbody.position + inputDirection * speed * Time.fixedDeltaTime);
}
#endregion Unity Methods
private void CheckGroundStatus() {
RaycastHit hitInfo;
#if UNITY_EDITOR
// helper to visualise the ground check ray in the scene view
Debug.DrawLine(transform.position + (Vector3.up * 0.1f), transform.position + (Vector3.up * 0.1f) + (Vector3.down * groundCheckDistance));
#endif
// 0.1f is a small offset to start the ray from inside the character
// it is also good to note that the transform position in the sample assets is at the base of the character
if (Physics.Raycast(transform.position + (Vector3.up * 0.1f), Vector3.down, out hitInfo, groundCheckDistance, groundLayerMask)) {
isGrounded = true;
} else {
isGrounded = false;
}
}
}
}
GroundLayerMask๋ฅผ ground๋ก ๋ณ๊ฒฝํด์ค๋ค.