一、角色跳跃
Character
类中已经有了相应函数的实现,因此添加如下代码即可:
PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
二、创建火药桶类
课后作业要求:
用C++实现一个火药桶,在受击后会发生爆炸产生冲击波,并与周围的Actor产生物理交互。
- 要让模拟物理为
true
才能实现碰撞。 - 将
ForceComp
附加到MeshComp
上,再设置力作用的半径,力的强度,是否考虑质量,碰撞类型等。
//设置作用对象的碰撞类型
ForceComp->AddCollisionChannelToAffect(ECC_WorldDynamic);
//是否考虑将力作用到组件的拥有者
ForceComp->bIgnoreOwningActor = false;
force
和Impulse
的区别:
AddForce
: 用于在多个物理帧上施加一个持续的力。它的效果类似于不断推动或拉动物体,使物体逐渐加速。
AddImpulse
: 用于在单个物理帧上施加一个瞬时的冲击力。它的效果类似于一个瞬间的推动,使物体立即加速。
bImpulseVelChange
的作用:这个参数决定了冲击力是以速度的变化形式施加还是以惯性形式施加。
- 当
bImpulseVelChange
为true
:冲击力将直接改变物体的速度,而不考虑物体的质量。这意味着无论物体的质量是多少,速度的变化量将是相同的。 - 当
bImpulseVelChange
为false
:冲击力将按照物体的质量来施加。也就是说,冲击力的效果将会根据物体的质量而不同,较重的物体受到的速度变化将会较小。
URadialForceComponent::FireImpulse()
是URadialForceComponent
类中的一个方法,用于在一个指定半径内施加辐射冲击力。
- 对于
ForceComp->FireImpulse()
的源码分析:
void URadialForceComponent::FireImpulse()
{
//获取组件位置,作为施加冲击力的原点
const FVector Origin = GetComponentLocation();
// Find objects within the sphere
//用于存储重叠结果的数组
TArray<FOverlapResult> Overlaps;
//定义查询参数,不进行复杂碰撞
FCollisionQueryParams Params(SCENE_QUERY_STAT(FireImpulseOverlap), false);
// Ignore owner actor if desired
//如果需要忽略拥有该组件的Actor
if (bIgnoreOwningActor)
{
Params.AddIgnoredActor(GetOwner());
}
//在世界中查询与球体重叠的对象
GetWorld()->OverlapMultiByObjectType(Overlaps, Origin, FQuat::Identity, CollisionObjectQueryParams, FCollisionShape::MakeSphere(Radius), Params);
// A component can have multiple physics presences (e.g. destructible mesh components).
// The component should handle the radial force for all of the physics objects it contains
// so here we grab all of the unique components to avoid applying impulses more than once.
// 一个组件可以有多个物理存在(例如,可破坏的网格组件)。
// 该组件应处理其包含的所有物理对象的径向力
// 因此我们在这里抓取所有唯一的组件,以避免多次施加冲击力。
TArray<UPrimitiveComponent*, TInlineAllocator<1>> AffectedComponents;
AffectedComponents.Reserve(Overlaps.Num());
//遍历所有重叠结果,添加唯一的组件到受影响组件数组
for(FOverlapResult& OverlapResult : Overlaps)
{
if(UPrimitiveComponent* PrimitiveComponent = OverlapResult.Component.Get())
{
AffectedComponents.AddUnique(PrimitiveComponent);
}
}
//遍历所有受影响的组件
for(UPrimitiveComponent* PrimitiveComponent : AffectedComponents)
{
//如果破坏性伤害大于一个非常小的值
if(DestructibleDamage > SMALL_NUMBER)
{
//如果该组件实现了破环性接口
if(IDestructibleInterface* DestructibleInstance = Cast<IDestructibleInterface>(PrimitiveComponent))
{
//对破坏性组件施加范围伤害
DestructibleInstance->ApplyRadiusDamage(DestructibleDamage, Origin, Radius, ImpulseStrength, Falloff == RIF_Constant);
}
}
// Apply impulse
//对组件施加径向冲击力
PrimitiveComponent->AddRadialImpulse(Origin, Radius, ImpulseStrength, Falloff, bImpulseVelChange);
// See if this is a target for a movement component, if so apply the impulse to it
//如果该组件不是被设置为忽略径向冲击力
if (PrimitiveComponent->bIgnoreRadialImpulse == false)
{
// 临时数组,用于存储运动组件
TInlineComponentArray<UMovementComponent*> MovementComponents;
if(AActor* OwningActor = PrimitiveComponent->GetOwner())
{
//获取拥有该组件的Actor的所有运动组件
OwningActor->GetComponents<UMovementComponent>(MovementComponents);
for(const auto& MovementComponent : MovementComponents)
{
//如果运动组件更新的组件是当前组件
if(MovementComponent->UpdatedComponent == PrimitiveComponent)
{
//对运动组件施加径向冲击力
MovementComponent->AddRadialImpulse(Origin, Radius, ImpulseStrength, Falloff, bImpulseVelChange);
break;
}
}
}
}
}
}
- 总的来说,
URadialForceComponent::FireImpulse()
方法的主要作用是查找在特定半径内的所有物体,并对它们施加径向冲击力。如果这些物体具有破坏性接口,则还会对它们施加破坏性伤害。此外,如果这些物体是运动组件的一部分,冲击力也会施加到相关的运动组件上。
代码如下:
SurExplosiveBarrel.h
// SurExplosiveBarrel.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "SurExplosiveBarrel.generated.h"
class UStaticMeshComponent;
class URadialForceComponent;
UCLASS()
class SURKEAUE_API ASurExplosiveBarrel : public AActor
{
GENERATED_BODY()
public:
ASurExplosiveBarrel();
protected:
UPROPERTY(VisibleAnywhere)
UStaticMeshComponent* MeshComp;
UPROPERTY(VisibleAnywhere)
URadialForceComponent* ForceComp;
UFUNCTION()
void OnActorHit();
};
SurExplosiveBarrel.cpp
// SurExplosiveBarrel.cpp
#include "SurExplosiveBarrel.h"
#include "PhysicsEngine/RadialForceComponent.h"
#include "Components/StaticMeshComponent.h"
// Sets default values
ASurExplosiveBarrel::ASurExplosiveBarrel()
{
MeshComp = CreateDefaultSubobject<UStaticMeshComponent>("MeshComp");
// UE中的“模拟物理”选项
MeshComp->SetSimulatePhysics(true);
// 等同于在UE中将“碰撞预设”设置为“PhysicsActor”
MeshComp->SetCollisionProfileName(UCollisionProfile::PhysicsActor_ProfileName);
RootComponent = MeshComp;
ForceComp = CreateDefaultSubobject<URadialForceComponent>("ForceComp");
ForceComp->SetupAttachment(MeshComp);
ForceComp->Radius = 750.0f; // 爆炸范围
ForceComp->ImpulseStrength = 700.0f; // 冲击力
ForceComp->bImpulseVelChange = true; // 忽略质量大小;见UE中ForceComp的“冲量速度变更”
}
void ASurExplosiveBarrel::OnActorHit()
{
ForceComp->FireImpulse();
}