起因:前不久美術提出一個需求,需要讓樣條線的上生成點光源,然后需要相機的改變,使得樣條線上的燈光參數也改變,但有一個最大距離的燈光參數,和一個最小距離的參數,當小於這個最小距離則按照最小距離的參數設置,大於最大距離按照最大距離參數設置,並且需要在Editor模式下也能看見設置效果,要實現在Editor模式下也能看見,則UE4藍圖實現不了,必須使用C++調用UE4的GEditor這一個變量,此變量是全局變量,所以不用擔心引用問題,部分代碼為:
1 FLevelEditorViewportClient* Client = (FLevelEditorViewportClient*)GEditor->GetActiveViewport()->GetClient(); 2 if (Client) 3 { 4 FVector ViewLoction = Client->GetViewLocation(); // 編輯器相機世界位置 5 FVector ActorLoction = GetActorLocation(); // 自身Actor的世界位置 6 float Lenght = (ViewLoction - ActorLoction).Size(); // 該長度則為編輯器模式相機位置與自身Actor位置長度 7 OnEditorViewPos(ViewLoction); 8 }
現在雖然獲取了編輯器模式的相機位置,但是我們怎么才能使得Actor的Tick函數也能在編輯器里面響應呢?那就需要重寫ShouldTickIfViewportsOnly()函數:
virtual bool ShouldTickIfViewportsOnly() const override;
bool AEditorViewValue::ShouldTickIfViewportsOnly() const { return true; // 把這個返回值設置為true,則Tick函數則可以在編輯器模式響應 }
既然已經可以在編輯器模式下使用Tick()函數,那怎么區分他在編輯器模式還是在游戲模式呢?可以使用 WITH_EDITOR 這個宏,但是我使用不是使用獨立窗口運行的話則這個宏不會改變,我的方法是在BeginPlay()這個函數里把一個布爾值設置則可以區分。
void AEditorViewValue::BeginPlay() { Super::BeginPlay(); bIsGameEnable = true; }
喔,忘記一個點了,需要使用FLevelEditorViewportClient類和GEditor變量,需要導入該庫
#if WITH_EDITOR #include "Editor.h" #include "UnrealEd.h" #include "LevelEditorViewport.h" #endif // WITH_EDITOR
...
if (Target.bBuildEditor == true) // 使用該庫是需要判定是否在編輯器模式,在編輯器模式下則導入該庫,不在則不導入 { PublicIncludePaths.AddRange( new string[] { // ... add public include paths required here ... } ); PrivateIncludePaths.AddRange( new string[] { //"Editor/UnrealEd/Private" // ... add other private include paths required here ... } ); PrivateDependencyModuleNames.AddRange( new string[] { "InputCore", "UnrealEd", "LevelEditor", } ); // @todo api: Only public because of WITH_EDITOR and UNREALED_API }
...
同時需要在c#中導入該類型庫!
好!基礎的框架已經弄好了,現在需要繼承該類做應用層的東西了!
應用層:現在我們在繼承的框架類的新類里寫一個需要修改的結構體,該結構體可在藍圖里面使用:
USTRUCT(BlueprintType) struct FLightParameterSetting { GENERATED_BODY() // 燈光個數 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = LightParameterSetting) int LightNumber = 0; ... };
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "LightSetting") FLightParameterSetting MinCameraPosLightParameter; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "LightSetting") FLightParameterSetting MaxCameraPosLightParameter;
接下來我們需要獲取游戲模式的相機,游戲模式的相機我們不知道他是否使用了USpringArmComponent類,所以我們需要判定
if (!MyPawn) { UE_LOG(LogTemp, Warning, TEXT("Map don't have Pawn")); return 0.f; } USpringArmComponent* Arm = Cast<USpringArmComponent>(MyPawn->GetComponentByClass(USpringArmComponent::StaticClass())); float ArmLength = Arm ? Arm->TargetArmLength : 0.f; // 判定相機Actor是否存在SpringArmComponent類,存在則相機位置不止是相機位置與Actor之間的長度 float ActorLength = (MyPawn->GetActorLocation() - this->GetActorLocation()).Size(); // 游戲模式相機與Actor之間的距離
假如我們修改了編輯器的參數,我們需要刷新一次燈光值得話,我們需要重寫PreEditChange()函數!
其他應用層的修改就不必過多的贅述了,如果有什么問題可以回復我,需要插件源碼:https://github.com/Monocluar/UE4SpecialLightEditorPlugins