Vehicle support

HI

New to UE4.5 having shifted over from UDK and trying to get a customised vehicle running using C++ (and little to no blue-prints if possible).
Having worked on a bunch of console/PC/handheld racing games I thought vehicles would be a good place to start and should be fairly straightforward.

Wasted 2 days on trying to customise a car fully via the Vehicle Game blueprint template and got nowhere - a horrendous number of problems.
Configuring a car over about 20+ different blueprints/tabs/graphs/locations/files is horrific and making changes to the source skeletal mesh and re-importing is an extremely painful process. Trying to compare two vehicle setups across all these data locations leads to madness.
Encountered all sorts of problems with floating car, incorrect physics, bizarre suspension behaviour, very odd vehicle rig, blah, blah.

So I gave up on that and tried the advanced vehicle C++ template instead and managed to import my car and have it driving about using the coded default setup in about 30 mins.

However, this is where progress halted and I can’t work out how to fully tune all the PhysX/UE car setup params.
For example, in the vehicle template MaxEngineRPM value is set in the constructor of the vehicle pawn class like this:


Vehicle4W->MaxEngineRPM = 5700.0f;

I don’t think this does anything & only appears to work as it happens to match the default RPM set elsewhere.
Changing this RPM value and the resulting TorqueCurve still shows 5700 as the MaxRPM when using the physics debugger.
Having plowed through some of the PhysX/UE code I don’t see how it can work as the VehicleSetup function isn’t being called (again).
Changing the default gear ratios from code seems to be somewhat impossible out of the box via C++?

I started to look into my own WheeledVehicleMovementComp class, but there seems to be issues with including the required PhysX types at game code level (I’ll admit I’ve not spent too long looking into this yet). The flow of data to/from PhysX and the UE classes isn’t entirely clear to me, nor is the process for changing values after all the PhysX/UE init work has been done. Is this documented anywhere?

I’ve looked at the forums and there seems to be some ongoing similar issues.

Vehicle setup shouldn’t be this difficult/complicated - ideally there’s only 1 function required that’s used to setup the car fully that’s easily overriden for different car types and just calls “SetupVehicle” to update. It should also easily allow car modifications to be applied for support of player “tuning”. Normally I’d just drive this data from Excel and auto-generate the code for setup per car.

Apologies in advance if I’m missing something obvious here - if anyone can help at all with this I’d be very thankful.

Cheers
William

Hello.

Changing MaxEngineRPM in code should work fine. Just make sure you provide changes to torque curve to correspond to the value change, since if engine produces 0 torque, RPM won’t go higher i believe :slight_smile:

Regarding the tuning process within C++, you actually should not do that. It would be much better for you to create Blueprint asset based on your class and tweak the properties inside editor, it increases iteration speed in many times. This Blueprint in this case may not contain any “code” at all, since all logic is handled within C++ parent class, so it would be data-only Blueprint that nearly produces no performance hit at all. Of course you could tweak your actors within C++, but it totally does not worth it, you should just set your default values there. There are not so many properties categories that change vehicle behavior, they’re mostly correspondingly named, except “Physics” category, its changes also apply to vehicle, since it’s rigid-body actor.

SetupVehicle is called within CreateVehicle. The thing is, that WheeledVehicleMovementComponent is the base class for wheeled vehicles, such as motorcycle, standard car, or n-wheeled car. So SetupVehicle function is implemented only in WheeledVehicleMovementComponent4W.

To change gear ratios in C++, you should do something like the following in constructor:



FVehicleGearData Gear;
Gear.Ratio = 1.3f;
Gear.DownRatio = 0.5f;
Gear.UpRatio = 0.8f;

TransmissionSetup.ForwardGears.Add(Gear);

Hope it helps.

HI

Thanks for taking the time to respond; have you actually tested what you are suggesting?

If you change the vehicle template C++ code from:


	Vehicle4W->MaxEngineRPM = 5700.0f;
	Vehicle4W->EngineSetup.TorqueCurve.GetRichCurve()->Reset();
	Vehicle4W->EngineSetup.TorqueCurve.GetRichCurve()->AddKey(0.0f, 400.0f);
	Vehicle4W->EngineSetup.TorqueCurve.GetRichCurve()->AddKey(1890.0f, 500.0f);
	Vehicle4W->EngineSetup.TorqueCurve.GetRichCurve()->AddKey(5730.0f, 400.0f);

to:


	Vehicle4W->MaxEngineRPM = 9000.0f;
	Vehicle4W->EngineSetup.TorqueCurve.GetRichCurve()->Reset();
	Vehicle4W->EngineSetup.TorqueCurve.GetRichCurve()->AddKey(0.0f, 700.0f);
	Vehicle4W->EngineSetup.TorqueCurve.GetRichCurve()->AddKey(3250.0f, 800.0f);
	Vehicle4W->EngineSetup.TorqueCurve.GetRichCurve()->AddKey(6000.0f, 900.0f);
	Vehicle4W->EngineSetup.TorqueCurve.GetRichCurve()->AddKey(9000.0f, 1000.0f);

There will be NO CHANGE to the engine RPM as reported by the physics debugger/visualizer. The reasons for this are described in my first post.

No, you should not use Blueprints for advanced vehicle setup for many reasons:

  • They are an unneccessary abstraction of only a partial set of the parameters available, ie: it’s an over complication to provide only limited setup.
  • Data is spread out across a horrendous number of places.
  • Comparing data across multiple vehicles is very difficult
  • Updating blueprint changes across multiple setups is painful (I suppose you could attempt some kind of template/wrapper blueprint)
  • Changing the base class of a blueprint you’ve configured doesn’t seem possible and cutting/pasting into a different class based blue print has issues (I’ll admit I’m new, so there may be a way to do this?)
  • They do not scale well to 100+ cars or their potential dynamic modification (upgrade shops, damage systems, etc)
  • They are not easily generated via data tables (Excel, etc) (I suppose with a bit of effort you could pull this off, but why bother when you can code it more easily)
    • all the issues/problems listed in the original post

If design/compilation time is a concern then a customised vehicle param tuner window that exposes EVERYTHING in the one place is the way to go. This would also allow you to copy & paste a car setup for modification with 1 click.

What you are suggesting for gear setup does work as it’s done in the constructor (assuming of course you clear the existing gears array and setup the other required params as well)

However:

  • WheeledVehicleMovementComponent4W is an engine side class that directly references PhysX and uses PhysX defaults for everything. I want to replace it and I’ve yet to work out how I can write my own replacement for this class on the game side and reference PhysX (I’m guessing this must be do-able?).
  • I don’t want vehicle setup to be done via constructor methods alone as they are extremely limiting( Ex: modifications and tuning after setup/creation, remove/add damage attributes, reset to default whilst playing). I’d prefer a base class constructor to call some overridable “SetupData” fn instead, which allows for it to be called whenever is required with the ability to call another fn that makes sure the Physics engine, etc is updated with the new params/data.
  • Constructor based setup of torque graphs, steering curves, etc, etc are currently generated in the base class constructor only to be torn down and rebuilt in derived classes later on. You cannot rely on safely not calling a parent constructor as code may change in the future, etc, etc.
    • the other issues as per the first post

Ideally you don’t even have multiple car type classes, blueprints or anything complex. Just a generic vehicle class that can point to a data block for initialisation & updates.

Anyway, has anyone fully configured a vehicle from C++? Any tips on how you went about it would be great.

Cheers
William

OK, part of the problem with the vehicle template example seems to be that it’s trying to set MaxEngineRPM which is delcared as part of WheeledVehicleMovementComponent.

However, UWheeledVehicleMovementComponent4W actually adds a var called EngineSetup which is a FVehicleEngineData struct containing a MaxRPM param.
This seems to be the value the code should be setting/using from the vehicle pawn class as it does modify the max RPM reached as show by the physics debugger.
There is some sort of “conversion” fn called UWheeledVehicleMovementComponent4W::ComputeConstants() which copies this over, but it’s never called in the example code.

This highlights part of the problem from my first post regarding it not being clear what the data flow from/to UE/PhysX classes is or what the order of init/modification is/should be.

sorry i cant help, just empathizing with you, ive encountered similar problems but assumed it was down to me not understanding how ue4 c++ classes function or something.
there is also something in the car behavior that is not right, try a high speed crash and you will see ‘strange and magical forces’ acting on the vehicle.
im in the process of delving into the physx code just for fun, but hopefully at some point i will discover either how to write my own physx vehicle or implement some other kind of physics model altogether.
and i totally agree on the blueprint thing, they seem to be favored in ue4 for some unknown reason.

Well, changing component’s MaxEngineRPM did work for me before, not sure why it didn’t work out for you. I’ll test this later when i get home.

You can reparent Blueprint by going to File menu and select Reparent Blueprint element.

Vehicles parameters initialization happens in SetupVehicle() function, there are also various functions like UpdateEngineSetup, UpdateDifferentialSetup, UpdateTransmissionSetup functions available, that could be called during run-time to change PhysX vehicle parameters. UWheeledVehicleMovementComponent::ComputeConstants(), SetupVehicle and others are called in UWheeledVehicleMovementComponent::CreateVehicle(). CreateVehicle is called in UActorComponent::CreatePhysicsState().
Hope it will help you to see initialization flow.

If you want to implement your own vehicle, you’d better start with PhysXVehicleManager class to see how it’s being initialized; i’ve been looking through it a while back, the code is quite confusing actually, and i never had time to get anything good out of it.

Regarding the favor of Blueprints. As i already pointed out, changing actors properties is much faster within Blueprints, the weird thing here is actually why some people want to stick to C++ only? Think of Blueprint as an actor’s representation inside editor. You also have full source code access, expose whatever properties you would want to edit. However, William has point here.

Hi William,

I agree with your points and I do think we need to refactor some of this code to make it simpler/easier to understand data flow.
If you make changes that you think are helpful with this direction I’d really appreciate a pull request from you (or anyone else!) as I think it would help us move in the right direction.

Thanks!

good to hear from you again

just reading and trying to understand the inner workings of the wheeled vehicle and i noticed something that could potentially be an issue.
UWheeledVehicleMovementComponent::UpdateDrag()
this applies a force in local -X according to forward speed (as far as i can tell ,ComponentToWorld.GetUnitAxis( EAxis::X )), so if you are going at all sideways the drag force will be wrong and cause unnatural behavior specially at high speed.

Hi ,

I think you’re right this looks wrong. We should be using the linear velocity vector. If you change this do you get better results?
Again PR are really appreciated with this if you get a chance to submit!

since it uses
ChassisDragArea = ChassisHeight * ChassisWidth
as a quick test i changed these values in the blueprint to 0.01, it wouldn’t accept 0, and it does indeed improve the behavior a little.

Thanks - I hadn’t gotten to the root of that issue yet - I’d nullified the effect of it somewhat by setting the DragCoefficient to a really low value :slight_smile:

If you know, I’d be interested to understand what the vehicle template UpdatePhysicsMaterial fn is supposed to be doing.
It looks as if it’s trying to do something when the car is upside down, but the logic looks all wrong to me- I just commented it all out for now.

Also, any insights you have into COMOffset and InertiaTensorScale would be good.
The comment for COMOffset says “Override center of mass offset, makes tweaking easier [uu]”
What original center of mass offset is it overriding, is this really an offset (if so, what from exactly) or is it specifying the COM?
I’ve traced through the code, but I don’t understand why the example code uses COMOffset to offset by 8 on the X axis??? with a comment on the buggy being low (surely a z-axis offset would then be appropriate?)
I’m going to start testing value inputs on these to see what happens

I’m trying to work out why I can’t get a car to drive in a straight line above 180kph, it will gradually start turning (always left) and eventually tail spin with zero steering input, even with SteerAngle set to 0.0 for ALL wheels and all wheels configured the same way, even with 4wd. Setting physics material friction to something like 4.0 seems to fix it but that’s 4 times the value I’d expect to use - still tracking this down.

@ - good to know I’m not alone in thinking it could be done differently
@ - hello, see you’ve moved over from UDK as well - thanks for the vehicle feedback
@BiggestSmile- thanks again for your input, would be interested to know if you do get that MaxEngineRPM to work

Are you using 4.5 or the latest in github? There has been some changes to COMOffset in 4.6 so that we no longer do it in the way that comment describes. There is COMOffset on the skeletal mesh of the car, but we were overriding it in the tuning of the vehicle. This was removed and we are now just using the skeletal mesh COM offset as having it in two places was just adding complexity.

I’d say take a look at 4.6 for COM changes before looking at those too deeply as we fixed some major issues with the way it was being used.

Hey William. I empathize completely with this issue. I recently rewrote my blueprints vehicle game in C++ and I hit a big of a snag tuning the vehicle in C++. With hotreload improving constantly and a similar desire to not spread single responsibility across multiple classes (eg, having a c++ and bp class for a single vehicle pawn), I was not keen on subclassing with blueprint merely to set values. Here’s what I did to get this working – fair warning, it’s a hack. I do plan to update the WheeledVehicleMovementComponent accordingly, I just didn’t feel like rebuilding my engine at the time.



void AVehiclePawn::PostInitializeComponents()
{
    // ...
    GetWorldTimerManager().SetTimer(this, &AVehiclePawn::Initialized, 0.3f, false); // Rama ;)
}

void AVehiclePawn::Initialized()
{
    // do some late setup stuff
    DoEngineSetup();
}

void AVehiclePawn::DoEngineSetup()
{
    UWheeledVehicleMovementComponent4W* Vehicle4W = CastChecked<UWheeledVehicleMovementComponent4W>(VehicleMovement);
    check(Vehicle4W->WheelSetups.Num() == 4);
    Vehicle4W->MaxEngineRPM = 4500.0f;
    Vehicle4W->EngineSetup.TorqueCurve.GetRichCurve()->Reset();
    // etc
}


One odd thing I noticed was that the gears (TransmissionSetup) were happier if set in the pawn’s constructor, while the EngineSetup properties would take only if they were set after PostInitializeComponents(). The timer/initialize call is just some extra padding, an idea I borrowed from Rama.

I haven’t dug in yet but it’s on my todo list. Let me know if you want to pair up on this, I would be interested in contributing.

hello william, good to see you over here.
hopefully between all the interested parties we can make the wheeled vehicle on par with the graphics quality, eventually.

so how did you/where did you find/how do you use it… the physics debugger?
i downloaded the physx sdk and the debugger from nvidia earlier but havnt had chance to look at it yet, is it that?

cheers

@ - ah, ok, thanks - I’d synced to the 4.5 branch on Github, I’ll take a look at the latest changes for 4.6 re COMOffset

@piinecone - thanks for the tip - that is indeed quite a hack :slight_smile: I think we are indeed looking to achieve the same thing - I’ll be looking into a more “correct” way to do it at some point, if I come up with something I’ll post the details.
What you describe regarding gears transmission & EngineSetup properties is odd; I’ve only conducted tests in a derived wheeledvehiclecomponent class constructor - which works fine so far (I think) - doing anything in the pawn constructor isn’t really ideal as far as I can work out - so I’m avoiding doing that.

@ - not sure if I’ve called it the correct thing - I’m just referring to the vehicle debug graphs you get by typing “showdebug vehicle” in the console/command line (accessed via the “~” key at runtime).

If I find/fix anything interesting I’ll post the details

Cheers
William

thanks
“accessed via the “~” key at runtime”

anyone know what key to press on a french keyboard?
nothing seems to open the console

edit;
@william
did you see this?
https://forums.unrealengine.com/showthread.php?26120-How-to-modify-vehicle-properties-during-runtime&p=180178&viewfull=1#post180178
RecreatePhysicsState() seems like it might be what you need to call to change params at runtime

As I recall, the offset of 8 for the ‘buggy’ refers to settings we made for the off-road vehicle in the first ‘vehicle game’. The X-axis is fore-aft, and I believe we biased it so that the car handled better when going over jumps.

Go into the project settings, input, and at the very bottom, change the tild by ². Tild is a modified key on french keyboard (alt gr + é (or 2 if you prefere)).