2026-05-18 애니메이션 설계 수정
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
[RequireComponent(typeof(Collider2D))]
|
||||
@@ -27,6 +28,15 @@ public class Enemy : MonoBehaviour, IDamageable
|
||||
private float _hitReactionTimer;
|
||||
private bool _isGrounded;
|
||||
private Vector2 _lastVelocity;
|
||||
private Collider2D[] _bodyColliders;
|
||||
private readonly List<RaycastHit2D> _castResults = new();
|
||||
private const float HitPositionSkinWidth = 0.02f;
|
||||
private bool _isHitPositionCorrecting;
|
||||
private bool _correctHitPositionY;
|
||||
private float _hitPositionCorrectionTimer;
|
||||
private float _hitPositionCorrectionDuration;
|
||||
private Vector2 _hitPositionCorrectionStart;
|
||||
private Vector2 _hitPositionCorrectionTarget;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
@@ -34,6 +44,7 @@ private void Awake()
|
||||
_rb = GetComponent<Rigidbody2D>();
|
||||
_anim = GetComponentInChildren<Animator>();
|
||||
_spriteRenderer = GetComponentInChildren<SpriteRenderer>();
|
||||
_bodyColliders = GetComponentsInChildren<Collider2D>();
|
||||
if (_spriteRenderer != null)
|
||||
_originalColor = _spriteRenderer.color;
|
||||
}
|
||||
@@ -54,10 +65,13 @@ private void Update()
|
||||
private void FixedUpdate()
|
||||
{
|
||||
if (_rb != null)
|
||||
{
|
||||
ApplySmoothHitPositionCorrection();
|
||||
_lastVelocity = _rb.linearVelocity;
|
||||
}
|
||||
}
|
||||
|
||||
public void TakeDamage(int amount, Vector2 hitVelocity = default, string hitReactionAnimationState = null)
|
||||
public void TakeDamage(int amount, Vector2 hitVelocity = default, string hitReactionAnimationState = null, Vector2? hitTargetPosition = null, bool correctHitTargetY = false, int hitPositionSolidMask = 0, float hitPositionCorrectionDuration = 0f)
|
||||
{
|
||||
if (_currentHealth <= 0) return;
|
||||
|
||||
@@ -80,6 +94,8 @@ public void TakeDamage(int amount, Vector2 hitVelocity = default, string hitReac
|
||||
_rb.linearVelocity = Vector2.zero;
|
||||
_lastVelocity = Vector2.zero;
|
||||
|
||||
BeginHitTargetPositionCorrection(hitTargetPosition, correctHitTargetY, hitPositionSolidMask, hitPositionCorrectionDuration);
|
||||
|
||||
Vector2 nextVelocity = GetHitReactionVelocity(hitVelocity);
|
||||
if (nextVelocity != Vector2.zero)
|
||||
{
|
||||
@@ -130,6 +146,98 @@ private Vector2 GetHitReactionVelocity(Vector2 hitVelocity)
|
||||
return nextVelocity;
|
||||
}
|
||||
|
||||
private void BeginHitTargetPositionCorrection(Vector2? hitTargetPosition, bool correctHitTargetY, int solidMask, float correctionDuration)
|
||||
{
|
||||
_isHitPositionCorrecting = false;
|
||||
if (!hitTargetPosition.HasValue || _rb == null) return;
|
||||
|
||||
Vector2 targetPosition = hitTargetPosition.Value;
|
||||
if (!correctHitTargetY)
|
||||
targetPosition.y = _rb.position.y;
|
||||
|
||||
targetPosition = GetSafeHitTargetPosition(targetPosition, solidMask);
|
||||
if ((targetPosition - _rb.position).sqrMagnitude <= 0.0001f) return;
|
||||
|
||||
if (correctionDuration <= 0f)
|
||||
{
|
||||
_rb.position = targetPosition;
|
||||
return;
|
||||
}
|
||||
|
||||
_isHitPositionCorrecting = true;
|
||||
_correctHitPositionY = correctHitTargetY;
|
||||
_hitPositionCorrectionTimer = 0f;
|
||||
_hitPositionCorrectionDuration = correctionDuration;
|
||||
_hitPositionCorrectionStart = _rb.position;
|
||||
_hitPositionCorrectionTarget = targetPosition;
|
||||
}
|
||||
|
||||
private void ApplySmoothHitPositionCorrection()
|
||||
{
|
||||
if (!_isHitPositionCorrecting || _rb == null) return;
|
||||
|
||||
_hitPositionCorrectionTimer += Time.fixedDeltaTime;
|
||||
float normalizedTime = Mathf.Clamp01(_hitPositionCorrectionTimer / Mathf.Max(_hitPositionCorrectionDuration, Time.fixedDeltaTime));
|
||||
float easedTime = Mathf.SmoothStep(0f, 1f, normalizedTime);
|
||||
Vector2 nextPosition = _rb.position;
|
||||
nextPosition.x = Mathf.Lerp(_hitPositionCorrectionStart.x, _hitPositionCorrectionTarget.x, easedTime);
|
||||
if (_correctHitPositionY)
|
||||
nextPosition.y = Mathf.Lerp(_hitPositionCorrectionStart.y, _hitPositionCorrectionTarget.y, easedTime);
|
||||
|
||||
_rb.MovePosition(nextPosition);
|
||||
|
||||
if (normalizedTime >= 1f)
|
||||
_isHitPositionCorrecting = false;
|
||||
}
|
||||
|
||||
private Vector2 GetSafeHitTargetPosition(Vector2 targetPosition, int solidMask)
|
||||
{
|
||||
if (solidMask == 0) return targetPosition;
|
||||
|
||||
Vector2 startPosition = _rb.position;
|
||||
Vector2 moveDelta = targetPosition - startPosition;
|
||||
float distance = moveDelta.magnitude;
|
||||
if (distance <= 0.001f) return targetPosition;
|
||||
|
||||
Vector2 direction = moveDelta / distance;
|
||||
float closestDistance = GetClosestBodyCastDistance(direction, distance + HitPositionSkinWidth, solidMask);
|
||||
if (closestDistance >= distance + HitPositionSkinWidth)
|
||||
return targetPosition;
|
||||
|
||||
float allowedDistance = Mathf.Max(closestDistance - HitPositionSkinWidth, 0f);
|
||||
return startPosition + direction * allowedDistance;
|
||||
}
|
||||
|
||||
private float GetClosestBodyCastDistance(Vector2 direction, float distance, int solidMask)
|
||||
{
|
||||
if (_bodyColliders == null || _bodyColliders.Length == 0)
|
||||
_bodyColliders = GetComponentsInChildren<Collider2D>();
|
||||
|
||||
ContactFilter2D filter = new ContactFilter2D
|
||||
{
|
||||
useLayerMask = true,
|
||||
layerMask = solidMask,
|
||||
useTriggers = false
|
||||
};
|
||||
|
||||
float closest = float.PositiveInfinity;
|
||||
for (int i = 0; i < _bodyColliders.Length; i++)
|
||||
{
|
||||
Collider2D bodyCollider = _bodyColliders[i];
|
||||
if (bodyCollider == null || bodyCollider.isTrigger) continue;
|
||||
|
||||
_castResults.Clear();
|
||||
int hitCount = bodyCollider.Cast(direction, filter, _castResults, distance);
|
||||
for (int j = 0; j < hitCount; j++)
|
||||
{
|
||||
if (_castResults[j].distance < closest)
|
||||
closest = _castResults[j].distance;
|
||||
}
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
private void UpdateGroundedState(Collision2D collision)
|
||||
{
|
||||
for (int i = 0; i < collision.contactCount; i++)
|
||||
|
||||
Reference in New Issue
Block a user