UE 5.4在CharacterMovementController中引入了对自定义重力的支持。了解如何利用它并做一些很酷的事情,比如重力拼图,或者创建一个像重力游戏一样的迷你星球。
简介
在本教程中,我们将利用UE 5.4的重力覆盖功能,使Player能够在一个小行星上奔跑。
这将为您自己的项目提供任何其他类型的重力操作的良好基础。
对于此项目,我们将扩展第三人称蓝图项目。本教程不需要初学者内容包,因此我跳过了它,但欢迎您将其包含在内。
这是我们在本教程中唯一需要的C++类,其他所有内容都将在蓝图中。让我们通过单击工具 → 创建新的C++类...
对于父类,我们现在只需选择“无”,无论如何,我们都将在下一步中将代码复制并粘贴到其中。
调用新类GravityController,然后创建它。Unreal现在会将项目转换为C++项目,并为我们创建一个默认代码模块。
按“OK”继续。
按“No”关闭此对话框。
转到项目的文件夹并打开Source文件夹。其中应该有一个与您的项目同名的子文件夹,这是您的默认游戏模块。我们的新类应该在那里。
#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 space
FRotator 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 ViewRotation
FRotator 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/documentation/en-us/unreal-engine/setting-up-visual-studio-development-environment-for-cplusplus-projects-in-unreal-engine)。
使用新的重力控制器
我们现在已经创建了GravityController类,但我们还需要通知Unreal使用该类,而不是默认的内置类。
和重力相关的鼠标输入
现在我们需要稍微修复一下鼠标输入。对于左/右Pawn输入,第三人称Character会丢弃控制器控制旋转的Pitch部分,以便输入值垂直于Player的胶囊体,即始终伸向Player。否则,如果摄像机面朝下,播放器会变慢,因为控件旋转也会朝下。而且我们也只需要Yaw部分用于前置/后置输入。
但是旋转控制已经旋转了!所以我们不能再丢弃Pitch了。
我们的解决方法是,首先将旋转控制从世界变换转换为相对的“局部重力”变换。然后,我们可以像往常一样丢弃Pitch,然后将控制旋转转换回世界变换,然后再将其馈送到Player Pawn。
我们在上一步中添加的代码介绍了几个便捷的蓝图函数,即GetGravityRelativeRotation和GetGravityWorldRotation,它们可以帮助我们做到这一点。
要让Gravity Rotation节点显示三个浮点数,而不是上面屏幕截图中的Rotator,您可以右键单击Rotator Return Value引脚并选择“Split Struct Pin”。
修正动画图表
第三人称Character假定X和Y速度是其行走速度。但是,如果角色旋转,则不成立。我们需要它考虑到所有轴的行走速度。
打开Content/Characters/Mannequins/Animations/ABP_Manny,在这里我们可以修改地面速度计算以使用整个矢量的长度,而不仅仅是X和Y。我们可以修改注释。
操纵重力
现在进入有趣的部分!您现在可以通过其SetGravityDirection蓝图节点任意修改CharacterMovementComponent的重力!
重力切换器
行星引力
太逼真了!
《荒野机器人》概念图和动画制作幕后
他用PS把Blender模型都涂成了脑洞超大的概念图