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

02-13 10:15