最简单的 UE 4 C++ 教程 —— Actor 线轨迹(line trace)碰撞检测【十七】

举报
ShaderJoy 发表于 2021/11/19 01:03:34 2021/11/19
【摘要】 原教程是基于 UE 4.18,我是基于 UE 4.25】 英文原地址 接上一节教程,创建一个新的 actor,在这个例子中,我们将新建的 Actor 子类称为 ActorLineTrace 。 我们不需要在头文件中做任何事情。以防万一,下面是默认创建的头文件。 ActorLineTrace.h #pragma onc...

原教程是基于 UE 4.18,我是基于 UE 4.25】

英文原地址

接上一节教程,创建一个新的 actor,在这个例子中,我们将新建的 Actor 子类称为 ActorLineTrace

我们不需要在头文件中做任何事情。以防万一,下面是默认创建的头文件。

ActorLineTrace.h


  
  1. #pragma once
  2. #include "CoreMinimal.h"
  3. #include "GameFramework/Actor.h"
  4. #include "ActorLineTrace.generated.h"
  5. UCLASS()
  6. class UNREALCPP_API AActorLineTrace : public AActor
  7. {
  8. GENERATED_BODY()
  9. public:
  10. // Sets default values for this actor's properties
  11. AActorLineTrace();
  12. protected:
  13. // Called when the game starts or when spawned
  14. virtual void BeginPlay() override;
  15. public:
  16. // Called every frame
  17. virtual void Tick(float DeltaTime) override;
  18. };

为了帮助我们可视化 线轨迹,我们将包含 DrawDebugHelpers 头文件。这将允许我们绘制一条高亮的线轨迹。我们还将包含 ConstructorHelpers.h ,以立即向 actor 添加一个网格以实现可视化表示。通常首选在编辑器中添加一个网格(没有 ConstructorHelpers.h 帮助的情况下),但我们应该继续在 c++ 中尝试新的东西。


  
  1. #include "ActorLineTrace.h"
  2. // add these scripts to use their functions
  3. #include "ConstructorHelpers.h"
  4. #include "DrawDebugHelpers.h"

我们通过创建 UStaticMeshComponentDefaultSubobject 向 actor 添加一个立方体。然后,我们让新的立方体成为 actor 的根组件。我们通过从 ConstructorHelpers 调用 FObjectFinder,以编程方式向 actor 添加一个网格。在 FObjectFinder 中,我们提供了到网格的路径。在此处我们需要检查我们是否成功得到网格。如果我们成功获得了网格,我们就设置 actor 的 StaticMesh, RelativeLocationScale

下面是我们放入 actor 的构造函数中的代码。


  
  1. AActorLineTrace::AActorLineTrace()
  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. // add cube to root
  6. UStaticMeshComponent* Cube = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("VisualRepresentation"));
  7. Cube->SetupAttachment(RootComponent);
  8. static ConstructorHelpers::FObjectFinder<UStaticMesh> CubeAsset(TEXT("/Game/StarterContent/Shapes/Shape_Cube.Shape_Cube"));
  9. if (CubeAsset.Succeeded())
  10. {
  11. Cube->SetStaticMesh(CubeAsset.Object);
  12. Cube->SetRelativeLocation(FVector(0.0f, 0.0f, 0.0f));
  13. Cube->SetWorldScale3D(FVector(1.f));
  14. }
  15. // add another component in the editor to the actor to overlap with the line trace to get the event to fire
  16. }

接下来,在 actor 的 Tick 函数上,我们想要绘制线条轨迹,看看它是否碰到了什么东西。

对于本例,我们将检查同一 actor 内是否有其他对象。让我们先分别创建变量 HitResultStartingPosition


  
  1. void AActorLineTrace::Tick(float DeltaTime)
  2. {
  3. Super::Tick(DeltaTime);
  4. FHitResult OutHit;
  5. FVector Start = GetActorLocation();
  6. }

起始位置是矢量,这意味着它有X,Y,Z三个分量。我想要向上移动线轨迹,让其更靠近网格的中心,同时又要让它和网格保持一定距离,这样它才不会与自己碰撞。那么上面的代码修改为


  
  1. void AActorLineTrace::Tick(float DeltaTime)
  2. {
  3. Super::Tick(DeltaTime);
  4. FHitResult OutHit;
  5. FVector Start = GetActorLocation();
  6. Start.Z += 50.f;
  7. Start.X += 200.f;
  8. }

在那之后,让我们通过使用 GetActorForwardVector() 来获得网格的前向向量,以确保线轨迹是从网格的前面移动出来的。然后我们将创建 End 变量来告诉线轨迹到哪里结束。在这个例子中,行跟踪将从 50 个单位以上开始,向前 200 个单位,并从起点 500 个单位结束。

同时,我们还要为线轨迹函数创建碰撞参数变量。


  
  1. void AActorLineTrace::Tick(float DeltaTime)
  2. {
  3. Super::Tick(DeltaTime);
  4. FHitResult OutHit;
  5. FVector Start = GetActorLocation();
  6. Start.Z += 50.f;
  7. Start.X += 200.f;
  8. FVector ForwardVector = GetActorForwardVector();
  9. FVector End = ((ForwardVector * 500.f) + Start);
  10. FCollisionQueryParams CollisionParams;
  11. }

在开发时,我们希望看到我们的线轨迹。通过上面的变量,我们将使用 DrawDebugLine 函数来画一条绿色的线。如果线轨迹接触到我们这个 actor 中的任何组件,将向屏幕打印一条消息。


  
  1. void AActorLineTrace::Tick(float DeltaTime)
  2. {
  3. Super::Tick(DeltaTime);
  4. FHitResult OutHit;
  5. FVector Start = GetActorLocation();
  6. Start.Z += 50.f;
  7. Start.X += 200.f;
  8. FVector ForwardVector = GetActorForwardVector();
  9. FVector End = ((ForwardVector * 500.f) + Start);
  10. FCollisionQueryParams CollisionParams;
  11. DrawDebugLine(GetWorld(), Start, End, FColor::Green, false, 1, 0, 5);
  12. if(ActorLineTraceSingle(OutHit, Start, End, ECC_WorldStatic, CollisionParams))
  13. {
  14. GEngine->AddOnScreenDebugMessage(-1, 1.f, FColor::Green, FString::Printf(TEXT("The Component Being Hit is: %s"), *OutHit.GetComponent()->GetName()));
  15. }
  16. }

以下是完整的 cpp 代码


  
  1. #include "ActorLineTrace.h"
  2. #include "UObject/ConstructorHelpers.h"
  3. #include "DrawDebugHelpers.h"
  4. // Sets default values
  5. AActorLineTrace::AActorLineTrace()
  6. {
  7. // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
  8. PrimaryActorTick.bCanEverTick = true;
  9. // add cube to root
  10. UStaticMeshComponent* Cube = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("VisualRepresentation"));
  11. Cube->SetupAttachment(RootComponent);
  12. static ConstructorHelpers::FObjectFinder<UStaticMesh> CubeAsset(TEXT("/Game/StarterContent/Shapes/Shape_Cube.Shape_Cube"));
  13. if (CubeAsset.Succeeded())
  14. {
  15. Cube->SetStaticMesh(CubeAsset.Object);
  16. Cube->SetRelativeLocation(FVector(0.0f, 0.0f, 0.0f)); ///< 根据自己的实际情况调整
  17. Cube->SetWorldScale3D(FVector(1.f));
  18. }
  19. // add another component in the editor to the actor to overlap with the line trace to get the event to fire
  20. }
  21. // Called when the game starts or when spawned
  22. void AActorLineTrace::BeginPlay()
  23. {
  24. Super::BeginPlay();
  25. }
  26. // Called every frame
  27. void AActorLineTrace::Tick(float DeltaTime)
  28. {
  29. Super::Tick(DeltaTime);
  30. FHitResult OutHit;
  31. FVector Start = GetActorLocation();
  32. Start.Z += 50.f;
  33. Start.X += 200.f; ///< 根据自己的实际情况调整
  34. FVector ForwardVector = GetActorForwardVector();
  35. FVector End = ((ForwardVector * 500.f) + Start);
  36. FCollisionQueryParams CollisionParams;
  37. DrawDebugLine(GetWorld(), Start, End, FColor::Green, false, 1, 0, 5);
  38. if(ActorLineTraceSingle(OutHit, Start, End, ECC_WorldStatic, CollisionParams))
  39. {
  40. GEngine->AddOnScreenDebugMessage(-1, 1.f, FColor::Green, FString::Printf(TEXT("The Component Being Hit is: %s"), *OutHit.GetComponent()->GetName()));
  41. }
  42. }

实际的运行效果如下 

 

 

文章来源: panda1234lee.blog.csdn.net,作者:panda1234lee,版权归原作者所有,如需转载,请联系作者。

原文链接:panda1234lee.blog.csdn.net/article/details/119133207

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。