I’m having trouble with this particular concept. I know that I cannot call a Command from a non-player object.
I have a player which is able to launch a grenade. The grenade pops out, and a few seconds later explodes. When the explosion occurs, I want to check to see if any players are within a certain radius of the grenade position. Here is what I have thought of doing/tried:
Spawn a 2D collider at the point of the explosion and if it collides with any players apply damage to them.
Do a distance check using Vector2.Distance on all players in the game, and if any are within the blast radius, damage them.
My problem is that the grenade that is spawned is not a player object, and I cannot call any Commands from it. Using method 1 above, I am not able to spawn an ‘explosion collider object’ on all clients - only the server is able to do it
Has anyone got any recommendations or guidance for me?
Essentially, I would like to be able to run some code from my grenade component that checks for any players around it, and damages them if found.
I don’t know if that will help but this is how we deal damage in multiplayer for our game and it works great:
First, our game is authoritative meaning that only the server spawns objects and only the server runs the game logic - the players receive the results. So basically the server will calculate the explosion (using Physics.OverlapSphere), check to see if there are any players and damage them. We don’t spawn any collider objects for the explosion and you shouldn’t have to either. Once the server damages the playerobject, the player object sends it’s health/state to the other players. So basically, the grenade object would fly and explode (visually) on all players’ machines and will only do damage on the server’s machine.
That helps with the logic, but my circumstance is a bit different I would say.
The problem I’m finding is that the grenade object is not a player, and not attached to the player at all. The player fires one out, and it is spawned on the network using NetworkServer.Spawn(), but then it is its own entity. Although it has a NetworkIdentity component as well as a NetworkTransform component to keep its position synced across the network for all players, when it detonates on it’s timer, I am not able to find a way to do a search from it’s current position in a radius around it to see if there are any players nearby and damage them if so.
Can’t you just return the array of colliders from Physics.OverlapSphere and then cycle through them to see if there are damagable objects or player objects (these would be objects with a player script attached) ? Then if you find a player, check whether or not you should damage it and then damage it.
The way I have done it is that the player does not spawn the grenade, but rather sends a Command to the server requesting a grenade be spawned. The server then spawns a grenade using NetworkServer.Spawn, which is then instantiated on all clients. Once a certain amount of time has elapsed (on the server grenade), on the server you run a check of some sort to detect collisions (OverlapSphere being the simplest way) and then apply the damage accordingly (still on the server). Damage taken by player objects is then synced across the network (likely using SyncVars). This takes care of the logic aspect of it. To give visual feedback to players, you can call a ClientRPC on the grenade object to instantiate an “explosion effect” prefab, so that the clients can see that the grenade blew up. This explosion doesn’t actually run any logic. Finally, you can Network destroy the grenade.
Thanks Iron-Warrior - that makes total sense. I’ve just needed it to be explained to me in a different way I think - still wrapping my head around client/server concepts!
I eventually had a chance to take another look at this and I was really just over thinking things. It was really simple to get this working and just as you described.