[UE4]物理和刚体相关的注意事项(Simulate Physics and RigidBody)
keywords: UE4, Collision, Simulate Physics, RigidBody
UProjectileMovementComponent相关
官方第一人称射击模版项目中,是在构造函数中就设置好了速度:
ProjectileMovement = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("ProjectileComp"));
ProjectileMovement->UpdatedComponent = CollisionComp;
ProjectileMovement->InitialSpeed = 3000.f;
ProjectileMovement->MaxSpeed = 3000.f;
ProjectileMovement->bRotationFollowsVelocity = true;
ProjectileMovement->bShouldBounce = true;
两个问题:
- 如何停止移动;
- 如何在运行时期间修改速度;
问题1解决方法:
默认情况下,Actor spawn之后,就会受到 ProjectileMovement 影响立即移动,如何在 Spawn 之后马上停止移动:
ProjectileMovement->Deactivate();
问题2解决方法:
如何在 Spawn 之后修改 Speed,两种方式:
UProjectileMovementComponent->SetVelocityInLocalSpace(FVector NewVelocity);
或者
UProjectileMovementComponent->Velocity = NewVelocity;
Velocity计算方式:
Velocity = Velocity.GetSafeNormal() * InitialSpeed;
前者速度方向是相对于 UProjectileMovementComponent本地坐标系 的相对Rotation,后者速度方向是相对于世界坐标系的绝对Rotation。
注意:当使用 UProjectileMovementComponent 后,UPrimitiveComponent::SetSimulatePhysics() 启用物理会与 ProjectileMovement 冲突。如果要使用物理,那么只能去掉 UProjectileMovementComponent ,使用 Add Impulse 来代替。
参考:
Simulate Physics and Projectile Movement Component
https://answers.unrealengine.com/questions/736999/simulate-physics-and-projectile-movement-component.html
UProjectileMovementComponent处理平面滑动
bool UProjectileMovementComponent::HandleSliding(FHitResult& Hit, float& SubTickTimeRemaining)
模拟物理时StaticMesh和CollisionComponent冲突
记住:StaticMesh自带刚体(RigidBody),并能执行碰撞(Collision)相关逻辑。
比如新建一个 Actor,并在该 Actor 内部创建了一个 BoxComponent ,然后再创建一个 StaticMeshComponent 并 Attach 到 BoxComponent 上。
如果不模拟物理,那么没有问题,一旦模拟物理并执行 AddImpulse 时,就会出问题。
现象:
如果只对 StaticMeshComponent 执行击飞,那么 BoxComponent 会停在原地,如果对 BoxComponent 击飞: BoxComponent->BodyInstance.AddImpulse()
,那么 StaticMeshComponent 不会动。
解决办法:
直接使用 StaticMeshComponent Collision ,不用与 Col1isionComponent 附加。
如何处理发射刚体与角色刚体冲突
问题现象:
当角色的CollisionComponent
半径较大时,此时想在角色面前发射(AddImpulse
)一个Simulate Physics
的StaticMeshActor
,但是当这个 Actor 刚发射之前,其刚体正好和角色的刚体相互影响,导致 Actor 没能按预定方向和速度运动。
三种解决办法:
- 减小角色刚体半径,或者发射点放在刚体半径以外。或者将发射物的生成坐标放在角色胶囊体之外。
- 通过自定义碰撞通道将两个Mesh的碰撞避开。
- 使用
UPrimitiveComponent::IgnoreActorWhenMoving()
将胶囊体从子弹的碰撞检测中过滤掉。
不使用 MovementComponent 情况下设置 Gravity 大小
MovementComponent 有个属性Gravity Scale
来设置重力大小。
假设一个 Actor 如果没有添加 MovementComponent ,只有一个 StaticMeshComponent ,此时 StaticMeshComponent 模拟物理时,其重力加速度较小,这种情况下有没办法设置重力加速度大小?方式如下:
StaticMeshComp->SetSimulatePhysics(true);
StaticMeshComp->AddImpulse(SpeedInWorld);
然后在 Tick 函数中每帧设置:
FVector Velocity = StaticMeshComp->GetPhysicsLinearVelocity();
Velocity.Z -= 100.f;
StaticMeshComp->SetPhysicsLinearVelocity(Velocity);
说明:GetPhysicsLinearVelocity
默认为0,这里修改成 -100.f 的重力下降速率,
禁用、开启物理
//禁用所有子组件的物理模拟(但是没有对应的开启物理的API)
AActor::DisableComponentsSimulatePhysics();
//禁用指定组件的物理模拟
GetCapsuleComponent()->SetSimulatePhysics(false);
GetMesh()->SetSimulatePhysics(false);
Ingore special Actor’s Collision when it moving
/**
* Tells this component whether to ignore collision with all components of a specific Actor when this component is moved.
* Components on the other Actor may also need to be told to do the same when they move.
* Does not affect movement of this component when simulating physics.
*/
void UPrimitiveComponent::IgnoreActorWhenMoving(AActor* Actor, bool bShouldIgnore)
mesh scale 与物理
如果修改mesh (StaticMesh和SkeletalMesh)的Scale,则会影响刚体碰撞问题,比如,一个碎片在地面上微微飘到。
所以不建议修改资产的scale,且SpawnActor()
接口中的Transform参数,如果修改Scale默认是不生效的,官方也不建议修改Scale。
收集资料
Using Async Collision Traces in Unreal Engine 4
https://medium.com/@bryan.corell/using-async-collision-traces-in-unreal-engine-4-2cc312c825f5
Inside Unreal Physics
http://www.recursiveblueprints.fun/inside-unreal-physics/
UE4 How to Connect Skeletal Mesh with object using Physics Constraints in Unreal Engine 4 Tutorial.
https://www.youtube.com/watch?v=uHV6VHzPqxM
The Art of PhysX
https://pdfs.semanticscholar.org/presentation/faec/14b559373222fa1f2150e3aaaaf6f20b3b2e.pdf