UE4 C++:事件绑定(输入碰撞检测定时器)
Posted BBBourne
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UE4 C++:事件绑定(输入碰撞检测定时器)相关的知识,希望对你有一定的参考价值。
目录
轴映射与动作映射:SetupPlayerInputComponent
获取经过时间和剩余时间:GetTimerElapsed & GetTimerRemaining
虚幻引擎中的碰撞响应参考 | 虚幻引擎5.0文档 (unrealengine.com)
变量、定时器和事件 | 虚幻引擎5.0文档 (unrealengine.com)
虚幻引擎中的Gameplay定时器 | 虚幻引擎5.0文档 (unrealengine.com)
Input输入事件绑定
轴映射与动作映射:SetupPlayerInputComponent
编辑器设置对应名称、代码设置响应事件,实现具体动作
绑定名称及事件,Action还需绑定按键
void AMyCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
Super::SetupPlayerInputComponent(PlayerInputComponent);
PlayerInputComponent->BindAction("DropItem", EInputEvent::IE_Pressed, this, &AMyCharacter::DropItem);
PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &AMyCharacter::Jump);
PlayerInputComponent->BindAxis("MoveForward", this, &AMyCharacter::MoveForward);
PlayerInputComponent->BindAxis("MoveRight", this, &AMyCharacter::MoveRight);
PlayerInputComponent->BindAxis("PitchCamera", this, &AMyCharacter::PitchCamera);
PlayerInputComponent->BindAxis("YawCamera", this, &AMyCharacter::YawCamera);
事件:
void AMyCharacter::MoveForward(float AxisValue)
MovementInput.X = FMath::Clamp<float>(AxisValue, -1.f, 1.f);
void AMyCharacter::MoveRight(float AxisValue)
MovementInput.Y = FMath::Clamp<float>(AxisValue, -1.f, 1.f);
void AMyCharacter::PitchCamera(float AxisValue)
CameraInput.Y = AxisValue;
void AMyCharacter::YawCamera(float AxisValue)
CameraInput.X = AxisValue;
设置按键,游戏暂停可以继续响应
InputComponent->BindAction("ESCEvent", IE_Pressed, this, &ASLAiPlayerController::ESCEvent).bExecuteWhenPaused=true;//游戏暂停可以执行
C++设置添加轴和动作映射
//添加、绑定ActionKeyMapping轴映射 方法一
FInputActionKeyMapping onFire("OnFire", EKeys::LeftMouseButton, 0, 0, 0, 0);
UPlayerInput::AddEngineDefinedActionMapping(onFire);
PlayerInputComponent->BindAction("OnFire", IE_Pressed, this, &AMyCharacter::OnFire);
//添加、绑定ActionKeyMapping轴映射 方法二
UPlayerInput::AddEngineDefinedActionMapping(FInputActionKeyMapping("Sprint",EKeys::LeftShift));
PlayerInputComponent->BindAction("Sprint", IE_Pressed,this,&AMyCharacter::StartSprint);
PlayerInputComponent->BindAction("Sprint", IE_Released,this,&AMyCharacter::StopSprint);
//添加、绑定AxisMapping轴映射
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("Turn", EKeys::MouseX, 1.0f));
PlayerInputComponent->BindAxis("Turn", this, &AMyCharacter::OnTurn);
碰撞检测事件绑定
碰撞对象通道与预设
- 默认提供碰撞对象类型,如WorldStatic、WorldDynamic等,允许用户自定义
- 默认提供碰撞预设,如NoCollision、BlockAll、OverlapAll。允许用户自定义
碰撞响应设置:是否模拟物理碰撞以及触发Overlap事件
碰撞响应类型:Blokc、Overlap、Ignore
C++实现
- 注意Overlap Begin/End 的函数参数
- 注意OnHit的函数参数
- 注意Generated Hit Event的函数名
- 绑定函数可以用AddDynamic,也可以用FScriptDelegate委托
- 部分设置可不写,蓝图使用时再手动设置
- 写法支持UShapeComponent及其派生类,如USphereComponent、UBoxComponent等
UPROPERTY(EditAnywhere)
USceneComponent* Root;
UPROPERTY(EditAnywhere)
UStaticMeshComponent* Cube;
UFUNCTION()
virtual void OnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
UFUNCTION()
virtual void OnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
UFUNCTION()
virtual void OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);
ACollisionActor::ACollisionActor()
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
Root = CreateDefaultSubobject<USceneComponent>(TEXT("RootScene"));
SetRootComponent(Root);
Cube = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Cube"));
Cube->SetupAttachment(Root);
static ConstructorHelpers::FObjectFinder<UStaticMesh> mesh(TEXT("StaticMesh'/Engine/BasicShapes/Cube.Cube'"));
if (mesh.Succeeded())
Cube->SetStaticMesh(mesh.Object);
// 设置是否开启物理模拟
Cube->SetSimulatePhysics(false);
// 开启 Generated Hit Event
Cube->SetNotifyRigidBodyCollision(true);
// 开启CCD Continuous collision detection (CCD) 连续式碰撞检测
Cube->BodyInstance.SetUseCCD(true);
// 开启Generate Overlap Events
Cube->SetGenerateOverlapEvents(true);
// 设置碰撞预设
Cube->SetCollisionProfileName(TEXT("OverlapAll"));
//Cube->SetCollisionResponseToAllChannels(ECR_Overlap);
// 设置碰撞响应设置
Cube->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
// 绑定函数
Cube->OnComponentBeginOverlap.AddDynamic(this, &ACollisionActor::OnOverlapBegin);
// 绑定函数 使用委托
FScriptDelegate OverlapEndDelegate;
OverlapEndDelegate.BindUFunction(this, TEXT("OnOverlapEnd"));
Cube->OnComponentBeginOverlap.Add(OverlapEndDelegate);
// 绑定碰撞函数
Cube->OnComponentHit.AddDynamic(this, &ACollisionActor::OnHit);
void ACollisionActor::OnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
UE_LOG(LogTemp, Warning, TEXT("Overlap Begin"));
void ACollisionActor::OnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
UE_LOG(LogTemp, Warning, TEXT("Overlap End"));
void ACollisionActor::OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
UE_LOG(LogTemp, Warning, TEXT("Hit"));
Destroy();
定时器Timer与事件绑定
- 定时执行操作,可执行一次,或循环执行直到手动终止
- 定时器在全局定时管理器(FTimerManager类型)中管理。全局定时器管理器存在于游戏实例对象上以及每个场景中
- 定时器需要绑定委托或函数、作为执行体。这些函数将填充FTimerHandle定时器句柄
- FTimerHandle支持暂停、恢复倒计时;查询或更改剩余时间;取消定时器
- 设置定时器的函数
- SetTimer 定时执行
- SetTimerForNextTick 下一帧执行
- 案例
- 定时SpawnActor
- 定时销毁
- buff持续、如霸体、持续伤害
设置定时器:SetTimer
- 支持FTimerDelegate委托,可以扩展使用Lambda表达式,可以带参数
template<class UserClass>
void SetTimer
(
FTimerHandle & InOutHandle,
UserClass * InObj,
typename FTimerDelegate::TUObjectMethodDelegate_Const< UserClass >::FMethodPtr InTimerMethod,
float InRate,
bool InbLoop,
float InFirstDelay
)
FTimerHandle SpawnerHandle;
GetWorldTimerManager().SetTimer(SpawnerHandle, this, &AEnenmySpawner::SpawnEnemy, 5.0f, true);
void AEnenmySpawner::SpawnEnemy()
GEngine->AddOnScreenDebugMessage(-1, 1.0f, FColor::Red, "Spawn");
清空定时器:ClearTimer
- ClearAllTimerForObject:清空与特定对象关联的所有定时器
GetWorldTimerManager().ClearTimer(SpawnerHandle);
// 参数传入一个对象,本例以 this 举例
GetWorldTimerManagerr().ClearAllTimersForObject(this);
暂停和恢复:PauseTimer和UnPauseTimer
GetWorldTimerManager().PauseTimer(SpawnerHandle);
GetWorldTimerManager().UnPauseTimer(SpawnerHandle);
GetWorldTimerManager().IsTimerPaused(SpawnerHandle);
判断是否活跃且未暂停:IsTimerActive
GetWorldTimerManager().IsTimerActive(SpawnerHandle);
获取定时器速率:GetTImerRate
句柄若无效则返回-1
GetWorldTimerManager().GetTimerRate(SpawnerHandle);
获取经过时间和剩余时间:GetTimerElapsed & GetTimerRemaining
句柄若无效,返回-1
句柄若无效,返回-1
GetWorldTimerManager().GetTimerElapsed(SpawnerHandle);
GetWorldTimerManager().GetTimerRemaining(SpawnerHandle);
UE4 定时器和事件分发机制(C++和蓝图)
1. 自己写的机制
2. 用C++调用Unreal的事件分发机制
3. 用蓝图调用Unreal的事件分发机制
4.蓝图调用C++写的Pawn
记得绑定好,Pawn
先是自己写的一个简单的事件分发机制(自己写的肯定有考虑不到的地方(垃圾回收什么什么。。。))
先看自己写的机制:
一个蓝图宏库
一个发起事件者Pawn
一个接口(调用实现了这个接口的接口方法)
一个基类,然后继承这个基类做事件绑定(基类只是给了一个外观)
一个存数据的类
蓝图宏库:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "EventManage.generated.h"
/**
*
*/
UCLASS()
class EVEVT_FENFA_API UEventManage : public UBlueprintFunctionLibrary
GENERATED_BODY()
private:
//要分发的类的集合
static TMap<FString, TArray<UObject*>> AllListeners;
public:
//添加到集合中
UFUNCTION(BlueprintCallable, Category = "Event Dispather Utility")
static void AddEventListener(FString EventName, UObject* Listener);
//从集合中移除
UFUNCTION(BlueprintCallable, Category = "Event Dispather Utility")
static void RemoveEventListener(FString EventName, UObject* Listener);
//分发给集合中的每一个
UFUNCTION(BlueprintCallable, Category = "Event Dispather Utility")
static FString DispatchEvent(FString EventName, UObject* Data);
//用来创建一个实例,返回这个实例的Obj 再转换
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Event Dispather Utility")//BlueprintPure声明为一个纯的函数
static UObject* NewAsset(UClass* ClassType);
;
// Fill out your copyright notice in the Description page of Project Settings.
#include "EventDispather/EventManage.h"
#include "EventDispather/EventInterface.h"
TMap<FString, TArray<UObject*>> UEventManage::AllListeners;
void UEventManage::AddEventListener(FString EventName, UObject* Listener)
if (EventName == ""
|| Listener == nullptr
|| !Listener->IsValidLowLevel()//!Listener->IsValidLowLevel()这个是判断有没有被垃圾回收收了
|| !Listener->GetClass()->ImplementsInterface(UEventInterface::StaticClass()))//这个是判断是否实现接口
return;
TArray<UObject*>* Arr = UEventManage::AllListeners.Find(EventName);
if (Arr == nullptr || Arr->Num() == 0)
TArray<UObject*> NewArr = Listener ;
UEventManage::AllListeners.Add(EventName, NewArr);
else
Arr->Add(Listener);
void UEventManage::RemoveEventListener(FString EventName, UObject* Listener)
TArray<UObject*>* Arr = UEventManage::AllListeners.Find(EventName);
if (Arr != nullptr && Arr->Num() != 0)
Arr->Remove(Listener);
FString UEventManage::DispatchEvent(FString EventName, UObject* Data)
TArray<UObject*>* Arr = UEventManage::AllListeners.Find(EventName);
if (Arr == nullptr || Arr->Num() == 0)
return "'" + EventName + "' NO Listener.";
FString ErrorInfo = "\\n";
for (int i=0;i<Arr->Num();i++)
UObject* Obj = (*Arr)[i];
if (Obj == nullptr
|| !Obj->IsValidLowLevel()
|| !Obj->GetClass()->ImplementsInterface(UEventInterface::StaticClass()))
Arr->RemoveAt(i--);//RemoveAt会帮我们补上删除的那个空的
else
UFunction* FUn=Obj->FindFunction("OnReceiveEvent");
if (FUn==nullptr||!FUn->IsValidLowLevel())
ErrorInfo += "'" + Obj->GetName() + "'No 'OnReceiveEvent' Function.\\n";
else
Obj->ProcessEvent(FUn,&Data);
return ErrorInfo;
UObject* UEventManage::NewAsset(UClass* ClassType)
UObject* Obj = NewObject<UObject>(GetTransientPackage(), ClassType);
return Obj;
Pawn:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "MyBpAndCpp_Sender.generated.h"
UCLASS()
class EVEVT_FENFA_API AMyBpAndCpp_Sender : public APawn
GENERATED_BODY()
public:
// Sets default values for this pawn's properties
AMyBpAndCpp_Sender();
UPROPERTY(VisibleAnywhere)
class UStaticMeshComponent* Sphere;
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;
;
// Fill out your copyright notice in the Description page of Project Settings.
#include "EventDispather/MyBpAndCpp_Sender.h"
#include "Components/StaticMeshComponent.h"
#include "UObject/ConstructorHelpers.h"
#include "TimerManager.h"
#include "EventDispather/EventManage.h"
#include "EventDispather/MyData.h"
// Sets default values
AMyBpAndCpp_Sender::AMyBpAndCpp_Sender()
PrimaryActorTick.bCanEverTick = true;
Sphere = CreateAbstractDefaultSubobject<UStaticMeshComponent>(TEXT("Sphere"));
RootComponent = Sphere;
static ConstructorHelpers::FObjectFinder<UStaticMesh> StaticMeshAsset(TEXT("StaticMesh'/Engine/BasicShapes/Sphere.Sphere'"));
static ConstructorHelpers::FObjectFinder<UMaterialInterface> MaterialAsset(TEXT("Material'/Engine/BasicShapes/BasicShapeMaterial.BasicShapeMaterial'"));
if (StaticMeshAsset.Succeeded() && MaterialAsset.Succeeded())
Sphere->SetStaticMesh(StaticMeshAsset.Object);
Sphere->SetMaterial(0, MaterialAsset.Object);
// Called when the game starts or when spawned
void AMyBpAndCpp_Sender::BeginPlay()
Super::BeginPlay();
FTimerHandle TimerHandle;
auto qwr=[]()
UMyData* Data = Cast<UMyData>(UEventManage::NewAsset(UMyData::StaticClass()));
Data->Param = FMath::RandRange(0, 100);
UEventManage::DispatchEvent("MyBpAndCpp_DispatchEvent", Data);
;
GetWorld()->GetTimerManager().SetTimer(TimerHandle, FTimerDelegate::CreateLambda(qwr), 3.0f, true);
// Called every frame
void AMyBpAndCpp_Sender::Tick(float DeltaTime)
Super::Tick(DeltaTime);
// Called to bind functionality to input
void AMyBpAndCpp_Sender::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
Super::SetupPlayerInputComponent(PlayerInputComponent);
一个接口(调用实现了这个接口的接口方法):
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "EventInterface.generated.h"
// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UEventInterface : public UInterface
GENERATED_BODY()
;
/**
*
*/
class EVEVT_FENFA_API IEventInterface
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
// 蓝图可以找到
UFUNCTION(BlueprintNativeEvent,Category="Event Dispather Utilty")
void OnReceiveEvent(UObject* Data);
;
一个基类,然后继承这个基类做事件绑定
子Actor;
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "EventDispather/MyBpAndCpp_Receiver_Parent.h"
#include "EventDispather/EventInterface.h"
#include "MyMyBpAndCpp_Receiver_Parent_G.generated.h"
/**
*
*/
UCLASS()
class EVEVT_FENFA_API AMyMyBpAndCpp_Receiver_Parent_G : public AMyBpAndCpp_Receiver_Parent,public IEventInterface
GENERATED_BODY()
protected:
virtual void BeginPlay() override;
public:
virtual void BeginDestroy() override;
virtual void OnReceiveEvent_Implementation(UObject* Data);
;
// Fill out your copyright notice in the Description page of Project Settings.
#include "EventDispather/MyMyBpAndCpp_Receiver_Parent_G.h"
#include "..\\..\\Public\\EventDispather\\MyMyBpAndCpp_Receiver_Parent_G.h"
#include "Engine/Engine.h"
#include "EventDispather/MyData.h"
#include "EventDispather/EventManage.h"
#include "TimerManager.h"
void AMyMyBpAndCpp_Receiver_Parent_G::BeginPlay()
Super::BeginPlay();
UEventManage::AddEventListener("MyBpAndCpp_DispatchEvent",this);
FTimerHandle TimerHandle;
auto qwe=[this]()
UEventManage::RemoveEventListener("MyBpAndCpp_DispatchEvent", this);
;
//GetWorld()->GetTimerManager().SetTimer(TimerHandle, FTimerDelegate::CreateLambda(qwe), 5.0f, false);
void AMyMyBpAndCpp_Receiver_Parent_G::BeginDestroy()
UEventManage::RemoveEventListener("MyBpAndCpp_DispatchEvent", this);
Super::BeginDestroy();
void AMyMyBpAndCpp_Receiver_Parent_G::OnReceiveEvent_Implementation(UObject* Data)
GEngine->AddOnScreenDebugMessage(INDEX_NONE, 3.0f, FColor::Green, FString::Printf(TEXT("%i"), Cast<UMyData>(Data)->Param));
存数据的类:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "MyData.generated.h"
/**
*
*/
UCLASS(Blueprintable)//可以被蓝图继承
class EVEVT_FENFA_API UMyData : public UObject
GENERATED_BODY()
public:
UMyData();
UPROPERTY(BlueprintReadWrite)
int Param;
;
就一个变量。。
结果:分发一个随机数
下面是使用Unreal的分发机制(C++):
一个发事件的Pawn
一个Actor
Pawn:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "MyPawn_Sender.generated.h"
UCLASS()
class EVEVT_FENFA_API AMyPawn_Sender : public APawn
GENERATED_BODY()
public:
// Sets default values for this pawn's properties
AMyPawn_Sender();
DECLARE_MULTICAST_DELEGATE_OneParam(FUECpp_Broadcast, int);//单参数多播
//DECLARE_MULTICAST_DELEGATE_OneParam(FUECpp_Broadcast, int,value);//这个是暴露给蓝图的蓝图调用后返回一个value的参数
//UPROPERTY(BlueprintAssignable)
FUECpp_Broadcast UECpp_Broadcast;
UPROPERTY(VisibleAnywhere)
class UStaticMeshComponent* Sphere;
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;
;
// Fill out your copyright notice in the Description page of Project Settings.
#include "UE_CPP/MyPawn_Sender.h"
#include "Components/StaticMeshComponent.h"
#include "UObject/ConstructorHelpers.h"
#include "TimerManager.h"
// Sets default values
AMyPawn_Sender::AMyPawn_Sender()
// Set this pawn to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
Sphere = CreateAbstractDefaultSubobject<UStaticMeshComponent>(TEXT("Sphere"));
RootComponent = Sphere;
static ConstructorHelpers::FObjectFinder<UStaticMesh> StaticMeshAsset(TEXT("StaticMesh'/Engine/BasicShapes/Sphere.Sphere'"));
static ConstructorHelpers::FObjectFinder<UMaterialInterface> MaterialAsset(TEXT("Material'/Engine/BasicShapes/BasicShapeMaterial.BasicShapeMaterial'"));
if (StaticMeshAsset.Succeeded() && MaterialAsset.Succeeded())
Sphere->SetStaticMesh(StaticMeshAsset.Object);
Sphere->SetMaterial(0,MaterialAsset.Object);
// Called when the game starts or when spawned
void AMyPawn_Sender::BeginPlay()
Super::BeginPlay();
FTimerHandle TimerHandle;//定义一个句柄,用来控制时间定时器的
/*auto Lambda = [=]()
UECpp_Broadcast.Broadcast(FMath::RandRange(0, 100));
;*/
auto qwe = [](FUECpp_Broadcast* ucb) //拉姆达表达式
ucb->Broadcast(FMath::RandRange(0, 100));//调用所有绑定了Int 类的事件
;
GetWorld()->GetTimerManager().SetTimer(TimerHandle, FTimerDelegate::CreateLambda(qwe,&UECpp_Broadcast),3.0f,true);//以事件设置定时器
// Called every frame
void AMyPawn_Sender::Tick(float DeltaTime)
Super::Tick(DeltaTime);
// Called to bind functionality to input
void AMyPawn_Sender::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
Super::SetupPlayerInputComponent(PlayerInputComponent);
结果一样是输出一个随机数,
蓝图的:
Pawn:
Aotor:
结果:输出一个随机数
蓝图调用C++写的Pawn:
以上是关于UE4 C++:事件绑定(输入碰撞检测定时器)的主要内容,如果未能解决你的问题,请参考以下文章