일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- Unreal Engine
- unity
- dirty cow
- Aegis
- map design
- 언리얼 엔진
- gameplay effect
- 유니티
- rpc
- UI
- attribute
- os
- gameplay tag
- gameplay ability system
- gravity direction
- gas
- listen server
- animation
- MAC
- photon fusion2
- Replication
- Multiplay
- 언리얼엔진
- 게임 개발
- local prediction
- stride
- CTF
- 게임개발
- ability task
- nanite
Archives
- Today
- Total
Replicated
[ChronoSpace] TActorIterator를 이용한 LabyrinthKey 활성화 (Random Activation of Actor) (ClockworkLabyrinth) 본문
언리얼 엔진/ChronoSpace
[ChronoSpace] TActorIterator를 이용한 LabyrinthKey 활성화 (Random Activation of Actor) (ClockworkLabyrinth)
라구넹 2025. 2. 13. 05:16일단 유니티 SetActive같은게 언리얼 액터에 없다는게 놀랍다
void ACSLabyrinthKeyActivator::SetActorActive(AActor* Actor, bool bActive)
{
Actor->SetActorHiddenInGame(!bActive);
Actor->SetActorEnableCollision(bActive);
//SetActorTickEnabled(bActive);
}
Tick 쓸 거면 주석 해제하고 사용
저 대로 쓰면 액티베이트 조정 됨
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CSLabyrinthKeyActivator.generated.h"
UCLASS()
class CHRONOSPACE_API ACSLabyrinthKeyActivator : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ACSLabyrinthKeyActivator();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
void SetActorActive(AActor* Actor, bool bActive);
void SetLabyrinthKey();
UPROPERTY()
TArray< TObjectPtr<class ACSLabyrinthKey> > Keys;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "MaxKeyCount")
int32 MaxKeyCount;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "Actor/CSLabyrinthKeyActivator.h"
#include "EngineUtils.h"
#include "Actor/CSLabyrinthKey.h"
#include "ChronoSpace.h"
// Sets default values
ACSLabyrinthKeyActivator::ACSLabyrinthKeyActivator()
{
bReplicates = true;
RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
MaxKeyCount = 3;
}
// Called when the game starts or when spawned
void ACSLabyrinthKeyActivator::BeginPlay()
{
Super::BeginPlay();
if ( HasAuthority() )
{
SetLabyrinthKey();
}
}
void ACSLabyrinthKeyActivator::SetActorActive(AActor* Actor, bool bActive)
{
Actor->SetActorHiddenInGame(!bActive);
Actor->SetActorEnableCollision(bActive);
//SetActorTickEnabled(bActive);
}
void ACSLabyrinthKeyActivator::SetLabyrinthKey()
{
for (TActorIterator<ACSLabyrinthKey> It(GetWorld()); It; ++It)
{
ACSLabyrinthKey* LabyrinthKey = *It;
if ( LabyrinthKey )
{
SetActorActive(LabyrinthKey, false);
Keys.Emplace(LabyrinthKey);
}
}
int8 length = Keys.Num();
if ( length < MaxKeyCount )
{
return;
}
//UE_LOG(LogCS, Log, TEXT("SetLabyrinthKey : %d"), length);
int32 ActivatedKeysCount = 0;
while ( ActivatedKeysCount < MaxKeyCount )
{
int8 Idx = FMath::RandRange(0, length);
if ( !Keys.IsValidIndex(Idx) || Keys[Idx]->GetActorEnableCollision() )
{
continue;
}
SetActorActive(Keys[Idx], true);
++ActivatedKeysCount;
}
}
활성화 시킬 총량 조절 시 MaxCount 조절하면 된다
단 애초에 개수가 부족하면 return
월드에 배치하고
랜덤으로 오브젝트가 활성화 되는 걸 알 수 있다
이렇게 완성된 줄 알았는데 멀티에선 안된다
아까 만든 Unactive 함수로 동기화한게 동기화가 안된 것 같다
어차피 Activator에 SetActive 만든 것도 마음에 안든다 코드 고치자
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CSLabyrinthKey.generated.h"
UCLASS()
class CHRONOSPACE_API ACSLabyrinthKey : public AActor
{
GENERATED_BODY()
public:
ACSLabyrinthKey();
UPROPERTY(ReplicatedUsing = OnRep_bIsActive)
bool bIsActive;
UFUNCTION()
void OnTriggerBeginOverlapCallback(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepHitResult);
UFUNCTION()
void OnTriggerEndOverlapCallback(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
UFUNCTION()
void Interact();
void SetActive(bool bActive);
protected:
UPROPERTY(VisibleAnywhere, Category = "Trigger", Meta = (AllowPrivateAccess = "true"))
TObjectPtr<class USphereComponent> SphereTrigger;
UPROPERTY(VisibleAnywhere, Category = "Mesh", Meta = (AllowPrivateAccess = "true"))
TObjectPtr<class UStaticMeshComponent> StaticMeshComp;
UPROPERTY(VisibleAnywhere)
TObjectPtr<class UWidgetComponent> InteractionPromptComponent;
UFUNCTION()
void OnRep_bIsActive();
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
float TriggerRange = 100.0f;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "Actor/CSLabyrinthKey.h"
#include "Character/CSCharacterPlayer.h"
#include "Components/StaticMeshComponent.h"
#include "Components/SphereComponent.h"
#include "Physics/CSCollision.h"
#include "Subsystem/CSLabyrinthKeyWorldSubsystem.h"
#include "Blueprint/UserWidget.h"
#include "Components/WidgetComponent.h"
#include "Net/UnrealNetwork.h"
#include "ChronoSpace.h"
// Sets default values
ACSLabyrinthKey::ACSLabyrinthKey()
{
bReplicates = true;
// SphereTrigger
SphereTrigger = CreateDefaultSubobject<USphereComponent>(TEXT("GravitySphereTrigger"));
SphereTrigger->SetSphereRadius(TriggerRange, true);
SphereTrigger->SetRelativeLocation(FVector(0.0f, 0.0f, 0.0f));
RootComponent = SphereTrigger;
SphereTrigger->SetCollisionProfileName(CPROFILE_CSTRIGGER);
SphereTrigger->SetIsReplicated(true);
// Static Mesh
StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
StaticMeshComp->SetRelativeLocation(FVector(0.0f, 0.0f, 0.0f));
StaticMeshComp->SetupAttachment(SphereTrigger);
StaticMeshComp->SetCollisionProfileName(CPROFILE_CSCAPSULE);
StaticMeshComp->SetIsReplicated(true);
static ConstructorHelpers::FObjectFinder<UStaticMesh> StaticMeshRef(TEXT("/Script/Engine.StaticMesh'/Game/Mesh/StaticMesh/BlockSphere.BlockSphere'"));
if (StaticMeshRef.Object)
{
StaticMeshComp->SetStaticMesh(StaticMeshRef.Object);
}
float MeshRadius = 50.0f;
float MeshScale = (TriggerRange / MeshRadius) * 0.75f;
StaticMeshComp->SetRelativeScale3D(FVector(MeshScale, MeshScale, MeshScale));
SphereTrigger->OnComponentBeginOverlap.AddDynamic(this, &ACSLabyrinthKey::OnTriggerBeginOverlapCallback);
SphereTrigger->OnComponentEndOverlap.AddDynamic(this, &ACSLabyrinthKey::OnTriggerEndOverlapCallback);
// Widget
InteractionPromptComponent = CreateDefaultSubobject<UWidgetComponent>(TEXT("InteractionPromptComponent"));
InteractionPromptComponent->SetupAttachment(SphereTrigger);
InteractionPromptComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 100.0f));
static ConstructorHelpers::FClassFinder<UUserWidget> InteractionPromptWidgetRef(TEXT("/Game/Blueprint/UI/BP_InteractionPrompt.BP_InteractionPrompt_C"));
if (InteractionPromptWidgetRef.Class)
{
InteractionPromptComponent->SetWidgetClass(InteractionPromptWidgetRef.Class);
InteractionPromptComponent->SetWidgetSpace(EWidgetSpace::Screen);
InteractionPromptComponent->SetDrawSize(FVector2D(500.0f, 30.f));
InteractionPromptComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}
InteractionPromptComponent->SetVisibility(false);
SetActive(false);
}
void ACSLabyrinthKey::OnTriggerBeginOverlapCallback(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepHitResult)
{
ACSCharacterPlayer* Player = Cast<ACSCharacterPlayer>(OtherActor);
if ( Player )
{
Player->OnInteract.Clear();
InteractionPromptComponent->SetVisibility(true);
Player->OnInteract.AddDynamic(this, &ACSLabyrinthKey::Interact);
}
}
void ACSLabyrinthKey::OnTriggerEndOverlapCallback(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
ACSCharacterPlayer* Player = Cast<ACSCharacterPlayer>(OtherActor);
if (Player)
{
InteractionPromptComponent->SetVisibility(false);
Player->OnInteract.Clear();
}
}
void ACSLabyrinthKey::Interact()
{
UCSLabyrinthKeyWorldSubsystem* LabyrinthKeySubsystem = GetWorld()->GetSubsystem<UCSLabyrinthKeyWorldSubsystem>();
if (LabyrinthKeySubsystem)
{
LabyrinthKeySubsystem->SetLabyrinthKeyCount((LabyrinthKeySubsystem->GetLabyrinthKeyCount()) + 1);
UE_LOG(LogCS, Log, TEXT("ACSLabyrinthKey - Interact : %d"), LabyrinthKeySubsystem->GetLabyrinthKeyCount());
}
Destroy();
}
void ACSLabyrinthKey::OnRep_bIsActive()
{
if ( GetWorld() )
{
UE_LOG(LogCS, Log, TEXT("[NetMode : %d] OnRep_bIsActive, %d"), GetWorld()->GetNetMode(), bIsActive);
}
SetActorHiddenInGame(!bIsActive);
SetActorEnableCollision(bIsActive);
//SetActorTickEnabled(bIsActive);
}
void ACSLabyrinthKey::SetActive(bool bActive)
{
if ( HasAuthority() )
{
bIsActive = bActive;
OnRep_bIsActive();
}
}
void ACSLabyrinthKey::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
DOREPLIFETIME(ACSLabyrinthKey, bIsActive);
}
SetActive 설정을 Key에서 해준다
Replicated 되어 있으면 처음 입장할 때부터 Replication 되니까 Key 각각에서 bIsActive 관리를 해주는게 맞다
void ACSLabyrinthKeyActivator::SetLabyrinthKey()
{
for (TActorIterator<ACSLabyrinthKey> It(GetWorld()); It; ++It)
{
ACSLabyrinthKey* LabyrinthKey = *It;
if ( LabyrinthKey )
{
Keys.Emplace(LabyrinthKey);
}
}
int8 length = Keys.Num();
if ( length < MaxKeyCount )
{
return;
}
//UE_LOG(LogCS, Log, TEXT("SetLabyrinthKey : %d"), length);
int32 ActivatedKeysCount = 0;
while ( ActivatedKeysCount < MaxKeyCount )
{
int8 Idx = FMath::RandRange(0, length);
if ( !Keys.IsValidIndex(Idx) || Keys[Idx]->GetActorEnableCollision() )
{
continue;
}
Keys[Idx]->SetActive(true);
++ActivatedKeysCount;
}
}
액티베이터는 Key의 함수를 발동시키도록 바뀌었다
동기화 됐다
'언리얼 엔진 > ChronoSpace' 카테고리의 다른 글
[ChronoSpace] Key 흩뿌리기 (Clorkwork Labyrinth) (0) | 2025.02.15 |
---|---|
[ChronoSpace] Change Level in Multiplay (0) | 2025.02.15 |
[ChronoSpace] 키 아이템과 상호작용 with Subsystem Singleton (ClockworkLabyrinth) (0) | 2025.02.13 |
[ChronoSpace] Map Design - Clockwork Labyrinth 뼈대 (0) | 2025.02.10 |
[ChronoSpace] Preivew Box 로컬 클라이언트만 보이게 하기 (0) | 2025.02.06 |