44.Weapon Class
45.PickupWidget
46.Variable Replication
아래 내용은 3편(44~46강)의 연속 강의를 한 편의 블로그 글처럼 정리한 것입니다.
무기(Weapon) 클래스를 만들고, 픽업(Pickup) 위젯을 통해 무기를 집을 수 있는 UI를 표시하며,
변수 복제(Replication)를 통해 서버-클라이언트 간 동기화를 어떻게 처리하는지에 대한 강의 내용입니다.
목차
- 무기(Weapon) 클래스 생성 및 기본 구성
- 픽업(Pickup) 위젯 만들기
- 변수 복제(Replication)로 무기 상태 동기화
- 마무리 및 팁
1. 무기(Weapon) 클래스 생성 및 기본 구성
1.1 무기 클래스 생성
- 새 C++ 클래스를 생성하고, 부모 클래스로 AActor를 선택합니다.
- 폴더 구조상 Weapon 전용 폴더를 만들어 관리하면 추후 여러 무기 파생 클래스 작성 시 편리합니다.
// Weapon.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Weapon.generated.h"
UENUM(BlueprintType)
enum class EWeaponState : uint8
{
EWS_Initial UMETA(DisplayName="Initial State"),
EWS_Equipped UMETA(DisplayName="Equipped"),
EWS_Dropped UMETA(DisplayName="Dropped"),
EWS_MAX UMETA(DisplayName="Default MAX")
};
UCLASS()
class AWeapon : public AActor
{
GENERATED_BODY()
public:
AWeapon();
protected:
virtual void BeginPlay() override;
private:
// 무기 메시에 사용할 스켈레탈 메시
UPROPERTY(VisibleAnywhere, Category = "Weapon Properties")
USkeletalMeshComponent* WeaponMesh;
// 플레이어가 일정 거리 내에 들어올 때 무기를 집을 수 있도록 감지하는 구체
UPROPERTY(VisibleAnywhere, Category = "Weapon Properties")
class USphereComponent* AreaSphere;
// 무기의 현재 상태
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Weapon Properties", meta = (AllowPrivateAccess = "true"))
EWeaponState WeaponState;
public:
// 무기 상태 제어 함수 등 추후 구현
};
구성 요소 설명
- USkeletalMeshComponent* WeaponMesh: 실제 무기의 형태(골격)를 표시.
- USphereComponent* AreaSphere: 플레이어와의 겹침(Overlap)을 감지하는 역할.
- EWeaponState: 무기가 현재 “바닥에 놓여있음(Initial)”, “장착됨(Equipped)”, “버려짐(Dropped)” 등의 상태를 표현.
1.2 Weapon.cpp 주요 초기 설정
AWeapon::AWeapon()
{
// 무기 메시 초기화
WeaponMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("WeaponMesh"));
SetRootComponent(WeaponMesh);
// 필요에 따라 충돌 여부 설정
WeaponMesh->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
WeaponMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
// 구체 컴포넌트 초기화
AreaSphere = CreateDefaultSubobject<USphereComponent>(TEXT("AreaSphere"));
AreaSphere->SetupAttachment(RootComponent);
// 구체는 기본적으로 모든 충돌을 무시하도록 설정한 뒤,
// 서버에서만 실제 겹침을 활성화할 수 있도록 구성(멀티플레이 고려)
AreaSphere->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
AreaSphere->SetCollisionEnabled(ECollisionEnabled::NoCollision);
WeaponState = EWeaponState::EWS_Initial;
}
- 멀티플레이 상황을 고려해, 충돌이나 겹침은 서버 권한(HasAuthority())이 있을 때만 활성화하도록 두는 편이 안전합니다.
- 무기 상태(WeaponState)는 초기화할 때 기본적으로 EWS_Initial로 설정.
1.3 무기 블루프린트(BP) 설정
- 언리얼 에디터에서 Weapon C++ 클래스를 기반으로 한 **블루프린트(BP)**를 만듭니다.
- 무기 메시(Skeletal Mesh)로 실제 총기(예: 돌격소총, 샷건 등)를 할당합니다.
- AreaSphere의 Sphere Radius를 적당히 조절하여, 플레이어가 가까워졌을 때 감지하도록 설정합니다.
이렇게 하면 레벨 위에 해당 BP 무기를 배치해둘 수 있고, 플레이어 캐릭터가 다가오면(겹침되면) 무기를 주울 수 있는 로직을 구현할 수 있게 됩니다.
2. 픽업(Pickup) 위젯 만들기
무기가 바닥에 떨어져 있을 때, 플레이어가 가까이 가면 “E 키를 눌러 주울 수 있음” 같은 안내 메시지를 표시하는 UI가 필요합니다. 이를 위해 Widget Blueprint를 사용합니다.
2.1 새 위젯 블루프린트 생성
- HUD 관련 폴더(혹은 원하는 폴더)에서 우클릭 → User Interface → Widget Blueprint를 생성하고 이름을 WBP_PickupWidget 등으로 설정합니다.
- 캔버스 위젯 대신 텍스트 블록 하나만 두고, "Press E to Pick Up"처럼 안내 문구를 작성합니다.
- 폰트 크기나 정렬 등을 취향껏 조절합니다.
2.2 Weapon 클래스에 UWidgetComponent 추가
// Weapon.h (일부)
private:
UPROPERTY(VisibleAnywhere, Category = "Weapon Properties")
class UWidgetComponent* PickupWidget;
// Weapon.cpp (생성자에서)
PickupWidget = CreateDefaultSubobject<UWidgetComponent>(TEXT("PickupWidget"));
PickupWidget->SetupAttachment(RootComponent);
PickupWidget->SetVisibility(false); // 처음엔 보이지 않게
- UWidgetComponent를 통해 3D 월드 공간에서도 UI를 띄울 수 있습니다.
- 위젯 클래스로 우리가 만든 WBP_PickupWidget을 할당해 주면, 무기 위에 "Press E to Pick Up" 라벨이 뜨게 됩니다(가시성 활성화 시).
2.3 구체 겹침(Overlap)으로 위젯 제어
- 플레이어가 AreaSphere에 들어오면 Widget 가시성을 true로, 벗어나면 false로 설정.
- 다만 이 겹침은 서버 권한에서만 감지하게(멀티플레이 기준) 설계하는 것이 일반적입니다.
- 서버에서만 “캐릭터가 무기에 겹쳤다”는 로직이 유효하게 동작 → 이후 필요한 변수(예: ‘현재 겹치는 무기’)를 서버-클라이언트 간에 복제.
3. 변수 복제(Replication)로 무기 상태 동기화
멀티플레이어 환경에서는 “서버에서만 중첩(Overlap) 이벤트 발생 → 해당 정보를 클라이언트와 동기화”가 핵심입니다.
언리얼에서 RepNotify(= Replicated Using) 기능과 관련 매크로들을 활용해 쉽게 설정할 수 있습니다.
3.1 캐릭터에 “현재 겹치는 무기” 변수 추가
플레이어 캐릭터 클래스(BlasterCharacter 등)에 다음과 같은 변수를 둡니다.
// BlasterCharacter.h
private:
UPROPERTY(ReplicatedUsing = OnRep_OverlappingWeapon)
class AWeapon* OverlappingWeapon;
UFUNCTION()
void OnRep_OverlappingWeapon(); // RepNotify 함수
- ReplicatedUsing을 통해 OverlappingWeapon이 서버에서 변경될 때, 클라이언트에서 복제된 후 자동으로 OnRep_OverlappingWeapon()이 호출됩니다.
- 즉, “어떤 무기가 겹치고 있는지”를 서버가 결정하고, 그 결과만 클라이언트에 알려주는 방식.
3.2 RepNotify 함수 구현
// BlasterCharacter.cpp
void ABlasterCharacter::OnRep_OverlappingWeapon()
{
if (OverlappingWeapon)
{
OverlappingWeapon->ShowPickupWidget(true);
}
else
{
// 이전 무기를 숨기고 싶다면, 과거 OverlappingWeapon 정보도 확인 가능
// 혹은 별도 로직으로 현재 UI 숨김 처리
}
}
- OverlappingWeapon이 Null이 아닌 경우 → 클라이언트 측에서 “무기를 집을 수 있음” 위젯을 표시.
- Null이 된 경우(겹침 해제) → 더 이상 표시하지 않음.
3.3 변수 등록(도입) & 조건부 복제
- 언리얼은 GetLifetimeReplicatedProps 함수를 오버라이드하여 어떤 변수를 복제할지 지정합니다.
- 조건부 복제(예: COND_OwnerOnly)를 사용하면, 해당 무기를 겹치는 플레이어(소유자) 만 변수 정보를 받도록 할 수 있습니다.
// BlasterCharacter.cpp
void ABlasterCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
// OverlappingWeapon 변수를 소유자(Owner)에게만 복제
DOREPLIFETIME_CONDITION(ABlasterCharacter, OverlappingWeapon, COND_OwnerOnly);
}
- 이렇게 하면 다른 클라이언트에게는 “내 캐릭터가 어떤 무기를 겹치는지” 정보를 굳이 보낼 필요가 없어, 네트워크 트래픽을 절감할 수 있습니다.
4. 마무리 및 팁
- Weapon 클래스
- Skeletal Mesh, Sphere Overlap, WidgetComponent를 기본으로 두고,
- EWeaponState 같은 열거형으로 무기 상태를 구분하면 확장성이 좋습니다.
- Pickup Widget
- UWidgetComponent로 월드 공간에 위젯 표시.
- 겹침 이벤트 발생 시 Widget 가시성 활성화.
- 변수 복제(Replication)
- “서버에서만 상태 결정” 후, 필요한 정보만 “클라이언트에게 복제”하는 원칙이 중요.
- RepNotify를 통해 클라이언트 측에서 수신 즉시 UI를 켜거나 끄는 식으로 처리.
- COND_OwnerOnly 등 조건부 복제를 활용해 불필요한 트래픽을 줄임.
추가 팁
- Physics & Collision:
무기를 “버리거나(Dropped)” 상태일 때 물리로 굴러다니도록 하려면, WeaponMesh->SetSimulatePhysics(true)와 적절한 충돌 채널 설정이 필요합니다. - 상태별 분기:
무기 상태 EWeaponState를 활용해, Equipped이면 플레이어 손에 붙이고, Dropped이면 땅에 떨어뜨리고, Initial이면 바닥에 고정해두는 식으로 분기 처리할 수 있습니다.
시각 자료 제안
- 클래스 다이어그램
- BlasterCharacter ↔ AWeapon (OverlappingWeapon 포인터 관계)
- AWeapon 내부 구성(스켈레탈 메시, 구체 컴포넌트, 위젯 컴포넌트)
- 변수 복제 흐름도
- 서버 권한에서 OverlappingWeapon 설정 → 클라이언트에 RepNotify 호출 → 위젯 표시
- 코드 스니펫 표 정리파일 주요 코드 설명
Weapon.h USkeletalMeshComponent* WeaponMesh; 등 무기 구성 요소 및 EWeaponState BlasterCharacter.h AWeapon* OverlappingWeapon; 현재 겹치는 무기에 대한 포인터(복제)
결론
이번 강의 시리즈(무기 클래스 구현 → 픽업 위젯 표시 → 변수 복제)는 언리얼 엔진에서의 멀티플레이 프로그래밍 기초를 잘 보여줍니다.
- 무기 클래스: Skeletal Mesh, 충돌 감지 구체, UI 위젯 컴포넌트를 구성
- 픽업 위젯: 겹침 시 플레이어에게 “E 키로 픽업” 메시지 제공
- Replication(변수 복제): 서버에서만 무기 겹침 로직을 처리하고, 결과를 소유한 클라이언트로 복제하여 UI를 표시
여기까지 따라오셨다면,
이후에는 무기 장착, 사격 로직, 물리 시뮬레이션 등을 추가해 더 다양한 게임플레이를 구현할 수 있습니다.
다음 단계로 넘어가기 전, 지금까지 구성한 시스템이 잘 동작하는지 충분히 테스트해 보시길 추천드립니다.
감사합니다!
더 궁금한 점이나, 다른 멀티플레이 관련 주제가 있다면 댓글로 알려주세요.
'UnraealEngine > Multiplayer Shooter' 카테고리의 다른 글
| 47. Equipping Weapons (0) | 2025.03.13 |
|---|---|
| 46.Variable Replication (0) | 2025.03.13 |
| 41.Seamless Travel and Lobby (0) | 2025.03.12 |
| 42.Network Role (0) | 2025.03.12 |
| 25. Join Sessions from the Menu (0) | 2025.03.12 |