本篇博文用到的关键类有:
UInputComponent 用来绑定鼠标的按下和释放事件 BindAction
UPhysicsHandleComponent 设置被抓取物体的抓取,移动,释放
GrabComponentAtLocationWithRotation
ReleaseComponent
SetTargetLocation
UPrimitiveComponent 抓取组件抓取的对象
还可以获取质量 GetMass
首先,添加鼠标事件,在项目设置中,引擎->输入->操作映射,按加号,添加一个映射对象,然后添加一个鼠标左键事件,一个空格键事件。
在代码中创建一个 UInputComponent对象。
在grabber.h文件中,定义个人建议使用前置声明,把头文件放在cpp里面去包含。
并且添加两个函数,一个表示按下,一个表示释放。
#include
void Grab();
void Release();
UInputComponent* inputComponent = nullptr;
在cpp文件中添加:
// Called when the game starts
void Ugrabber::BeginPlay()
{
Super::BeginPlay();
inputComponent = GetOwner()->FindComponentByClass<UInputComponent>();
if (nullptr != inputComponent)
{
UE_LOG(LogTemp, Warning, TEXT("find inputComponent"));
inputComponent->BindAction("grab", IE_Pressed, this, &Ugrabber::Grab);
inputComponent->BindAction("grab", IE_Released, this, &Ugrabber::Release);
}
else
{
UE_LOG(LogTemp, Error, TEXT("not find inputComponent"));
}
}
void Ugrabber::Grab()
{
UE_LOG(LogTemp, Warning, TEXT("inputComponent press"));
}
void Ugrabber::Release()
{
UE_LOG(LogTemp, Error, TEXT("inputComponent release"));
}
然后在虚幻编译器中进行编译,运行,鼠标按下释放,空格按下释放,都能打印日志,表示事件被触发。
添加的句柄对应的类是UPhysicsHandleComponent。
在grabber.h文件中,定义个人建议使用前置声明,把头文件放在cpp里面去包含。
并且添加两个函数,一个表示按下,一个表示释放。
class UPhysicsHandleComponent;
UPhysicsHandleComponent* physicsHandel = nullptr;
在grabber.cpp文件中添加:
BeginPlay()
{
physicsHandel = GetOwner()->FindComponentByClass<UPhysicsHandleComponent>();
}
// Called every frame
void Ugrabber::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
// 设置抓取物体跟随移动
if (physicsHandel && physicsHandel->GrabbedComponent)
{
physicsHandel->SetTargetLocation(getLineEnd());
}
}
void Ugrabber::Grab()
{
UE_LOG(LogTemp, Warning, TEXT("inputComponent press"));
FHitResult hit = lineTrace();
UPrimitiveComponent* primit = hit.GetComponent();
if (hit.GetActor() && physicsHandel)
{
UE_LOG(LogTemp, Warning, TEXT("Grab"));
physicsHandel->GrabComponentAtLocationWithRotation(primit, NAME_None, primit->GetOwner()->GetActorLocation(), GetOwner()->GetActorRotation());
}
}
void Ugrabber::Release()
{
UE_LOG(LogTemp, Error, TEXT("inputComponent release"));
if (physicsHandel)
{
physicsHandel->ReleaseComponent();
}
}
这里把物体的抓取和释放的函数修改了。
要计算物体重量,需要给物体添加一个选项: 生成重叠事件
一定要把物体的 生成重叠事件 这个选项勾选,否则没法被检查到。物体质量也没法计算。
在openDoor.h文件中添加一个函数:
float GetTotalMassInTrigger();
在openDoor.cpp文件中添加如下代码:
float UopenDoor::GetTotalMassInTrigger()
{
if (nullptr == trigger)
{
return 0.0f;
}
TArray<AActor*> actArr;
trigger->GetOverlappingActors(OUT actArr);
float totalMass = 0.0f;
for (const AActor* act : actArr)
{
totalMass += act->FindComponentByClass<UPrimitiveComponent>()->GetMass();
}
UE_LOG(LogTemp, Warning, TEXT("total mass %f"), totalMass);
return totalMass;
}
// Called every frame
void UopenDoor::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
// if (nullptr != trigger && trigger->IsOverlappingActor(pawn))
if(trigger && GetTotalMassInTrigger() > 25.0f)
{
openDoor();
lastTime = GetWorld()->GetTimeSeconds();
}
if (GetWorld()->GetTimeSeconds() - lastTime > openTime)
{
closeDoor();
}
}
在 TickComponent 函数中添加了质量判断,还修改开门的方式,桌子和椅子一共的重量添加,才能触发开门。
运行起来,桌子和椅子一起在触发器范围内,总质量为30kg,触发机关,门打开了。
当然角色老是会在空中飘着,给角色也设置一个模拟物体的属性,这样物体就带重力了,跳上去也会慢慢落下来。
到此,游戏基本完成,下篇博文会使用蓝图对开门等操作,设置动画效果。