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);
View Code

   最后,在输入事件中添加油门和刹车,这里的 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()

 

posted @ 2025-04-08 10:47  zxc0210  阅读(133)  评论(0)    收藏  举报