ํ๊ต์์ ์ผ์ฃผ์ผ๊ฐ ์งํํ๋ ๊ฒ์ ๊ต์ก ํน๊ฐ์ ๋ฃ๊ณ , ์ค ์ฐํด๋ ๊ฒน์ณ์ ์์ ์ค์ผ์ฅด์ด ๋ค์ ๋ฐ๋ ธ๋ค. ์ค ์ฐํด๊ฐ ๋๋ ํ์ ํ์๋ฅผ ์งํํ๊ณ , ํ๋ก์ ํธ ์ข ๋ฃ์ผ์ธ 2์ ๋ง๊น์ง ์ผ๋ง ๋จ์ง ์์ ํ์ ์ธ๋ถ์ ์ธ ๋ํ ์ผ์ ํฌ๊ธฐํ๊ธฐ๋ก ํ๋ค.
์บ๋ฆญํฐ๊ฐ ์จ๋ ๋ชจ์ , ์ ์ด ์ฐพ๋ ์๋์ ํ๋ ๋ชจ์ , ๋ฌธ ์ด๋ฆฌ๊ฑฐ๋ ์ํธ์์ฉํ๋ ๋ชจ์ ๋ฑ์ด ์์ผ๋ฉด ๊ฒ์ ์์ฑ๋๋ ์ฌ๋ผ๊ฐ์ง๋ง ์๊ฐ์ด ๋ถ์กฑํ๋ค. ๋์์ด๋ ๋๋ ํ ๋ถ๋ฐ์ ์๋ค๋ณด๋ UI์ ๋ฐฐ๊ฒฝ์์ ๋ ํ์ ์ผ ํ๋๋ฐ ๊ทธ๊ฑฐ๊น์ง ํ ์๊ฐ์ด ์์ผ์ค ๊ฒ ๊ฐ๋ค.
๊ทธ๋์, ์ฐ์ ๊ฒ์ ํ๋ ์ด์ ํ์์ ์ธ ์์๋ค๋ง ๋จผ์ ๋น ๋ฅด๊ฒ ๊ตฌํํ๊ธฐ๋ก ํ๋ค. ์ ๋ฒ ๊ธ์์ ์ฃผ์ธ๊ณต ์บ๋ฆญํฐ์ Idle, Walk ์ ๋๋ฉ์ด์ ์ ์์ ํ๋๋ฐ, ๋ค์ ์ ๋๋ฉ์ด์ ์ ๋ฌ๋ฆฌ๊ธฐ(Run)๋ค.
1. ๋ฌ๋ฆฌ๊ธฐ(Run) ์ ๋๋ฉ์ด์ ์ ์ํ๊ธฐ
๊ฑท๊ธฐ(Walk)๋ฅผ ํ ๋ฒ ๋ง๋ค์ด๋ดค๋ ํ์ธ์ง, ์ต์ํด์ ธ์ ๋ฌ๋ฆฌ๊ธฐ(Run) ๋ชจ์ ์ ๊ทธ๋ฆฌ ์ค๋ ๊ฑธ๋ฆฌ์ง ์์๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก ๋ฌ๋ฆฌ๊ธฐ ๋ชจ์ ์ ํ๋ ์๋ณ๋ก ๋ํ๋ธ ๊ทธ๋ฆผ์ ์ฐธ๊ณ ํ์ฌ ๋ง๋ค์ด๋ดค๋ค. 2D Bone Animation์ ํ๊ณ๋ก ์ผ์ ๋ชจ์์ ์ด์ฉ์๊ฐ ์์๋ค.
๋ฌ๋ฆฌ๊ธฐ ๋ชจ์ ์ด๋ค๋ณด๋, ์กฐ๊ธ ๋น ๋ฅด๊ฒ ์์ง์ฌ์ผ ํ๋ฏ๋ก 5 ํ๋ ์ ๋จ์๋ก ๊ตฌ์ฑํ๋ค. ๋ฌ๋ฆฌ๊ธฐ๋ฅผ ํ ๋ ์์ฒด๋ ์์ฐ์ค๋ฝ๊ฒ ์์ฌ์ง๋ฏ๋ก ์์๊ณ , ๋ค๋ฆฌ๊ฐ ๊ต์ฐจํ๋ฉฐ ๋ฐ๋ฅ์ ๋ฟ์ผ ๋๋ง๋ค ์์ฒด ๋ผ๋ฅผ ์์ง์ฌ ๋ฐ๋์ ์คฌ๋ค. ์ค๋ฅธ์์ ํด๋ํฐ์ ์ฅ๊ณ ์๊ธฐ ๋๋ฌธ์, ๋ฐ๋ฉด์ ์ค๋ ๋ชธ์ ๋ฐ๋์ผ๋ก ์ธํ ์ฝ๊ฐ์ ์์ง์๋ง ์คฌ๋ค. ๋ง๋๋๋ฐ 30๋ถ๋ ์ ๊ฑธ๋ ธ๋ ๊ฒ ๊ฐ๋ค.
์ ๋๋ฉ์ดํฐ ๊ตฌ์กฐ ๋ณ๊ฒฝ (Blend Tree ์ฌ์ฉ)
Idle, Walk, Run ์ ๋๋ฉ์ด์ ์ด ์๊ฒผ๋ค๋ณด๋, ๊ธฐ์กด ๋ฐฉ๋ฒ๋๋ก๋ ๋ณต์กํ๊ณ ๋ค๋ฃจ๊ธฐ ํ๋ค ๊ฒ ๊ฐ์๋ค. ๊ทธ๋์ ๋ธ๋ ๋ ํธ๋ฆฌ(Blend Tree)๋ฅผ ํ๋ ๋ง๋ค์ด์ "Move"๋ผ๊ณ ์ด๋ฆ์ ์ง์ด์คฌ๋ค.
๊ทธ๋ฆฌ๊ณ , Float ํ์ ์ ๋งค๊ฐ๋ณ์๋ฅผ ์์ฑํ๊ณ , "Move"๋ผ๊ณ ์ด๋ฆ์ ์ง์๋ค. ์ด Move ๋งค๊ฐ๋ณ์ ๊ฐ์ด 0์ผ ๋ "Idle", 0.5์ผ ๋ "Walk", 1์ผ ๋ "Run"์ผ๋ก ์ ๋๋ฉ์ด์ ์ ํ์ด ์ผ์ด๋๋๋ก ๊ตฌ์ฑํ๋ค.
Automate Thresholds ์ต์ ์ ์ฒดํฌ ํด์ ํ๊ณ , ๊ฐ Threshold ๊ฐ์ ๊ณํํ๋ ๊ฐ๋ค์ ๋ฃ์๋ค. ์ด์ ์คํฌ๋ฆฝํธ๋ฅผ ์์ ํ๋ ์ผ๋ง ๋จ์๋ค.
2. ์คํฌ๋ฆฝํธ(Script) ์์ ํ๊ธฐ
- ์ผ์ชฝ ์ฌํํธ(Left Shift)์ ๋ฐฉํฅํค ์ ๋ ฅ์ด ์๋ค๋ฉด, ๋ฌ๋ฆฌ๊ธฐ(Run)
- ์ผ์ชฝ ์ฌํํธ(Left Shift) ์ ๋ ฅ์ ์์ง๋ง ๋ฐฉํฅํค ์ ๋ ฅ์ด ์๋ค๋ฉด ๊ฑท๊ธฐ(Walk)
- ๋ ์ ๋ ฅ ๋ชจ๋ ์๋ค๋ฉด ๊ฐ๋งํ ์๊ธฐ(Idle)
ํ์ฌ ๋ฌ๋ฆฌ๋ ์ํ์ธ์ง๋ฅผ ์ฒดํฌํ๊ธฐ ์ํด boolean ๋ณ์๋ฅผ ํ๋ ์ถ๊ฐํ๋ค.
private bool isRunning;
Update() ํจ์์์ ์ผ์ชฝ ์ฌํํธ์ ๋ํ ์ ๋ ฅ์ ๋ฐ์๋ค.
void Update()
{
walkDirection = Input.GetAxisRaw("Horizontal");
isRunning = Input.GetButton("Run"); // ์ถ๊ฐ
}
๋ฌผ๋ก , Input Manager์์ Run ๋ฒํผ์ ๋ํ ํ๋๋ฅผ ์ถ๊ฐํด์คฌ๋ค. ๊ทธ ๋ถ๋ถ์ ๋ฐ์ "๋๋ณด๊ธฐ" ํด๋ฆญ
Unity Editor์ ์ผ์ชฝ ์๋จ Edit → Project Settings → Input Manager → Run ํ๋ ์ถ๊ฐ
๊ธฐ์กด์ ์์๋ Walk() ํจ์๋ฅผ ์ญ์ ํ๊ณ , Move() ํจ์๋ก ํตํฉํ๋ค. ๊ทธ๋ฆฌ๊ณ , ์ฝ๊ฐ์ ๋ฆฌํฉํ ๋ง ๊ณผ์ ์ ๊ฑฐ์ณค๋ค.
void FixedUpdate()
{
bool hasControl = !Mathf.Approximately(walkDirection, 0f);
TurnOtherSide(hasControl);
Move(hasControl);
}
private void Move(bool hasControl) // 0f : Idle, 0.5f : Walk, 1f : Run
{
if (hasControl && isRunning)
{
animator.SetFloat("Move", 1f);
_rigidBody.velocity = new Vector2(walkDirection * walkSpeed * 2f,
_rigidBody.velocity.y);
return;
}
float walkValue = (hasControl && !isRunning) ? 0.5f : 0f;
animator.SetFloat("Move", walkValue);
_rigidBody.velocity = new Vector2(walkDirection * walkSpeed, _rigidBody.velocity.y);
}
์ด๋ ๊ฒ ํจ์ผ๋ก์จ, ๋ฌ๋ฆฌ๊ธฐ ์ ๋๋ฉ์ด์ ์ ์ ๋ฐ ์ ์ฉ์ด ์๋ฃ๋์๋ค. ๋นจ๋ฆฌ ์ ํ๋ ์ํธ์์ฉ ํ๋ฌ ๊ฐ์ผ๊ฒ ๋ค...
โ๏ธ์ ์ฒด ์คํฌ๋ฆฝํธ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SujiMoveController : MonoBehaviour
{
public float walkSpeed;
public Transform sujiTransform;
private Animator animator;
private Rigidbody2D _rigidBody;
private float walkDirection;
private float initScaleX;
private bool isRunning;
void Start()
{
_rigidBody = GetComponent<Rigidbody2D>();
animator = GetComponentInChildren<Animator>();
initScaleX = sujiTransform.localScale.x;
}
void Update()
{
walkDirection = Input.GetAxisRaw("Horizontal");
isRunning = Input.GetButton("Run");
}
void FixedUpdate()
{
bool hasControl = !Mathf.Approximately(walkDirection, 0f);
TurnOtherSide(hasControl);
Move(hasControl);
}
private void Move(bool hasControl) // 0f : Idle, 0.5f : Walk, 1f : Run
{
if (hasControl && isRunning)
{
animator.SetFloat("Move", 1f);
_rigidBody.velocity = new Vector2(walkDirection * walkSpeed * 2f,
_rigidBody.velocity.y);
return;
}
float walkValue = (hasControl && !isRunning) ? 0.5f : 0f;
animator.SetFloat("Move", walkValue);
_rigidBody.velocity = new Vector2(walkDirection * walkSpeed, _rigidBody.velocity.y);
}
private void TurnOtherSide(bool hasControl)
{
if (!hasControl)
return;
var scaleX = sujiTransform.localScale.x;
if (Mathf.Approximately(walkDirection * scaleX, initScaleX))
return;
var scaleY = sujiTransform.localScale.y;
var scaleZ = sujiTransform.localScale.z;
sujiTransform.localScale = new Vector3(-scaleX, scaleY, scaleZ);
}
}