I was wondering how you would implement collisions in the best way in an RTS? I’ve read that creating many GameObjects is bad for performance, and the only way I’ve seen to detect collision in Unity is with triggers and RigidBodys connected to GameObjects. I guess only projectiles need collision detected to check if they have impacted with a unit/building or the terrain itself, buildings don’t move and units can check the map before moving (I’m using a tilemap).
I have done some reading and one way of optimizing games is to not attach GameObjects to dataclasses unless they’re in the field of view/camera. This would not be possible if you need GameObjects for collision detection. Optimizing is very important in RTS-like games as they are usually very demanding if you have many units.
You should watch the Unite Keynote segment on high performance, because it touches on a lot of issues you mention. The demo actually uses an Entity system which does treat its units as pure data, onscreen or not. This demo has tens of thousands of units running at >60fps, and they push it up to 100,000 units while still getting >30fps. That demo uses some techniques that are not yet publicly available (there will be a beta at some point soon for them) like the job system and the entity system, but it’s good to know where the engine is heading.
Until then, there are techniques to take advantage of like object pooling which mitigates the impact of instantiation overhead.
For collisions specifically, there are some things to keep in mind. Most simply, if you can use sphere colliders, do it - they’re the cheapest collision shape by far. In games with a lot of units, you want to avoid squaring your collision checks. What I mean by this is mainly: avoid at all costs having objects check against their own layer, because that will add up quick - the number of collision checks will be the square of the number of objects in the scene. In fact, the narrower you can set the object’s collision layers, the better.
First, I would definitely only use this technique if you’re going to use object pooling as linked above, because instantiation and destruction overhead will kill your gains otherwise. Secondly, you can usually cheat the physics if the units are offscreen. There’s no need to simulate collision with the ground for example. Unless maybe you need physics for line of sight or something? Even so, you don’t need to have the units existent as rigidbodies to raycast for line of sight for the building, and if the building is part of a MeshCollider it shouldn’t add much to your physics processing time.
I’m currently implementing an EntityComponentSystem and currently I’m working on the collision part as well as targeting. My idea was to do object pooling for the objects that get created/destroyed a lot; components, entities and GameObjects. I’m a programmer, so I’m used to working with things like that, but I’m not a game programmer, so I don’t always know which tools and aproach to use.
What exactly did you mean with what you said about cheating the physics if the units offscreen? I’m not using physics for line of sight. I was thinking about just checking the height of the projectile against the height of the tile when a projectile enters a new tile.
How would one achieve checking collisions against their own layer? Do you mean air-to-surface missiles don’t need to check for collisions with aircraft or…?
You don’ really need to use the physics system for collisions in an RTS. You can perform your own sphere-sphere intersection tests and adjust units accordingly. You’ll also want to use flowfields for unit pathfinding which will minimize the amount of intersection tests required.
OK, yep, that’s super easy, and if that’s all you’re using the physics system for I would say don’t even use physics even when they’re on screen - it’s overkill. You can easily sample the height of a terrain at a given point and just check your projectile’s Y position against it.
That’s the basic idea. Open the physics settings in the inspector, and there’s a grid of which layers collide with which. Though, again, this is something which you can easily do and improve on the physics system, as @GroZZleR was getting at. In the case of missiles, you don’t need to check against all ground units, probably just the one you’re targeting. (And this can be a simple distance check - which you can make a little faster by using .sqrMagnitude rather than Distance.) This can make those much more efficient than physics, which will have to do checking against all the nearby objects in that layer.
Unless you have stuff like grenades rolling around realistically on the ground or something, there’s probably little to no reason to use physics at all ultimately. Everything that’s not something like that is really easy to fake with your own code, and you can custom-tailor your code to your use case to make it faster than physics would be.
This does make me think of one aspect. If whatever you’re doing with physics isn’t reliant on other things going on in physics, then PhysX is very good at multithreading, so work can be offloaded onto multiple processor cores. So in examples like this, if you have rigidbody debris hanging out in multiple piles (which aren’t touching each other), by and large each pile will likely be put on a separate core. In that sense, if smartly managed, you can get some amount physics work “for free” assuming that your additional cores would otherwise be idle (which they often are).
This is most likely only true for smaller flourishes like debris, though. More integral code would be more likely to be dependent on other bodies and therefore harder to multithread.
I checked out the keynote, and though it was interesting, it’s nothing I can start using yet. However, it’s good to know that some of the features that are coming very soon might be worth looking into. I must say though that if the simulation was run on a 10 core CPU as he mentioned, then that’s not really a good benchmark, as not many people have one of those yet
I did forget to mention that my tilemap has height/elevation, does that impact the layers somehow?
At the moment, I hadn’t planned on adding debris, but if I did, they would be implemented in a deterministic manner (easier to implement, easier to sync).
No grenades rolling on the ground.
If I got right what you people said, I should choose one of the following options:
option 1:
use sphere colliders
use sphere to sphere intersections to detect collisions
option 2:
use the physx engine
use layers to limit the nr of collisions to be checked
use rigidbodies
do raycast checks (?)
Option 1 seems easier to implement, do you know any good links where they apply it in a similar way to what I’m trying to do? Then I can check it out, learn the idea and try to adapt it to my code.
Those aren’t really options. Unity uses PhysX for physics so you don’t have a choice. My point was that you shouldn’t use it for things like unit movement because it’s not deterministic. In terms of sphere checks or raycasts - use whatever works for what you’re trying to solve at the moment. We use both all over the place. The more important thing is to use layer masks diligently to check only the layers you care about instead of checking everything.
Also - why would your debris need to be deterministic? Unless the debris has some importance as gameplay mechanic.
I just got used to the idea of layers. You name a layer, and then you assign objects to it, so other things not needing to be tested, don’t get tested. You can include the layer in the raycast.
This isn’t as big of a deal on desktop platforms. We’ll use square magnitude for stuff that has the potential to run hundreds of times in a single frame but otherwise stick to magnitude for readability.
Well collision detection would be that kind of thing, but you are right it doesn’t make a significant change. I just believe when it is feasible take the faster approach.
I don’t have much experience with this, but generally, there are applications for most things in a game engine otherwise they wouldn’t be in there. A real time strategy has some differences, but you might want to use colliders for certain situations. Maybe a unit collider or something, I don’t know. These things are in here because they are very convenient.
I finally got time to do some more reading, and came to the following conclusion on how to implement it;
The projectiles will have a SphereCollider + rigidbody. Other entities (Buildings/Units) will only have SphereColliders.
To check if projectiles collide with the terrain, I can just check the hight of the tilemap against the height of the projectiles.
To detect the collision itself, I’ll try to use triggers, as they are more effective than raycasts and OnCollisionEnter. To further improve performance, layers and mask can be used to decrease the amount of collision checks.
If there are buildings and units that can’t have a SphereCollider, I simplified MeshCollider can be used, but they have worse performance and are much harder to check manually compared to SphereColliders. Another option is to have multiple child GameObjects with each having their own SphereCollider, but that also increases complexity and may reduce performance if many entities like that exist.
If no triggers, raycasts nor OnCollisionEnter are used, you could query the tilemap for nearby entities and use
the formula McDev02 stated: “bool collision = (A.position - B-position).magnitude <= A.Radius + B.Radius;”
to check if they collide. I do wonder how to handle situations when buildings/units that span more than 1 tile, to know which tiles to query in order to find which ones need collision checks?