Search Unity

Resolved Vehicle Design Approach (ECS)

Discussion in 'Data Oriented Technology Stack' started by MrRobinJohannesson, Sep 6, 2021.

  1. MrRobinJohannesson

    MrRobinJohannesson

    Joined:
    Jul 15, 2017
    Posts:
    11
    Can someone help me how to approach this? So I'm making a vehicle system with ECS in mind. I have Entity which contains engine, clutch and gearbox as IComponentData. But now comes with the differentials and the wheels, which can either be IBufferElementData or single IComponentData but on a different entity.

    Which approach is best and why? I can see why using a buffer system would be nice, because no reference to an entity and the extra step of getting the component data. Instead, having everything on one entity is easier to talk with each other.

    However con with that, is not very memory beneficial, right? With the chunk system and how ECS is the layed out. If I would have 50+ cars in the scene, and wheels & differentials vary from amount to amount. Will not the chunk system be at waste then, because it can only find certains entities with same archetype instead of getting all entities which has the wheel component as archetype. (Should I also split up engine, clutch and gearbox component as well? To get better results from chunk system)
     
    Last edited: Sep 6, 2021
  2. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,743
    I think no matter how many vehicles you have in your scene and no matter how you implement them, it's likely that the overwhelming majority of the frame cost of your vehicles will just be the physics simulation/queries either way. For that reason, I'd suggest picking whatever approach is easiest to work with for you and not worry too much about it.

    It's hard to imagine a game still running smooth with more than 500 active vehicles in the scene, and even at that count, I don't think memory access patterns will make a huge difference. Especially if getting better memory access patterns means you have to schedule more jobs or make main thread structural changes; the extra cost might very well cancel out whatever performance benefits the linear chunk iteration gave you at such a -relatively- low amount of iterations

    ----------

    With that being said, I see 3 obvious implementations:

    Option A
    Option B
    Option C
    Hard to tell which one of these will perform the best.
    • At a low vehicle/wheel count, I'd go with OptionA or OptionB. But the problem is that I'm not sure what a "low" vehicle count would be; we'd have to profile and see. It could be 50 or 5000. Because of the cost of the physics update compared to the cost of the vehicle logic update, it's possible that the vehicle/wheel count threshold at which Option C starts to perform better than A or B will be way past what the physics engine can handle at an acceptable framerate
    • Option C will give you the best memory access pattern for the wheel update alone, but it needs more jobs to schedule, and in total it needs one more ComponentDataFromEntity<> access per wheel than Option A. Again, it's unclear if it would be worth it
    • OptionB would be more efficient than OptionA because it needs one less ComponentDataFromEntity<> access per wheel. But it is also a bit less flexible/fool-proof than Option A. In OptionB, you might still want to have a Wheel component on wheel entities so that the wheel can be removed from the vehicle & still preserve its data, but you have to make sure you remember to update the wheel data in the DynamicBuffer<Wheel> on the associated vehicle whenever you decide to change the data of the wheel
    I've created a very simplistic Vehicle system in DOTS (see attachments), and I went with something similar to option A or B. My example didn't have any per-wheel data, but if I needed it, I could've stored that data either directly in the bufferElement, or in a Wheel component on the wheel entity
     

    Attached Files:

    Last edited: Sep 10, 2021
    apkdev and RaL like this.
unityunity