Multiplayer taking damage; commands and clientrpc
Quick question about players taking damage using Unity's HLAPI for multiplayer networking.
My player objects have a method called 'TakeDamage' that accepts the amount of damage and modifies a syncvar on itself called currentHealth.
The players have a box collider in front of them that is activated/deactivated while attacking (melee). While attacking if the player hits something (another player), then it will call 'TakeDamage' on them.
I'm a bit fuzzy on the best practice for this and how I should route the behavior through commands and clientrpc's.
If the player detects a collision with it's melee collider, should it call a command to get the server to call the TakeDamage() method that updates the currentHealth syncvar. Or should the command send an ClientRpc command for the specific player to call TakeDamage on itself?
I know there are many ways of solving the problem, just wondering how others have structured their signal flow.
I'll post some code examples when I make it home to give an idea of what I mean. Thanks for any input in advance!
Edit: Here is an example of what I am doing. I have some more movement and input handling code but this is how I am triggering and taking damage. Am I using commands here correctly? And does the TakeDamage method need to be a ClientRpc call or is making the currentHealth property a syncvar good enough? Thanks again for any help.
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
[RequireComponent(typeof(CharacterController), typeof(Animator), typeof(NetworkAnimator))]
public class PlayerCharacter : NetworkBehaviour {
[SyncVar] public int currentHealth;
public int maxHP = 800;
public int playerID;
public BoxCollider basicAtkCollider;
public NetworkAnimator networkAnimator;
public void Start() {
currentHealth = maxHP;
playerID = Random.Range (1, 1000);
networkAnimator = GetComponent<NetworkAnimator> ();
}
public void BasicAttack() {
basicAtkCollider.enabled = true;
networkAnimator.SetTrigger ("BasicAttack");
}
public void TakeDamage(int dmg) {
currentHealth -= dmg;
if (currentHealth <= 0) {
currentHealth = maxHP;
}
}
public void OnTriggerEnter(Collider c) {
if (isLocalPlayer && c.gameObject.tag == "Player") {
PlayerCharacter enemy = c.gameObject.GetComponent<PlayerCharacter> ();
if (enemy.playerID != playerID) {
int dmg = 34;
if (!Network.isServer) {
CmdAttackPlayer(enemy.playerID, dmg);
} else {
InvokePlayerAtk(enemy.playerID, dmg);
}
basicAtkCollider.enabled = false;
}
}
}
[Command]
public void CmdAttackPlayer(int damagedPlayerID, int dmg) {
InvokePlayerAtk (damagedPlayerID, dmg);
}
public void InvokePlayerAtk(int damagedPlayerID, int dmg) {
PlayerCharacter[] players = FindObjectsOfType (typeof(PlayerCharacter)) as PlayerCharacter[];
foreach (PlayerCharacter player in players) {
if (player.playerID == damagedPlayerID) {
player.TakeDamage(dmg);
}
}
}
}
just want to note that the code generating the player UUID and disabling the box collider is handled better in my codebase, just trying to demonstrate the idea with pseduo-code.
I love this question. I have lots of these types of questions asking about best practices ins$$anonymous$$d of only how to. Did anyone ever get an answer to you about this? or did you figure it out?
Your answer