Files
Northbound/Assets/Scripts/AttackAction.cs
dal4segno dc2292cd58 플레이어의 공격 기능 추가
EnemyUnit에 Collider 강제
2026-01-27 16:06:42 +09:00

126 lines
4.0 KiB
C#

using Unity.Netcode;
using UnityEngine;
namespace Northbound
{
/// <summary>
/// 액션 - 공격 (팀 시스템 적용)
/// </summary>
public class AttackAction : NetworkBehaviour, IAction
{
[Header("Attack Settings")]
public float attackRange = 2f;
public int attackDamage = 10;
public float attackCooldown = 0.5f;
public LayerMask attackableLayer = ~0;
[Header("Animation")]
public string attackAnimationTrigger = "Attack";
[Header("Visual")]
public GameObject attackEffectPrefab;
public Transform attackPoint;
private float _lastAttackTime;
private Animator _animator;
private ITeamMember _teamMember;
private void Awake()
{
_animator = GetComponent<Animator>();
_teamMember = GetComponent<ITeamMember>();
}
public bool CanExecute(ulong playerId)
{
return Time.time - _lastAttackTime >= attackCooldown;
}
public void Execute(ulong playerId)
{
if (!CanExecute(playerId))
return;
_lastAttackTime = Time.time;
// 애니메이션 재생
PlayAttackAnimation();
// 범위 내 적 검색
Vector3 attackOrigin = attackPoint != null ? attackPoint.position : transform.position;
Collider[] hits = Physics.OverlapSphere(attackOrigin, attackRange, attackableLayer);
foreach (Collider hit in hits)
{
// 자기 자신은 제외
if (hit.transform.root == transform.root)
continue;
// 대상 확인
var targetDamageable = hit.GetComponent<IDamageable>();
var targetTeamMember = hit.GetComponent<ITeamMember>();
if (targetDamageable != null)
{
// 팀 확인 - 적대 관계인 경우에만 공격
if (_teamMember != null && targetTeamMember != null)
{
if (!TeamManager.CanAttack(_teamMember, targetTeamMember))
{
continue;
}
}
var netObj = hit.GetComponent<NetworkObject>();
if (netObj != null)
{
AttackServerRpc(NetworkObjectId, netObj.NetworkObjectId);
}
}
}
}
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
private void AttackServerRpc(ulong attackerNetworkId, ulong targetNetworkId)
{
if (NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(targetNetworkId, out NetworkObject targetObj))
{
var damageable = targetObj.GetComponent<IDamageable>();
damageable?.TakeDamage(attackDamage, attackerNetworkId);
}
}
private void PlayAttackAnimation()
{
// 애니메이션 트리거
if (_animator != null && !string.IsNullOrEmpty(attackAnimationTrigger))
{
_animator.SetTrigger(attackAnimationTrigger);
}
// 이펙트 생성
if (attackEffectPrefab != null && attackPoint != null)
{
GameObject effect = Instantiate(attackEffectPrefab, attackPoint.position, attackPoint.rotation);
Destroy(effect, 1f);
}
}
public string GetActionName()
{
return "Attack";
}
public string GetActionAnimation()
{
return attackAnimationTrigger;
}
private void OnDrawGizmosSelected()
{
Vector3 attackOrigin = attackPoint != null ? attackPoint.position : transform.position;
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(attackOrigin, attackRange);
}
}
}