起因:前不久美术提出一个需求,需要让样条线的上生成点光源,然后需要相机的改变,使得样条线上的灯光参数也改变,但有一个最大距离的灯光参数,和一个最小距离的参数,当小于这个最小距离则按照最小距离的参数设置,大于最大距离按照最大距离参数设置,并且需要在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/a948022284/UE4SpecialLightEditorPlugins