Post

UE - LyraExperienceDefinition

UnrealEngine

UE - LyraExperienceDefinition

게임 피처의 확장 버전인 LyraExperienceDefinition에 대해 공부해봤다.

B_ShooterGame_Elimination

LyraExperienceDefinition 데이터 에셋으로 만든 클래스다. 에디터 맵의 첫 번째 포탈로 이동하는 레벨에 대한 정보를 담고 있다.
여기서 액션에 대해 조사해봤다.

이 익스피리언스의 Action들은 총 3가지 Add Abilities, 컴포넌트 추가, Add Widgets가 있다.

Add Abilities는 캐릭터와 GAS와 연관이 있으니 패스했고, 위젯은 아직 배우지 않아서 넘어갔다.

컴포넌트 추가는 GameFeatures의 기본적인 Action이므로 이 부분에 대해 조사했다.

여기서 추가하는 컴포넌트들은 총 6가지로, 마지막 컴포넌트 빼고는 다 LyraGameState에 추가해주고 있다. (마지막은 컨트롤러에 추가헤준다.)

B_TeamDeathMatchScoring

B_TeamDeathMatchScoring은 B_Shooter_Game_Scoring_Base 블루프린트의 자식이다.

이름처럼 데스메치에서 점수를 측정할 규칙을 정의하는 컴포넌트다.

전체적인 블루 프린트

여긴 서버인지 클라이언트인지 분간 후 서버면 페이즈를 시작하는 파트다.

Switch Has Authority 가 서버인지 클라이언트인지 분간한다고 한다.

플레이어 수를 기반해 목표 점수를 설정하는 파트다.

6명 이상이면 30점, 그 이하는 15점으로 세팅하며 카운트 다운도 1200초, 720초로 설정된다.

설정이 끝나고 1초마다 타이머로 이벤트를 호출해준다.

둘 다 부모 클래스의 함수다.

Reset All Active Player: Lyra Character 클래스의 액터들 중 어빌리티 시스템과 컨트롤러가 아직 생성되지 않은 폰, 아직 자신의 게임 플레이 태그가 Status.SpawningIn 인 경우를 제외한 나머지 폰들에게 GameplayEvent.RequestReset 태그를 보내준다.

Reset Misc Actors: B Weapon Spawner들의 쿨다운 초기화, B Granade들의 Destroy Actor를 호출한다.

여긴 위에서 세팅한 타이머 이벤트 파트다.

0초가 되면 타이머 핸들을 지워버린다.

그 다음, 팀 스코어를 비교해 승패를 결정한다.

HandleVictory: 본인에게 큐 태그를 보내주는 것으로 보인다.

큐 태그는 이긴 팀 id만 보내준다.

그 후 페이즈를 다시 시작한다.

B_MusicManagerComponent

소리 부분은 아직 모르기에 패스했다.

B_ShooterBotSpawner

이건 데이터 전용 블루프린트. 부모는 C++클래스인 Lyra Bot Creation Component

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// Copyright Epic Games, Inc. All Rights Reserved.  
  
#pragma once  
  
#include "Components/GameStateComponent.h"  
  
#include "LyraBotCreationComponent.generated.h"  
  
class ULyraExperienceDefinition;  
class ULyraPawnData;  
class AAIController;  
  
UCLASS(Blueprintable, Abstract)  
class ULyraBotCreationComponent : public UGameStateComponent  
{  
    GENERATED_BODY()  
  
public:  
    ULyraBotCreationComponent(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());  
  
    //~UActorComponent interface  
    virtual void BeginPlay() override;  
    //~End of UActorComponent interface  
  
private:  
    void OnExperienceLoaded(const ULyraExperienceDefinition* Experience);  
  
protected:  
    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category=Gameplay)  
    int32 NumBotsToCreate = 5;  
  
    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category=Gameplay)  
    TSubclassOf<AAIController> BotControllerClass;  
  
    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category=Gameplay)  
    TArray<FString> RandomBotNames;  
  
    TArray<FString> RemainingBotNames;  
  
protected:  
    UPROPERTY(Transient)  
    TArray<TObjectPtr<AAIController>> SpawnedBotList;  
  
    /** Always creates a single bot */  
    UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category=Gameplay)  
    virtual void SpawnOneBot();  
  
    /** Deletes the last created bot if possible */  
    UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category=Gameplay)  
    virtual void RemoveOneBot();  
  
    /** Spawns bots up to NumBotsToCreate */  
    UFUNCTION(BlueprintNativeEvent, BlueprintAuthorityOnly, Category=Gameplay)  
    void ServerCreateBots();  
  
#if WITH_SERVER_CODE  
public:  
    void Cheat_AddBot() { SpawnOneBot(); }  
    void Cheat_RemoveBot() { RemoveOneBot(); }  
  
    FString CreateBotName(int32 PlayerIndex);  
#endif  
};

봇을 생성 및 삭제하는 부분으로 보인다.

이게 B_ShooterBotSpawner다.

봇의 생성 숫자, AI 컨트롤러, 봇의 이름 말고는 바뀐게 없다.

봇을 소환하는 맵들은 각자의 BotSpawner 데이터 에셋을 만들어놨다.

B_TeamSetup_TwoTeams

여기도 데이터 전요 블루프린트로 BotSpawner와 유사하게 팀을 생성하는 데이터 에셋.

이건 Lyar TeamCreation Component를 상속받았다.

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
  
#pragma once  
  
#include "Components/GameStateComponent.h"  
  
#include "LyraTeamCreationComponent.generated.h"  
  
class ULyraExperienceDefinition;  
class ALyraTeamPublicInfo;  
class ALyraTeamPrivateInfo;  
class ALyraPlayerState;  
class AGameModeBase;  
class APlayerController;  
class ULyraTeamDisplayAsset;  
  
UCLASS(Blueprintable)  
class ULyraTeamCreationComponent : public UGameStateComponent  
{  
    GENERATED_BODY()  
  
public:  
    ULyraTeamCreationComponent(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());  
  
    //~UObject interface  
#if WITH_EDITOR  
    virtual EDataValidationResult IsDataValid(class FDataValidationContext& Context) const override;  
#endif  
    //~End of UObject interface  
  
    //~UActorComponent interface    virtual void BeginPlay() override;  
    //~End of UActorComponent interface  
  
private:  
    void OnExperienceLoaded(const ULyraExperienceDefinition* Experience);  
  
protected:  
    // List of teams to create (id to display asset mapping, the display asset can be left unset if desired)  
    UPROPERTY(EditDefaultsOnly, Category = Teams)  
    TMap<uint8, TObjectPtr<ULyraTeamDisplayAsset>> TeamsToCreate;  
  
    UPROPERTY(EditDefaultsOnly, Category=Teams)  
    TSubclassOf<ALyraTeamPublicInfo> PublicTeamInfoClass;  
  
    UPROPERTY(EditDefaultsOnly, Category=Teams)  
    TSubclassOf<ALyraTeamPrivateInfo> PrivateTeamInfoClass;  
  
#if WITH_SERVER_CODE  
protected:  
    virtual void ServerCreateTeams();  
    virtual void ServerAssignPlayersToTeams();  
  
    /** Sets the team ID for the given player state. Spectator-only player states will be stripped of any team association. */  
    virtual void ServerChooseTeamForPlayer(ALyraPlayerState* PS);  
  
private:  
    void OnPlayerInitialized(AGameModeBase* GameMode, AController* NewPlayer);  
    void ServerCreateTeam(int32 TeamId, ULyraTeamDisplayAsset* DisplayAsset);  
  
    /** returns the Team ID with the fewest active players, or INDEX_NONE if there are no valid teams */  
    int32 GetLeastPopulatedTeamID() const;  
#endif  
};

봇 스포너와 비슷한 것처럼 보인다.

B_TeamSpawingRules

동일하고, 여기는 TDM_PlayerSpawningManagementComponent를 상속받았다.

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
// Copyright Epic Games, Inc. All Rights Reserved.  
  
#pragma once  
  
#include "Player/LyraPlayerSpawningManagerComponent.h"  
  
#include "TDM_PlayerSpawningManagmentComponent.generated.h"  
  
class AActor;  
class AController;  
class ALyraPlayerStart;  
class UObject;  
  
/**  
 * */  
UCLASS()  
class UTDM_PlayerSpawningManagmentComponent : public ULyraPlayerSpawningManagerComponent  
{  
    GENERATED_BODY()  
  
public:  
  
    UTDM_PlayerSpawningManagmentComponent(const FObjectInitializer& ObjectInitializer);  
  
    virtual AActor* OnChoosePlayerStart(AController* Player, TArray<ALyraPlayerStart*>& PlayerStarts) override;  
    virtual void OnFinishRestartPlayer(AController* Player, const FRotator& StartRotation) override;  
  
protected:  
  
};

팀 데스매치 모드 전용 플레이어 스폰을 관리하는 클래스로 예상한다.

B_PickRandomCharacter

이건 Controller에 붙는 컴포넌트다.

컨트롤러에 붙긴 하는데 노드를 보면 캐릭터와 연관 있는 부분인 것 같다.

이건 Lyra Controller Component Character Parts를 상속받는다.

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// A component that configure what cosmetic actors to spawn for the owning controller when it possesses a pawn  
UCLASS(meta = (BlueprintSpawnableComponent))  
class ULyraControllerComponent_CharacterParts : public UControllerComponent  
{  
    GENERATED_BODY()  
  
public:  
    ULyraControllerComponent_CharacterParts(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());  
  
    //~UActorComponent interface  
    virtual void BeginPlay() override;  
    virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;  
    //~End of UActorComponent interface  
  
    // Adds a character part to the actor that owns this customization component, should be called on the authority only    UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category=Cosmetics)  
    void AddCharacterPart(const FLyraCharacterPart& NewPart);  
  
    // Removes a previously added character part from the actor that owns this customization component, should be called on the authority only  
    UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category=Cosmetics)  
    void RemoveCharacterPart(const FLyraCharacterPart& PartToRemove);  
  
    // Removes all added character parts, should be called on the authority only  
    UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category=Cosmetics)  
    void RemoveAllCharacterParts();  
  
    // Applies relevant developer settings if in PIE  
    void ApplyDeveloperSettings();  
  
protected:  
    UPROPERTY(EditAnywhere, Category=Cosmetics)  
    TArray<FLyraControllerCharacterPartEntry> CharacterParts;  
  
private:  
    ULyraPawnComponent_CharacterParts* GetPawnCustomizer() const;  
  
    UFUNCTION()  
    void OnPossessedPawnChanged(APawn* OldPawn, APawn* NewPawn);  
  
    void AddCharacterPartInternal(const FLyraCharacterPart& NewPart, ECharacterPartSource Source);  
  
    void AddCheatPart(const FLyraCharacterPart& NewPart, bool bSuppressNaturalParts);  
    void ClearCheatParts();  
  
    void SetSuppressionOnNaturalParts(bool bSuppressed);  
  
    friend class ULyraCosmeticCheats;  
};

맨 위 주석을 해석해보니 “이 컴포넌트는 컨트롤러가 폰을 소유할 때 어떤 코스메틱 액터를 생성할지 구성한다.” 라고 한다.

코스메틱 요소는 캐릭터의 스킨, 장비, 액세서리, 특수 효과 등이 포함될 수 있다고 한다.

결론

  1. B_TeamDeathMatchScoring: 데스매치에서 점수를 측정할 규칙을 정의하는 컴포넌트다.
  2. B_MusicManagerComponent: 아직 확인 안했다.
  3. B_ShooterBotSpawner: 봇을 스폰하는 스포너로, 데이터 기반 블루프린트라 데이터 값만 바꿔준다.
  4. B_TeamSetup_TwoTeams: 팀 생성하는 컴포넌트로, 이것도 데이터 기반 블프
  5. B_TeamSpawningRules: 플레이어 스폰 로직을 담당한다.
  6. B_PickRandomCharacter: 컨트롤러에 부착되는 코스메틱 엑터를 정해주는 컴포넌트. 여기선 메쉬를 정해준다.

Actions에는 게임 규칙과 관련된 컴포넌트들을 추가해 주는 것으로 확인했다.

물론 다른 익스피리언스에서도 동일한지는 모르기에 다른 것들도 분석이 필요하다고 생각한다.

This post is licensed under CC BY 4.0 by the author.