일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- nanite
- 유니티
- unity
- Aegis
- Multiplay
- 게임개발
- 언리얼엔진
- attribute
- CTF
- ability task
- widget
- gameplay ability system
- listen server
- Unreal Engine
- 언리얼 엔진
- photon fusion2
- gameplay effect
- Replication
- MAC
- C++
- stride
- gas
- gameplay tag
- os
- rpc
- 게임 개발
- animation
- 보안
- UI
- local prediction
Archives
- Today
- Total
Replicated
[Drag Down] 맵 이동 포탈 본문
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "DDInteractable.generated.h"
// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UDDInteractable : public UInterface
{
GENERATED_BODY()
};
/**
*
*/
class DRAGDOWN_API IDDInteractable
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
virtual void Interact(AActor* InterActor) = 0;
virtual bool CanInteract(AActor* InterActor) = 0;
virtual void BeginInteract(AActor* InterActor) = 0;
virtual void EndInteract(AActor* InterActor) = 0;
virtual FText GetInteractionText(AActor* InterActor) = 0;
};
인터렉션 용도의 인터페이스
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "DDInteractionManagerComponent.generated.h"
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class DRAGDOWN_API UDDInteractionManagerComponent : public UActorComponent
{
GENERATED_BODY()
public:
UDDInteractionManagerComponent();
virtual void BeginPlay() override;
// Input
public:
void SetInteractionInputComponent();
protected:
void InteractionInputPressed();
UFUNCTION(Server, Reliable)
void ServerInteractionInputPressed();
void HandleInteractionInputPressed();
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, Meta = (AllowPrivateAccess = "true"))
TObjectPtr<class UInputAction> InteractAction;
protected:
UFUNCTION()
void OnComponentBeginOverlapCallback(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepHitResult);
UFUNCTION()
void OnComponentEndOverlapCallback(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
TObjectPtr<AActor> CurrentInteractionActor;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "ActorComponent/DDInteractionManagerComponent.h"
#include "Character/DDCharacterBase.h"
#include "Components/CapsuleComponent.h"
#include "EnhancedInputSubsystems.h"
#include "EnhancedInputComponent.h"
#include "Interface/DDInteractable.h"
#include "DragDown.h"
// Sets default values for this component's properties
UDDInteractionManagerComponent::UDDInteractionManagerComponent()
{
SetIsReplicatedByDefault(true);
}
void UDDInteractionManagerComponent::BeginPlay()
{
Super::BeginPlay();
ADDCharacterBase* Character = Cast<ADDCharacterBase>(GetOwner());
if ( Character && Character->GetTrigger() )
{
Character->GetTrigger()->OnComponentBeginOverlap.AddDynamic(this, &UDDInteractionManagerComponent::OnComponentBeginOverlapCallback);
Character->GetTrigger()->OnComponentEndOverlap.AddDynamic(this, &UDDInteractionManagerComponent::OnComponentEndOverlapCallback);
}
}
void UDDInteractionManagerComponent::SetInteractionInputComponent()
{
if ( IsValid( GetOwner()->InputComponent ) )
{
UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(GetOwner()->InputComponent);
EnhancedInputComponent->BindAction(InteractAction, ETriggerEvent::Started, this, &UDDInteractionManagerComponent::InteractionInputPressed);
}
}
void UDDInteractionManagerComponent::InteractionInputPressed()
{
if ( GetOwner()->HasAuthority() )
{
HandleInteractionInputPressed();
}
else
{
ServerInteractionInputPressed();
}
}
void UDDInteractionManagerComponent::HandleInteractionInputPressed()
{
if ( CurrentInteractionActor )
{
IDDInteractable* Interaction = Cast<IDDInteractable>(CurrentInteractionActor);
Interaction->Interact(GetOwner());
}
}
void UDDInteractionManagerComponent::ServerInteractionInputPressed_Implementation()
{
HandleInteractionInputPressed();
}
void UDDInteractionManagerComponent::OnComponentBeginOverlapCallback(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepHitResult)
{
IDDInteractable* Interaction = Cast<IDDInteractable>(OtherActor);
if ( Interaction )
{
Interaction->BeginInteract(GetOwner());
CurrentInteractionActor = OtherActor;
}
}
void UDDInteractionManagerComponent::OnComponentEndOverlapCallback(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
IDDInteractable* Interaction = Cast<IDDInteractable>(OtherActor);
if (Interaction)
{
Interaction->EndInteract(GetOwner());
CurrentInteractionActor = nullptr;
}
}
UDDInteractionManagerComponent를 만들어서 F를 누르면 인터렉션할 수 있게 만들었음
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Interface/DDInteractable.h"
#include "DDPortalActorBase.generated.h"
UCLASS()
class DRAGDOWN_API ADDPortalActorBase : public AActor, public IDDInteractable
{
GENERATED_BODY()
public:
ADDPortalActorBase();
protected:
virtual void BeginPlay() override;
UPROPERTY(EditAnywhere, BlueprintReadOnly)
TObjectPtr<class UStaticMeshComponent> StaticMeshComp;
UPROPERTY(EditAnywhere, BlueprintReadOnly)
TObjectPtr<class USphereComponent> Trigger;
UPROPERTY(EditAnywhere, BlueprintReadOnly)
TObjectPtr<class UWidgetComponent> InteractionPromptComponent;
UPROPERTY(EditAnywhere, BlueprintReadOnly)
TObjectPtr<class UDDPromptWidget> PromptWidget;
public:
virtual void Interact(AActor* InterActor) override;
virtual bool CanInteract(AActor* InterActor) override;
virtual void BeginInteract(AActor* InterActor) override;
virtual void EndInteract(AActor* InterActor) override;
virtual FText GetInteractionText(AActor* InterActor) override;
protected:
const FText DefaultDescription = FText::FromString( TEXT("Press < F >") );
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "Actor/DDPortalActorBase.h"
#include "Components/StaticMeshComponent.h"
#include "Components/SphereComponent.h"
#include "Components/WidgetComponent.h"
#include "UI/DDPromptWidget.h"
#include "Physics/DDCollision.h"
#include "DragDown.h"
ADDPortalActorBase::ADDPortalActorBase()
{
StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMeshComp"));
StaticMeshComp->SetIsReplicated(true);
StaticMeshComp->SetCollisionEnabled(ECollisionEnabled::NoCollision);
RootComponent = StaticMeshComp;
Trigger = CreateDefaultSubobject<USphereComponent>(TEXT("Trigger"));
Trigger->SetSphereRadius(80.0f, true);
Trigger->SetCollisionProfileName( CPROFILE_OVERLAPALL );
Trigger->SetupAttachment(StaticMeshComp);
InteractionPromptComponent = CreateDefaultSubobject<UWidgetComponent>(TEXT("InteractionPromptComponent"));
InteractionPromptComponent->SetupAttachment(StaticMeshComp);
InteractionPromptComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 130.0f));
InteractionPromptComponent->SetWidgetSpace(EWidgetSpace::Screen);
InteractionPromptComponent->SetDrawSize(FVector2D(500.0f, 30.0f));
InteractionPromptComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
InteractionPromptComponent->SetVisibility(false);
}
void ADDPortalActorBase::BeginPlay()
{
Super::BeginPlay();
UUserWidget* UserWidget = InteractionPromptComponent->GetWidget();
if ( UserWidget )
{
PromptWidget = Cast<UDDPromptWidget>(UserWidget);
}
}
void ADDPortalActorBase::Interact(AActor* InterActor)
{
if (!CanInteract(InterActor)) return;
}
bool ADDPortalActorBase::CanInteract(AActor* InterActor)
{
return true;
}
void ADDPortalActorBase::BeginInteract(AActor* InterActor)
{
APawn* Pawn = Cast<APawn>(InterActor);
if ( Pawn && !Pawn->IsLocallyControlled() )
{
return;
}
if ( InteractionPromptComponent && PromptWidget )
{
PromptWidget->SetDescription( GetInteractionText(InterActor) );
InteractionPromptComponent->SetVisibility(true);
}
else
{
UE_LOG(LogDD, Error, TEXT("BeginInteract is failed"));
}
}
void ADDPortalActorBase::EndInteract(AActor* InterActor)
{
APawn* Pawn = Cast<APawn>(InterActor);
if (Pawn && !Pawn->IsLocallyControlled())
{
return;
}
if ( InteractionPromptComponent )
{
InteractionPromptComponent->SetVisibility(false);
}
}
FText ADDPortalActorBase::GetInteractionText(AActor* InterActor)
{
return DefaultDescription;
}
포탈의 베이스가 되는 클래스
로컬에서만 Visibility 갱신을 시킬 수 있도록 했다,
InteractionManagerComponent가 트리거에서 겹치고 나가는 것을 관리하여 설명 위젯을 보이게 하거나 안보이게 한다
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "DDPromptWidget.generated.h"
/**
*
*/
UCLASS()
class DRAGDOWN_API UDDPromptWidget : public UUserWidget
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable)
void SetDescription( const FText& InDescription );
protected:
UPROPERTY(meta = (BindWidget))
TObjectPtr<class UTextBlock> Description;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "UI/DDPromptWidget.h"
#include "Components/TextBlock.h"
void UDDPromptWidget::SetDescription(const FText& InDescription)
{
if ( Description )
{
Description->SetText(InDescription);
}
}
인터렉션 설명을 해줄 위젯
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Actor/DDPortalActorBase.h"
#include "DDWaitingToGamePortalActor.generated.h"
/**
*
*/
UCLASS()
class DRAGDOWN_API ADDWaitingToGamePortalActor : public ADDPortalActorBase
{
GENERATED_BODY()
public:
virtual void BeginPlay() override;
virtual void Interact(AActor* InterActor) override;
virtual bool CanInteract(AActor* InterActor) override;
virtual void BeginInteract(AActor* InterActor) override;
virtual FText GetInteractionText(AActor* InterActor) override;
void UpdateDescription();
UFUNCTION()
void UpdateAndSetDescription();
protected:
FText CurrentDescription = FText::FromString(TEXT("Not Initialized"));
const FText StartDescription = FText::FromString(TEXT("Press F To Start"));
const FText NotHostDescription = FText::FromString(TEXT("Only Host Can Start"));
const FText NotReadyDescription = FText::FromString(TEXT("Not All Players Are Ready"));
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "Actor/DDWaitingToGamePortalActor.h"
#include "Game/DDWaitingGameState.h"
#include "UI/DDPromptWidget.h"
void ADDWaitingToGamePortalActor::BeginPlay()
{
Super::BeginPlay();
ADDWaitingGameState* GameState = Cast<ADDWaitingGameState>(GetWorld()->GetGameState());
if ( GameState )
{
GameState->OnGameInfoChanged.AddDynamic(this, &ADDWaitingToGamePortalActor::UpdateAndSetDescription);
}
}
void ADDWaitingToGamePortalActor::Interact(AActor* InterActor)
{
Super::Interact(InterActor);
if ( CanInteract(InterActor) )
{
GetWorld()->ServerTravel("L_Map_Game");
}
}
bool ADDWaitingToGamePortalActor::CanInteract(AActor* InterActor)
{
if ( !InterActor->HasAuthority() )
{
return false;
}
ADDWaitingGameState* GameState = Cast<ADDWaitingGameState>(GetWorld()->GetGameState());
if (GameState)
{
if (GameState->AreAllPlayerReady())
{
return true;
}
else
{
return false;
}
}
return false;
}
void ADDWaitingToGamePortalActor::BeginInteract(AActor* InterActor)
{
UpdateDescription();
Super::BeginInteract(InterActor);
}
FText ADDWaitingToGamePortalActor::GetInteractionText(AActor* InterActor)
{
return CurrentDescription;
}
void ADDWaitingToGamePortalActor::UpdateDescription()
{
if ( !HasAuthority() )
{
CurrentDescription = NotHostDescription;
return;
}
ADDWaitingGameState* GameState = Cast<ADDWaitingGameState>(GetWorld()->GetGameState());
if (GameState)
{
if (GameState->AreAllPlayerReady())
{
CurrentDescription = StartDescription;
}
else
{
CurrentDescription = NotReadyDescription;
}
}
}
void ADDWaitingToGamePortalActor::UpdateAndSetDescription()
{
UpdateDescription();
if ( PromptWidget )
{
PromptWidget->SetDescription(CurrentDescription);
}
}
대기방 -> 게임 이동시키는 포탈
플레이어가 호스트인지 아닌지, 모든 플레이어가 레디 상태인지 체크하여 다른 안내를 한다
'언리얼 엔진 > Drag Down' 카테고리의 다른 글
[Drag Down] Patrol 몬스터 추가 (0) | 2025.05.26 |
---|---|
** [Drag Down] 채팅 기능 구현 (Chatting) ** (0) | 2025.05.24 |
[Drag Down] PlayerState에서 이름과 Ready 관리, GameState 전체 상태 관리 (0) | 2025.05.21 |
[Drag Down] 게임 모드 및 컨트롤러 분리 (0) | 2025.05.19 |
[Drag Down] GameState에서 Player Idx 및 Ready 상태 관리하기 (PlayerState로 분리 예정) (0) | 2025.05.18 |