找回密码
 立即注册
首页 业界区 安全 UEC++个人速查

UEC++个人速查

杠氯 昨天 16:20
个人速查

这里是鄙人在学习U++时候整理的部分笔记,后面也会把自己用到的补充上来。这个笔记存在的唯一原因只是UE的API太过简陋,所以自己找教程看,把基础内容写过来用于copy。接下来自己的学习安排是,打算做一个相对复杂点的蓝图项目熟悉下游戏架构,再将一些蓝图替换成C++,简单的C++游戏已经抄了俩了。后面再看怎么做小型的网络游戏(排队游戏的某个关卡
之类的)。
创建Actor和组件挂载

组件头文件


  • Components/SceneComponent.h(挂载点,任何组件都必须挂载在挂载点上)
  • Components/StaticMeshComponent.h(网格体组件)
  • Components/BoxComponent.h(碰撞组件)
  • Particles/ParticleSystemComponent.h(粒子系统组件)
  • Components/AudioComponent.h(声音组件)
    只有Actor能挂组件哦。
声明
  1. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "MySceneComponent")
  2. class USceneComponent* MyScene;
  3. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "MySceneComponent")
  4. class UStaticMeshComponent* MyMesh;
  5. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "MySceneComponent")
  6. class UParticleSystemComponent* MyParticle;
  7. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "MySceneComponent")
  8. class UBoxComponent* MyBox;
  9. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "MySceneComponent")
  10. class UAudioComponent* MyAudio;
复制代码
挂载和定义

一般常在构造函数中声明并挂载
定义
  1. MyScene = CreateDefaultSubobject<USceneComponent>(TEXT("CustomSceneName"));
  2. MyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("CustomStaticMeshName"));
  3. MyParticle = CreateDefaultSubobject<UParticleSystemcComponent>(TEXT("MyCustomParticleSystemName"));
  4. MyBox = CreateDefaultSubobject<UBoxComponent>(TEXT("MyCustomBox"));
  5. MyAudio = CreateDefaultSubobject<UAudioComponent>(TEXT("MyCustomAudio"));
复制代码
挂载

因为只能挂载到DefaultSubobject,所以最好让RootComponent为DefaultSubobject这样就能挂更多组件。一般常在构造方法挂载。
  1. RootComponent = MyScene;
  2. MyMesh->SetupAttachment(MyScene);
  3. MyParticle->SetupAttachment(MyScene);
  4. MyBox->SetupAttachment(MyScene);
  5. MyAudio->SetupAttachment(MyBox);
复制代码
静态加载

静态加载资源

资源文件写死,在确定组件的层级结构后,传入资源并指定到组件对象的某个属性上。声明定义挂载后的下一个选择环节。
FObjectFinder中的参数可以去蓝图中看,蓝图中这些组件的detail中引入用的啥参数就用啥参数。静态加载的时候定义必须写在构造方法中。
  1. //.hUPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "MySceneComponent")
  2. class USceneComponent* MyScene;
  3. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "MySceneComponent")
  4. class UStaticMeshComponent* MyMesh;
  5. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "MySceneComponent")
  6. class UParticleSystemComponent* MyParticle;
  7. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "MySceneComponent")
  8. class UBoxComponent* MyBox;
  9. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "MySceneComponent")
  10. class UAudioComponent* MyAudio;//.cppstatic ConstructorHelpers::FObjectFinderTempStaticMesh(TEXT(“网格体模型资产的引用”));MyMesh->SetStaticMesh(TempStaticMesh.Object);static ConstructorHelpers::FObjectFinderTempParticleSystem(TEXT("粒子特效的资产引用"));MyParticle->SetTemplate(TemParticleSystem.Object); static ConstructorHelpers::FObjectFinderTempSound(TEXT("音效资产引用"));MyAudio->SetSound(TempSound.Object);
复制代码
静态加载资源类

不再通过class 加组件的形式前向声明了,而是通过TSubclassOf来实现声明。静态加载的时候定义必须写在构造方法中。同样是将一个资源用一个指针储存,但是涉及到蓝图的类型,所以试用TSubclassOf用一个对象存储任何AActor的子类,
  1. //。h
  2. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "MyClass")
  3. TSubclassOf MyActor;
  4. //.cpp
  5. static ConstructorHelpers::FClassFinder TempMyActor(TEXT("蓝图类资源引用_C"));
  6. MyActor = TempMyActor.class;
复制代码
动态加载

动态加载资源

动态加载放在构造方法外的其他位置,比如BeginPlay中。相对于静态加载资源没啥变化
  1. UStaticMesh* MyTempStaticMesh = LoadObject<UStaticMesh>(nullptr,TEXT("资源引用"));
  2. if(MyTempStaticMesh)MyMesh->SetStaticMesh(MyTempStaticMesh);
复制代码
动态加载类资源
  1. UClass* MyTempClass = LoadClass(this,TEXT("蓝图类资源引用_C"));
  2. if(MyTempClass)AActor* SpawnActor = GetWorld()->SpawnActor(MyTempClass,FVector::ZeroVector,FRotator::ZeroRotator);
复制代码
相机和相机臂

类型选择


  • 必然Pawn或者character这样的panw子类了。
头文件


  • GameFramework/SpringArmComponent.h(相机臂)
  • Camera/CameraComponent.h(相机组件)
声明
  1. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "MySceneComponent")
  2. USceneComponent* MyRoot;
  3. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "MySceneComponent")
  4. USpringArmComponent* MySprintArm;
  5. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "MySceneComponent")
  6. UCameraComponent* MyCamera;
复制代码
挂载和定义

定义

在构造方法中实现初始化定义。
  1. MyRoot = CreateDefaultSubobject<USceneComponent>(TEXT("MyRootComponent"));
  2. MySpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("MySpringArmComponent"));
  3. MyCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("MyCameraComponent"));
复制代码
挂载

这里挂载也放在构造函数
  1. RootComponent = MyRoot;
  2. MySpringArm->SetupAttachment(MyRoot);
  3. MyCamera->SetupAttachment(MySpringArm);
复制代码
其他配置
  1. MySpringArm->bDoCollisionTest = false;//取消摄像机的碰撞
复制代码
按键映射和鼠标滑轮

类型选择

一般常用PlayerController。因为它提供了很多接口,重载就行,无需造轮子。
似乎PlayerController本身就自带了一个InputComponent,换句话说,如果自己不使用playercontroller只用pawn就得将InputComponent给导入并在构造函数创建即可(不需要挂载),在beginplay启动输入并调用手动实现的setupinputcomponent。其他相同。
头文件导入

PlayerController控制的那个Pawn的头文件,想要控制Pawn上的摄像机臂或者pawn的位置,必须有其引用。
声明

重载接口函数
  1. virtual void SetupInputComponent();
复制代码
声明映射函数
  1. void WheelUpFunction();
  2. void WheelDownFUnction();
  3. //我是一个辅助函数
  4. void Zoom(bool Direction,ZoomSpeed);
复制代码
定义

在SetupInputComponent()函数中将按键设置和触发类型以及回调函数绑定到inputComponent上来。
  1. Super::SetuupInputComponent();
  2. InputComponent->BindAction(“按键配置名”,IE_Pressed,this,&AmyPlayerController::WheelUpFunction);
  3. InputComponent->BindAction(“按键配置名”,IE_Pressed,this,&AmyPlayerController::WheelDownFunction);
复制代码
在映射函数中WheelUpFunction();通过PlayerController的GetPawn获取受控的引用经过类型判断后进行摄像机臂处理。
  1. if(GetPawn())
  2. {
  3.         AMyPawn* MyCameraPawn = Cast(GetPawn());
  4.         if(MyCameraPawn)
  5.         {
  6.                 MyCameraPawn->Zoom(1,10);
  7.         }
  8. }
复制代码
在Zoom(Direction,ZoomSpeed)函数;根据传入方向和速度进行弹簧臂的拉近和延伸。
  1. if(Direction)
  2. {
  3.         if(MySpringArm->TargetArmLength >=300 && MySpringArm->TargetArmLength<5000)
  4.                 MySpringArm->TargetArmLength+=(ZoomSpeed*2);
  5. }
  6. else
  7. {
  8.         if(MySpringArm->TargetArmLength>300 && MySpringArm->TargetArmLength<=5000)
  9.                 MySpringArm->TargetArmLength0-(ZoomSpeed*2);
  10. }
复制代码
Actor的位置偏移

类型选择


  • Actor及其子类因为相关的Actor类都实现了。
使用

相对于根节点移动

控制整个Actor的移动,相对于根节点的移动(根节点不动)

  • 需要一个MyOffset表示某个对象移动的方向和距离。
  • 是否忽略碰撞
  • 需要一个HitResult的引用存储是否发生了碰撞作
  1. FVector MyOffset = FVector(1,0,0);
  2. FHitResult HitResult;
  3. AddActorLocalOffset(MyOffset,false,&HitResult);
复制代码
相对于世界的移动

参数同上
  1. AddActorWorldOffset(MyOffset,false,&HitResult);
复制代码
Actor的碰撞-Overlap

头文件


  • Components/BoxComponent.h(碰撞组件)
声明
  1. MyBox = CreateDefaultSubobject<UBoxComponent>(TEXT("MyCustomBox"));
复制代码
定义与挂载

定义
  1. MyBox = CreateDefaultSubobject<UBoxComponent>(TEXT("MyCustomBox"));
复制代码
挂载
  1. MyBox->SetupAttachment(MyScene);
复制代码
使用

绑定
  1. MyBox->OnComponentBeginOverlap.AddDynamic(this,&AMyActor::BeginOverlapFunction);
  2. MyBox->OnComponentBeginOverlap.AddDynamic(this,&AMyActor::EndOverlapFunction);
复制代码
其他配置--待绑定函数的声明


  • 当前actor的碰撞盒组件
  • 另一个碰撞actor
  • 另一个碰撞actor的碰撞组件
  • 对方组件的body索引(无视)
  • 一个物体是否是主动带着速度撞过来的
  • 主动撞过来时的命中等信息
  1. UFUNCTION()
  2. void BeginOverlapFunction(
  3.          UPrimitiveComponent* OverlappedComponent,
  4.          AActor* OtherActor,
  5.          UPrimitiveComponent* OtherComp,
  6.          int32 OtherBodyIndex,
  7.          bool bFromSweep,
  8.          const FHitResult& SweepResult);
  9. UFUNCTION()
  10. void EndOverlapFunction(
  11.         UPrimitiveComponent* OverlappedComponent,
  12.         AActor* OtherActor,
  13.         UPrimitiveComponent* OtherComp,
  14.         int32 OtherBodyIndex);
复制代码
其他配置--待绑定函数的实现
  1. void AMyActor::BeinOverlapFunction(UPrimitiveComponent* OverlappedComponent,
  2.          AActor* OtherActor,
  3.          UPrimitiveComponent* OtherComp,
  4.          int32 OtherBodyIndex,
  5.          bool bFromSweep,
  6.          const FHitResult& SweepResult)
  7. {
  8.         UELOG(......)
  9. }
复制代码
Actor的碰撞Hit

hit不同于beginoverlap的第一次碰撞才触发,hit只要有接触就会触发。
头文件


  • Components/BoxComponent.h(碰撞组件)
声明
  1. MyBox = CreateDefaultSubobject<UBoxComponent>(TEXT("MyCustomBox"));
复制代码
定义与挂载

定义
  1. MyBox = CreateDefaultSubobject<UBoxComponent>(TEXT("MyCustomBox"));
复制代码
挂载
  1. MyBox->SetupAttachment(MyScene);
复制代码
使用

绑定
  1. MyBox->OnComponentHit.AddDynamic(this,&AMyActor::HitFunction)
复制代码
其他配置--带绑定函数的声明
  1. UFUNCTION()
  2. void HitFunction(
  3.         UPrimitiveComponent* HitComponent,
  4.         AActor* OtherActor,
  5.         UPrimitiveComponent* OtherComp,
  6.         FVector NormalImpulse,
  7.         const FHitResult& Hit);
复制代码
Actor的碰撞设置

头文件


  • Components/BoxComponent.h(碰撞组件)
声明
  1. MyBox = CreateDefaultSubobject<UBoxComponent>(TEXT("MyCustomBox"));
复制代码
定义与挂载

定义
  1. MyBox = CreateDefaultSubobject<UBoxComponent>(TEXT("MyCustomBox"));
复制代码
挂载
  1. MyBox->SetupAttachment(MyScene);
复制代码
使用

碰撞设置
  1. MyBox->SetCollisionEnabled(ECollisionEnabled::NoCollision);
  2. MyBox->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
  3. MyBox->SetCollisionEnabled(ECollisionEnabled::PhysicsOnly);
  4. MyBox->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
  5. MyBox->SetCollisionEnabled(ECollisionEnabled::ProbeOnly);
  6. MyBox->SetCollisionEnabled(ECollisionEnabled::QueryAndProbe);
复制代码
碰撞类型
  1. MyBox->SetCollisionObjectType(ECC_WorldStatic);
  2. MyBox->SetCollisionObjectType(ECC_WorldDynamic);
  3. MyBox->SetCollisionObjectType(ECC_Pawn);
  4. MyBox->SetCollisionObjectType(ECC_PhysicsBody);
  5. MyBox->SetCollisionObjectType(ECC_Vehicle);
  6. MyBox->SetCollisionObjectType(ECC_Destructible);
复制代码
碰撞响应

多个通道
  1. MyBox->SetCollisionResponseToALllChannels(ECR_Block); //设置所有通道响应为block
  2. MyBox->SetCollisionResponseToAllChannels(ECR_Overlap);//设所有通道响应为重叠
  3. MyBox->SetCollisionResponseToAllChannels(ECR_Ignore);//设所有通道响应为忽略
复制代码
单个通道
  1. MyBox->SetCollisionResponseToChannel(ECR_Pawn,ECR_Overlap);//对pawn设置为重叠
  2. MyBox->SetCollisionResponseToChannel(ECC_WorldStatic,ECR_Block);//对世界静态设置为阻挡
  3. MyBox->SetCollisionResponseToChannel(ECC_WorldDynamic,ECR_Block);//对世界动态设置为忽略
复制代码
Actor的粒子特效的激活和失效

头文件


  • Particles/ParticleSystemComponent.h(粒子系统组件)
声明
  1. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "MySceneComponent")
  2. class USceneComponent* MyScene;
  3. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "MySceneComponent")
  4. class UStaticMeshComponent* MyMesh;
  5. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "MySceneComponent")
  6. class UParticleSystemComponent* MyParticle;
  7. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "MySceneComponent")
  8. class UBoxComponent* MyBox;
  9. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "MySceneComponent")
  10. class UAudioComponent* MyAudio;
复制代码
挂载和定义

一般常在构造函数中声明并挂载
定义
  1. MyScene = CreateDefaultSubobject<USceneComponent>(TEXT("CustomSceneName"));
  2. MyParticle = CreateDefaultSubobject<UParticleSystemcComponent>(TEXT("MyCustomParticleSystemName"));
复制代码
挂载

因为只能挂载到DefaultSubobject,所以最好让RootComponent为DefaultSubobject这样就能挂更多组件。一般常在构造方法挂载。
  1. RootComponent = MyScene;
  2. MyParticle->SetupAttachment(MyScene);
复制代码
使用-激活和失效
  1. MyParticle->Activate();
  2. MyParticle->Deactivate();
复制代码
用户控件--按钮

类型选择


  • 选择C++的Widget的UserWidget类进行派生
  • 选则一个PlayerController处理控件的显示。
头文件


  • 控件父类:

    • Components/Button.h

  • PlayerController类

    • Blueprint/UserWidget.h

声明


  • 使用meta的bindwidget相当于将控件名为ButtonStart和ButtonQuit的两个控件的操作句柄暴露给C++方法了。
  1. UPROPERTY(meta=(BindWidget))
  2. UButton* ButtonStart;
  3. UPROPERTY(meta=(BindWidget))
  4. UButton* ButtonQuit;
  5. virtual bool Initialize() override;
复制代码
定义
  1. bool UMyUserWidget::Initialize()
  2. {
  3.         if(!Super::Initialize())
  4.         {
  5.                 return false;
  6.         }
  7.         ButtonStart->OnClicked.AddDynaic(this,&UMyUserWidget::Start());
  8.         ButtonQuit->OnClicked.AddDynaic(this,&UMyUserWidget::Quit());
  9.         return ture;
  10. }
复制代码
其他配置--待绑定方法声明和定义
  1. //声明:
  2. UFUNCTION()
  3. void Start();
  4. UFUNCTION()
  5. void Quit();
  6. //定义
  7. void UMyUserWidget::Start(){
  8.         GEngine->AddOnScreenDebugMessage(-1,5.0f,FColor::Red,TEXT("Start"));
  9. }
  10. void UMyUserWidget::Quit(){
  11.         GEngine->AddOnScreenDebugMessage(-1,5.0f,FColor::Red,TEXT("Quit"));
  12. }
复制代码
使用--这里用了动态加载。


  • 进入一个PlayerController类,其实选其他类也是可以的,但是Pawn可能会死,可能会换,World需要手动管理声明周期,而playercontroller几乎贯穿玩家和游戏交互的全流程,因此选择PlayerController。
  • 先将蓝图子类加载到内存,在用UUserWidget这个控件父类指针去指向基于蓝图子类创建出来的Widget。所以LoadClass真的只是读取一个类而不是一个对象,通过指针将控件添加到视口。类似于TSubClassOf,指针存储底稿,运行时根据底稿来创建副本并进行修改。
  1. void AMyPlayerController::BeinPlay()
  2. {
  3.         Super::BeginPlay();
  4.         UClass* widgetClass = LoadClass<UUserWidget>(NULL,TEXT("控件的蓝图子类的资源引用_C"));
  5.         UUserWidget* MyWidgetClass = nullptr;
  6.         MyWidgetClass = CreateWidget<UUserWidget>(GetWorld(),widgetClass);
  7.         MyWidgetClass->AddToViewPort();
  8. }
复制代码
用户控件--进度条

类型选择


  • 选择C++的Widget的UserWidget类进行派生
  • 选则一个PlayerController处理控件的显示。
头文件


  • 控件父类:

    • Components/ProgressBar.h

  • PlayerController类

    • Blueprint/UserWidget.h

声明
  1. UPROPERTY(meta=(BindWidget))
  2. UProgressBar* ProgressBarHealth;
  3. UPROPERTY(EditAnywhere,BlueprintReadWrite,Category = "MyHealth")
  4. float CurrentHealth = 100.0f;
  5. UPROPERTY(EditAnywhere,BlueprintReadWrite,Category = "MyHealth")
  6. float MaxHealth = 100.0f;
  7. void UpdateHealth();
复制代码
定义
  1. void UMyUserWidget::UpdateHealth()
  2. {
  3.         float Percent = FMath::Clamp(CurrentHealth/MaxHealth,0.f,1.f);
  4.         if(ProgressBarHealth)ProgressBarHealth->SetPercent(Percent);
  5.         if (CurrentHealth <= 0)
  6.                 GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Death"));
  7.         else
  8.                 GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, TEXT("-10"));
  9. }
复制代码
其他配置

找一个函数负责调用UpdateHealth().
  1. void UMyUserWidget::Start()
  2. {
  3.         UpdateHealth();
  4. }
复制代码
代理--单播

类型选择

选了Actor来派生
代理的声明


  • 代理的声明依靠一个宏,这个宏会在预编译阶段被替换成对一个类的声明,也就是会根据代理名替换城几个类NoParamDelegate,OneParamDelegate,TwoParamDelegate,ThreeParamDelegate,RevalDelegate这些类。
  1. DECLARE_DELEGATE(NoParamDelegate);
  2. DECLARE_DELEGATE_OneParam(OneParamDelegate,FString);
  3. DECLARE_DELEGATE_TwoParams(TwoParamDelegate,FString,int32);
  4. DECLARE_DELEGATE_ThreeParams(ThreeParamsDelegate,FString,int32,float);
  5. DECLARE_DELEGATE_RetVal(FString,RevalDelegate);
复制代码

  • 通过宏声明了代理后(创建了代理类后)就需要实例化这个所谓的代理(感觉所谓的代理就是一个容器,负责在调用的时候将绑定上去的函数一起执行掉)
  1. NoParamDelegate NoParamDelegate;
  2. OneParamDelegate OneParamDelegate;
  3. TwoParamDelegate TwoParamDelegate;
  4. ThreeParamsDelegate ThreeParamDelegate;
  5. RevalDelegate RevalDelegate;
复制代码

  • 我觉得是函数容器也并非空穴来风,因为真的很像,这里就是在声明函数了。
  1. void NoParamFunction();
  2. void OneParamFunction(FString str);
  3. void TwoParamFunction(FString str,int32 value);
  4. void ThreeParamFunction(FString str,int32 value,float value1);
  5. FString RevalParamFunction();
复制代码
定义
  1. void AMyDelegateActor::NoParamFunction()
  2. {
  3.         GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, TEXT("NoParamDelegate"));
  4. }
  5. void AMyDelegateActor::OneParamFunction(FString str)
  6. {
  7.         GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, FString::Printf(TEXT("%s"), *str));
  8. }
  9. void AMyDelegateActor::TwoParamFunction(FString str, int32 value)
  10. {
  11.         GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, FString::Printf(TEXT("%s %d"), *str,value));
  12. }
  13. void AMyDelegateActor::ThreeParamFunction(FString str, int32 value, float value1)
  14. {
  15.         GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, FString::Printf(TEXT("%s %d %f"), *str, value,value1));
  16. }
  17. FString AMyDelegateActor::RevalParamFunction()
  18. {
  19.         FString str = FString::Printf(TEXT("RevalParamDelegate"));
  20.         return str;
  21. }
复制代码
使用


  • 绑定方法到代理----在构造方法中将函数绑定到容器中。
  1. NoParamDelegate.BindUObject(this, &AMyDelegateActor::NoParamFunction);
  2. OneParamDelegate.BindUObject(this, &AMyDelegateActor::OneParamFunction);
  3. TwoParamDelegate.BindUObject(this, &AMyDelegateActor::TwoParamFunction);
  4. ThreeParamDelegate.BindUObject(this, &AMyDelegateActor::ThreeParamFunction);
  5. RevalDelegate.BindUObject(this, &AMyDelegateActor::RevalParamFunction);
复制代码

  • 执行代理---此处在beginplay执行
  1. void AMyDelegateActor::BeingPlay()
  2. {
  3.          SUper::BeginPlay();
  4.          NoParamDelegate.ExecuteIfBound();
  5.          OneParamDelegate.ExecuteIfBound("OneParamDelegate");
  6.          TwoParamDelegate.ExecuteIfBound("TwoParamDelegate",10);
  7.          ThreeParamDelegate.ExecuteIfBound("ThreeParamDelegate",10,5.0);
  8.          FString strValue = RevalDelegate.Execute();
  9. }
复制代码
代理--多播

类型选择

同上单播
代理的声明

我说实话,多播感觉就更像一个容器了。

  • 代理声明
  1. DECLARE_MULTICAST_DELEGATE_OneParam(OneParamMultiDelegate,FString)
复制代码

  • 代理实例化
  1. OneParamMultiDelegate OneParamMultiDelegate;
复制代码

  • 绑定函数的声明
  1. UFUNCTION()
  2. void MultiDelegateFunction1(FString str);
  3. UFUNCTION()
  4. void MultiDelegateFunction2(FString str);
  5. UFUNCTION()
  6. void MultiDelegateFUnction3(FString str);
复制代码
定义

定义函数
  1. void AMyDelegateActor::MultiDelegateFunction1(FString str)
  2. {
  3.         FString TempStr = str.Append("1");
  4.         GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, FString::Printf(TEXT("%s"), *TempStr));
  5. }
  6. void AMyDelegateActor::MultiDelegateFunction2(FString str)
  7. {
  8.         FString TempStr = str.Append("2");
  9.         GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, FString::Printf(TEXT("%s"), *TempStr));
  10. }
  11. void AMyDelegateActor::MultiDelegateFUnction3(FString str)
  12. {
  13.         FString TempStr = str.Append("3");
  14.         GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, FString::Printf(TEXT("%s"), *TempStr));
  15. }
复制代码
使用


  • 绑定代理,感觉多播更像容器了---这里在构造方法绑定的
  1. OneParamMultiDelegate.AddUObject(this, &AMyDelegateActor::MultiDelegateFunction1);
  2. OneParamMultiDelegate.AddUObject(this, &AMyDelegateActor::MultiDelegateFunction2);
  3. OneParamMultiDelegate.AddUObject(this, &AMyDelegateActor::MultiDelegateFUnction3);
复制代码

  • 执行代理---这里再Beginplay执行的
  1. OneParamMultiDelegate.Broadcast("OneParamMultiDelegate");
复制代码
代理--动态多播

类型选择

同上单播,动态多播好像是可以给蓝图用。
代理的声明


  • 声明代理,动态多播必须用F开头作为标识
  1. DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDynamicMultiDelegate, FString, param);
复制代码

  • 实例化
  1. UPROPERTY(BlueprintAssignable)
  2. FDynamicMultiDelegate DynamicMultiDelegate;
复制代码
使用

因为动态多播可以给蓝图用,所以不需要实现函数并绑定(当然也可以),那就只剩执行了---这里放在Beginplay中了
  1. DynamicMultiDelegate.Broadcast("DynamicMultiDelegate");
复制代码
发射物类

基类选择

Actor
头文件


  • Components/StaticMeshComponent.h(子弹怎么能没有网格体呢?)
  • Components/CapsuleComponent.h(子弹必须有碰撞网格,最好是胶囊体)
  • GameFramework/ProjectileMovementComponent.h(发射物运动组件,发射物必备)
声明
  1. public:
  2.         UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category="MyComponent")
  3.         UStaticMeshComponent* MyBullet;
  4.         UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "MyComponent")
  5.         UCapsuleComponent* MyCapsule;
  6.         UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "MyComponent")
  7.         UProjectileMovementComponent* MyProjectile;
复制代码
定义

在构造方法进行初始化

  • 创建组件并完成挂载
  • 静态加载网格体模型
  • 设置Bullet相对于的根节点大小
  • UMovementComponent提供了一批移动转向相关的函数,其子类负责实现在tick中调用这些函数实现运动逻辑
  • SetupDatedComponent后面跟的就是打算将移动委托给移动组件处理的一个组件
  • InitialSpeed发射瞬间速度,MaxSpeed飞行速度上限,bRotationFollowsVelocity弹头是否使用面朝飞行方向,bIsHomingProjectile是否启用追踪效果,ProjectileGravityScale重力倍率
  1. MyBullet = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MyBulletComponent"));
  2. MyCapsule = CreateDefaultSubobject<UCapsuleComponent>(TEXT("MyCapsuleComponent"));
  3. MyProjectile = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("MyProjectileComponent"));
  4. static ConstructorHelpers::FObjectFinder<UStaticMesh> TmpStaticMesh(TEXT("网格体引用"));
  5. MyBullet->SetStaticMesh(TmpStaticMesh.Object);
  6. MyBullet->SetRelativeScale3D(FVector(0.4, 0.4, 0.4));
  7. RootComponent = MyBullet;
  8. MyCapsule->SetupAttachment(MyBullet);
  9. MyProjectile->SetUpdatedComponent(MyBullet);
  10. MyProjectile->InitialSpeed = 1200.0f;
  11. MyProjectile->MaxSpeed = 2400.f;
  12. MyProjectile->bRotationFollowsVelocity = true;
  13. MyProjectile->bIsHomingProjectile = true;
  14. MyProjectile->ProjectileGravityScale = 1.5f;
复制代码
Character和增强输入

派生方式

派生自一个Character类
Build配置

添加"EnhancedInput"于Build.cs
头文件


  • InputActionValue.h
  • EnhancedInputComponent.h
  • EnhancedInputSubsystems.h
  • GameFramework/Controller.h
  • GameFramework/SpringArmComponent.h
  • Camera/CameraComponent.h
  • GameFramework/CharacterMovementComponent.h
声明


  • 两个摄像机相关组件
  • 一个映射上下文组件(个人理解:老输入映射方式是在项目配置里写,实际上是更类似于宏一样的方式,很死板,增强输入引入一个资产用于保存输入输出映射,这个资产就是UInputMappingContext。而UInputAction就是UInputMappingContext的字段,只不过得写在同级的属性中。)
  1. public:
  2.         UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category="MySceneComponent")
  3.         USpringArmComponent* MySpringArm;
  4.         UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "MySceneComponent")
  5.         UCameraComponent* MyCamera;
  6.         UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
  7.         class UInputMappingContext* DefaultMappingContext;
  8.         UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
  9.         class UInputAction* MoveAction;
  10.         UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
  11.         class UInputAction* LookAction;
  12.         void Move(const FInputActionValue& Value);
  13.         void Look(const FInputActionValue& Value);
复制代码
定义


  • 初始化

    • 创建组件并命名
    • 进行配置

      • 配置相机臂长度
      • 将角色的yaw,poll,pitch,的旋转和摄像机隔离开,方便摄像机环顾而角色朝向独立(ARPG)

    • 将角色朝向锁定到移动的方向

  • BeginPlay

    • 在当前character为玩家控制时,获取输入系统并利用这个子系统将输入方案挂载到玩家上。(个人理解,子系统就是个翻译,它会查UInputMappingContext表并返回输入映射数据)
    • 指定要查的表UInputMappingContext.

  • SetupPlayerInputComponent

    • 绑定函数到表中的两个字段

  • Move

    • Value是在组件内就绑定在委托上的输入了。
    • 获取相机朝向并抽取XOY平面上的朝向
    • 将朝向这个向量拆分成两个X轴和Y轴的分向量,并将移动信息替换到位置信息。

  1. AMyCharacter::AMyCharacter()
  2. {
  3.         // Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
  4.         PrimaryActorTick.bCanEverTick = true;
  5.        
  6.         //创建组件并命名挂载
  7.         MySpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("MySpringArmComponent"));
  8.         MyCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("MyCameraComponent"));
  9.         MyCamera->SetupAttachment(MySpringArm);
  10.         MySpringArm->SetupAttachment(RootComponent);
  11.         /*1. 配置相机臂长度
  12.         1. 将角色的yaw,poll,pitch,的旋转和摄像机隔离开,方便摄像机环顾而角色朝向独立(ARPG)*/
  13.         MySpringArm->TargetArmLength = 400.0f;
  14.         bUseControllerRotationPitch = false;
  15.         bUseControllerRotationYaw = false;
  16.         bUseControllerRotationRoll = false;
  17.         //将角色朝向锁定到移动的方向
  18.         GetCharacterMovement()->bOrientRotationToMovement = true;
  19.         //
  20.         MySpringArm->bUsePawnControlRotation = true;
  21. }
  22. void AMyCharacter::BeginPlay()
  23. {
  24.         Super::BeginPlay();
  25.         if (APlayerController* PlayerController = Cast(Controller))
  26.         {
  27.                 if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
  28.                 {
  29.                         Subsystem->AddMappingContext(DefaultMappingContext,0);
  30.                 }
  31.         }
  32. }
  33. void AMyCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
  34. {
  35.         Super::SetupPlayerInputComponent(PlayerInputComponent);
  36.         if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent))
  37.         {
  38.                 EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AMyCharacter::Move);
  39.                 EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &AMyCharacter::Look);
  40.         }
  41. }
  42. void AMyCharacter::Move(const FInputActionValue& Value)
  43. {
  44.         FVector2D MovementVector = Value.Get<FVector2D>();
  45.         if (Controller!=nullptr)
  46.         {
  47.                 const FRotator Rotation = Controller->GetControlRotation();
  48.                 const FRotator YawRotation(0, Rotation.Yaw, 0);
  49.                 const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
  50.                 const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
  51.                 AddMovementInput(ForwardDirection, MovementVector.Y);
  52.                 AddMovementInput(RightDirection, MovementVector.X);
  53.         }
  54. }
  55. void AMyCharacter::Look(const FInputActionValue& Value)
  56. {
  57.         FVector2D LookAxisVector = Value.Get<FVector2D>();
  58.         if (Controller != nullptr)
  59.         {
  60.                 AddControllerYawInput(LookAxisVector.X);
  61.                 AddControllerPitchInput(LookAxisVector.Y);
  62.         }
  63. }
复制代码
接口

选择类型


  • Interface进行派生
  • MyCharacter类
头文件


  • MyCharacter:Myinterface.h
声明

接口是一个给别的类继承的抽象类,所以只有什么没有定义,定义在其他类
  1. public:
  2.         virtual void Attack() {};
  3.         virtual void CalculateHealth() {};
复制代码
重载声明
  1. class XXXXXXX_API AMyCharacter : public ACharacter,public IMyInterface
  2. {
  3. public:
  4.         virtual void Attack() override;
  5.         virtual void CalculateHealth() override;
  6. }
复制代码
定义
  1. void AMyCharacter::Attack()
  2. {
  3.         IMyInterface::Attack();
  4.         GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("Attack"));
  5. }
  6. void AMyCharacter::CalculateHealth()
  7. {
  8.         IMyInterface::CalculateHealth();
  9.         GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("CalculateHealth"));
  10. }
复制代码
使用

尝试载beginplay中调用。
TimeHndle定时器

派生方式

派生自Scharacter,还是之前的MyCharacter类。
头文件


  • TimeManager.h
声明


  • 声明一个操纵定时器的句柄
  1. FTimerHandle Time;
复制代码
其他配置--回调函数
  1. //声明
  2. void PrintF();
  3. //定义
  4. void AMyCharacter::PrintF()
  5. {
  6.         GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("Time"));
  7. }
复制代码
使用


  • 设置定时器--常在Beginplay里
  • 参数:定时器句柄,this,回调函数,定时器时间长度s,是否循环定时。
  • UWorld中管理着所有定时器,gettimermanager可以返回一个单例,这个单例有存放句柄的素组,这个单例提供了设置定时器句柄数组的方式入SetTimer和ClearTimer.
  1. void AMyCharacter::BeginPlay()
  2. {
  3.         GetWorld()->GetTimerManager().SetTimer(Time, this, &AMyCharacter::PrintF, 1.0, true);
  4.         if(Time.IsValid())
  5.         {
  6.                 GetWorld()->GetTimerManager().ClearTimer(Time);
  7.         }
  8. }
复制代码
3DWidget

派生方式


  • 使用UserWidget进行派生->MyHealthWidget
  • 做出来的控件给MyCharacter类调用
头文件


  • MyCharacter类

    • Components/WidgetComponent.h(用父类指针指向蓝图子类对象)

  • MyHealthWidget

    • 无(因为这里没有使用控件组件,按钮之类的,所有视觉元素都在蓝图中构建的。)

声明


  • MyHealthWidget类
  1. public:
  2.         UPROPERTY(EditAnywhere,BlueprintReadWrite,Category="MyWidget")
  3.         float CurrentHealth=100.0f;
  4.         UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="MyWidget")
  5.         float MaxHealth = 100.0f;
复制代码

  • MyCharacter类
  1. UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "MySceneComponent")
  2. UWidgetComponent* MyWidgetHealth;
复制代码
定义


  • MyHealthWidget类:没有源文件定义,定义(如UI,函数等)写在对应控件蓝图子类中。
  • MyCharacter类

    • 创建一个控件组件并命名且挂载
    • 静态读取资源类引用
    • 配置一个空间蓝图的蓝图类资源句柄到控件组件上,并配置组件的位置,再让UI贴在屏幕上,和缩放。

  1. AMyCharacter::AMyCharacter()
  2. {
  3.         MyWidgetHealth = CreateDefaultSubobject<UWidgetComponent>(TEXT("MyWidgetComponent"));
  4.         MyWidgetHealth->SetupAttachment(RootComponent);
  5.         static ConstructorHelpers::FClassFinder<UUserWidget>WidgetClass(TEXT("蓝图资源引用_C"));
  6.         MyWidgetHealth->SetWidgetClass(WidgetClass.Class);
  7.         MyWidgetHealth->SetRelativeLocation(FVector(0, 0, 100));
  8.         MyWidgetHealth->SetWidgetSpace(EWidgetSpace::Screen);
  9.         MyWidgetHealth->SetDrawSize(FVector2D(400,20));
  10. }
复制代码
Damage相关

派生方式

MyActor
头文件


  • Kismet/GameplayStatic.h
  • MyCharacter.h
声明


  • AMyCharacter--重载并声明TakeDamage方法
  1. virtual float TakeDamage(float DamageAmount,struct FDamageEvent const & DamageEvnt,class AController* EventInstigator,AActor* DamageCause) override;
复制代码
定义


  • AMyCharacter
  1. float AMyCharacter::TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvnt,
  2.         class AController* EventInstigator, AActor* DamageCause)
  3. {
  4.         UMyHealthWidget* MyWidget = Cast<UMyHealthWidget>(MyWidgetHealth->GetUserWidgetObject());
  5.         if (MyWidget)
  6.         {
  7.                 if (MyWidget->CurrentHealth <=0)
  8.                 {
  9.                         return 0.0f;
  10.                 }
  11.                 MyWidget->CurrentHealth -= 5.0;
  12.         }
  13.         return 0.0f;
  14. }
复制代码
使用


  • AMyActor,施加伤害---常用在碰撞事件中.

    • 这是一个用于绑定到6参数委托上的函数
    • 将另外一个Actor尝试转换,如果另一个Actor是MyCharacter那就调用施加伤害的函数
    • 参数:待受伤Actor,伤害数值,伤害施加者的控制器(为空可能来源于陷阱),伤害世家这,上海类型

  1. void AMyActor::BeingOverlapFunction(UPrimitiveComponent* OverlappedComponent,
  2.          AActor* OtherActor,
  3.          UPrimitiveComponent* OtherComp,
  4.          int32 OtherBodyIndex,
  5.          bool bFromSweep,
  6.          const FHitResult& SweepResult)
  7. {
  8.         AMyCharacter* MyCharacter = Cast(OtherActor);
  9.         if(MyCharacter)
  10.         {
  11.                 UGameplayStatics::ApplyDamage(MyCharacter,5.0f,nullptr,this,UDamageType::StaticClass());
  12.         }
  13. }
复制代码
Timeline开关门

派生方式

Actor
头文件


  • Components/BoxComponent.h
  • Components/TimelineComponent.h
  • MyCharacter.h(涉及类型转换,特定类型去触发)
声明



  1. FOnTimelineFloat TimelineDelegate;
  2. FOnTimelineEvent TimelineFinishedDelegate;
  3. UFUNCTION()
  4. void TimelineStart(float value);
  5. UFUNCTION()
  6. void TimelineFinished(float value);
  7. UPROPERTY(EditAnywhere,BlueprintReadWrite,Category = "MySceneComponent")
  8. USceneComponent* MyScene;
  9. UPROPERTY(EditAnywhere,BlueprintReadWrite,Category = "MySceneComponent")
  10. UStaticMeshComponent* MyStaticMesh;
  11. UPROPERTY(EditAnywhere,BlueprintReadWrite,Category ="MySceneComponent")
  12. UBoxComponent* MyBox;
  13. UPROPERTY(EditAnywhere,BlueprintReadWrite,Category = "MyCurve")
  14. UCurveFloat* MyCurveFloat;
  15. UPROPERTY(EditAnywhere,BlueprintReadWrite,Category = "MySceneComponet")
  16. UTimelineComponent* MyTimeline;
  17. UFUNCTION()
  18. void BeginOverlapFunction(
  19.         UPrimitiveComponent* OverlappedComponent,
  20.         AActor* OtherActor,
  21.         UPrimitiveComponent* OtherComp,
  22.         int32 OtherBodyIndex,
  23.         bool bFromSweep,
  24.         const FHitResult& SweepResult);
  25. UFUNCTION()
  26. void EndOverlapFunction(
  27.         UPrimitiveComponent* OverlappedComponent,
  28.         AActor* OtherActor,
  29.         UPrimitiveComponent* OtherComp,
  30.         int32 OtherBodyIndex);
复制代码
定义


  • 构造函数初始化

    • 创建并声明组件MyTimelineComponent,MySene,StaticMesh,Box
    • 静态加载网格体
    • 构建挂载层级
    • 配置碰撞盒的大小,位置

  • BeginPlay进行配置

    • 将帧更新的回调绑定到TimelineStart函数
    • 将播放完成的回调绑定到TimelineFinished函数
    • 使用曲线去驱动浮点量
    • 播放完就停,设置为不循环
    • 设置未从0秒开始播放
    • 设置立即开始播放
    • 把播放结束回调给timeline
    • 绑定两个回调函数到碰撞盒

  1. AMyTimelineActor::AMyTimelineActor()
  2. {
  3.         // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
  4.         PrimaryActorTick.bCanEverTick = true;
  5.         MyTimeline = CreateDefaultSubobject<UTimelineComponent>(TEXT("MyTimelineComponent"));
  6.         MyScene = CreateDefaultSubobject<USceneComponent>(TEXT("MySceneComponent"));
  7.         MyStaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MyStaticMeshComponent"));
  8.         MyBox = CreateDefaultSubobject<UBoxComponent>(TEXT("MyBoxComponent"));
  9.         static ConstructorHelpers::FObjectFinder<UStaticMesh>TmpStaticMesh(TEXT("资源引用"));
  10.         if (TmpStaticMesh.Succeeded())
  11.         {
  12.                 MyStaticMesh->SetStaticMesh(TmpStaticMesh.Object);
  13.         }
  14.         RootComponent = MyScene;
  15.         MyStaticMesh->SetupAttachment(MyScene);
  16.         MyBox->SetupAttachment(MyScene);
  17.         MyBox->SetBoxExtent(FVector(200, 100, 100));
  18.         MyBox->SetRelativeLocation(FVector(200, 0, 0));
  19. }
  20. void AMyTimelineActor::BeginPlay()
  21. {
  22.         Super::BeginPlay();
  23.         TimelineDelegate.BindUFunction(this, TEXT("TimelineStart"));
  24.         TimelineFinishedDelegate.BindUFunction(this, TEXT("TimelineFinished"));
  25.         MyTimeline->AddInterpFloat(MyCurveFloat, TimelineDelegate);
  26.         MyTimeline->SetLooping(false);
  27.         MyTimeline->PlayFromStart();
  28.         MyTimeline->Play();
  29.         MyTimeline->SetTimelineFinishedFunc(TimelineFinishedDelegate);
  30.        
  31.         MyBox->OnComponentBeginOverlap.AddDynamic(this, &AMyTimelineActor::BeginOverlapFunction);
  32.         MyBox->OnComponentEndOverlap.AddDynamic(this, &AMyTimelineActor::EndOverlapFunction);
  33. }
复制代码
其他配置--待绑定函数的定义
  1. void AMyTimelineActor::TimelineStart(float value)
  2. {
  3.         GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("Timelineplay"));
  4.         float YawRotation = FMath::Lerp(0, 90, value);
  5.         MyStaticMesh->SetRelativeRotation(FRotator(0, YawRotation, 0));
  6. }
  7. void AMyTimelineActor::TimelineFinished(float value)
  8. {
  9.         GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("TimelineFinished"));
  10. }
  11. void AMyTimelineActor::BeginOverlapFunction(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
  12.         UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
  13. {
  14.         AMyCharacter* TmpCharacter = Cast(OtherActor);
  15.         if (TmpCharacter)
  16.         {
  17.                 MyTimeline->PlayFromStart();
  18.         }
  19. }
  20. void AMyTimelineActor::EndOverlapFunction(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
  21.         UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
  22. {
  23.         AMyCharacter* TmpCharacter = Cast(OtherActor);
  24.         if (TmpCharacter)
  25.         {
  26.                 MyTimeline->ReverseFromEnd();
  27.         }
  28. }
复制代码
射线检测

派生方式

Actor
声明
  1. FVector StartLocation;
  2. FVector ForwardVector;
  3. FVector EndLocation;
  4. FHitResult HitResult;
复制代码
使用


  • 通道检测

    • 需要起始点位置和起始点朝向,终点位置
    • 进行Visibility通道的射线检测,命中单位写入HitResult中
    • 如果命中了,就获取命中结果中的Actor,并抽取命中的表面点(ImpactPoint)

  1. void AMyCharacter::Tick(float DeltaTime)
  2. {
  3.         Super::Tick(DeltaTime);
  4.         StartLocation = MyCamera->GetComponentLocation();
  5.         ForwardVector = MyCamera->GetForwardVector();
  6.         EndLocation = StartLocation + ForwardVector * 9999;
  7.         bool bHit = GetWorld()->LineTraceSingleByChannel(HitResult, StartLocation, EndLocation, ECC_Visibility);
  8.         if (bHit)
  9.         {
  10.                 AActor* HitActor = HitResult.GetActor();
  11.                 FVector ImpactPoint = HitResult.ImpactPoint;
  12.                 FVector HitLocation = HitResult.Location;
  13.                 GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, FString::Printf(TEXT("%s"), *HitActor->GetName()));
  14.         }
  15. }
复制代码

  • 对象检测

    • 构建射线的发出点和方向,和重点位置
    • 构建对象类型查询列表FCollisionObjectQueryParams实例
    • 想列表添加类型

  1. void AMyCharacter::Tick(float DeltaTime)
  2. {
  3.         Super::Tick(DeltaTime);
  4.         StartLocation = MyCamera->GetComponentLocation();
  5.         ForwardVector = MyCamera->GetForwardVector();
  6.         EndLocation = StartLocation + ForwardVector * 9999;
  7.         FCollisionObjectQueryParams objectType;
  8.         objectType.AddObjectTypesToQuery(ECC_WorldDynamic);
  9.         bool bHit2 = GetWorld()->LineTraceSingleByObjectType(HitResult, StartLocation, EndLocation, objectType);
  10.         if (bHit2)
  11.         {
  12.                 AActor* HitActor2 = HitResult.GetActor();
  13.                 FVector ImpactPoint2 = HitResult.ImpactPoint;
  14.                 FVector HitLocation2 = HitResult.Location;
  15.                 GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, FString::Printf(TEXT("%s"), *HitActor2->GetName()));
  16.         }
  17. }
复制代码
多射线通道检测和对象检测

派生方式

Actor
声明
  1. //射线检测
  2. FVector StartLocation;
  3. FVector ForwardVector;
  4. FVector EndLocation;
  5. //多通道射线检测
  6. TArray<FHitResult> HitResults;
复制代码
使用


  • 多通道检测和单通道检测的区别在于多通道有穿透。
  1. void AMyCharacter::Tick(float DeltaTime)
  2. {
  3.         Super::Tick(DeltaTime);
  4.         StartLocation = MyCamera->GetComponentLocation();
  5.         ForwardVector = MyCamera->GetForwardVector();
  6.         EndLocation = StartLocation + ForwardVector * 9999;
  7.         bool HitMulti = GetWorld()->LineTraceMultiByChannel(HitResults, StartLocation, EndLocation, ECC_Visibility);
  8.         if (HitMulti)
  9.         {
  10.                 for (int32 i = 0;i<HitResults.Num();i++)
  11.                 {
  12.                         AActor* HitMultiActor = HitResults[i].GetActor();
  13.                         FVector HitLocation = HitResults[i].Location;
  14.                         FVector HitImpactPoint = HitResults[i].ImpactPoint;
  15.                         GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, FString::Printf(TEXT("%s"), *HitMultiActor->GetName()));
  16.                 }
  17.         }
  18. }
复制代码

  • 多对象检测
  1. void AMyCharacter::Tick(float DeltaTime)
  2. {
  3.         Super::Tick(DeltaTime);
  4.         StartLocation = MyCamera->GetComponentLocation();
  5.         ForwardVector = MyCamera->GetForwardVector();
  6.         EndLocation = StartLocation + ForwardVector * 9999;
  7.         FCollisionObjectQueryParams objectType;
  8.         objectType.AddObjectTypesToQuery(ECC_WorldStatic);
  9.         bool HitMulti = GetWorld()->LineTraceMultiByObjectType(HitResults, StartLocation, EndLocation, ECC_Visibility);
  10.         if (HitMulti)
  11.         {
  12.                 for (int32 i =0;i<HitResults.Num();i++)
  13.                 {
  14.                         AActor* HitMultiActor = HitResults[i].GetActor();
  15.                         FVector HitLocation = HitResults[i].Location;
  16.                         FVector HitImpactPoint = HitResults[i].ImpactPoint;
  17.                         GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, FString::Printf(TEXT("%s"), *HitMultiActor->GetName()));
  18.                 }
  19.         }
  20. }
复制代码
软引用和同异步资源加载

概念

UE提供了两种引用软引用和应引用

  • 硬引用,拥有资源对象的属性,硬引用被加载在内存中,则被引用的资源也会被载入到内存,如直接的指针,或者TSubclassOf引用,或者组件子对象
  • 软引用,仅存储资源路径,只有在需要时才会被加载到内存中。
派生方式

Actor->派生一个MySoftActor
头文件


  • Engine/AssetManager.h
声明
  1. UPROPERTY(EditAnywhere,BlueprintReadWrite,Category = "Path")
  2. FSoftObjectPath AssetObjectPath;
  3. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Path")
  4. FSoftClassPath AssetClassPath;
  5. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Path")
  6. TSoftObjectPtr AssetObjectPtr;
  7. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Path")
  8. TSoftClassPtr AssetClassPtr;
复制代码
使用

异步加载资源

  • 初始化资源加载的路径
  • 用指针存储待会要异步加载的资源的句柄但是暂时还不加载
  • 通过句柄进行异步加载,仅在GetLoadedAsset()的时候才加载资源
  1. void AMySoftActor::BeginPlay()
  2. {
  3.         Super::BeginPlay();
  4.         FSoftObjectPath Path1 = TEXT("/Script/Engine.StaticMesh'/Game/StarterContent/Props/SM_Chair.SM_Chair'");
  5.         TSharedPtr<FStreamableHandle>SyncStreamHandle = UAssetManager::GetStreamableManager().RequestAsyncLoad(Path1);
  6.         if (SyncStreamHandle)
  7.         {
  8.                 UTexture2D* Image1 = Cast<UTexture2D>(SyncStreamHandle->GetLoadedAsset());
  9.                 if (Image1)
  10.                 {
  11.                         GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, FString::Printf(TEXT("%s"), *Image1->GetName(())));
  12.                 }
  13.         }
  14. }
复制代码
同步加载
  1. void AMySoftActor::BeginPlay()
  2. {
  3.         Super::BeginPlay();  
  4.         FSoftObjectPath Path2 = TEXT("/Script/Engine.StaticMesh'/Game/StarterContent/Props/SM_Chair.SM_Chair'");
  5.         TSharedPtr<FStreamableHandle> SyncStreamHandle = UAssetManager::GetStreamableManager().RequestSyncLoad(Path2);
  6.         if (SyncStreamHandle)
  7.         {
  8.                 UTexture2D* Image2 = Cast<UTexture2D>(SyncStreamHandle->GetLoadedAsset());
  9.                 if (Image2)
  10.                 {
  11.                         GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, FString::Printf(TEXT("%s"), *Image2->GetName()));
  12.                 }
  13.         }
  14. }
复制代码
UE共享指针和引用以及弱指针

派生方式

Actor->派生MySmartPtrActor
辅助工具
  1. class TestA
  2. {
  3. public:
  4.         int a = 0;
  5.         float b = 0;
  6.         TestA()
  7.         {
  8.                 a = 0;
  9.                 b = 0;
  10.         };
  11.         TestA(int a, float b)
  12.         {
  13.                 this->a = a;
  14.                 this->b = b;
  15.         }
  16.         ~TestA()
  17.         {
  18.                 UE_LOG(LogTemp, Warning, TEXT("xigou"));
  19.         };
  20. };
复制代码
使用

共享指针


  • 共享指针时可以初始化为空的并用MakeSharedable进行重新赋值。
  • ESPMode::ThreadSafe可以用于创造线程安全的共享指针,本质上是让操作原子化,保证读取只能读取写入完的数据或者未写入的数据,不存在写了几个字节没写完的数据。
  1. %% 原始的指针需要手动delete %%
  2. TestA* ptr1 = new TestA(1,2.0f);
  3. %% 用裸指针左值赋值共享指针,可能会导致裸指针释放后共享指针再次释放 %%
  4. TSharedPtr<TestA> Sharedptr2(ptr1);
  5. ptr1 = nullptr;
  6. %% 共享指针右值初始化,资源在创建的时候理解被共享指针接管,无所有权歧义 %%
  7. TSharedPtr<TestA>Sharedptr3(new TestA(3, 4.0f));
  8. %% 拷贝构造函数初始化,同类数据左值传入 %%
  9. TSharedPtr<TestA>Sharedptr4(Sharedptr3);
  10. %% UE的方式初始化共享指针,共享指针时可以初始化未空的,通过MakeShareable再赋值 %%
  11. TSharedPtr<TestA>Sharedptr5 = nullptr;
  12. Sharedptr5 = MakeShareable(new TestA(5, 6.0f));
  13. %% 线程安全的共享指针 %%
  14. TSharedPtr<TestA, ESPMode::ThreadSafe>Sharedptr6(new TestA(7, 8.0f));
复制代码

  • SharedRef创建一个共享引用。
  • SharedPtr类的ToSharedRef方法可以创建指向数据的一个引用并返回
  • SharedPtr类的GetSharedReferenceCount可以获取引用数
  • IsUnique判断是否引用计数为1
  • Get方法获取裸指针
  • Reset()将指针充值为nullptr,并将引用计数减一。本质上来说是让此共享指针放弃所有权。
  1. if (Sharedptr5.IsValid())
  2. {
  3.         TSharedRef<TestA>SharedRef1(new TestA(9, 10.0));
  4.         SharedRef1 = Sharedptr5.ToSharedRef();
  5.         int32 Count1 = Sharedptr5.GetSharedReferenceCount();//获取引用计数
  6.         UE_LOG(LogTemp, Warning, TEXT("Count1 is %d"), Count1);
  7.         if (!Sharedptr5.IsUnique())
  8.         {
  9.                 UE_LOG(LogTemp, Warning, TEXT("sharedptr is not unique"));
  10.         }
  11.         Sharedptr5.Get()->a;//Get方法解引用。
  12.         UE_LOG(LogTemp, Warning, TEXT("sharedptr is %d"), Sharedptr5.Get()->a);
  13.         Sharedptr5.Reset();//把共享指针包裹的裸指针置为null。
  14.         int32 Count2 = Sharedptr5.GetSharedReferenceCount();
  15.         UE_LOG(LogTemp, Warning, TEXT("Count2 is %d"), Count2);
  16. }
复制代码
共享引用


  • 类似于引用,是不存在空这种状态的。
  • 底层实现和共享指针完全一样,所以还是用->解引用
  • 共享引用转共享指针无开销
  1. %% 共享引用初始化时必须指向一个有效的对象 %%
  2. TSharedRef<TestA> SharedRef2(new TestA(7, 8.0f));
  3. if (SharedRef2.IsUnique())
  4. {
  5.         %% 共享引用也用指针访问 %%
  6.         SharedRef2->a;
  7.         UE_LOG(LogTemp, Warning, TEXT("Sharedref2a is %"), SharedRef2->a);
  8.         %% 共享引用->共享指针 %%
  9.         TSharedPtr<TestA> SharedPtr6;
  10.         SharedPtr6 = SharedRef2;
  11.         SharedPtr6.Get()->b;
  12.         UE_LOG(LogTemp, Warning, TEXT("Sharedptr6 b is %f"), SharedPtr6.Get()->b);
  13. }
复制代码
弱指针


  • 弱指针用于循环引用,可以不占用引用计数
  • 不能组织对象被销毁
  • 在堆上创建一个数据并用共享指针指向。
  • 创建一个引用,应用着堆上一个对象
  • 声明弱指针,指向两个指针的数据,不拥有,只查看
  • 判断对象是否存活,强引用计数大于0才存活
  • Pin用于提升弱指针到强指针,只要pin时对象存在就会将引用计数加一并返回共享指针。
  1. %% 弱指针解决了循环引用,只对弱指针保留引用权,不增加引用计数 %%
  2. %% 不能阻止对象被销毁。 %%
  3. TSharedPtr<TestA>Sharedptr7 = MakeShareable(new TestA(10, 11.0f));
  4. TSharedRef<TestA>SharedRef3(new TestA(12, 13.0f));
  5. //声明弱指针
  6. TWeakPtr<TestA>WeakPtr1(Sharedptr7);
  7. TWeakPtr<TestA>WeakPtr2(SharedRef3);
  8. if (WeakPtr1.IsValid())
  9. {
  10.         TSharedPtr<TestA>Sharedptr8(WeakPtr1.Pin());
  11.         if (Sharedptr8.IsValid())
  12.         {
  13.                 Sharedptr8.Get()->a;
  14.                 UE_LOG(LogTemp, Warning, TEXT("Sharedptr8a is %d"), Sharedptr8.Get()->a);
  15.         }
  16. }
复制代码
常用函数

派生方式

这里用的Actor,但是并不重要,这里是函数的列表查看吧。
头文件


  • Kismet/GameplayStatics.h
声明
  1. public:
  2.         UFUNCTION(BlueprintCallable,Category="MyTestFunction")
  3.         void MyOpenlevel();
  4.         UFUNCTION(BlueprintCallable, Category = "MyTestFunction")
  5.         void MyCurrentLevelName();
  6.         UFUNCTION(BlueprintCallable, Category = "MyTestFunction")
  7.         void MyQuitGame();
复制代码
定义


  • BeginPlay

    • GetAllActorOfClass():查找关卡世界中所有StaticClass类的对象并塞入OutActors容器。
    • 遍历并输出容器中actor的名称

  • MyOpenLevel

    • 打开名称指定的地图

  • MyCurrentLevelName

    • 获取当前关卡的名称并输出

  • MyQuitGame

    • 调用退出游戏命令。

  1. void AMyFunctionLibraryActor::BeginPlay()
  2. {
  3.         Super::BeginPlay();
  4.         TArrayOutActors;
  5.         UGameplayStatics::GetAllActorsOfClass(GetWorld(), AActor::StaticClass(), OutActors);
  6.         for (int32 i =0;i<OutActors.Num();i++)
  7.         {
  8.                 UE_LOG(LogTemp, Warning, TEXT("Actor is %s"), *OutActors[i]->GetName());
  9.         }
  10. }
  11. void AMyFunctionLibraryActor::MyOpenLevel()
  12. {
  13.         UGameplayStatics::OpenLevel(GetWorld(), TEXT("关卡名称"));
  14. }
  15. void AMyFunctionLibraryActor::MyCurrentLevelName()
  16. {
  17.         FString MyCurrentLevelName = UGameplayStatics::GetCurrentLevelName(GetWorld());
  18.         GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, FString::Printf(TEXT("MyCurrentLevelName is %s"), *MyCurrentLevelName));
  19. }
  20. void AMyFunctionLibraryActor::MyQuitGame()
  21. {
  22.         UGameplayStatics::GetPlayerController(GetWorld(), 0)->ConsoleCommand("quit");
  23. }
复制代码
字符串操作

派生方式

Actor->派生MyStringActor
头文件


  • Kismet/KismetStringLibrary.h
使用


  • 查看是否存在指定字符
  1. %% 查找字符串是否包含指定字符。 %%
  2. bool isFind1 = MyString.Contains("b", ESearchCase::IgnoreCase, ESearchDir::FromStart);
  3. bool isFind2 = UKismetStringLibrary::Contains(MyString, "b", ESearchCase::CaseSensitive, ESearchDir::FromStart);
复制代码

  • 判断两子妇产是否相等
  1. bool isFind3 = MyString.Equals("123");
复制代码

  • 拼接字符串
  1. FString MyString2 = MyString.Append("OBJ");
复制代码

  • 字符串长度
  1. int32 Num = MyString.Len();
  2. int32 Num2 = UKismetStringLibrary::Len(MyString);
复制代码

  • 字符串是否为空
  1. bool isEmpty = MyString.IsEmpty();
复制代码

  • 从指定位置开始的字符串返回一个子字符串
  1. FString MyChildString = UKismetStringLibrary::GetSubstring(MyString,0,3);
复制代码

  • 查看字符串中的子字符串的起始索引
  1. int32 Index1 = UKismetStringLibrary::FindSubstring(MyString,"123",false,false,0);
复制代码

  • 返回第几个字符的ascaii吗
  1. int32 Index2 = UKismetStringLibrary::GetCharacterAsNumber(MyString,0);
复制代码

  • 返回一个数组
  1. TArray<FString>MyArrayString;
  2. MyArrayString = UKismetStringLibrary::GetCharacterArrayFromString(MyString);
复制代码

  • 大写化
  1. FString MyUpperString = MyString.ToUpper();
复制代码

  • 小写化
  1. FString MyLowerString = MyString.ToLower();
复制代码

  • 在字符串左右侧填充指定数量字符
  1. FString MyLeftpadString = MyString.LeftPad(3);
  2. FString MyRightpadString = MyString.RightPad(3);
复制代码

  • 检查字符串中是否包含数字字符
  1. bool IsNumber = MyString.IsNumeric();
复制代码

  • 测试字符串是否以给定的字符串为开头或者结尾
  1. bool isStart = MyString.StartsWith("abcd",ESearchCase::IgnoreCase);
  2. bool isEnd = MyString.EndsWith("1234",ESearchCase::IgnoreCase);
复制代码

  • 字符串替换,将a换成$
  1. UKismetStringLibrary::Replace(MyString,"a","$",ESearchCase::IgnoreCase);
复制代码

  • 返回最左边或最右边给定的字符数
  1. UKismetStringLibrary::Left(MyString,2);
  2. UKismetStringLibrary::Right(MyString,2);
复制代码

  • 返回最左边或者最右边给定的字符数,从末尾切掉给定数量的字符
  1. UKismetStringLibrary::LeftChop(MyString,1);
  2. UKismetStringLibrary::RightChop(MyString,2);
复制代码

  • 从起始位置返回count个字符的子字符串
  1. UKismetStringLibrary::Mid(MyString,2,3);
复制代码

  • 分割出左右俩字符串
  1. FString Left;
  2. FString Right;
  3. MyString.Split("_",&Left,&Right,ESearchCase::IgnoreCase,ESearchDir::FromStart);
复制代码

  • 从分割符划分的元字符中获取字符串数组,并可选择剔除空字符
  1. TArray<FString> MyStringArrayParse;
  2. MyString.ParseIntoArray(MyStringArrayParse,TEXt("_"),true);
  3. for(auto TestArray:MyStringArrayParse){
  4.         GEngine->AddOnScreenDebugMessage(-1,5.0f,FColor::Red,FString::Printf(TEXT("%s"),*TestArray));
  5. }
复制代码
动态材质实例

派生方式

Actor->MyMaterialActor
头文件


  • "Components/StaticMeshComponent.h"
  • "UObject/ConstructorHelpers.h"
声明
  1. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category="MySceneComponent")
  2. class USceneComponent* MyScene;
  3. UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category="MySceneComponent")
  4. class UStaticMeshComponent* MyMesh;
  5. UMaterialInstanceDynamic* DynamicMaterial;
复制代码
定义


  • AMyMaterialActor

    • 创建组件USceneComponent,和StaticMeshComponent并命名和挂载
    • 通过FObjectfinder同步加载网格资源到网格体组件上

  • BeginPlay()

    • beginplay是运行时了,这里是运行时加载一个资产并生成材质
    • 为网格体贴上材质并生成一个材质句柄返回
    • 调整材质的两个参数

  1. AMyMaterialActor::AMyMaterialActor()
  2. {
  3.         // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
  4.         PrimaryActorTick.bCanEverTick = true;
  5.         MyScene = CreateDefaultSubobject<USceneComponent>(TEXT("MyCustomScene"));
  6.         MyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MyCustomStaticMesh"));
  7.         RootComponent = MyScene;
  8.         MyMesh->SetupAttachment(MyScene);
  9.         static ConstructorHelpers::FObjectFinder<UStaticMesh>TempStaticMesh(TEXT("/Script/Engine.StaticMesh'/Game/StarterContent/Shapes/Shape_TriPyramid.Shape_TriPyramid'"));
  10.         MyMesh->SetStaticMesh(TempStaticMesh.Object);
  11. }
  12. // Called when the game starts or when spawned
  13. void AMyMaterialActor::BeginPlay()
  14. {
  15.         Super::BeginPlay();
  16.         UMaterialInterface* Material = LoadObject<UMaterialInterface>(nullptr, TEXT("/Script/Engine.Material'/Game/M_testMaterial.M_testMaterial'"));
  17.         DynamicMaterial = MyMesh->CreateDynamicMaterialInstance(0, Material);
  18.         DynamicMaterial->SetVectorParameterValue("BaseColor", FLinearColor::Red);
  19.         DynamicMaterial->SetScalarParameterValue("BaseMetallic", 1);
  20. }
复制代码
文件操作

派生方式

BlueprintFunctionLibrary->派生
头文件


  • "Engine/Engine.h"
  • "Misc/FileHelper.h"
  • Runtime/Core/Public/HAL/FileManagerGeneric.h(处理文件夹)
声明
  1. public:
  2.         UFUNCTION(BlueprintCallable, Category="File")
  3.         static bool LoadStringFromFIle(FString FilePath, FString& ResultString);
  4.         UFUNCTION(BlueprintCallable, Category="File")
  5.         static bool WriteStringToFile(TArray<FString>SaveFile, FString FIlePath);
  6.         UFUNCTION(BlueprintCallable,Category="File")
  7.         static FString GetFilePath(FString Path);
  8.         UFUNCTION(BlueprintCallable,Category = "File")
  9.         static FString GetFileName(FString InPath,bool bRemoveForwardPath);
  10.         UFUNCTION(BlueprintCallable,Category="File")
  11.         static FString GetFileExtension(FString InPath, bool bIncludeDot);
  12.         UFUNCTION(BlueprintCallable,Category="File")
  13.         static void CreateFolder(FString FolderName);
  14.         UFUNCTION(BlueprintCallable, Category="FIle")
  15.         static void RemoveFolder(FString FolderName);
  16.         UFUNCTION(BlueprintCallable,Category="FIle")
  17.         static bool MoveFileTo(FString To, FString From);
  18.         UFUNCTION(BlueprintCallable,Category="File")
  19.         static TArray<FString> FindFileFolder(FString Path,FString FileType,bool Files,bool Folders);
复制代码
定义
  1. bool UMyBlueprintFunctionLibrary::LoadStringFromFIle(FString FilePath, FString& ResultString)
  2. {
  3.         if (!FilePath.IsEmpty())
  4.         {
  5.                 if (FFileHelper::LoadFileToString(ResultString,*FilePath))
  6.                 {
  7.                         return true;
  8.                 }
  9.                 else
  10.                 {
  11.                         GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("error"));
  12.                 }
  13.         }
  14.         return false;
  15. }
  16. bool UMyBlueprintFunctionLibrary::WriteStringToFile(TArray<FString>SaveFile, FString FIlePath)
  17. {
  18.         if (!FIlePath.IsEmpty())
  19.         {
  20.                 if (FFileHelper::SaveStringArrayToFile(SaveFile,*FIlePath))
  21.                 {
  22.                         return true;
  23.                 }
  24.                 else
  25.                 {
  26.                         GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("error"));
  27.                 }
  28.         }
  29.         return false;
  30. }
  31. FString UMyBlueprintFunctionLibrary::GetFilePath(FString Path)
  32. {
  33.         FString result;
  34.         result = FPaths::GetPath(*Path);
  35.         return result;
  36. }
  37. FString UMyBlueprintFunctionLibrary::GetFileName(FString InPath, bool bRemoveForwardPath)
  38. {
  39.         return FPaths::GetBaseFilename(*InPath, bRemoveForwardPath);
  40. }
  41. FString UMyBlueprintFunctionLibrary::GetFileExtension(FString InPath, bool bIncludeDot)
  42. {
  43.         return FPaths::GetExtension(*InPath, bIncludeDot);
  44. }
  45. void UMyBlueprintFunctionLibrary::CreateFolder(FString FolderName)
  46. {
  47.         FString Path = FPaths::ProjectContentDir() / *FolderName;
  48.         FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*Path);
  49. }
  50. void UMyBlueprintFunctionLibrary::RemoveFolder(FString FolderName)
  51. {
  52.         FString Path1 = FPaths::ProjectContentDir() / *FolderName;
  53.         FPlatformFileManager::Get().GetPlatformFile().DeleteDirectoryRecursively(*Path1);
  54. }
  55. bool UMyBlueprintFunctionLibrary::MoveFileTo(FString To, FString From)
  56. {
  57.         return IFileManager::Get().Move(*To, *From);
  58. }
  59. TArray<FString> UMyBlueprintFunctionLibrary::FindFileFolder(FString Path, FString FileType, bool Files, bool Folders)
  60. {
  61.         TArray<FString> OutPathList;
  62.         OutPathList.Empty();
  63.         FFileManagerGeneric::Get().FindFilesRecursive(OutPathList, *Path, *FileType, Files, Folders);
  64.         return OutPathList;
  65. }
复制代码
Delay实现函数

派生方式

Actor->MyMaterialActor
头文件


  • Kismet/KismetSystemLibrary.h
声明
  1. public:
  2.         UFUNCTION()
  3.         void DelayFunctionFinish();
复制代码
使用


  • UE通过this指针和DelayFunctionFinish这个字符串反射找到UFunction中AMyMaterialActor:elayFunctionFinish方法,再在Delay中延时回调。
  • 我只能说UE为了兼容蓝图整的操作真心有点看不懂。
  1. void AMyMaterialActor::BeginPlay()
  2. {
  3.         Super::BeginPlay();
  4.         const FLatentActionInfo LatentInfo(0, FMath::Rand(), TEXT("DelayFunctionFinish"), this);
  5.         UKismetSystemLibrary::Delay(this,1.0f ,LatentInfo);
  6. }
复制代码
其他配置--待回调函数
  1. void AMyMaterialActor::DelayFunctionFinish()
  2. {
  3.         GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("Delay Finished"));
  4. }
复制代码
Destory

派生方式

Actor-->MyActor
头文件


使用


  • 放在碰撞函数中,调用就销毁Actor。
  1. void AMyActor::BeingOverlapFunction(
  2.         UPrimitiveComponent* OverlappedComponent,
  3.         AActor* OtherActor,
  4.         UPrimitiveComponent* OtherComp,
  5.         int32 OtherBodyIndex,
  6.         bool bFromSweep,
  7.         const FHitResult& SweepResult)
  8. {
  9.         Destory();
  10. }
复制代码

  • 调用就销毁指定Component
  1. void AMyActor::BeingOverlapFunction(
  2.         UPrimitiveComponent* OverlappedComponent,
  3.         AActor* OtherActor,
  4.         UPrimitiveComponent* OtherComp,
  5.         int32 OtherBodyIndex,
  6.         bool bFromSweep,
  7.         const FHitResult& SweepResult)
  8. {
  9.         MyParticle->DestroyComponent();
  10. }
复制代码
JSON文件解析

引入模块
  1. PrivateDependencyModuleNames.AddRange(new string[]{"Json","JsonUtilities"});
复制代码
派生方式

BlueprintFunctionLibrary-->MyBlueprintFunctionLibrary
声明
  1. UFUNCTION(BlueprintCallable,Category="Json")
  2. static void ReadJson(FString JsonValueString);
  3. UFUNCTION(BlueprintCallable,Category = "JsonToMap")
  4. static TMap<FString, FString> JsonToMap(FString JsonValueString);
  5. UFUNCTION(BlueprintCallable,Category = "MapToJson")
  6. static FString MapToJson(TMap<FString, FString> InMap);
复制代码
定义

读取Json


  • JSonReaderFactory::Create是一个工厂函数,返回一个FString的Json读取器
  • 创建一个根对象,并对读取器进行反序列化到根对象上。
  • 利用根对象获取其中的数据。
  1. void UMyBlueprintFunctionLibrary::ReadJson(FString JsonValueString)
  2. {
  3.         TSharedRef<TJsonReader<TCHAR>> JsonReader = TJsonReaderFactory<TCHAR>::Create(JsonValueString);//通过jsonreader工厂创建一个解析器
  4.         TSharedPtr<FJsonObject> JsonObject;
  5.         bool isOk = FJsonSerializer::Deserialize(JsonReader, JsonObject);
  6.         if (isOk)
  7.         {
  8.                 int32  code = JsonObject->GetIntegerField("code");
  9.                 FString msg = JsonObject->GetStringField("msg");
  10.                 TSharedPtr<FJsonObject> DataObject = JsonObject->GetObjectField("data");
  11.                 FString MyUserName = DataObject->GetStringField("username");
  12.                 FString MyUserID = DataObject->GetStringField("userid");
  13.                 FString MyToken = DataObject->GetStringField("token");
  14.                 GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, FString::Printf(TEXT("%d"), code));
  15.                 GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, FString::Printf(TEXT("%s"), *msg));
  16.                 GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, FString::Printf(TEXT("%s"), *MyUserName));
  17.         }
  18. }
复制代码
JsonToMap


  • 使用json工厂函数创建json读取器,并序列化创建根对象。
  • 创建一个数据结构,将对象的key作为key,用指针直接指向对象中的数据。
  • 遍历数据结构,并通过指向对象中数据的指针取数据,并添加到结果中。
  1. TMap<FString, FString> UMyBlueprintFunctionLibrary::JsonToMap(FString JsonValueString)
  2. {
  3.         TMap<FString, FString> result;
  4.         TSharedRef<TJsonReader<TCHAR>> JsonReader = TJsonReaderFactory<TCHAR>::Create(JsonValueString);
  5.         TSharedPtr<FJsonObject> JsonObject;
  6.         bool isOk = FJsonSerializer::Deserialize(JsonReader, JsonObject);
  7.         if (isOk)
  8.         {
  9.                 TMap<FString, TSharedPtr<FJsonValue>> keys = JsonObject->Values;
  10.                 for (auto currJson = keys.CreateIterator();currJson;++currJson)
  11.                 {
  12.                         FString key = (*currJson).Key;
  13.                         FString value = JsonObject->GetStringField(key);
  14.                         result.Add(key, value);
  15.                 }
  16.         }
  17.         return result;
  18. }
复制代码
MapToJson


  • 用一个工厂函数创建一个写入器并指定写入的目标。
  • 创建一个数组存放keys,通过遍历数组,获取key对应的value,并将key和value写入字符串中。
  • TCondensedJsonPrintPolicy是压缩策略(不缩进,不换行,体积最小,最不可读),TPrettyJsonPrintPolicy会带缩进。
  1. FString UMyBlueprintFunctionLibrary::MapToJson(TMap<FString, FString> InMap)
  2. {
  3.         FString JsonStr;
  4.         TSharedRef<TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR>>>JsonWriter = TJsonWriterFactory<TCHAR, TCondensedJsonPrintPolicy<TCHAR>> ::Create(&JsonStr);
  5.         JsonWriter->WriteObjectStart();
  6.         TArray<FString> keys;
  7.         InMap.GetKeys(keys);
  8.         for (size_t i=0;i<keys.Num();i++)
  9.         {
  10.                 FString* value = InMap.Find(keys[i]);
  11.                 JsonWriter->WriteValue(keys[i], *value);
  12.         }
  13.         JsonWriter->WriteObjectEnd();
  14.         JsonWriter->Close();
  15.         return JsonStr;
  16. }
复制代码
其他配置

实例json
  1. {
  2.         "code":200,
  3.         "msg":"成功",
  4.         "data":{
  5.                 "username":"zhangsan",
  6.                 "userid":'123456',
  7.                 "token":"adadadsdawdsadw47dad2sd5a4d"
  8.         }
  9. }
复制代码
GameInstanceSubsystem

派生方式

GameInstanceSubsystem--->MyGameInstanceSubsystem(本质上就是一个全局的单例)
头文件


声明
  1. public:
  2.         virtual bool ShouldCreateSubsystem(UObject* Outer) const override;
  3.         virtual void Initialize(FSubsystemCollectionBase& Collection) override;
  4.         virtual void Deinitialize() override;
  5.         static UMyGameInstanceSubsystem* MyInstanceSubsystem;
  6.         UFUNCTION(BlueprintCallable, Category= "MyTestSubsystem")
  7.         static UMyGameInstanceSubsystem* Get();
  8.         UFUNCTION(BlueprintCallable,Category = "MyTestSubsystem")
  9.         void  StartThread();
  10.         UFUNCTION(BlueprintCallable, Category = "MyTestSubsystem")
  11.         void StopThread();
复制代码
定义


  • Subsystem用单例实现,单例不需要构造方法,它需要一个指向自己的指针MyInstanceSubsystem并设置为nullptr。
  • shouldCreateSubsystem,Initialize,Deinitialize方法。并在初始化中将本实例赋值给指向自己的指针。这三个函数由UE引擎负责调用(因为gamemode和level是关卡级的,而gameinstance和subsystem是游戏级的),游戏开始根据前者决定是否init,游戏结束调用deinit。
  1. UMyGameInstanceSubsystem* UMyGameInstanceSubsystem::MyInstanceSubsystem = nullptr;
  2. bool UMyGameInstanceSubsystem::ShouldCreateSubsystem(UObject* Outer) const
  3. {
  4.         return true;
  5. }
  6. void UMyGameInstanceSubsystem::Initialize(FSubsystemCollectionBase& Collection)
  7. {
  8.         Super::Initialize(Collection);
  9.         MyInstanceSubsystem = this;
  10.         UE_LOG(LogTemp, Warning, TEXT("Initialize MyGameInstance MySubsystem"));
  11. }
  12. void UMyGameInstanceSubsystem::Deinitialize()
  13. {
  14.         Super::Deinitialize();
  15.         UE_LOG(LogTemp,Warning,TEXT("Deinitialize MyGameInstance MySubsystem"))
  16. }
  17. UMyGameInstanceSubsystem* UMyGameInstanceSubsystem::Get()
  18. {
  19.         return MyInstanceSubsystem;
  20. }
  21. void UMyGameInstanceSubsystem::StartThread()
  22. {
  23.         UE_LOG(LogTemp, Warning, TEXT("StartThread MyGameInstanceSubsystems"));
  24. }
  25. void UMyGameInstanceSubsystem::StopThread()
  26. {
  27.         UE_LOG(LogTemp, Warning, TEXT("StopThread MyGameInstanceSubsystems"));
  28. }
复制代码
多线程--FRunnable和FRunnableThread

派生方式

None-->MyRunnable,并将方法和类前加上F前缀。并让类继承自FRunnable
  1. class COOPGAME_API FMyRunnable:public FRunnable
  2. {
  3. public:
  4.         FMyRunnable();
  5.         ~FMyRunnable();
  6. };
复制代码
GameInstance
头文件


  • MyRunnable

    • HAL/Runnable.h
    • HAL/ThreadSafeBool.h
    • MyGameInstanceSubsystem.h(Subsystem是进程级的,常用在多线程中)

  • MyGameInstanceSubsystem

    • MyRunnable.h

声明

MyRunnable

将一个FRunnable类派生的线程对象传入FRunnableThread::Create(),这个对象会自动调用其Init的函数,再根据init函数结果的真假决定调用Run函数与否(所以需要重载)
  1. public:
  2.         FMyRunnable();
  3.         FMyRunnable(FString InThreadName);
  4.         ~FMyRunnable();
  5.         virtual bool Init() override;
  6.         virtual uint32 Run() override;
  7.         virtual void Stop() override;
  8.         virtual void Exit() override;
  9.         FString ThreadName;
  10.         bool IsRunning;
复制代码
MyGameInstanceSubsystem
  1. protected:
  2.         TSharedPtr<FMyRunnable> MyRunnable;
  3.         FRunnableThread* MyRunnableThread;
复制代码
定义

MyRunnable

MyRunnable这个类,负责多线程需要执行的一个函数,类似于单独存在的线程(消息队列).

  • Run方法

    • 调整InRunning并进入循环,每三秒获取一次单例对象Instance。

  1. FMyRunnable::FMyRunnable()
  2. {
  3.         UE_LOG(LogTemp,Warning,TEXT("Constructor Function0"))
  4. }
  5. FMyRunnable::FMyRunnable(FString InThreadName):ThreadName(InThreadName)
  6. {
  7.         UE_LOG(LogTemp, Warning, TEXT("Constructor Function1"))
  8. }
  9. FMyRunnable::~FMyRunnable()
  10. {
  11.         UE_LOG(LogTemp, Warning, TEXT("DeConstructor Function0"))
  12. }
  13. bool FMyRunnable::Init()
  14. {
  15.         UE_LOG(LogTemp, Warning, TEXT("Init Runnable "));
  16.         return true;
  17. }
  18. uint32 FMyRunnable::Run()
  19. {
  20.         IsRunning = true;
  21.         while (IsRunning)
  22.         {
  23.                 FPlatformProcess::Sleep(3.0);
  24.                 UMyGameInstanceSubsystem* Instance = UMyGameInstanceSubsystem::Get();
  25.                 if (Instance)
  26.                 {
  27.                         UE_LOG(LogTemp, Warning, TEXT("Run Thread"));
  28.                 }
  29.         }
  30.         return uint32();
  31. }
  32. void FMyRunnable::Stop()
  33. {
  34.         IsRunning = false;
  35.         UE_LOG(LogTemp, Warning, TEXT("Stop Thread"));
  36. }
  37. void FMyRunnable::Exit()
  38. {
  39.         UE_LOG(LogTemp,Warning,TEXT("Exit Thread"))
  40. }
复制代码
MyGameInstanceSubsystem

MyGameInstanceSubsystem负责线程的创建,以及线程中运行的功能。

  • StartThread

    • 通过FMyRunnable的构造方法创建一个对象
    • 使用FRunnableThread::Create(线程体,线程名),将一个FRunnable类派生的线程对象传入FRunnableThread::Create(),这个对象会自动调用其Init的函数,再根据init函数结果的真假决定调用Run函数与否(所以需要重载)

  • StopThread()

    • 在线程对象合法时停止线程
    • 在线程池合法时等待线程结束并删除线程,并将线程置为null.

  1. void UMyGameInstanceSubsystem::StartThread()
  2. {
  3.         //创建对象
  4.         MyRunnable = MakeShared<FMyRunnable>(TEXT("MyRunnable"));
  5.         //创建线程
  6.         MyRunnableThread = FRunnableThread::Create(MyRunnable.Get(),*(MyRunnable->ThreadName));
  7.         UE_LOG(LogTemp, Warning, TEXT("StartThread MyGameInstanceSubsystems"));
  8. }
  9. void UMyGameInstanceSubsystem::StopThread()
  10. {
  11.         if (MyRunnable.IsValid())
  12.         {
  13.                 MyRunnable->Stop();
  14.         }
  15.         if (MyRunnableThread)
  16.         {
  17.                 MyRunnableThread->WaitForCompletion();
  18.                 delete MyRunnableThread;
  19.                 MyRunnableThread = nullptr;
  20.         }
  21.         UE_LOG(LogTemp, Warning, TEXT("StopThread MyGameInstanceSubsystems"));
  22. }
复制代码
多线程--AsyncTask

派生方式

None-->FMyAsyncTask
Actor-->MyAsyncTestActor(测试用)
头文件

FMyAsyncTask

  • Async/AsyncWork.h
    MyAsyncTestActor
  • FMyAsyncTask.h
声明


  • FNonAbandonableTask告诉线程池,此任务不可以被取消,必须dowork完才嗯释放
  • 通过友元声明将此类列入到线程管家(估计也是某个类)的友元中,让它可以访问此类的私有和受保护方法。
  • FORCENOINLINE用于强制要求编译器不可以使用内联策略(如某个函数只有一行代码运算,编译器通过内联策略,将这个函数取消替换成一行别的代码,提升了性能,但也无法从堆栈分析调试了)
  • RETURN_QUICK_DECLARE_CYCLE_STAT本质上就是返回此函数的一个生成的id(程序运行前就创建了)用于计时此线程的耗时。(两个参数分别是任务名称和任务ID)
  1. class COOPGAME_API FMyAsyncTask : public FNonAbandonableTask
  2. {
  3.         friend class FAutoDeleteAsyncTask<FMyAsyncTask>;
  4. public:
  5.         FMyAsyncTask();
  6.         ~FMyAsyncTask();
  7. public:
  8.         void DoWork();
  9.         FORCENOINLINE TStatId GetStatId() const
  10.         {
  11.                 RETURN_QUICK_DECLARE_CYCLE_STAT(FMyAsyncTask,STATGROUP_ThreadPoolAsyncTasks);
  12.         }
  13.         FORCENOINLINE static const TCHAR* GetTaskName()
  14.         {
  15.                 return TEXT("FMyAsyncTask");
  16.         }
  17. };
复制代码
定义
  1. FMyAsyncTask::~FMyAsyncTask()
  2. {
  3.         UE_LOG(LogTemp, Warning, TEXT("AsyncTask End>>>>>>>>>>>>>>"));
  4. }
  5. void FMyAsyncTask::DoWork()
  6. {
  7.         UE_LOG(LogTemp,Warning,TEXT("AsyncTask Start>>>>>>>>"));
  8.         for (int32 i=0;i<1000;i++)
  9.         {
  10.                 UE_LOG(LogTemp, Warning, TEXT("i=%d"),i);
  11.         }
  12. }
复制代码
多线程--Async

派生方式

Actor-->MyAsyncTaskActor
头文件

Async/Async.h
使用
  1. void AMyAsyncTaskActor::BeginPlay()
  2. {
  3.         Super::BeginPlay();
  4.         FAutoDeleteAsyncTask<FMyAsyncTask>* MyTask = new FAutoDeleteAsyncTask<FMyAsyncTask>();
  5.         MyTask->StartBackgroundTask();//异步线程
  6. //        MyTask->StartSynchronousTask();//当前线程
  7. }
复制代码
多线程--综述


  • AsyncTask:是一个模板类,创建按在后台线程运行的任务,它可以在任务完成后自动删除自己,很适合用于创建按一次性的异步任务。例如用于加载资源,或者进行一次复杂的计算,或者http请求后端资源。
  • Async:是一个函数,用于后台线程运行一个Lambda表达式,很适合创建简单的异步任务,如加载资源和一次复杂的计算。
  • FRunnable:是一个接口,用于创建一个在单独线程上运行的任务,它需要手动管理生命周期,适合复杂任务。例如WebSocket做与后端的长连接,长时间任务。
编码处理--Base64

我现在感觉之前网上到处找第三方实现的我像个傻叉,不过我感觉也不怪我,U++相关的api介绍真的挺少,官方的API介绍太简洁且API又太多,谁会乐意每次差一个api等半天浏览器响应呢?
声明
  1. void AMyAsyncTaskActor::BeginPlay()
  2. {
  3.         Super::BeginPlay();
  4.         Async(EAsyncExecution::ThreadPool, []
  5.                 {
  6.                         for (int32 i = 0; i < 1000; ++i)
  7.                         {
  8.                                 UE_LOG(LogTemp, Warning, TEXT("i=%d"), i);
  9.                         }
  10.                 });
  11.        
  12. }
复制代码
定义
  1. //字符串到base64
  2. UFUNCTION(BlueprintPure, Category = "CommonLibrary")
  3. static FString StringToBase64Encode(const FString& Source);
  4. //字节到base64
  5. UFUNCTION(BlueprintPure, Category = "CommonLibrary")
  6. static FString BytesToBase64Encode(const TArray<uint8>& Source);
  7. //Bas64到字符串
  8. UFUNCTION(BlueprintPure, Category = "CommonLibrary")
  9. static bool Base64DecodeFString(const FString& Source,FString& Dest);
  10. //Bas64到字节
  11. UFUNCTION(BlueprintPure, Category = "CommonLibrary")
  12. static bool Base64DecodeBytes(const FString& Source,TArray<uint8>& Dest);
复制代码
编码处理--URL

头文件

GenericPlatform/GenericPlatfoormHttp.h
模块引入

http
声明
  1. FString UFileSystemBPLibrary::StringToBase64Encode(const FString& Source)
  2. {
  3.         return FBase64::Encode(Source);
  4. }
  5. FString UFileSystemBPLibrary::BytesToBase64Encode(const TArray<uint8>& Source)
  6. {
  7.         return FBase64::Encode(Source);
  8. }
  9. bool UFileSystemBPLibrary::Base64DecodeFString(const FString& Source, FString& Dest)
  10. {
  11.         return FBase64::Decode(Source, Dest);
  12. }
  13. bool UFileSystemBPLibrary::Base64DecodeBytes(const FString& Source, TArray<uint8>& Dest)
  14. {
  15.         return FBase64::Decode(Source, Dest);
  16. }
复制代码
定义
  1. UFUNCTION(BlueprintPure,Category = "CommonLibrary")
  2. static FString URLEncode(const FString& Source);
  3. UFUNCTION(BlueprintPure,Category = "CommonLibrary")
  4. static FString URLDecode(const FString& Source);
复制代码
编码处理--MD5

声明
  1. FString UFileSystemBPLibrary::URLEncode(const FString& Source)
  2. {
  3.         return FGenericPlatformHttp::UrlEncode(Source);
  4. }
  5. FString UFileSystemBPLibrary::URLDecode(const FString& Source)
  6. {
  7.         return FGenericPlatformHttp::UrlDecode(Source);
  8. }
复制代码
定义
  1. UFUNCTION(BlueprintPure,Category = "CommonFunctionLibrary")
  2. static FString MD5Encode(const FString& Source);
复制代码
时间戳

声明
  1. FString UFileSystemBPLibrary::MD5Encode(const FString& Source)
  2. {
  3.         return FMD5::HashAnsiString(*Source);
  4. }
复制代码
定义
  1. //获得UTC时间戳
  2. UFUNCTION(BlueprintPure,Category = "CommonLibrary")
  3. static FString GetUTCTimestamp();
  4. //UTC毫秒级13位时间戳
  5. UFUNCTION(BlueprintPure,Category = "CommonLibrary")
  6. static FString GetMillUTCTimestamp();
  7. //RFC1123时间和时区表示
  8. UFUNCTION(BlueprintPure,Category = "CommonFunctionLibrary")
  9. static FString GetUTCRFC1123();
复制代码
单例设计

概念

让一个类有且仅有一个实例,提供一个访问该实例的节点,仅在首次请求单例对象时进行初始化。
方案

将默认构造函数设为私有,放置其他对象使用单例类的new运算符。新建一个静态构造方法作为构造函数。
派生方式

UObject---->SingletonObject
声明


  • 在类中定义一个指向本类的指针用private藏好,并初始化为nullptr。
  • 定义获取instance方法,进行首次的初始化。
  • 用static进行修饰让USingletonObject指针存放的值在此类中唯一化,即此类只能存在一个这个值,怎么new都只有一个。如果不适用static修饰需要参考原始的C++方式(手动删除构造方法,拷贝构造方法,赋值构造方法)
  1. FString UFileSystemBPLibrary::GetUTCTimestamp()
  2. {
  3.         FString TImestamp;
  4.         FDateTime Time = FDateTime::UtcNow();
  5.         int64 unixTimestamp = Time.ToUnixTimestamp();
  6.         TImestamp = FString::Printf(TEXT("%lld"), unixTimestamp);
  7.         return TImestamp;
  8. }
  9. FString UFileSystemBPLibrary::GetMillUTCTimestamp()
  10. {
  11.         FDateTime CurrentTime = FDateTime::UtcNow();
  12.         int64 TimestampMillSeconds = CurrentTime.ToUnixTimestamp() * 1000 + CurrentTime.GetMillisecond();
  13.         FString  MillTimestamp;
  14.         MillTimestamp = FString::Printf(TEXT("%lld"), TimestampMillSeconds);
  15.         return MillTimestamp;
  16. }
  17. FString UFileSystemBPLibrary::GetUTCRFC1123()
  18. {
  19.         return FDateTime::UtcNow().ToHttpDate();
  20. }
复制代码
定义
  1. public:
  2.         UFUNCTION(BlueprintCallable)
  3.         static USingletonObject* GetSingletonObjectInstance();
  4.         UFUNCTION(BlueprintCallable)
  5.         void SetValue(int32 NewValue);
  6.         UFUNCTION(BlueprintCallable)
  7.         int32 GetValue();
  8. private:
  9.         static USingletonObject* SingletonObject;
  10.         int32 value;
复制代码
简单工厂设计

概念

向一个工厂类传入参数就能创建来源于Prototype抽象类的其他类。
方案


  • 创建抽象Prototype类
  • 基于Prototype派生具体类
  • 创建工厂类,通过静态方法根据传入不通的参数从而创建不通的派生类实例。
派生方式


  • UObject---->rotoTypeObject
  • ProtoTypeObject--->MyProductA
  • ProtoTypeObject--->MyProductB
  • UObject---->FactoryObject
  • Actor---->FactorActor(测试与使用)
头文件

FactoryObject

  • ProtoTypeObject.h
FactorActor

  • ProtoTypeObject.h
  • FactoryObject.h
  • MyProductA.h
  • MyProductB.h
声明与定义

ProtoTypeObject

  • 需指定UCLASS为Abstract,抽象类,
  • 通过virtual创建接口。
  1. USingletonObject* USingletonObject::SingletonObject = nullptr;
  2. USingletonObject* USingletonObject::GetSingletonObjectInstance()
  3. {
  4.         if (SingletonObject == nullptr)
  5.         {
  6.                 SingletonObject = NewObject<USingletonObject>();
  7.         }
  8.         return SingletonObject;
  9. }
  10. void USingletonObject::SetValue(int32 NewValue)
  11. {
  12.         value = NewValue;
  13. }
  14. int32 USingletonObject::GetValue()
  15. {
  16.         return  value;
  17. }
复制代码
ProductA和B

  • 重写ProtoType提供的接口
  1. UCLASS(Abstract)
  2. class COOPGAME_API UProtoTypeObject : public UObject
  3. {
  4.         GENERATED_BODY()
  5. public:
  6.         virtual void ShowInfo() { UE_LOG(LogTemp, Warning, TEXT("ProtoTypeObject")) };
  7. };
复制代码
FactoryObject

  • 传入一个兼容的类对象的指针用于存放产品对象
  • 传入要生产的产品类
  1. //ProductA
  2. public:
  3.         virtual void ShowInfo() override{UE_LOG(LogTemp,Warning,TEXT("This is ProductA"))};
  4.        
  5.        
  6. //ProductB
  7. public:
  8.         virtual void ShowInfo() override{UE_LOG(LogTemp,Warning,TEXT("This is ProductB"))};
复制代码
使用
  1. public:
  2.         static UProtoTypeObject* CreateNewProduct(UObject* Outer, TSubclassOf<UProtoTypeObject> ProductClass)
  3.         {
  4.                 return NewObject<UProtoTypeObject>(Outer, ProductClass);
  5.         };
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册