건물 홀로그램이 무엇입니까?
건물 홀로그램은 건물을 건설할 때 발생하는 논리를 제어하고 플레이어가 건물을 배치할 수 있는 위치를 결정합니다.
각 FGBuildable
은 건설되기 위해 지정된 홀로그램이 필요합니다.
대부분의 경우, 커피 스테인에서 만든 기존 홀로그램 클래스를 재사용할 수 있습니다.
그들은 이미 많은 일반적인 사용 사례를 다루고 있기 때문입니다.
그러나 건물을 업그레이드하거나
다른 건물에 부착하거나
환경의 무언가에 부착할 때와 같은
추가 기능을 위해 자체 로직을 작성하고 싶을 수 있습니다.
자신의 홀로그램 로직을 작성하려면 일부 C++ 코드를 작성해야 합니다. 이 페이지는 C++에 대한 기본 지식을 가정합니다.
나만의 홀로그램 클래스 만들기
먼저 FGBuildableHologram
또는 그 서브클래스 중
하나를 확장하는 클래스를 만들어야 합니다.
예를 들어, FGFactoryBuildingHologram
(주프를 구현함) 또는
FGSplineHologram
(파이프 및 벨트에 사용됨)과 같은
클래스를 사용하여 일부 기능을 재사용할 수 있습니다.
대부분의 기본 게임 홀로그램 헤더는 Source/FactoryGame/Public/Hologram/
에서 찾을 수 있습니다.
이 문서 페이지는 여러분의 홀로그램 클래스가 AMyModHologram
이라고 가정합니다.
홀로그램 단계
홀로그램 코드는 건설 메뉴에서 건물을 선택할 때 활성화됩니다. 유효한 충돌, 부착, 구성된 기타 조건이나 테스트를 확인하는 것으로 시작합니다. 이러한 검사는 지속적으로 실행되지만, 아래에서 논의된 대로 구성할 수 있습니다.
사용자가 활성 홀로그램으로 "실행" (즉, 클릭)할 때마다 홀로그램을 다음 단계로 나아가게 하는 함수가 호출됩니다.
기본 함수는 bool FGHologram::DoMultiStepPlacement(bool isInputFromARelease)
입니다.
인라인 문서에 명시된 대로, 이 함수가 true
를 반환할 때 건설이 완료됩니다.
벨트, 빔, 전선 등과 같은 다단계 홀로그램을 만들려면 내부 상태를 추적해야 합니다.
상태를 추적하고 코드를 읽기 쉽게 만들기 위해 열거형을 만드는 것이 좋습니다. FGBeamHologram과 같은 방식으로요.
각 클릭이 발생할 때, 중요한 정보를 저장하고, 내부 상태를 진행시키며, false
를 반환합니다.
필요한 모든 정보를 수집한 후 마지막 실행에서 true
를 반환합니다.
첫 번째 클릭에서 모든 정보를 수집한 경우 true
를 반환해도 되며, 기본 클래스에 따라 이 함수를 재정의할 필요가 없을 수도 있습니다.
건물에 필요한 모든 정보를 적절한 함수로 제공하면 준비가 완료됩니다. 아래는 정수 대신 열거형을 사용하여 5단계 홀로그램이 어떻게 보일 수 있는지에 대한 의사 코드입니다.
AMyModHologram::iMaxStepCount = 5;
void AMyModHologram::DoMultiStepPlacement(bool isInputFromARelease)
{
myPointArray[iCurrentStep] = HitResult.GetLocation();
iCurrentStep++;
return iCurrentStep == iMaxStepCount;
}
건설 모드
건설 모드는 사용자가 건물을 건설할 때 선택할 수 있는 다양한 옵션입니다. 예를 들어, 파이프 및 하이퍼튜브의 경우 곡선과 수직 및 수평 모드 등이 있으며, 벽 및 토대의 경우 기본 또는 주프 모드가 있습니다.
홀로그램은 GetSupportedBuildModes
의 구현을 통해
건물에 대해 지원되는 모드를 정의합니다.
다음은 FGHologram.h
에서 건설 모드와 관련된 몇 가지 C++ 헤더입니다:
/**
* 홀로그램에 대해 구현된 건설 모드를 가져옵니다.
* @param out_buildmodes 모든 지원되는 건설 모드가 포함된 배열
*/
UFUNCTION( BlueprintNativeEvent, Category = "Hologram" )
void GetSupportedBuildModes( TArray< TSubclassOf<UFGHologramBuildModeDescriptor> >& out_buildmodes ) const;
UFUNCTION( BlueprintPure, Category = "Hologram" )
TSubclassOf<UFGHologramBuildModeDescriptor> GetCurrentBuildMode();
UFUNCTION( BlueprintCallable, Category = "Hologram" )
void SetBuildMode( TSubclassOf<UFGHologramBuildModeDescriptor> mode );
UFUNCTION( BlueprintCallable, Category = "Hologram" )
void CycleBuildMode( int32 deltaIndex );
UFUNCTION( BlueprintPure, Category = "Hologram" )
bool IsCurrentBuildMode( TSubclassOf<UFGHologramBuildModeDescriptor> buildMode ) const;
virtual void OnBuildModeChanged();
아래 예제에서는 맞춤 홀로그램이 상위 클래스에서 상속한
지원되는 건설 모드에 추가 건설 모드 mNewBuildmode
를 추가합니다.
건설 모드는 문자열 및 현지화 참조를 포함하는 데이터 객체이며, 실제 로직은 포함하지 않습니다.
void AMyModHologram::GetSupportedBuildModes_Implementation(TArray<TSubclassOf<UFGHologramBuildModeDescriptor>>& out_buildmodes) const
{
Super::GetSupportedBuildModes_Implementation(out_buildmodes);
if(mNewBuildmode)
{
out_buildmodes.AddUnique(mNewBuildmode);
}
}
같은 BuildMode 클래스를 두 번 추가하지 말고,
또한 유효하지 않은 BuildMode를 추가하지 마십시오!
이러한 이유 때문에 예제에서 |
건설 모드는 일반적으로 사용자가 빌드건을 꺼낼 때 할당 키를 눌러 변경됩니다(기본값 R
).
그러나 SetBuildMode(mNewBuildmode)
또는 CycleBuildMode(1)
(다음) / CycleBuildMode(-1)
(이전)을 통해 프로그래밍 방식으로도 변경할 수 있습니다.
활성 건설 모드에 따라 홀로그램의 동작을 변경할 수 있습니다. 이를 감지하는 몇 가지 방법이 있습니다.
첫 번째는 IsCurrentBuildMode(mNewBuildmode)
함수를 사용하여 현재 건설 모드가 mNewBuildmode
인지 테스트하는 것입니다.
또한 GetCurrentBuildMode()
를 통해 활성 건설 모드를 가져오고 이를 mNewBuildmode
와 비교할 수 있습니다.
또한 건설 모드가 변경될 때 작업을 수행할 수 있습니다.
예를 들어, 아래 스니펫은 OnBuildModeChanged()
를 사용하여 변경된 건설 모드에 따라 MyFloat
를 설정합니다.
void AMyModHologram::OnBuildModeChanged()
{
Super::OnBuildModeChanged();
if(IsCurrentBuildMode(MyBuildMode))
{
MyFloat = 0.0f;
}
}
건설 모드 참조를 재사용하려면, 일반적으로 건물의 홀로그램에 있는 필드로 찾을 수 있습니다. 이 경우, 여러분의 홀로그램은 해당 건설 모드를 소유하는 클래스를 상속해야 합니다. 그렇지 않으면, 홀로그램의 BeginPlay/Construction에서 클래스의 CDO에서 참조를 읽을 수 있습니다.
세계에서 배치 제한
홀로그램은 물리적 한계(예: "바닥이 너무 가파름"), 건물 유형(전력 케이블과 같은) 또는 고급 로직(예: FicsIt-Network 컴퓨터 구성 요소, 컴퓨터 케이스 내부에만 배치 가능)에 따라 다양한 제약을 가질 수 있습니다.
여러분은 필요와 사용 사례에 맞게 이 로직을 사용자 정의해야 할 수도 있습니다. 예를 들어:
-
벽에만 건설 허용
-
자원 노드에 배치 요구
-
하나 이상의 기존 건물 클래스에 부착
-
여러분의 창의력이 요구하는 모든 것
FGBuildableHologram
클래스는 원하는 제약을 달성하기 위해
여러분의 홀로그램에서 오버라이드 할 수 있는 다양한 메서드를 노출합니다.
유효한 충돌 확인
빌드건이 게임 세계의 어딘가를 가리킬 때마다,
여러분의 홀로그램 클래스에서 정의된 IsValidHitResult
메서드가 호출됩니다.
hitResult
인수는 위치에 대한 정보와
현재 조준하고 있는 Actor
를 포함합니다.
이 데이터를 사용하여 특정 객체를 가리킬 때만 배치를 허용할 수 있습니다.
예를 들어, 여러분이 특정 기둥 MyModSpecificPillar
를 만들었다고 가정해 보겠습니다.
이 기둥은 미적 이유로 특정 지지대 UMyModSpecificPillarSupport
위에만 배치할 수 있습니다.
이를 위해 다음과 같이 메서드를 재정의할 수 있습니다.
bool UMyModSpecificPillarHologram::IsValidHitResult(const FHitResult& hitResult) const
{
AActor* Actor = hitResult.GetActor();
// 특정 건물 클래스로 형변환을 시도합니다.
const UMyModSpecificPillarSupport* = Cast<UMyModSpecificPillarSupport>(Actor);
// 형변환 결과가 유효하면, UMyModSpecificPillarSupport를 조준하고 있다는 의미입니다.
if (IsValid(UMyModSpecificPillarSupport))
{
// 이곳에서 더 많은 정보를 확인할 수 있습니다.
// 예를 들어, 높이, 지지대에서 이미 바인딩된 필드 확인 등.
// 단순화를 위해 여기서는 간단히 배치를 허용하겠습니다.
return true;
}
return false;
}
이 메서드에서 |
다른 건물에 부착
때때로 건물이 하나의 액터에 부착하고 "잠기는" 것을 원하실 수 있습니다.
예를 들자면 송전선이 기존 전신주/연결부에 "부착"하는 경우가 있습니다.
이 상황의 특이점은 부착된 동안에는 홀로그램 위치가 업데이트되지 않는다는 것입니다.
즉, SetHologramLocationAndRotation
메서드가 호출되지 않습니다.
부착을 제어하기 위해서는 AFBuildableHologram::TrySnapToActor
메서드를 구현해야 합니다.
참고로, 기본 게임에서 이 행동은 다음 상황에서 구현됩니다.
-
공장 연결을 다른 입/출력부에 부착(파이프, 벨트)
-
지정된 부착 지점에 부착(전광판처럼)
이 동작은 격자에 정렬하는 것과 같은 것에는 의도되지 않았습니다. 그런 경우에는
"부착"이라는 용어는 "고정"을 의미하며, 건물을 이동할 수 없도록 하고 부착된 액터에 연결 을 표시하고 싶을 때 사용해야 합니다. |
여러분의 반짝반짝한 새 창문 건물(MyModGlassWindow
)을 기존의 벽에 부착하고 싶다고 가정하고 예를 들어보겠습니다.
부착했다면, 창문은 더 이상 움직일 수 없도록 벽에 고정되어야 합니다. 따라서 다음과 같이 작성하겠습니다.
// 헤더 파일에서는 Snapped 속성을 정의하여 현재 부착된 오브젝트를 추적합니다.
AFGBuildableWall* Snapped = nullptr;
// cpp 파일에서는 부착 메서드를 오버라이드 합니다.
bool UMyModGlassWindowHologram::TrySnapToActor(const FHitResult& hitResult)
{
const auto Actor = hitResult.Actor.Get();
if (!IsValid(Actor))
{
// 이전 부착에서 벗어났으므로 추적기를 치웁니다
Snapped = nullptr;
return false;
}
if (Actor->IsA<AFGBuildableWall>())
{
Snapped = Cast<AFGBuildableWall>(Actor);
// 여기에서 맞춤 부착 로직을 추가할 수 있습니다.
// `SetActorLocationAndRotation`을 사용하여 단일 속성을 설정하는 것보다 성능을 개선시킵니다.
SetActorLocationAndRotation(Actor->GetActorLocation(), Actor->GetActorRotation());
// 부착되었습니다. 이제 true를 반환하여 다음 업데이트를 비활성화합니다
return true;
}
Snapped = nullptr;
return false;
}
만약 메서드가 true를 반환하면, 홀로그램의 위치와 회전은 자동으로 업데이트되지 않을 것입니다. 홀로그램을 움직이기 위해선 맞춤 부착 로직을 작성해야 합니다. |
만약 |
자격 없는 비활성 홀로그램 표시
건물을 배치하는 동안 빌드건으로 배치를 허용하지 않으면서도 빨간 외곽선과 홀로그램을 띄울 수 있습니다. 기본 게임에서는 "바닥이 너무 가파릅니다" 메시지와 함께 빨간 홀로그램이 뜨는 것을 예로 들 수 있습니다. 망할 철도 같으니!
비슷하게 건물에 구현하고 싶다면,
간단히 IsValidHitResult
메서드에서 true를 반환하면 됩니다
(TrySnapToActor
또는 CheckValidPlacement
같은 메서드가 연속적으로 호출되게 합니다).
그리고 유효하지 않은 배치가 발견되었다면,
AddConstructDisqualifier()
를 사용하여 플레이어에게 오류를 알릴 수 있습니다.
이전의 MyModGlassWindow
예에서,
부착되지 않았다면 자격이 없음을 추가해 보겠습니다.
이번에는 창문 홀로그램이 빨간색으로 강조된 것을 볼 수 있을 겁니다.
void UMyModGlassWindowHologram::CheckValidPlacement() {
if (!IsValid(Snapped) || !Snapped->IsA<AFGBuildableWall>()) {
AddConstructDisqualifier(UFGCDMustSnapWall::StaticClass());
}
Super::CheckValidPlacement();
}
|
기존 게임에 이미 존재하는 수많은 실격자 중 하나를 여러분의 건물을 위해 재사용할 수도 있습니다.
예를 들어 UFGCDMustSnapWall
는 벽에 부착되는 것을 요구합니다.
전체 목록은 Source/FactoryGame/Public/FGConstructDisqualifier.h
헤더 파일에서 찾을 수 있습니다.
다음처럼 나만의 맞춤 실격자를 정의할 수도 있습니다.
#define LOCTEXT_NAMESPACE "MyModLocNamespace"
UCLASS()
class UMyModCDMustSnapBeautifulWall : public UFGConstructDisqualifier {
GENERATED_BODY()
UMyModCDMustSnapBeautifulWall() {
mDisqfualifyingText = LOCTEXT( "UMyModCDMustSnapBeautifulWall", "아름다운 벽에 부착해야 합니다!" );
}
};
#undef LOCTEXT_NAMESPACE
속성의 철자는 mDisqualifyingText가 아닌 mDisqfualifyingText입니다. 이는 단순히 여러분의 파일과 일치해야 하는 게임 헤더의 오타입니다. |
건물 구성하기
홀로그램은 또한 건물이 지어짐에 따라 값을 제공하거나 건물에 변화를 줄 수 있게 합니다. 이를 통해 건물의 위치에 따라 메쉬를 변경하거나 구성 요소를 약간 회전시키거나 부착된 건물에 대한 참조를 설정할 수 있습니다.
건물 대해 무엇을 하고 싶은지, 그리고 언제 변경을 원하느냐에 따라 사용할 수 있는 단계가 다릅니다.
구성 함수는 다음 순서로 호출되므로 각자의 단계를 무시할 수 있습니다.
이 목록은 FGBuildableHologram.h
의 댓글에서 발췌한 것입니다.
-
PreConfigureActor( 건물 );
-
ConfigureActor( 건물 );
-
ConfigureBuildEffect( 건물 );
-
(세계에 건물 액터의 실제 소환을 수행합니다)
-
ConfigureComponents( 건물 );
-
(건물에서 BeginPlay가 호출됩니다)
이제 조금 더 자세히 알아봅시다.
PreConfigureActor
/**
* 설정이 발생하기 전에 액터에 대한 사전 초기화를 허용하는 기능입니다. 이 기능은 최종 점검을 허용하고
* 속성을 설정할 수 있도록 하기 위한 것으로, 여기서부터 모든 컴포넌트를 구성할 때처럼 설정할 수 있습니다
*/
virtual void PreConfigureActor( class AFGBuildable* inBuildable );
특정 경우에는 액터의 구성이 시작되기 전에 속성을 다시 확인해야 할 수도 있으며, 여기서 가능합니다.
ConfigureActor
/**
* 구성 함수: 실행 시 홀로그램에서 생성된 액터를 구성합니다.
* @param inBuildable - 완성되기 전에 구성할 세계에 배치된 건물입니다.
* @note 여기의 컴포넌트는 오브라이드 되므로 만지지 마십시오! ConfigureComponents를 사용하십시오.
*/
virtual void ConfigureActor( class AFGBuildable* inBuildable ) const;
액터 구성은 속성을 설정하는 데만 사용해야 하며, 컴포넌트를 생성하는 데 사용해서는 안 됩니다.
예를 들어, 건물 업그레이드를 수행할 때 업그레이드된 액터에서 새로운 액터로 속성을 이동하는 데 유용합니다.
건물 업그레이드
홀로그램은 또한 기존 건물의 업그레이드 구현을 가능하게 해줍니다. 이는 건물이 여러 티어를 가졌으며, 기존 요소를 해체하지 않고 업그레이드하길 원할 때 유용합니다.
예를 들어 기본 게임에서는 벨트에 사용됩니다.
다음은 업그레이드와 관련된 FGHologram.h
의 C++ 코드입니다.
/** 업그레이드된 액터 대상 얻기 */
virtual AActor* GetUpgradedActor() const override;
/** 업그레이드 가능한가? */
virtual bool TryUpgrade(const FHitResult& hitResult) override;
private:
/** 업그레이드된 액터 대상 */
UPROPERTY(Transient)
AActor* mUpgradedActor = nullptr;
부분별로 자세히 살펴보겠습니다.
mUpgradedActor
UPROPERTY(Transient)
AActor* mUpgradedActor = nullptr;
이 필드는 업그레이드를 시도할 때 우리가 보고 있는 액터를 참조합니다. 우리가 새 건물로 옮기고 싶은 정보는 아마도 오래된 건물일 것입니다.
GetUpgradedActor
/** 업그레이드된 액터 대상 얻기 */
virtual AActor* GetUpgradedActor() const override;
여기에서 대상 액터를 반환해야 합니다(이 예에서는 mUpgradedActor).
TryUpgrade
/** 업그레이드 가능한가? */
virtual bool TryUpgrade(const FHitResult& hitResult) override;
이 함수는 액터를 업그레이드할 수 있는지 확인하기 위해 호출됩니다.
여기서 충돌 결과를 바탕으로 mUpgradedActor
를 설정해야 합니다. 그렇지 않으면 이상한 일이 발생할 수 있습니다.
홀로그램의 위치를 충돌 액터의 위치로 설정해야 합니다.
true
를 반환한다는 것은 업그레이드가 허용된다는 것을 의미합니다.
업그레이드 홀로그램 예
C++ 부분의 매우 기본적인 예입니다:
액터 업그레이드를 위한 기본 게임 로직은 연결 지점이 동일한 위치와 이름을 사용하는 한 벨트, 파이프, 전원 연결을 자동으로 처리합니다. 그러나, 기계에서 선택한 제작법과 같은 필드처럼, 인벤토리 또한 수동으로 전송해야 합니다. 이에 대한 예로는 |
AActor* AMyModHologram::GetUpgradedActor() const
{
// 대상 액터를 반환하여 게임 내에서 숨김!
return mUpgradedActor;
}
bool AMyModHologram::TryUpgrade(const FHitResult& hitResult)
{
if(hitResult.GetActor())
{
const TSubclassOf<AActor> ActorClass = GetActorClass();
// 같은 액터를 업그레이드하진 않는지 확인. 클래스가 달라야 함!
if(hitResult.GetActor()->GetClass() != ActorClass)
{
// 중요: 우리의 홀로그램의 위치를 대상 액터에 설정해야 함
SetActorTransform(hitResult.GetActor()->GetActorTransform());
// UpgradedActor를 설정하고 유효하다면 true를 반환함(반드시 확인해야 함)
mUpgradedActor = hitResult.GetActor();
return mUpgradedActor != nullptr;
}
}
// 그렇지 않으면 UpgradedActor를 nullptr로 설정
mUpgradedActor = nullptr;
return Super::TryUpgrade(hitResult);
}
추가 시각화 표시
블루프린트 기계 홀로그램은 사용자가 건물을 배치하는 데 도움이 되는 맞춤 시각 요소를 생성할 수 있습니다. 맞춤 시각화를 사용하면 기본 시각화가 대체됩니다. 이 접근 방식은 맞춤 건물이 올바르게 보이기 위해 추가 설정과 구성이 필요할 때 일반적으로 사용됩니다. 다음 예시를 고려해 보십시오:
void FMyModModule::StartupModule() {
AFGBlueprintHologram::RegisterCustomBuildableVisualization(
AABCurvedDecorBuildable::StaticClass(),
AFGBlueprintHologram::FCreateBuildableVisualizationDelegate::CreateLambda([](AFGBlueprintHologram* blueprintHologram, AFGBuildable* buildable, USceneComponent* buildableRootComponent) {
// 건물 얻기
AMyBuildable* myBuildable = Cast<AMyBuildable>(buildable);
// - 모든 관련 컴포넌트에 대한 쩌는 코드
// 아마도 myBuildable을 참조하는 것과 관련 있음
// 건물 참조는 이 람다에만 적용되므로 계속 지속된다고 생각하지 말 것
// 예를 들어, 보여줄 맞춤 스플라인 메쉬 컴포넌트가 하나 있다면 다음과 같이 보일 수 있음:
USplineMeshComponent* splineMesh = Cast<USplineMeshComponent>(
// 내장된 설정 컴포넌트를 사용하므로 액터에 부착, 변환, 이동성, 커스터마이저 데이터, 홀로그램FX, 충돌 채널 등을 걱정할 필요가 없음
blueprintHologram->SetupComponent(
buildableRootComponent,
buildable->GetComponentByClass<USplineMeshComponent>(),
buildable->GetFName(),
FName()
)
);
// 예: 이제 맞춤 구성을 사용하고 있으므로 기본 구성에서는 적용되지 않는 구성을 수행
splineMesh->SetStartPosition(curve->StartPosition, false);
splineMesh->SetEndPosition(curve->EndPosition, false);
splineMesh->SetStartTangent(curve->StartTangent, false);
splineMesh->SetEndTangent(curve->EndTangent, false);
splineMesh->UpdateMesh_Concurrent();
})
);
}