UE5按键绑定(用C++实现绑定鼠标左键)

引擎项目设置
在这里插入图片描述

玩家控制器中需要添加PhysicsHandle组件
在这里插入图片描述
引用的源文件库

#include "GameFramework/Actor.h"//引用游戏框架的演员Actor的源文件库
#include "Engine/TriggerVolume.h"//引用引擎的触发区域TriggerVolume的源文件库
#include "Engine/World.h"//引用引擎的世界World的源文件库
#include "DrawDebugHelpers.h"//引用射线的源文件库
#include "PhysicsEngine/PhysicsHandleComponent.h"//引用引擎的物理手柄组件的源文件库

.h文件中的代码:

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "GameFramework/Actor.h"//引用游戏框架的演员Actor的源文件库
#include "Engine/TriggerVolume.h"//引用引擎的触发区域TriggerVolume的源文件库
#include "Engine/World.h"//引用引擎的世界World的源文件库
#include "DrawDebugHelpers.h"//引用射线的源文件库
#include "PhysicsEngine/PhysicsHandleComponent.h"//引用引擎的物理手柄组件的源文件库
#include "Grabber.generated.h"


UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
class PROJECT02_API UGrabber : public UActorComponent
{
    
    
	GENERATED_BODY()

public:
	// Sets default values for this component's properties
	UGrabber();

protected:
	// Called when the game starts
	virtual void BeginPlay() override;
public:
	// Called every frame
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
private:
	UPROPERTY(Editanywhere);
	float Reach = 1000.0f;//定义变量射线长度	
	UInputComponent* InputComponent = nullptr;//设置引擎默认输入组件为空
	UPhysicsHandleComponent* PhysicsHandle = nullptr;//设置物理手柄组件为空 
	FVector GetLineStartPos();//定义有返回值的方法名,射线开始位置
	FVector GetLineEndPos();//定义有返回值的方法名,射线结束位置	
	FHitResult GetFirstPhysicsActorInReach();//定义有返回值的方法名,射线碰撞到的第一个物体
	void SetPhysicsHandleComponent();//定义方法名设置物理手柄组件
	void SetInputComponent();//定义方法名设置输入组件
	void Grab();  //定义方法拿起
	void Release();//定义方法放下

};

.cpp文件中的部分代码:

// 游戏开始时调用
void UGrabber::BeginPlay()
{
    
    
	Super::BeginPlay();
    //设置物理手柄组件
	SetPhysicsHandleComponent();
	//设置输入组件
	SetInputComponent();

}
//设置物理手柄组件
void UGrabber::SetPhysicsHandleComponent()
{
    
    
	// 开始的时候找到玩家自身的物理手柄组件给引擎物理手柄组件赋值
	PhysicsHandle = GetOwner()->FindComponentByClass<UPhysicsHandleComponent>();
	if (PhysicsHandle == nullptr)
	{
    
    
		UE_LOG(LogTemp, Error, TEXT("!!!!!!PhySicsHandle Not Found"));//如果为空指针就报错,防止UE崩溃
        return;
	}
}
//设置输入组件
void UGrabber::SetInputComponent()
{
    
    
	// 开始的时候找到玩家自身的输入组件给引擎输入组件赋值
	InputComponent = GetOwner()->FindComponentByClass<UInputComponent>();
	if (InputComponent == nullptr)
	{
    
    
		UE_LOG(LogTemp, Error, TEXT("!!!!!!InputComponent Not Found"));//如果为空指针就报错,防止UE崩溃
        return;
	}
	else 
	{
    
    
		//按键按下绑定拿起方法
		InputComponent->BindAction(
		    "Grab",//项目设置Input中自己设置的按键名字
			EInputEvent::IE_Pressed,//输入事件按下
			this,//自身
			&UGrabber::Grab//指向一个拿起方法
		
		);
		//按键松开绑定放下方法
		InputComponent->BindAction(
			"Grab",//项目设置Input中自己设置的按键名字
			EInputEvent::IE_Released,//输入事件松开
			this,//自身
			&UGrabber::Release//指向一个放下方法

		);
	}
}
//拿起方法
void UGrabber::Grab()
{
    
    
	UE_LOG(LogTemp, Warning, TEXT("!!!!!Grab Me"));
}
//放下方法
void UGrabber::Release()
{
    
    
    UE_LOG(LogTemp, Warning, TEXT("!!!!!Release Me"));
}

在输出日志中打印如下:
在这里插入图片描述

备注:
这其中牵扯到射线检测
完整的.cpp文件代码:

// Fill out your copyright notice in the Description page of Project Settings.

#include "Grabber.h"

// Sets default values for this component's properties
UGrabber::UGrabber()
{
    
    
	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
	// off to improve performance if you don't need them.
	PrimaryComponentTick.bCanEverTick = true;

	// ...
}
// Called when the game starts
void UGrabber::BeginPlay()
{
    
    
	Super::BeginPlay();
	//设置物理手柄组件
	SetPhysicsHandleComponent();
	//设置输入组件
	SetInputComponent();

}
//设置物理手柄组件
void UGrabber::SetPhysicsHandleComponent()
{
    
    
	// 开始的时候找到玩家自身的物理手柄组件给引擎物理手柄组件赋值
	PhysicsHandle = GetOwner()->FindComponentByClass<UPhysicsHandleComponent>();
	if (PhysicsHandle == nullptr)
	{
    
    
		UE_LOG(LogTemp, Error, TEXT("!!!!!!PhySicsHandle Not Found"));//如果为空指针就报错,防止UE崩溃
		return;
	}
}
//设置输入组件
void UGrabber::SetInputComponent()
{
    
    
	// 开始的时候找到玩家自身的输入组件给引擎输入组件赋值
	InputComponent = GetOwner()->FindComponentByClass<UInputComponent>();
	if (InputComponent == nullptr)
	{
    
    
		UE_LOG(LogTemp, Error, TEXT("!!!!!!InputComponent Not Found"));//如果为空指针就报错,防止UE崩溃
		return;
	}
	else
	{
    
    
		//按键按下绑定拿起方法
		InputComponent->BindAction(
			TEXT("Grab"),//项目设置Input中自己设置的按键名字
			EInputEvent::IE_Pressed,//输入事件按下
			this,//自身
			&UGrabber::Grab//指向一个拿起方法

		);
		//按键松开绑定放下方法
		InputComponent->BindAction(
			TEXT("Grab"),//项目设置Input中自己设置的按键名字
			EInputEvent::IE_Released,//输入事件松开
			this,//自身
			&UGrabber::Release//指向一个放下方法

		);
	}
}
//拿起
void UGrabber::Grab()
{
    
    
	
	UE_LOG(LogTemp, Warning, TEXT("!!!!!Grab Me"));
	FHitResult HitResult = GetFirstPhysicsActorInReach();//射线碰撞结果
	UPrimitiveComponent* ComponentToGrab = HitResult.GetComponent();//引擎前提组件指针指向射线检测结果
	if (HitResult.GetActor()!=nullptr)//防止获取碰撞物体身上的组件为空,引发程序崩溃
	{
    
    
		//GrabComponentAtLocationWithRotation(,,,)实现拿起物体
		PhysicsHandle->GrabComponentAtLocationWithRotation(
			ComponentToGrab,
			NAME_None,
			HitResult.GetActor()->GetActorLocation(),
			HitResult.GetActor()->GetActorRotation()
		);
	}
	

}
//放下
void UGrabber::Release()
{
    
    
	UE_LOG(LogTemp, Warning, TEXT("!!!!!Release Me"));
	if (PhysicsHandle->GetGrabbedComponent()!=nullptr)//如果物理手柄获取抓到的组件不为空指针
	{
    
    
		//ReleaseComponent()实现放下物体,此时位置是固定的,没有实时变化
		PhysicsHandle->ReleaseComponent();
	}
}


// 每一帧运行(unity中的Update)
void UGrabber::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
    
    
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

	// 如果鼠标左键按下,每一帧都更新所拿起来的物体位置。
	if (PhysicsHandle->GetGrabbedComponent() != nullptr)//如果物理手柄获取抓到的组件不为空指针
	{
    
    
		//ReleaseComponent()实现放下物体,此时位置是实时变化
		PhysicsHandle->SetTargetLocation(GetLineEndPos());//设置目标在射线终点位置
	}
}
//获取射线起点
FVector UGrabber::GetLineStartPos() {
    
    
	FVector PlayerViewPointLocation;//定义射线的起点位置
	FRotator PlayerViewPointRotation;//定义射线的旋转后面朝方向
	//获取角色的位置和旋转方向
	GetWorld()->GetFirstPlayerController()->GetPlayerViewPoint(PlayerViewPointLocation, PlayerViewPointRotation);
	return PlayerViewPointLocation;
}
//获取射线终点
FVector UGrabber::GetLineEndPos() {
    
    
	FVector PlayerViewPointLocation;//定义射线的起点位置
	FRotator PlayerViewPointRotation;//定义射线的旋转后面朝方向
	//获取角色的位置和旋转方向
	GetWorld()->GetFirstPlayerController()->GetPlayerViewPoint(PlayerViewPointLocation, PlayerViewPointRotation);
	//射线终点位置(向量的加法,向量c=向量a+向量b)
	FVector LineTraceEndLocation = PlayerViewPointLocation + PlayerViewPointRotation.Vector() * Reach;
	return LineTraceEndLocation;
}
/// <summary>
/// 返回射线检测结果
/// </summary>

FHitResult UGrabber::GetFirstPhysicsActorInReach()
{
    
    

	//在场景中画线
	DrawDebugLine(
		GetWorld(),//获取(指向)当前运行世界(场景)
		GetLineStartPos(),//起点位置
		GetLineEndPos(),//终点位置
		FColor(255, 0, 0),//颜色
		false,//是否一直在世界中显示射线
		0.0f,
		0.0f,
		1.0f//射线粗细
	);


	//定义射线碰撞查询参数
	FCollisionQueryParams QueryParameter = FCollisionQueryParams(
		"",
		false, //false实心模型模糊检测,true空心模型高精度检测
		GetOwner()//射线检测忽略自己
	);
	//定义射线碰撞的结果
	FHitResult HitResult;
	//按对象类型获取世界中的射线轨迹
	GetWorld()->LineTraceSingleByObjectType(
		HitResult,
		GetLineStartPos(),//起点位置
		GetLineEndPos(),//终点位置
		FCollisionObjectQueryParams(ECollisionChannel::ECC_PhysicsBody),//按物体碰撞类型查询参数
		QueryParameter//射线碰撞查询参数
	);	
	return HitResult;
}

猜你喜欢

转载自blog.csdn.net/weixin_43834973/article/details/142025523