I am making a multiplayer game using Unet. Currently, the players can move independently (ie, if user one presses d, then character one will move right if user two presses d then character two will move right) - however, both players shoot 'through' the host.
My movement code is inside the PlayerUnit script. It has one !isLocalPlayer
check at the top, in the Update()
method. This check is performed before the script detects for user inputs (ie, w, s, mouse1, etc.).
This all works fine when the correct key is pressed; the proper action is performed. Eg:
if (Input.GetKeyDown(up))
Jump();
Shooting works in a slightly different way as it involves a different script.
When mouse1 is pressed, the Shoot()
method in PlayerUnit is called. This, in turn, uses a Command
inside the PlayerUnit script to call a ClientRpc
in a separate WeaponMaster script, which calls the Fire() coroutine.
In PlayerUnit:
private void Shoot ()
{
//WeaponMaster.wM.Shoot();
CmdShoot();
}
[Command]
void CmdShoot ()
{
WeaponMaster.wM.RpcShoot();
}
In WeaponMaster:
[ClientRpc]
public void RpcShoot ()
{
if (ammo != 0)
{
if (isAutomatic == true)
{
keepFiring = true;
StartCoroutine(Fire());
}
if (isAutomatic == false && noQuickFire == true)
StartCoroutine(Fire());
}
}
WeaponMaster has one !isLocalPlayer
check as well, once again in the Update()
method.
When debugging, I know that playerTwo
's (client) Shoot()
method is being called, but playerOne
's RpcShoot is being executed. Everything works fine when playerOne
shoots - hence the problem of both players shooting 'through' the host.
All the scripts are on the same object with one NetworkIdentity
component.
I'm convinced the problem is just a missing authority check - but I've tried adding !isLocalPlayer
tests in the various methods to no avail.
As said my guess is that a Singleton pattern in WeaponMaster.wM
is not a good approach here since you get the wrong reference and since everything goes through the server might simply always get the same reference no matter who called CmdShoot
.
You should rather store each players own WeaponMaster
reference and go through it like in PlayerUnit
// Already reference this via the inspector (drag&drop)
[SerializeField] private WeaponMaster weaponMaster;
// or as fallback get it on runtime
private void Awake()
{
if(!weaponMaster) weaponMaster = GetComponent<WeaponMaster>();
}
public void Shoot ()
{
if(!isLocalPlayer) return;
CmdShoot();
}
[Command]
private void CmdShoot ()
{
RpcShoot();
}
// Personally in general I would leave any RPC
// as close to the method calling it
// as possible for better maintainability
[ClientRpc]
private void RpcShoot ()
{
weaponMaster.Shoot();
}
and accordingly in WeaponMaster
public void Shoot()
{
if (ammo == 0) return;
if (isAutomatic)
{
keepFiring = true;
StartCoroutine(Fire());
}
else if (!isAutomatic && noQuickFire)
StartCoroutine(Fire());
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.