UE之使用C++实现驾驶载具
1.前期准备
首先,载具系统是基于UE5的 ChaosVehicle 插件实现的,不使用插件的方法见:【UE4高级载具教程·一】·汽车插件分享·详细演示&代码讲解 ·物理模拟车辆套件_哔哩哔哩_bilibili。确保先启用插件:
并在项目的 .Build.cs文件中添加:
PrivateDependencyModuleNames.AddRange(new string[] { "ChaosVehicles" });
随后创建载具的Pawn类 AMyTestCar继承自 AWheeledVehiclePawn ,以及轮子类继承自 UChaosVehicleWheel,这个类是用来进行物理模拟的,并不是指视觉上的轮子:
还需要准备载具的骨骼网格模型,如果没有的话可以在左下角内容浏览器中添加默认的载具模板:
2.AWheeledVehiclePawn类型
首先,我们先看看父类中有些什么内容:
UPROPERTY(Category = Vehicle, VisibleDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) TObjectPtr<class USkeletalMeshComponent> Mesh; /** vehicle simulation component */ UPROPERTY(Category = Vehicle, VisibleDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) TObjectPtr<class UChaosVehicleMovementComponent> VehicleMovementComponent;
包括一个Mesh以及一个MovementComponent,注意这里的移动组件在构造函数中实际上创建的是派生类UChaosWheeledVehicleMovementComponent的对象,只是返回的是一个基类的指针。
VehicleMovementComponent = CreateDefaultSubobject<UChaosVehicleMovementComponent, UChaosWheeledVehicleMovementComponent>(VehicleMovementComponentName);
3.载具类的实现
OK现在回到自定义的AMyTestCar中,初始化骨骼模型,相机,绑定输入操作等,这一步这里就省略了。注意要启用骨骼网格体的物理模拟:
GetMesh()->SetSimulatePhysics(true);
同时,我们还需要将基类的移动组件指针对象重新转为派生类,并在构造函数中进行相关设置:
UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "VehicleMovement") UChaosWheeledVehicleMovementComponent* WheelMovement;
int32 WheelNum = 4;
UPROPERTY(EditAnywhere)
UCurveFloat* EngineCurve;
WheelMovement = Cast<UChaosWheeledVehicleMovementComponent>(GetVehicleMovementComponent()); WheelMovement->WheelSetups.SetNum(WheelNum); //设置轮子的数量 WheelMovement->EngineSetup.TorqueCurve.ExternalCurve = EngineCurve; //设置发动机启动曲线
这一步设置好之后就可以看到:
现在数组的元素还是空的,因为我们并没有指定物理车轮,首先在之前创建的车轮类 UMyChaosVehicleWheel 中预先设置好车轮大小,悬挂等参数:
UMyChaosVehicleWheel::UMyChaosVehicleWheel() { // 车轮 WheelRadius = 35.0f; WheelWidth = 20.0f; // 悬挂 SuspensionMaxRaise = 10.0f; SuspensionMaxDrop = 10.0f; SuspensionDampingRatio = 0.5f; // 摩擦 FrictionForceMultiplier = 3.0f; }
还需要指定车轮的类型,前轮是转向轮,后轮是驱动轮,车辆类必须同时拥有这两种类型的轮子。这里可以创建两个车轮类实现,或者创建两个UMyChaosVehicleWheel的蓝图类在蓝图中指定:
AxleType = EAxleType::Front; //前轮 AxleType = EAxleType::Rear; //后轮
然后回到车辆类AMyTestCar中,指定每个物理车轮使用的类,以及匹配的骨骼等:

// 左前轮 WheelMovement->WheelSetups[0].WheelClass = UFrontWheel::StaticClass(); WheelMovement->WheelSetups[0].BoneName = TEXT("PhysWheel_FL"); // 骨骼名需匹配 WheelMovement->WheelSetups[0].AdditionalOffset = FVector(0, 0, 0); // 右前轮 WheelMovement->WheelSetups[1].WheelClass = UFrontWheel::StaticClass(); WheelMovement->WheelSetups[1].BoneName = TEXT("PhysWheel_FR"); WheelMovement->WheelSetups[1].AdditionalOffset = FVector(0, 0, 0); // 左后轮 WheelMovement->WheelSetups[2].WheelClass = URearWheel::StaticClass(); WheelMovement->WheelSetups[2].BoneName = TEXT("PhysWheel_BL"); WheelMovement->WheelSetups[2].AdditionalOffset = FVector(0, 0, 0); // 右后轮 WheelMovement->WheelSetups[3].WheelClass = URearWheel::StaticClass(); WheelMovement->WheelSetups[3].BoneName = TEXT("PhysWheel_BR"); WheelMovement->WheelSetups[3].AdditionalOffset = FVector(0, 0, 0);
最后,在输入事件中添加油门和刹车,这里的 powerValue 和 brakeValue 都在 [-1,1] 范围内:
void AMyTestCar::SetTraction(float powerValue, float brakeValue) { WheelMovement->SetThrottleInput(powerValue); WheelMovement->SetBrakeInput(brakeValue); }
现在按下W之后,车辆应该是可以动起来了。这里有一个很有意思的地方就是,即使把刹车设置的很小,比如0.001,但是刹车效果依旧很强劲。由于使用的是Brake,我们希望它的制动应该是线性的,而不是像Handbrake一样锁死车轮。因此可以将Brake的扭矩调小,以此来减弱刹车的效果:
最后,可以自定义车轮的旋转和转向函数实现车轮的视觉效果,或者在动画蓝图中添加车轮控制器实现:
4.获取速度
获取速度的方法:
float AMyTestCar::getSpeed() { FVector Velocity = GetMesh()->GetComponentVelocity(); float CurrentSpeed = Velocity.Size() * 0.036f; return CurrentSpeed; }
速度的方向可以通过 WheelMovement 获取:
WheelMovement->GetForwardSpeed()