EerieVillage/Assets/Scripts/Gameplay/PlayerAttackTicker.cs

80 lines
3.0 KiB
C#
Raw Normal View History

using Platformer.Mechanics;
using UnityEngine;
using static Platformer.Core.Simulation;
namespace Platformer.Gameplay
{
/// <summary>
/// Periodic PlayerAttack event emitter — BT7-Plan PD 지시 2026-04-24 VS 순수형 자동 발동.
/// Player GameObject에 부착되어 <see cref="attackInterval"/> 초마다 <see cref="PlayerAttack"/> 이벤트를 Schedule.
/// <para>
/// 기획 balance/01 v0.2 확정 전 임시 기본값: 0.5초 간격 · Phase 3-B 튠 대상.
/// 카드·특성 효과로 주기 수정이 필요해지면 외부에서 <see cref="attackInterval"/>을 직접 조작하거나
/// <see cref="ApplyIntervalMultiplier"/>를 통해 합산한다 (P13-1 공용 모듈 인터페이스 전략).
/// </para>
/// <para>
/// <b>설계 근거</b>: PlayerAttack.Execute는 이벤트 처리 로직, 본 컴포넌트는 발화 트리거.
/// 단일 책임 원칙 + 범용성 (C11) — 타이머 컴포넌트만 교체하면 발화 방식 전환 가능.
/// </para>
/// </summary>
[RequireComponent(typeof(PlayerController))]
public class PlayerAttackTicker : MonoBehaviour
{
/// <summary>
/// 공격 자동 발동 주기(초). balance/01 v0.2 확정 후 튠 대상.
/// </summary>
[Tooltip("공격 자동 발동 주기(초). 카드·특성으로 증감 가능.")]
public float attackInterval = 0.5f;
/// <summary>
/// 게임 시작 직후 첫 발화까지 지연(초). 플레이어 소환 애니메이션 여유.
/// </summary>
[Tooltip("게임 시작 직후 첫 발화까지의 지연(초). Spawn 애니메이션 여유.")]
public float startupDelay = 0.3f;
PlayerController player;
float attackTimer;
void Awake()
{
player = GetComponent<PlayerController>();
attackTimer = Mathf.Max(startupDelay, 0f);
}
void Update()
{
// 컨트롤 비활성 상태(마을 이동·메뉴 등)에서는 자동 공격 중단
if (player == null || !player.controlEnabled)
{
return;
}
// 유효 간격이 0 이하이면 tick 중단 (디자이너 실수 방지)
if (attackInterval <= 0f)
{
return;
}
attackTimer -= Time.deltaTime;
if (attackTimer <= 0f)
{
attackTimer += attackInterval;
var ev = Schedule<PlayerAttack>();
ev.player = player;
ev.direction = player.Facing;
}
}
/// <summary>
/// 카드·특성 효과가 공격 주기를 배수로 조정할 때 사용하는 편의 API.
/// </summary>
/// <param name="multiplier">1.0 미만이면 주기 단축(발동 가속), 1.0 초과면 둔화.</param>
public void ApplyIntervalMultiplier(float multiplier)
{
if (multiplier <= 0f) return;
attackInterval = Mathf.Max(0.05f, attackInterval * multiplier);
}
}
}