UE - LyraExperienceDefinition
UnrealEngine
게임 피처의 확장 버전인 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;
};
맨 위 주석을 해석해보니 “이 컴포넌트는 컨트롤러가 폰을 소유할 때 어떤 코스메틱 액터를 생성할지 구성한다.” 라고 한다.
코스메틱 요소는 캐릭터의 스킨, 장비, 액세서리, 특수 효과 등이 포함될 수 있다고 한다.
결론
- B_TeamDeathMatchScoring: 데스매치에서 점수를 측정할 규칙을 정의하는 컴포넌트다.
- B_MusicManagerComponent: 아직 확인 안했다.
- B_ShooterBotSpawner: 봇을 스폰하는 스포너로, 데이터 기반 블루프린트라 데이터 값만 바꿔준다.
- B_TeamSetup_TwoTeams: 팀 생성하는 컴포넌트로, 이것도 데이터 기반 블프
- B_TeamSpawningRules: 플레이어 스폰 로직을 담당한다.
- B_PickRandomCharacter: 컨트롤러에 부착되는 코스메틱 엑터를 정해주는 컴포넌트. 여기선 메쉬를 정해준다.
Actions에는 게임 규칙과 관련된 컴포넌트들을 추가해 주는 것으로 확인했다.
물론 다른 익스피리언스에서도 동일한지는 모르기에 다른 것들도 분석이 필요하다고 생각한다.