3.4 - 使发射物和世界场景形成交互

检测到发射物的碰撞交互后,即可决定对这些碰撞作出何种响应。在这步中,我们将对碰撞事件作出响应的 FPSProjectile 添加一个 OnHit 函数。

使发射物对碰撞作出反应

  1. Solution Explorer 中找到 FPSProjectile 类头文件并打开 FPSProjectile.h

  2. 将以下代码添加到 FPSProjectile 类声明:

    // 发射物命中物体时调用的函数。
    UFUNCTION()
    void OnHit(class AActor* OtherActor, class UPrimitiveComponent* OtherComponent, FVector NormalImpulse, const FHitResult& Hit);
  3. FPSProjectile.h 应与以下代码相似:

    // 在 Project Settings 的 Description 页面填入版权声明。
    
    #pragma once
    
    #include "GameFramework/Actor.h"
    #include "FPSProjectile.generated.h"
    
    UCLASS()
    class FPSPROJECT_API AFPSProjectile : public AActor
    {
        GENERATED_BODY()
    
    public: 
        // 设置该 actor 属性的默认值
        AFPSProjectile();
    
        // 游戏开始时或生成时调用
        virtual void BeginPlay() override;
    
        // 每帧调用
        virtual void Tick( float DeltaSeconds ) override;
    
        // 球体碰撞组件。
        UPROPERTY(VisibleDefaultsOnly, Category = Projectile)
        USphereComponent* CollisionComponent;
    
        // 发射物运动组件。
        UPROPERTY(VisibleAnywhere, Category = Movement)
        UProjectileMovementComponent* ProjectileMovementComponent;
    
        // 在发射方向上设置发射物初速度的函数。
        void FireInDirection(const FVector& ShootDirection);
    
        // 发射物命中物体时调用的函数。
        void OnHit(class AActor* OtherActor, class UPrimitiveComponent* OtherComponent, FVector NormalImpulse, const FHitResult& Hit);
    };
  4. Solution Explorer 中找到 FPSProjectile 类 CPP 文件并打开 FPSProjectile.cpp 添加以下代码:

    // 发射物命中物体时调用的函数。
    void AFPSProjectile::OnHit(AActor* OtherActor, UPrimitiveComponent* OtherComponent, FVector NormalImpulse, const FHitResult& Hit)
    {
        if (OtherActor != this && OtherComponent->IsSimulatingPhysics())
        {
            OtherComponent->AddImpulseAtLocation(ProjectileMovementComponent->Velocity * 100.0f, Hit.ImpactPoint);
        }
    }
  5. FPSProjectile 构造函数中创建 CollisionComp,然后添加以下命令行:

    CollisionComponent->OnComponentHit.AddDynamic(this, &AFPSProjectile::OnHit);
  6. FPSProjectile.cpp 应与以下代码相似:

    // 在 Project Settings 的 Description 页面填入版权声明。
    
    #include "FPSProject.h"
    #include "FPSProjectile.h"
    
    // 设置默认值
    AFPSProjectile::AFPSProjectile()
    {
        // 将此 actor 设为每帧调用 Tick()。不需要时可将此关闭,以提高性能。
        PrimaryActorTick.bCanEverTick = true;
    
        // 使用球体代表简单碰撞。
        CollisionComponent = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComponent"));
        CollisionComponent->BodyInstance.SetCollisionProfileName(TEXT("Projectile"));
        CollisionComponent->OnComponentHit.AddDynamic(this, &AFPSProjectile::OnHit);
    
        // 设置球体的碰撞半径。
        CollisionComponent->InitSphereRadius(15.0f);
        // 将碰撞组件设为根组件。
        RootComponent = CollisionComponent;
    
        // 使用此组件驱动此发射物的运动。
        ProjectileMovementComponent = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("ProjectileMovementComponent"));
        ProjectileMovementComponent->SetUpdatedComponent(CollisionComponent);
        ProjectileMovementComponent->InitialSpeed = 3000.0f;
        ProjectileMovementComponent->MaxSpeed = 3000.0f;
        ProjectileMovementComponent->bRotationFollowsVelocity = true;
        ProjectileMovementComponent->bShouldBounce = true;
        ProjectileMovementComponent->Bounciness = 0.3f;
    
        // 3 秒后消亡。
        InitialLifeSpan = 3.0f;
    }
    
    // 游戏开始时或生成时调用
    void AFPSProjectile::BeginPlay()
    {
        Super::BeginPlay();
    
    }
    
    // 每帧调用
    void AFPSProjectile::Tick( float DeltaTime )
    {
        Super::Tick( DeltaTime );
    
    }
    
    // 在发射方向上设置发射物初速度的函数。
    void AFPSProjectile::FireInDirection(const FVector& ShootDirection)
    {
        ProjectileMovementComponent->Velocity = ShootDirection * ProjectileMovementComponent->InitialSpeed;
    }
    
    // 发射物命中物体时调用的函数。
    void AFPSProjectile::OnHit(AActor* OtherActor, UPrimitiveComponent* OtherComponent, FVector NormalImpulse, const FHitResult& Hit)
    {
        if (OtherActor != this && OtherComponent->IsSimulatingPhysics())
        {
            OtherComponent->AddImpulseAtLocation(ProjectileMovementComponent->Velocity * 100.0f, Hit.ImpactPoint);
        }
    }
  7. 在 Visual Studio 中保存 FPSProjectile.hFPSProjectile.cpp

  8. Solution Explorer 中找到 FPSProject

  9. 右键单击 FPSProject 并选择 Build 编译项目。

    BuildFPSProject.png

测试发射物碰撞

  1. 构造完成后,返回 Unreal Editor,打开 FPSProject

  2. 选择 Floor StaticMesh

  3. 复制粘贴地板模型。

  4. 解锁比例锁定,将地面网格体副本(名为“Floor2”)设为 {0.2, 0.2, 3.0}。

  5. 将地面网格体副本放置在 {320, 0, 170}。

    点击图片放大查看。

  6. 向下滚动到 Physics 部分,勾选 Simulate Physics 框。

    点击图片放大查看。

  7. 保存地图,双击 BP_FPSProjectile 打开发射物蓝图进行编辑。

  8. 打开 Class Defaults Mode 并点击 Components 标签中的 ProjectileMeshComponent

  9. 找到 Collision 下的 Collision Presets 属性并将其设为 Projectile

    SetCollisionPresets.png

  10. 关闭 蓝图编辑器 之前 编译保存 蓝图

  11. 点击 关卡编辑器工具栏 中的 Play In 按钮。

  12. 点击鼠标左键发射物体,在场景中移动立方体。

    ProjectileComplete.png

    恭喜,发射物设置完成!

  13. 按下 Esc 键或点击关卡编辑器中的 Stop 按钮即可退出 Play in Editor(PIE)模式。