<기존 구조>
Weapon
|_ Sword
|_ Wand
|_ Hammer
<개선 후 구조>
Weapon + DA
|_ MeleeWeapon - Trace
|_ RangedWeapon - Projectile
<aside>
💡 무기 종류가 증가해도 구조 변경 없이 확장 가능하도록 설계
💡 공격 방식 기준으로 시스템 구조 재정의
💡 로직과 데이터(Data Asset)의 책임 분리
💡 코드 수정 없이 새로운 무기 추가 가능하도록 구성
</aside>
초기 설계에서는 공통되는 로직은 Weapon에 두고, 무기 종류를 기준으로 자식 클래스로 분리했습니다. Sword, Wand, Hammer 각각 별도 클래스를 두는 방식이었습니다.
Sword 이후 추가 무기 구현을 진행하면서 문제를 발견했습니다. 공통 공격 로직을 제외한 실질적인 차이는 Trace 방식 정도밖에 불과했습니다. 심지어 피격 판정마저 Trace냐, Projectiles냐의 차이일 뿐임을 자각했습니다.
유지 보수 문제 동일한 Trace 로직이 각 클래스에 분산되어 수정 시 여러 클래스를 동시에 변경해야 하는 구조
유사 코드 반복
****무기 종류가 증가할수록 **클래스 수만 증가하고 동일한 로직 계속 반복**
분류 기준이 잘못됐다고 판단했습니다.
기존 “어떤 무기인지(What)” 가 아니라 “어떻게 공격할지(How)” 에 따라 나누는 방식이 적합하다고 판단했습니다.
공격 방식 기준으로 구조를 재설계했습니다.
Weapon - 공통 기능
MeleeWeapon - Trace 기반 공격
void AMeleeWeapon::OnOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
...
UKismetSystemLibrary::BoxTraceSingle(
this,
Start,
End,
FVector(5.f, 5.f, 5.f),
TraceStart->GetComponentRotation(),
ETraceTypeQuery::TraceTypeQuery1,
false,
ActorsToIgnore,
EDrawDebugTrace::None,
BoxHit,
true
);
}
RangedWeapon - Projectile 기반 공격 (추후 구현 예정)
여기에 더해 세부 데이터는 Data Asset으로 분리했습니다. 클래스는 공격 방식인 행동만 담당하고, 데미지나 범위, 이펙트 등 수치 데이터를 Data Asset에서 관리하도록 책임을 나눠 코드 수정 없이 새로운 무기를 추가할 수 있도록 설계했습니다.