2
\$\begingroup\$

Im prototyping dynamic road building system as seen in most city builder games. I gather the points from user input (red dots) and programmatically generate mesh.

It's currently one big mesh, seems like a good default rendering performance wise.

enter image description here


Starting a new road/creating intersection from already existing road is a very important feature. Everything is pretty straight forward except how to know which segment user is hovering, clicking.

Options:

  • split segments into separate gameobjects and attach collider to each
  • use single big mesh and create empty gameobjects for colliders only

Is there a better way besides these two? That would be a lot of colliders if you consider the scale of city builders. I suspect there's a smarter way..

Note: on the other hand, if user adds new intersections, updating a huge mesh could be a problem. If I split meshes into reasonable chuncks, I could localize updates to only affected meshes.


Simplified data structure:

public class Road {
    public List<Segment> segments;
}

public class Segment {
    public Vector3 start;
    public Vector3 end;
}
\$\endgroup\$
  • \$\begingroup\$ Maybe you could add another property to the Segment, referring to its index on the road's list. \$\endgroup\$ – LinkWindcrafter Sep 10 '18 at 18:33
  • \$\begingroup\$ @LinkWindcrafter Im not sure how that would help me to get the segment user is hovering/clicking in more efficient way than the ones I listed above. Could you clarify? \$\endgroup\$ – Sir Sep 10 '18 at 18:51
2
\$\begingroup\$

You can use a large, procedurally generated mesh collider for your whole road network and still detect on which segment the user clicked.

Use Physics.Raycast to detect the road mesh collider under the mouse cursor. The RaycastHit structure has a property .triangleIndex which contains the number of the triangle where the hit occurred.

So all you need to do is keep a lookup table during your mesh generation which remembers which triangle of your procedurally generated mesh belongs to which logical road segment.

However, you might still want to consider to split your road network into multiple meshes for performance reasons. When the whole road network of the whole city is one big mess mesh, then the Unity rendering engine can't apply frustum culling to ignore the off-screen parts of it. You can't even use LOD groups, because the whole object needs to be rendered in the same level of detail. I also see problems with constantly rebuilding the whole mesh when the player makes changes to the road network.

There are different approaches you could take here, like handling all the roads in rectangular areas as game objects or handling each road from intersection to intersection as one game object. The best approach depends on your game.

\$\endgroup\$
  • \$\begingroup\$ One more quick question: how would you implement lookup table? List<List<int>> would cause a lot of looping each frame if every index is stored, List<Vector2> would also work for storing only ranges. or dictionary? Can't be too much data, need to keep it around. \$\endgroup\$ – Sir Sep 10 '18 at 22:44
  • \$\begingroup\$ @Sir I would turn Segment into a class (so it gets stored by reference and not by value) and then create an array of segments. The array index is the number of the triangle. So if you want to know which segment triangle 1317 belongs to, you would use segmentLookupTable[1317]. \$\endgroup\$ – Philipp Sep 10 '18 at 22:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.