- Home /
Changing the appearance of particles from another player's view
Okay so I've pretty much edited the entire question but it's still the exact same question. Currently we have a 4 person multiplayer game that works over a network. We use a particle emitter as a firing mechanism, each player has their own particle emitter but they all use the same "Fire" script.
How do we set the appearance of a players particles over the network. This includes force properties, shaders & textures and even states (eg flamethrower or normal shot) Should I just make 4 scripts one for each fire (which is what we resorted to for the player and everything works perfectly no torubles now) or is there a way to send a player's emitter state via RPC without it taking too much bandwidth sending every single variable?
We have a set up so that player one is the host who launches/runs the server. We have a pickup that activates the FLAMETHROWER and that works fine, locally. Each player can see the pickup and collect the pickup. When the player has collected the pickup it only shows on their machine. Everyone else registers the fact that a certain player has picked it up but still the particles remain the same. What we are looking for is a way to set what the particles are doing locally then send it over the network so that each player can see exactly how far your firing and whether or not your have a flamethrower etc (we also have aiming which increases the particles local velocity which needs to be synced)
This is what we have so far. The part in which we set emitter on and off over the network works fine however the RPC call "SwitchFire" doesn't work at all.Mainly because the variable we are setting doesn't do anything, just demonstrating the fact we have had several attempts (and failed each time, this just causes no problems)
private var wasEmitting : boolean = false; static var Ammo1 : float = 100; var AmmoRep : float = 100; static var AmmoUnlimited : boolean = false; var AuTime : float = 10; var Ammo1full : float = 100; var CanFire : boolean = true; var SpoutPos : Vector3 = new Vector3(-0.05,0.7,0.45); static var Aimvar : Vector3 = new Vector3(0,5,5); var bforce : Vector3 = new Vector3(0,-50,0); var isFlameThrower : boolean = false; var wasFlameThrower : boolean = false; static var FLAMETHROWER : boolean = false; var flameon : boolean = false; var hasfilled : boolean = false; var flamethrowerPos : Vector3 = new Vector3(0,0.35,0.05); var flameLife : float = 0.5; var flameAmount : float = 200; var flameVel : Vector3 = new Vector3(0,0,5); var flameSize : Vector3 = new Vector3(1,1,1); var forceOverTime : Vector3 = new Vector3(0,0,0); var flameSpeed : float = 0.5; var Fire : Texture; var Flame : Shader = Shader.Find( "Particles/Additive (Soft)" ); var Tea : Texture; var regShad : Shader = Shader.Find( "Transparent/Diffuse" );
function Update () { AmmoRep = Ammo1; if (networkView.isMine) { if (FLAMETHROWER == true) { flameon = true; networkView.RPC("SwitchFire", RPCMode.Others, flameon); QuickFill(); transform.localPosition = flamethrowerPos;
renderer.material.mainTexture = Fire; renderer.material.shader = Flame; particleEmitter.minEnergy = flameLife; particleEmitter.maxEnergy = flameLife; particleEmitter.minEmission = flameAmount; particleEmitter.maxEmission = flameAmount;
particleEmitter.localVelocity = flameVel; particleEmitter.rndVelocity = flameSize; blah = GetComponent (ParticleAnimator); blah.force = forceOverTime; blah.damping = flameSpeed;
if(Input.GetButton("Fire"))
{
particleEmitter.emit = true;
Ammo1 = Ammo1 - 9*Time.deltaTime;
if (Ammo1 <= 0)
{
FLAMETHROWER = false;
hasfilled = false;
CanFire = true;
networkView.RPC("SetIsOut", RPCMode.Others, particleEmitter.emit);
wasEmitting = particleEmitter.emit;
Refill();
}
}
else
{
particleEmitter.emit = false;
}
}
if (FLAMETHROWER == false)
{
flameon = false;
networkView.RPC("SwitchFire", RPCMode.Others, flameon);
hasfilled = false;
transform.localPosition = SpoutPos;
renderer.material.mainTexture = Tea;
renderer.material.shader = regShad;
particleEmitter.minEnergy = 1.5;
particleEmitter.maxEnergy = 1.5;
particleEmitter.minEmission = 25;
particleEmitter.maxEmission = 25;
particleEmitter.localVelocity = Aimvar;
particleEmitter.rndVelocity = Vector3(0.2,0.2,0.04);
blah = GetComponent (ParticleAnimator);
blah.force = bforce;
blah.damping = 10;
if (AmmoUnlimited == true)
{
Refill();
CanFire = true;
UnlimitedAmmoCountDown();
}
if (CanFire == true)
{
if(Input.GetButton("Fire"))
{
particleEmitter.emit = true;
if (AmmoUnlimited == false)
{
Ammo1 = Ammo1 - 9*Time.deltaTime;
}
if (Ammo1 <= 0)
{
CanFire = false;
networkView.RPC("SetIsOut", RPCMode.Others, particleEmitter.emit);
wasEmitting = particleEmitter.emit;
}
}
else
{
particleEmitter.emit = false;
if (Ammo1 <= Ammo1full)
{
Ammo1 = Ammo1 + 11*Time.deltaTime;
}
}
}
}
if (CanFire == false)
{
particleEmitter.emit = false;
Ammo1 = Ammo1 + 8*Time.deltaTime;
if (Ammo1 >= Ammo1full)
{
CanFire = true;
}
}
if(particleEmitter.emit != wasEmitting)
{
networkView.RPC("SetIsFiring", RPCMode.Others, particleEmitter.emit);
wasEmitting = particleEmitter.emit;
}
}
}
function QuickFill() { if (hasfilled == false) { Ammo1 = 100; hasfilled = true; } }
function Refill() { Ammo1 = 100; Debug.Log ("Refill function activated"); }
function Reloading () { CanFire = false; if (Ammo1 >= Ammo1full) { CanFire = true; } }
function UnlimitedAmmoCountDown() { yield WaitForSeconds (AuTime); AmmoUnlimited = false; }
@RPC function SetIsFiring(boolEmitting : boolean) { particleEmitter.emit = boolEmitting;
}
@RPC function SetIsOut(boolEmitting : boolean) { particleEmitter.emit = false;
}
@RPC function SwitchFire (flamebool : boolean) { flameon = flamebool; Debug.Log ("recieved fire RPC"); }
Answer by RedbeardRum · Mar 15, 2011 at 02:23 PM
Have you tried spliting it into four different scripts and have each script sending an rpc to set how it acts on other player's local machine?
I was afraid we would have to do this. I noticed this is simliar to a problem we had with jump pads and the player scripts. I think we will leave this as a last resort, cheers for your answer.
Answer by owenpat · Feb 26, 2011 at 11:40 PM
An RPC call is a 1-time thing -- it does that "tell other machine to set these locally" you wanted. So even sending 18 variables isn't very expensive. You're probably thinking of the auto-synching it does on a Network.Instantiate, which is sent 15 times/second to keep your player2 and his player2 synched up. Unity doesn't know how to auto-synch emitter properties, and, you're right, it would be a terrible waste of bandwidth.
If you have only 12 types of emitters, you certainly could send the "emitterNumber" and then have the SetEmmiter function use if(emitNum==1) set it this way...
The array idea, it seems it might be easier to make an array of transforms in your player script and then just use the inspector to drag in all the emitter prefabs. On a change, you could destroy the current emitter and spawn the new one. I guess you'd need a delay before killing the old one, to prevent the particles from winking out.
we are only using one emiiter per character and its exactly the same emitter, we don't have need for an array we simply need to send an RPC to set on a local machine whether a certain network player is firing a certain type (a list of settings) of particles
Answer by owenpat · Feb 26, 2011 at 04:57 PM
I'm guessing you're stuck on "how do I send a particle emmiter through an RPC?" Turns out you are only allowed to send ints, floats, transforms (which are just 9 floats...,) strings, but not larger objects.
You could number the potential emitters (or put them in an array) and do something like:
// pickup code:
// someone figures out new emmiter num
SetEmmiter(newEmitNum); // set for me
networkView.RPC("SetEmmiter", RPCMode.Others, newEmmitNum);
If you are allowing pretty much any change, you'll probably have to send the values by hand:
networkView.RPC("SetEmmiter", RPCMode.Others, matNum, minEmit, maxEmit, grow);
And then assign them by hand in SetEmmiter
Technically, this is known as serializing the emmiter. The system doesn't know how to send something that big over the network, so you have to tell it. If you happen to find someone who's already done that, you can skip all this.
It's the same emitter so not sure about the array? the second part seems like a good idea but wont it effect performance over network having to send so much information (ie all its variables) Is there some way to send an RPC to set how another players particles appear but on a local basis? sometihng like
if (flamethrower is on) send RPC to change th emitter of network player on local machine @ RPC set player's (who sent this RPC) fire type
as this is the way we have sent the RPC to turn on and off the fire on a local basis
Answer by Owen-Reynolds · Mar 15, 2011 at 02:51 AM
You're setting your emitter values every frame. You only need to set them when you switch, so the problem looks worse than it is. You're close. Try this:
// Main code // FLAMETHROWER=false; // replace this with: SwitchFire(false); // switch my stats networkView.RPC("SwitchFire", RPCMode.Others, false); // switch their stats
// FLAMETHROWER=true; // when you add this line, replace it with: SwitchFire(true); networkView.RPC("SwitchFire", RPCMode.Others, true);
If you get more guns, change FLAMETHROWER
to WEAPON_NUM
and use 0,1,2 instead of true/false.
Move all of the code that changes weapon stuff (including the emitter) to Switchfire
:
@RPC
// All code to set up weapon on a switch goes here:
function SwitchFire (flamebool : boolean) {
if(flamebool==true) {
// apply settings for flamethrower:
transform.localPosition = flamethrowerPos;
renderer.material.mainTexture = Fire;
renderer.material.shader = Flame;
particleEmitter.minEnergy = flameLife;
....
}
else {
// apply settings for the other weapon:
transform.localPosition = SpoutPos;
renderer.material.mainTexture = Tea;
renderer.material.shader = regShad;
particleEmitter.minEnergy = 1.5;
.......
}
FLAMETHROWER = flamebool; // save weapon type
Debug.Log ("recieved fire RPC");
} // end of SwitchFire
We tried something similar but it kept setting everyones flamethrower on when only one person had collected the pickup. We do have rather limited knowledge on networking so we may have missed a trick before.
If you have 4 players, each computer should have 4 sets of player variables, meaning 4 independant FLA$$anonymous$$ETHROWER vars. If player3 throws an RPC, the other machines know to run it for their P3 only. If you somehow made FLA$$anonymous$$ETHROWER into one global, it would change everyone's weapon. You do have the all important if (networkView.is$$anonymous$$ine)
guarding user input.
yeah FLA$$anonymous$$ETHROWER is a static variable so it's affected globally. It's the only way we could get pick-ups and things working, we tried using send message but for some reason couldn't crack it so we have the pickup script changing a global variable. Currently it only changes on a local machine but when we send an RPC like the one you provided it turns on everyone's flamethrower
Whoa...didn't even notice the static
! If multiple people can have one, FLA$$anonymous$$ETHROWER
should be normal. Are use using: playerScript.FLA$$anonymous$$ETHROWER=true
in your pickup? If so, change it to, ummm (I use C#), other.GetComponent("playerScript").FLA$$anonymous$$ETHROWER=true;
. BUT, to get the RPCs working, use other.GetComponent("playerScript").changeWeapon(true);`. Then have changeWeapon make the two calls to SwitchFire
.
Your answer
Follow this Question
Related Questions
Security: Sending RPC to all clients 0 Answers
Unet RPC call not working on clients 0 Answers
RPC activating gameobject on Host instead of on the Client 0 Answers
Buffered Network.Destroy? 0 Answers
Delete specific rpc in buffer 1 Answer