UE 5.4中的自定义重力
点击上方蓝字CG世界关注我们再点右上角···设为星标★UE 5.4在CharacterMovementController中引入了对自定义重力的支持。了解如何利用它并做一些很酷的事情,比如重力拼图,或者创建一个像重力游戏一样的迷你星球。
简介在本教程中,我们将利用UE 5.4的重力覆盖功能,使Player能够在一个小行星上奔跑。这将为您自己的项目提供任何其他类型的重力操作的良好基础。注:自定义重力在早期版本的Unreal中并不完全有效。相关代码可能存在,但存在一些问题使其无法使用。
创建项目对于此项目,我们将扩展第三人称蓝图项目。本教程不需要初学者内容包,因此我跳过了它,但欢迎您将其包含在内。
添加重力摄像机处理(C++)当您在游戏中移动鼠标时,Unreal将获取该鼠标输入并将其转发到Player Controller以用于在Player周围移动摄像机。但是鼠标坐标始终和世界本身保持相关,其Z轴向下。例如,当Player倒置时,这些鼠标输入需要考虑到这一点,否则我们的摄像机控制将颠倒。为了解决这个问题,我们将添加一些代码来接收此输入,然后将其转换为“局部重力空间”,以便摄像机控制可以保持“相对”。我们通过创建一个名为GravityController的新C++类来实现这个功能,该类扩展了普通的APlayerController类,但增加了对相对重力输入处理的支持。这是我们在本教程中唯一需要的C++类,其他所有内容都将在蓝图中。让我们通过单击工具 → 创建新的C++类...
对于父类,我们现在只需选择“无”,无论如何,我们都将在下一步中将代码复制并粘贴到其中。
调用新类GravityController,然后创建它。Unreal现在会将项目转换为C++项目,并为我们创建一个默认代码模块。
按“OK”继续。
按“No”关闭此对话框。
现在,我们将关闭Unreal并填充新类。转到项目的文件夹并打开Source文件夹。其中应该有一个与您的项目同名的子文件夹,这是您的默认游戏模块。我们的新类应该在那里。
在诸如Visual Studio甚至只是记事本这样的文本编辑器中打开GravityController.h。删除其中的所有内容并将其替换为以下代码:#pragma once
#include "CoreMinimal.h"#include "GameFramework/PlayerController.h"#include "GravityController.generated.h"
/** * A Player Controller class which adds input-handling functionality for * CharacterMovementController's custom gravity mechanics. */UCLASS()class AGravityController : public APlayerController{GENERATED_BODY()
public:virtual void UpdateRotation(float DeltaTime) override;
// Converts a rotation from world space to gravity relative space.UFUNCTION(BlueprintPure)static FRotator GetGravityRelativeRotation(FRotator Rotation, FVector GravityDirection);
// Converts a rotation from gravity relative space to world space.UFUNCTION(BlueprintPure)static FRotator GetGravityWorldRotation(FRotator Rotation, FVector GravityDirection);
private:FVector LastFrameGravity = FVector::ZeroVector;};现在打开GravityController.cpp,删除其中的所有内容并将其替换为以下代码:#include "GravityController.h"#include "GameFramework/Character.h"#include "GameFramework/CharacterMovementComponent.h"
void AGravityController::UpdateRotation(float DeltaTime){FVector GravityDirection = FVector::DownVector;if (ACharacter* PlayerCharacter = Cast<ACharacter>(GetPawn())){ if (UCharacterMovementComponent* MoveComp = PlayerCharacter->GetCharacterMovement()) { GravityDirection = MoveComp->GetGravityDirection(); }}
// Get the current control rotation in world spaceFRotator ViewRotation = GetControlRotation();
// Add any rotation from the gravity changes, if any happened.// Delete this code block if you don't want the camera to automatically compensate for gravity rotation.if (!LastFrameGravity.Equals(FVector::ZeroVector)){ const FQuat DeltaGravityRotation = FQuat::FindBetweenNormals(LastFrameGravity, GravityDirection); const FQuat WarpedCameraRotation = DeltaGravityRotation * FQuat(ViewRotation);
ViewRotation = WarpedCameraRotation.Rotator(); }LastFrameGravity = GravityDirection;
// Convert the view rotation from world space to gravity relative space.// Now we can work with the rotation as if no custom gravity was affecting it.ViewRotation = GetGravityRelativeRotation(ViewRotation, GravityDirection);
// Calculate Delta to be applied on ViewRotationFRotator DeltaRot(RotationInput);
if (PlayerCameraManager){ ACharacter* PlayerCharacter = Cast<ACharacter>(GetPawn());
PlayerCameraManager->ProcessViewRotation(DeltaTime, ViewRotation, DeltaRot);
// Zero the roll of the camera as we always want it horizontal in relation to the gravity. ViewRotation.Roll = 0;
// Convert the rotation back to world space, and set it as the current control rotation. SetControlRotation(GetGravityWorldRotation(ViewRotation, GravityDirection));}
APawn* const P = GetPawnOrSpectator();if (P){ P->FaceRotation(ViewRotation, DeltaTime);}}
FRotator AGravityController::GetGravityRelativeRotation(FRotator Rotation, FVector GravityDirection){if (!GravityDirection.Equals(FVector::DownVector)){ FQuat GravityRotation = FQuat::FindBetweenNormals(GravityDirection, FVector::DownVector); return (GravityRotation * Rotation.Quaternion()).Rotator();}
return Rotation;}
FRotator AGravityController::GetGravityWorldRotation(FRotator Rotation, FVector GravityDirection){if (!GravityDirection.Equals(FVector::DownVector)){ FQuat GravityRotation = FQuat::FindBetweenNormals(FVector::DownVector, GravityDirection); return (GravityRotation * Rotation.Quaternion()).Rotator();}
return Rotation;}编译项目在此部分,您需要安装Visual Studio。如果您尚未安装,请查看本教程,了解如何执行此操作:设置Visual Studio | Epic开发者社区(https://dev.epicgames.com/docume ... ts-in-unreal-engine)。打开项目的Visual Studio解决方案文件。
然后按F5键,或按“▷本地的Windows调试器”按钮,编译项目并使用新类运行Unreal编辑器。
使用新的重力控制器我们现在已经创建了GravityController类,但我们还需要通知Unreal使用该类,而不是默认的内置类。进入虚幻编辑器后,打开Content/ThirdPerson/Blueprints/BP_ThirdPersonGameMode蓝图,并修改PlayerControllerClass属性以使用我们的新GravityController类。
和重力相关的鼠标输入现在我们需要稍微修复一下鼠标输入。对于左/右Pawn输入,第三人称Character会丢弃控制器控制旋转的Pitch部分,以便输入值垂直于Player的胶囊体,即始终伸向Player。否则,如果摄像机面朝下,播放器会变慢,因为控件旋转也会朝下。而且我们也只需要Yaw部分用于前置/后置输入。但是旋转控制已经旋转了!所以我们不能再丢弃Pitch了。我们的解决方法是,首先将旋转控制从世界变换转换为相对的“局部重力”变换。然后,我们可以像往常一样丢弃Pitch,然后将控制旋转转换回世界变换,然后再将其馈送到Player Pawn。我们在上一步中添加的代码介绍了几个便捷的蓝图函数,即GetGravityRelativeRotation和GetGravityWorldRotation,它们可以帮助我们做到这一点。现在就使用它们吧!打开Content/ThirdPerson/Blueprints/BP_ThirdPersonCharacter(如果您愿意,也可以复制它以创建自己的,请记得修改BP_ThirdPersonGameMode),并将输入处理修改为以下内容:
单击图像以查看它的放大版本,或右键单击选择“在新选项卡中打开图片”。要让Gravity Rotation节点显示三个浮点数,而不是上面屏幕截图中的Rotator,您可以右键单击Rotator Return Value引脚并选择“Split Struct Pin”。
修正动画图表第三人称Character假定X和Y速度是其行走速度。但是,如果角色旋转,则不成立。我们需要它考虑到所有轴的行走速度。打开Content/Characters/Mannequins/Animations/ABP_Manny,在这里我们可以修改地面速度计算以使用整个矢量的长度,而不仅仅是X和Y。我们可以修改注释。修改前:
修改后:
操纵重力现在进入有趣的部分!您现在可以通过其SetGravityDirection蓝图节点任意修改CharacterMovementComponent的重力!重力切换器这就是您拥有一个体积所需的全部内容,当Player与它重叠时,它会改变Player的重力方向。它非常适合将重力倒置,或让Player爬墙。
行星引力如果您希望Player的重力每帧都改变,例如,使Player的重力始终与另一个对象(如行星),则可以将类似这样的内容放入PlayerCharacter的Tick函数中。“Target Gravity Actor”是一个变量,它包含您想要让Player行走的目标Actor。
全文完
太逼真了!
《荒野机器人》概念图和动画制作幕后
他用PS把Blender模型都涂成了脑洞超大的概念图
页:
[1]