- Home /
Shooting a projectile with Unet
Goodevening everyone!
I am stuck with a problem with Unet and projectiles.
Scenario:
The Player has a "Starting weapon" assigned to it, as in the following script which is assigned to the Player:
public class GunController : NetworkBehaviour
{
public Transform weaponHold;
public Gun startingGun;
Gun equippedGun;
void Start()
{
if (startingGun != null)
{
EquipGun(startingGun);
}
}
public void EquipGun(Gun gunToEquip)
{
if (equippedGun != null)
{
Destroy(equippedGun.gameObject);
}
equippedGun = Instantiate(gunToEquip, weaponHold.position, weaponHold.rotation) as Gun;
equippedGun.transform.parent = weaponHold;
}
public void Shoot()
{
if(equippedGun != null && isLocalPlayer)
{
equippedGun.CmdShoot(equippedGun.muzzle.position, equippedGun.muzzle.rotation);
}
}
The gun is instantiated when the player spawns, as a child of the Player's weaponhold child. This class will also execute the command for shooting the gun.
The Command for shooting is in the Gun class:
public class Gun : NetworkBehaviour {
public Transform muzzle;
public Projectile projectile;
public float msBetweenShots = 100;
public float muzzleVelocity = 35;
float nextShotTime;
[Command]
public void CmdShoot(Vector3 muzzlePos, Quaternion muzzleRot)
{
if (Time.time > nextShotTime)
{
nextShotTime = Time.time + msBetweenShots / 1000;
Projectile newProjectile = Instantiate(projectile, muzzlePos, muzzleRot) as Projectile;
newProjectile.SetSpeed(muzzleVelocity);
NetworkServer.SpawnWithClientAuthority(newProjectile.gameObject, transform.parent.parent.gameObject);
}
}
}
The Gun prefab also has a networkIdentity, with its local playerAuthority checked.
The input for the shooting is handeled with the Player class:
[RequireComponent(typeof(PlayerController))]
[RequireComponent(typeof(GunController))]
public class Player : NetworkBehaviour
{
public float moveSpeed = 5;
PlayerController playerController;
Camera viewCamera;
GunController gunController;
void Start()
{
playerController = GetComponent<PlayerController>();
gunController = GetComponent<GunController>();
viewCamera = Camera.main;
}
void Update()
{
if (isLocalPlayer)
{
// Movement Input
Vector3 moveInput = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
Vector3 moveVelocity = moveInput.normalized * moveSpeed;
playerController.Move(moveVelocity);
// Rotation Input
Ray ray = viewCamera.ScreenPointToRay(Input.mousePosition);
Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
float rayDistance;
if (groundPlane.Raycast(ray, out rayDistance))
{
Vector3 point = ray.GetPoint(rayDistance);
playerController.LookAt(point);
}
// Shooting Input
if (Input.GetMouseButton(0))
{
gunController.Shoot();
}
}
}
}
So if everything should work as I indended, the result would be:
There will be a projectile gameObject spawned each time the command is called. but instead there is this warning: "Trying to send command for object without authority."
Does anyone know how this would work without changing the hierarchy of my code?
Thanks in advance!
Here's a little snippet I use that works for me. I have things like bullets spawn with Client Authority as I want to spread the load of the processing between Clients rather than leaving the Server burdened with all the work. There is a trade off to be had between shifting the processing work and increasing the Network load.
This is the part of a player script which handles Firing.
@Client
public function ShootButtonPress() :void
{
if(isLocalPlayer) CmdSpawnOnNetwork();
}
@Command
function CmdSpawnOnNetwork()
{
var myPattern = myGun.bulletPattern;
var projectileObject = Instantiate(myGun.bulletType, Vector3(transform.position.x, transform.position.y, transform.position.z), transform.rotation * Quaternion.Euler(0, 180, 0));
NetworkServer.SpawnWithClientAuthority(projectileObject, netID.connectionToClient);
if(isServer) RpcSwerve(projectileObject);
}
@ClientRpc
function RpcSwerve(projObject:GameObject)
{
projObject.AddComponent(SwerveShot);
}