Unity / C#
Beginner
Unity 2022.3+ / Unity 6
2D 탑다운(Top-Down) 8방향 이동, 대시(Dash) 및 넉백 물리 제어
대각선 속도 왜곡을 방지하는 벡터 정규화, 무적 시간 동반 대시(Dash), 외부 피격 넉백(Knockback) 벡터를 부드럽게 감쇠·합산하는 탑다운 액션 모빌리티 구현.
#Unity #2D #TopDown #Movement #Dash #Knockback
핵심 개념탑다운 2D 게임에서 x와 y 입력을 단순히 더하면 대각선 이동 속도가 약 1.414배($\sqrt{2}$) 빨라집니다. 입력 벡터를 정규화(
normalized)하고, 플레이어의 의도된 이동과 적 공격에 의한 넉백(Knockback) 속도를 분리하여 지수 감쇠(Decay)시키는 구조를 갖춰야 자연스러운 피격 리액션이 완성됩니다.1. 탑다운 플레이어 컨트롤러 (대시 및 넉백 시스템)
using System.Collections;
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
public class TopDownCharacterController : MonoBehaviour
{
[Header("기본 이동")]
[SerializeField] private float walkSpeed = 6f;
[SerializeField] private float acceleration = 40f;
[Header("대시 설정")]
[SerializeField] private float dashSpeed = 18f;
[SerializeField] private float dashDuration = 0.18f;
[SerializeField] private float dashCooldown = 0.8f;
[Header("넉백 감쇠")]
[SerializeField] private float knockbackDecay = 12f;
private Rigidbody2D _rb;
private Vector2 _moveInput;
private Vector2 _currentMoveVelocity;
private Vector2 _knockbackVelocity;
private bool _isDashing;
private float _dashCooldownTimer;
public bool IsInvulnerable => _isDashing;
private void Awake()
{
_rb = GetComponent<Rigidbody2D>();
_rb.gravityScale = 0f; // 탑다운 중력 제거
}
private void Update()
{
if (_dashCooldownTimer > 0f)
_dashCooldownTimer -= Time.deltaTime;
if (_isDashing) return;
// 8방향 입력 수집 및 정규화
float h = Input.GetAxisRaw("Horizontal");
float v = Input.GetAxisRaw("Vertical");
_moveInput = new Vector2(h, v).normalized;
// 대시 입력
if (Input.GetKeyDown(KeyCode.Space) && _dashCooldownTimer <= 0f && _moveInput != Vector2.zero)
{
StartCoroutine(DashRoutine(_moveInput));
}
}
private void FixedUpdate()
{
// 넉백 지수 감쇠
_knockbackVelocity = Vector2.MoveTowards(_knockbackVelocity, Vector2.zero, knockbackDecay * Time.fixedDeltaTime);
if (_isDashing) return;
// 부드러운 가속 보간
Vector2 targetVelocity = _moveInput * walkSpeed;
_currentMoveVelocity = Vector2.MoveTowards(_currentMoveVelocity, targetVelocity, acceleration * Time.fixedDeltaTime);
// 이동 속도와 외부 넉백 합산 적용
_rb.linearVelocity = _currentMoveVelocity + _knockbackVelocity;
}
private IEnumerator DashRoutine(Vector2 direction)
{
_isDashing = true;
_dashCooldownTimer = dashCooldown;
// 대시 순간 기존 넉백 초기화 및 고속 돌진
_knockbackVelocity = Vector2.zero;
_rb.linearVelocity = direction * dashSpeed;
yield return new WaitForSeconds(dashDuration);
_currentMoveVelocity = direction * walkSpeed;
_isDashing = false;
}
/// <summary>
/// 적 타격 시 호출되는 외부 넉백 함수
/// </summary>
public void ApplyKnockback(Vector2 direction, float force)
{
if (_isDashing) return; // 대시 무적 중 넉백 무시
_knockbackVelocity = direction.normalized * force;
}
}
2. 피격 판정 및 넉백 전달 예제
using UnityEngine;
public class EnemyHitbox : MonoBehaviour
{
[SerializeField] private float damage = 10f;
[SerializeField] private float knockbackForce = 15f;
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.TryGetComponent<TopDownCharacterController>(out var player))
{
if (player.IsInvulnerable) return;
Vector2 pushDir = (collision.transform.position - transform.position).normalized;
player.ApplyKnockback(pushDir, knockbackForce);
}
}
}
3. 성능 및 설계 체크리스트
Vector2.normalized대각선 보정: 대각선 입력((1, 1))의 크기는 약 1.414이므로,.normalized처리를 하지 않으면 대각선 이동 시 적이나 총알을 따돌리기 쉬워지는 밸런스 붕괴가 일어납니다.- 충돌 콜라이더 회전 고정: 2D 캐릭터 이동 시 장애물 모서리와 비스듬히 충돌할 때 캐릭터가 회전하지 않도록
Rigidbody2D.constraints = RigidbodyConstraints2D.FreezeRotation을 반드시 활성화합니다.