BoxComponent的Overlap事件
添加一个继承自Character名为MyCharacter的C++类。
.h文件
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Components/BoxComponent.h"
#include "MyCharacter.generated.h"
UCLASS()
class EXECTEST_API AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
AMyCharacter();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
//Box对象
UBoxComponent* CollisionMesh;
//OverlapBegin事件的回调函数
UFUNCTION()
void OnTestOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherCom, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
//OverlapEnd事件的回调函数
UFUNCTION()
void OnTestOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherCom, int32 OtherBodyIndex);
};
回调函数一定要加UFUNCTION(),否则无法注册成功,因为UE4的代码生成工具需要通过该标识生成相应的代码,变相实现虚拟机编程语言(比如Java、C#)的反射。
.cpp文件
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyCharacter.h"
#include "Engine.h"
// Sets default values
AMyCharacter::AMyCharacter()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
//创建BoxComponent
CollisionMesh = CreateDefaultSubobject<UBoxComponent>(TEXT("TestCollision"));
CollisionMesh->SetBoxExtent(FVector(200.f, 200.f, 96.f));
CollisionMesh->bDynamicObstacle = true;
CollisionMesh->SetupAttachment(GetRootComponent());
//注意: 要触发Overlap事件,SetCollisionResponseToAllChannels要么不设置,要么设置为ECR_Overlap。
CollisionMesh->SetCollisionResponseToAllChannels(ECR_Overlap);
/*CollisionMesh->SetCollisionResponseToChannel(ECC_WorldStatic, ECR_Block);
CollisionMesh->SetCollisionResponseToChannel(ECC_WorldDynamic, ECR_Block);
CollisionMesh->SetCollisionResponseToChannel(ECC_Pawn, ECR_Block);
CollisionMesh->SetNotifyRigidBodyCollision(true);
CollisionMesh->SetSimulatePhysics(true);*/
//要触发Overlap事件,碰撞对象需要勾选属性: Generate Overlap Events
FScriptDelegate DelegateBegin;
DelegateBegin.BindUFunction(this, "OnTestOverlapBegin");
CollisionMesh->OnComponentBeginOverlap.Add(DelegateBegin);
FScriptDelegate DelegateEnd;
DelegateEnd.BindUFunction(this, "OnTestOverlapEnd");
CollisionMesh->OnComponentEndOverlap.Add(DelegateEnd);
}
// Called when the game starts or when spawned
void AMyCharacter::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void AMyCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// Called to bind functionality to input
void AMyCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
void AMyCharacter::OnTestOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherCom, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Yellow, FString("Begin++++++") + SweepResult.Location.ToString());
}
void AMyCharacter::OnTestOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherCom, int32 OtherBodyIndex)
{
GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Yellow, FString("End------") + OtherActor->GetName());
}
想触发Overlap事件时,场景中的碰撞对象需要勾选的选项:Generate Overlap Events
这样,当角色走到场景对象的附近,且身上的box与该物体发生碰撞时,就可以触发Overlap事件。
BoxComponent的Hit事件
.h文件
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Components/BoxComponent.h"
#include "MyCharacter.generated.h"
UCLASS()
class EXECTEST_API AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
AMyCharacter();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
//Box对象
UBoxComponent* CollisionMesh;
//Hit事件回调函数
UFUNCTION()
void OnTestHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComponent, FVector NormalImpulse, const FHitResult& Hit);
};
.cpp文件
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyCharacter.h"
#include "Engine.h"
// Sets default values
AMyCharacter::AMyCharacter()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
//创建BoxComponent
CollisionMesh = CreateDefaultSubobject<UBoxComponent>(TEXT("TestCollision"));
CollisionMesh->SetBoxExtent(FVector(200.f, 200.f, 96.f));
CollisionMesh->bDynamicObstacle = true;
CollisionMesh->SetupAttachment(GetRootComponent());
//注意: 如果要让CollisionMesh->OnComponentHit的回调事件触发,必须设置CollisionMesh->BodyInstance.SetCollisionProfileName
CollisionMesh->BodyInstance.SetCollisionProfileName("MyCollisionProfile");
CollisionMesh->SetNotifyRigidBodyCollision(true);
//要触发Hit事件,碰对对象需要勾选属性:Simulation Generates Hit Events
FScriptDelegate DelegateHit;
DelegateHit.BindUFunction(this, "OnTestHit");
CollisionMesh->OnComponentHit.Add(DelegateHit);
}
// Called when the game starts or when spawned
void AMyCharacter::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void AMyCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// Called to bind functionality to input
void AMyCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
void AMyCharacter::OnTestHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComponent, FVector NormalImpulse, const FHitResult& Hit)
{
GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Yellow, FString("Hit######") + Hit.Location.ToString());
}
注意,上面设置的ProfileName:MyCollisionProfile,是在Project Settings中设置的,具体步骤见下文 Collision Channel 设置。
场景中的碰撞对象需要设置的选项
注意,当首次勾选Simulate Physics时,Collision Presets会自动修改为PhysicsActor。
Simulate Physics:如果要触发Hit事件,这个属性是必须勾选的。
Simulation Generates Hit Events:表示是否触发当前物体的Hit事件,如果你需要回调事件不是这个物体的,可以不勾选该选项。对应的C++属性叫做: FBodyInstance::bNotifyRigidBodyCollision
Collision Presets:同上,如果不关心当前物体的碰撞规则,只是希望其他物体碰到当前物体时,能触发其他物体的碰撞事件,那么Collision Presets可以设置默认值。
Collision Channel 设置
打开Edit—>Project Settings—>Engine—>Collision
然后点击Object Channel下的New Object Channel:
输入一个名称,并将Default Response设置为Block。
然后点击Accept,这样Object Channels就多了一条记录。
然后点击Preset下的New:
Name自己定义,这里的Name就是之前C++代码中设置ProfileName中的名字;CollisionEnabled设置为Collision Enabled;ObjectType设置为上面步骤添加的记录;因为我们这里需要的是Hit事件,不需要Overlap,所以这里的Collision Response设置为Block。
其中 CollisionEnabled 类型如下:
No Collision 全部禁用,物体会坠入地表,且没有物理;
Query Only 只启用碰撞,不会坠入地表,但是没有物理;
Physics Only 只启用物理,但是会坠入地表;
Collision Enabled 同事启用碰撞和物理,既不会坠入地表,同时有物理;
点击Accept之后,就在Preset列表中多了一条记录