引擎项目设置
玩家控制器中需要添加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;
}