免费教程┆免费渲染┆免费模型免费软件┆下载中心┆ 资源QQ群┆学习QQ群 ┆在线课堂

3dmax吧

UE4教程(虚幻4)PhysFlying时动态物体的物理碰撞bug分析与解决方案
2018-02-10 14:38:21   来源:网络    评论:0 点击:

UE4教程(虚幻4)PhysFlying时动态物体的物理碰撞bug分析与解决方案这篇文章介绍了当character角色处于flying状态并且速度为0时,游戏场景内的动态物体可以穿过角色的bug以及对应解决方案。该bug在character处于
UE4教程(虚幻4)PhysFlying时动态物体的物理碰撞bug分析与解决方案
这篇文章介绍了当character角色处于flying状态并且速度为0时,游戏场景内的动态物体可以穿过角色的bug以及对应解决方案。
 
该bug在character处于swimming状态时一样会出现,其原理与解决方案都是类似的。
 
Bug重现
 
将character角色的MovementMode设定为MOVE_Flying
调用StopMovementImmediately()函数将其速度置为(0.f, 0.f, 0.f)
让场景中的动态物体向character角色运动,此时会发现物体将穿过角色
 

Unreal Engine 4 —— PhysFlying时动态物体的物理碰撞bug分析与解决方案

 
该bug已提交给Epic Games,对应issue为UE-35995
 
该bug官方预计在4.15版本进行修复,本博客提供的只是可行的workaround。
 
Bug分析
 
这个bug的玄机藏在UCharacterMovementComponent::PhysFlying(float deltaTime, int32 Iterations)函数中。在该函数里有代码如下:
 

[代码]:

1 FVector OldLocation = UpdatedComponent->GetComponentLocation();
2 const FVector Adjusted = Velocity * deltaTime;
3 FHitResult Hit(1.f);
4 SafeMoveUpdatedComponent(Adjusted, UpdatedComponent->GetComponentQuat(), true, Hit);
5  
6 if (Hit.Time < 1.f){...}
 
经过层层调用,会发现在USceneComponent::MoveComponentImpl(const FVector& Delta, const FQuat& NewRotation, bool bSweep, FHitResult* OutHit, EMoveComponentFlags MoveFlags, ETeleportType Teleport)中有这么一段代码:
 

[代码]:

1 // early out for zero case
2 if( Delta.IsZero() )
3 {
4     // Skip if no vector or rotation.
5     if (NewRotation.Equals(ComponentToWorld.GetRotation(), SCENECOMPONENT_QUAT_TOLERANCE))
6     {
7         return true;
8     }
9 }
 
也就是说,当Velocity为0.f时,会触发early out事件,将不检测碰撞而直接退出,这也就导致了该bug的产生。
 
Bug修复
 
更改引擎代码
 
若是想要彻底解决该问题,需要更改引擎代码,解决方案也较为直接:
 
可以直接重写UMovementComponent::MoveUpdatedComponent(const FVector& Delta, const FQuat& NewRotation, bool bSweep, FHitResult* OutHit, ETeleportType Teleport)方法即可。
 
自定义CharacterMovementComponent
 
由于更改引擎代码将带来代码管理以及团队协作的额外工作量,因此我个人更加推荐使用自定义的CharacterMovementComponent来进行该bug的修复。
 
创建UMainCharacterMovementComponent,对UCharacterMovementComponent进行public继承,并且重写PhysFlying(float deltaTime, int32 Iterations)方法。
 
重写方案有很多,我这里介绍一种工作量最小的修改方案:
 
由于UMovementComponent::SafeMoveUpdatedComponent(const FVector& Delta, const FQuat& NewRotation, bool bSweep, FHitResult& OutHit, ETeleportType Teleport)函数将对Delta为0的情况进行early out操作,因此我们可以让Velocity为0时先进行一个单位距离的移动,然后再将其移动回来。
 
也就是说将代码:
 

[代码]:

1 FVector OldLocation = UpdatedComponent->GetComponentLocation();
2 const FVector Adjusted = Velocity * deltaTime;
3 FHitResult Hit(1.f);
4 SafeMoveUpdatedComponent(Adjusted, UpdatedComponent->GetComponentQuat(), true, Hit);
5  
6 if (Hit.Time < 1.f){...}
 
改为:
 

[代码]:

1 FVector OldLocation = UpdatedComponent->GetComponentLocation();
2 const FVector Adjusted = Velocity.IsNearlyZero()? FVector(0.f, 0.f, -1.f): Velocity * deltaTime;
3 FHitResult Hit(1.f);
4 if (Velocity.IsNearlyZero())
5 {
6     SafeMoveUpdatedComponent(-Adjusted, UpdatedComponent->GetComponentQuat(), true, Hit);
7 }
8  
9 SafeMoveUpdatedComponent(Adjusted, UpdatedComponent->GetComponentQuat(), true, Hit);
 
这样一来便能够解决这个bug了,但是值得一提的是这只是一个workaround —— 会增加一些计算量,想要彻底解决这个问题怕是要伤筋动骨。

相关热词搜索:物体 物理 解决方案

上一篇:UE4教程(虚幻4) Unreal Engine 4 版本兼容的工作原理以及一些可优化项
下一篇:UE4教程(虚幻4) Unreal Engine 4禅意花园项目中的水池

版权声明:除本站原创外,本站提供的教程和资源均收集整理自网络,其版权归原始作者或原始出处所有!如有侵权请联系管理员删除(QQ:735017475)

本站提供的所有教程及模型素材等资料均用于免费分享,但是不可以盗链本站图片,也不可用于任何商业应用,否则后果自负.

版权所有:3Dmax吧网站(www.3dmax8.com)申请友情链接QQ:735017475,要求百度PR4以上。

湘ICP备05001069号 3DMAX吧(since-2002)