- Home /
How do I ApplyDamage to a specific player across network
Assuming an RPC call is the correct way to do this...here is my pseudocode. The problem is that RPC "RemoteApplyDamage" is executed on all clients. I want it to execute just on the clients who are in attack range. Is there some ID I can use to identify the Player(s) to damage? I have tried using gameObject.GetInstanceID() but the local InstanceID of a game object seems to be different than the remote InstanceID of the same game object. I need to be able to handle both scenarios - enemies within the level (bots) and also enemies who are network players.
var AttackPowerJab:int; var AttackPowerWhirl:int; var AttackPowerCombo:int;
var attackPosition = new Vector3(0,0,0.8); var attackRadius = 1.3;
private var attackJabHitTime = 1.0; private var attackWhirlHitTime = 1.8; private var attackComboHitTime = 1.8;
private var attackJabTime = 1.5; private var attackWhirlTime = 2; private var attackComboTime = 2;
private var waitHitTime = 0; private var waitTime = 0; private var attackPower = 0;
private var busy = false;
static private var InstanceID:int;
function Start(){
InstanceID = transform.gameObject.GetInstanceID();
}
function Update(){
if (Input.GetButton ("Jab")){
waitHitTime = attackJabHitTime;
waitTime = attackJabTime;
attackPower = AttackPowerJab;
if (!busy){
busy = true;
Attack();
}
}
else if (Input.GetButton ("Whirl")){
waitHitTime = attackWhirlHitTime;
waitTime = attackWhirlTime;
attackPower = AttackPowerWhirl;
if (!busy){
busy = true;
Attack();
}
}
else if (Input.GetButton ("AttackCombo")){
waitHitTime = attackComboHitTime;
waitTime = attackComboTime;
attackPower = AttackPowerCombo;
if (!busy){
busy = true;
Attack();
}
}
}
function Attack(){
yield WaitForSeconds(waitHitTime);
var pos = transform.TransformPoint(attackPosition);
// enemies
var enemies : GameObject[];
enemies = GameObject.FindGameObjectsWithTag("Enemy");
for (var go : GameObject in enemies) {
var enemy = go.GetComponent(EnemyLifeMeter);
if (enemy == null)
continue;
Debug.Log("Distance: " + Vector3.Distance(enemy.transform.position, pos));
//Debug.Break();
if (Vector3.Distance(enemy.transform.position, pos) < attackRadius){
if (Input.GetButton ("Jab") || Input.GetButton ("Whirl") || Input.GetButton ("AttackCombo"))
enemy.SendMessage("ApplyDamage",attackPower);
}
}
// enemies that are network players
var players : GameObject[];
players = GameObject.FindGameObjectsWithTag("Player");
for (var go : GameObject in players) {
/* var player = go.GetComponent(PlayerLifeMeter);
if ((player == null))
continue;
*/
Debug.Log("Game Object: " + go.GetInstanceID());
Debug.Log("Me: " + InstanceID);
//Debug.Break();
if ((Vector3.Distance(go.transform.position, pos) < attackRadius) && !(go.GetInstanceID() == InstanceID)){
if (Input.GetButton ("Jab") || Input.GetButton ("Whirl") || Input.GetButton ("AttackCombo")){
//go.SendMessage("ApplyDamage",attackPower);
networkView.RPC ("RemoteApplyDamage", RPCMode.Others, attackPower, go.GetInstanceID());
}
}
}
yield WaitForSeconds(waitTime - waitHitTime);
busy = false;
}
function OnDrawGizmosSelected(){
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(transform.TransformPoint(attackPosition), attackRadius);
}
@RPC function RemoteApplyDamage (liferested:int, instID:int) { //playerObject = GameObject.FindWithTag("Player"); //playerObject.SendMessageUpwards("ApplyDamage",liferested,SendMessageOptions.DontRequireReceiver);
//var gos : GameObject[];
//gos = GameObject.FindGameObjectsWithTag("Player");
//for (var go : GameObject in gos) {
//Debug.Log("InstID: " + instID);
//Debug.Log("go.InstID: " + go.GetInstanceID());
//Debug.Log("Name: " + go.name);
//if ((transform.gameObject.GetInstanceID() == instID)) {
//Debug.Log("-----------------Attacking: " + transform.gameObject.name);
SendMessageUpwards("ApplyDamage",liferested,SendMessageOptions.DontRequireReceiver);
//break;
//}
//}
}
I enabled syntax highlighting correctly for you. For future reference, there's a code formatting button just above the input text field which does this for you :) Also, I'd advice only paste code relevant for the question. You'll get much quicker and higher quality replies in return.
Answer by Brian-Kehrer · Feb 03, 2010 at 11:06 PM
This isn't exactly an answer to your question (and let me know if I've missed something here), but if this is an MMO, you'd probably want to implement most of the player logic and damage calculation on the server, and simply pass the resulting values to all of the clients.
Even things like the (ifBusy) check need to be reproduced on the server, particularly to prevent client side hacks.
Someone else may have a better understanding of the Unity Multiplayer system, but fundamentally you may want to change the location of critical game logic first.
Answer by AngryAnt · Feb 04, 2010 at 09:39 AM
Seconding what Brian Kehrer says, you definitely would want to do the health managing server-side. I would, however, still transmit the RPC to all connected units - allowing clients to play hit effect animations when the character receives damage. Here's one example of how you could do it:
@RPC
function ReceiveDamage (damage : float)
{
if (Network.isServer)
{
/*Apply the damage and figure out if the character dies - if
so, the server should send a CharacterDied RPC to all*/
}
else
{
/*Play hit animation - maybe select between a
few based on the damage value*/
}
}
Answer by Jamie Dowd · Feb 06, 2010 at 11:30 PM
how do I determine which player to subtract the hit points from though?
If this is a reply to my previous question, in the example I have a Network$$anonymous$$anager script running health, networking, equipment and such and a player script just controlling movement and aimation. I cant post the code here, because I am using it in a project. the Playerid is the Network id of the player, so applying damage to one self would be: networkView.RPC("NPDamage", RPC$$anonymous$$ode.Others, parseInt(Network.player.ToString())) sorry if this is to confusing... If this is not a reply to my post, then so what :P
Answer by mike002 · Mar 08, 2010 at 12:26 PM
Hey Jamie, bit late but....
http://unity3d.com/support/documentation/ScriptReference/NetworkView.RPC.html
function RPC (name : string, target : NetworkPlayer, params args : object[]) : void
Answer by Benproductions1 · Jun 30, 2012 at 01:29 PM
This can be done serverside or clientside, but having a list of players, players with the corresponding properties, and whenever applying damage/changing something just sending the corresponding id over an RPC is much easier:
//List of Network Players
var NPlayers:NPlayer[];
//Apply Damage
@RPC
function NPDamage(id:int, amount:float) {
for (obj in NPlayers) {
if (obj.id == id) {
obj.health -= amount;
//Other things like effects and such
break;
}
}
}
This is the method I always use, as it works quite well, even in a client based game.
Your answer
Follow this Question
Related Questions
Unity networking tutorial? 6 Answers
Help with multiplayer connection 0 Answers
Unity multiplayer over internet does not work using port forwarding 1 Answer
multi-player android and IOS 2 Answers