Spawn bullets outside of Player control script

I’m working on a multiplayer shooter, and so far I’ve got my networked movement and weapon pickup systems working. The weapon script works in single-player and now I have to port it in to multiplayer. Here is all the problem related code:

PlayerController.cs:

  • using UnityEngine;
  • using System.Collections;
  • using System;
    • public class PlayerController : MonoBehaviour
  • {
    • [SerializeField]
  • private float Speed;
  • public bool OnGamepad = false;
  • private bool OnPrimary = true;
    • private Vector3 MoveData = Vector3.zero;
  • private Rigidbody PlayerRB;
  • public Camera PlayerCam;
  • public Transform gunOrigin;
  • public CombatItem Primary;
  • public CombatItem Secondary;
    • void Start()
  • {
    • PlayerRB = GetComponent();
  • PlayerCam = Instantiate(PlayerCam, transform.position, transform.rotation) as Camera;
  • PlayerCam.GetComponent().target = transform;
  • PlayerCam.transform.parent = transform.parent;
  • }
    • void FixedUpdate ()
  • {
  • gameObject.SetActive(true);
  • checkConrolMethod();
  • Move();
  • if (OnPrimary && Primary != null) Action1(Primary);
  • else if(!OnPrimary && Secondary != null) Action1(Secondary);
  • if (OnGamepad)
  • {
  • GamepadRotate();
  • }
  • else
  • {
  • Rotate();
  • }
  • }
    • void Move()
  • {
  • float x = Input.GetAxisRaw(“Horizontal”);
  • float z = Input.GetAxisRaw(“Vertical”);
    • MoveData.Set(x, 0f, z);
  • MoveData = MoveData.normalized * Speed;
  • PlayerRB.MovePosition(PlayerRB.position + MoveData * Time.deltaTime);
  • }
    • void Rotate()
  • {
  • Ray camRay = PlayerCam.ScreenPointToRay(Input.mousePosition);
  • Plane floor = new Plane(Vector3.up, Vector3.zero);
  • float rayL;
    • if (floor.Raycast(camRay, out rayL))
  • {
  • Vector3 lookPoint = camRay.GetPoint(rayL);
  • transform.LookAt(new Vector3(lookPoint.x, transform.position.y, lookPoint.z));
  • }
  • }
    • void GamepadRotate()
  • {
  • Vector3 direction = Vector3.right * Input.GetAxisRaw(“GPLookHorizontal”)
    • Vector3.forward * -Input.GetAxisRaw(“GPLookVertical”);
  • if(direction.sqrMagnitude > 0.0f)
  • {
  • transform.rotation = Quaternion.LookRotation(direction, Vector3.up);
  • }
  • }
    • void checkConrolMethod()
  • {
  • if (Input.GetJoystickNames().Length != 0)
  • OnGamepad = true;
  • if (Input.GetAxisRaw(“Fire”) != 0
  • || Input.GetAxisRaw(“Mouse X”) != 0
  • || Input.GetAxisRaw(“Mouse X”) != 0)
  • OnGamepad = false;
  • }
    • void OnCollisionEnter(Collision c)
  • {
  • if(c.gameObject.tag == “Bullet”)
  • {
  • transform.position = new Vector3(0, transform.position.y, 0);
  • }
  • else if(c.gameObject.tag == “CombatItem”)
  • {
  • PickUp(c.gameObject);
  • }
  • }
    • void PickUp(GameObject g)
  • {
  • g.transform.parent = transform;
  • g.transform.position = gunOrigin.transform.position;
  • g.transform.rotation = gunOrigin.transform.rotation;
  • CombatItem c = g.GetComponent();
  • c.equiped = true;
  • if (OnPrimary) Primary = c;
  • else Secondary = c;
  • }
    • void Action1(CombatItem c)
  • {
  • if (Input.GetAxisRaw(“Fire”) != 0 || Input.GetAxisRaw(“GPFire”) == -1) c.Action1(true);
  • else c.Action1(false);
  • }
      • void OnDestroy()
  • {
  • PlayerCam.GetComponent().enabled = false;
  • }
  • }

CombatItem.cs:

  • using UnityEngine;
  • using System.Collections;
    • public class CombatItem : MonoBehaviour
  • {
  • public bool equiped = false;
    • public virtual void Action1(bool on){}
  • public virtual void Action2(bool on){}
  • }

GunContoller.cs:

  • using UnityEngine;
  • using System.Collections;
  • using System;
    • public class GunController : CombatItem
  • {
  • [SerializeField]
  • Transform Origin;
  • [SerializeField]
  • Bullet b;
    • float ROFCountDown;
  • float TimeBetweenShots;
  • public float RateOfFire;
  • bool SingleShot;
  • bool IsFiring;
    • void Start()
  • {
  • TimeBetweenShots = 60 / RateOfFire;
  • }
    • void Update()
  • {
  • Fire();
  • }
    • public void Fire()
  • {
  • ROFCountDown -= Time.deltaTime;
  • if (IsFiring)
  • {
  • if (ROFCountDown <= 0)
  • {
  • ROFCountDown = TimeBetweenShots;
  • Bullet newBullet = Instantiate(b, Origin.position, Origin.rotation) as Bullet;
  • }
  • }
  • }
    • public override void Action1(bool on)
  • {
  • IsFiring = on;
  • }
    • public override void Action2(bool on)
  • {
    • }
  • }

and Bullet.cs:

    • using UnityEngine;
  • using System.Collections;
    • public class Bullet : MonoBehaviour
  • {
    • public float Speed;
  • public float Range;
  • Vector3 initPosition;
    • void Start()
  • {
  • initPosition = transform.position;
  • }
    • void FixedUpdate()
  • {
  • transform.Translate(Vector3.forward * Speed * Time.deltaTime);
  • if (Vector3.Distance(transform.position, initPosition) > Range)
  • {
  • Destroy(this.gameObject);
  • }
  • }
  • }

So a quick sum-up of what’s going on. CombatItem is a class, which provides the player script with the ability to interface with multiple kinds of… well combat items - guns, grenades, melee weapons, the CTF flag if i get that far, etc. From there each type of combat Item inherits this class and uses Action1() and Action2() to trigger the functionality of the CombatItem, which is implemented in each CombatItem class.

Here’s the problem. In order for me to spawn the bullet, I need to send a [Command] function containing NetworkServer.Spawn(bulletGameObject) (for example). The problem is that I can’t do that in the GunController or the PlayerController scripts, since they are and have to be MonoBehaviour (this code is to be used in single-player as well). I need a way to spawn the bullet sort of “outside” of this code. I hope I explained this properly enough…

All the prefabs associated with these scripts have been properly setup with network identities and transforms, and have been added to the registered prefabs list. I undestand that in order to spawn the bullet I need NetworkServer.Spawn(), which requires a gameObject with client authority in order to spawn it properly. I just can’t figure out how to access the new bullet instance from a secondary script (possibly attatched to the player prefab).

EDIT: This is something close to what i need, keep in mind it’s mostly kinda pseudo-code

  • using UnityEngine;
  • using System.Collections;
  • using UnityEngine.Networking;
    • public class NetGun : NetworkBehaviour {
    • [SerializeField]
  • GunController GC;
      • void Start ()
  • {
    • }
    • void Update ()
  • {
  • if(GC.equiped)
  • {
  • this.GetComponent().AssignClientAuthority(connectionToClient);
  • }
    • CmdSpawnBullet();
  • }
    • [Command]
  • void CmdSpawnBullet()
  • {
  • if (GC.Fire() != null)
  • {
  • NetworkServer.Spawn(GC.Fire());
  • }
  • }
  • }

Like I said, this code isn’t functional, it’s to explain the situation a bit better.I want the gun to be able to spawn a bullet in a NetworkBehaviour script separate from the GunController. I want it this way, since there will be combat items that don’t spawn projectiles…

I am not sure I understand your question 100%.

But you could try making your own registry like this.

[Command]
CmdSpawnProjectil(int projectileIndex) //where the index 0 = bullet, 1 = grenade, 2 = rocket, etc.

Or a different Cmd for each type of action.

CmdSpawnBullet()
CmdSpawnGrenade()
CmdSpawnRocket()

or use UNET messages.

This is helpful, but what i need is for these implementations to be outside of the scripts above, in a new one. The thing is, once these implementations are in a separate script, I don’t know how to connect them to the scripts above

EDIT: I need the spawn commands themselves to be outside these scripts, but not the instantiate calls, since they have to stay inside the scripts above…

I’m not sure I follow what you are after.

But if you need it to be completely unrelated to any instance of a NetworkBehaviour script on the object then you can send a NetworkMessage (along with information like position, angle, etc.) to the server. Something like this.

-Client decides to fire a bullet
-Client sends NetworkMessageFireBullet to server (containing pos/rot data)
-Server deserializes & reads message (and pos/rot data)
-Server instantiates bullet object locally
-Server assigns data (like pos/rot)
-Server spawns object to clients
-Client receives spawn message & serialized data

I need a NetworkBehaviour script attached to the Gun (or whatever Combat Item) object that sends the NetworkServer.Spawn() command to the server, but I want it to be a separate behaviour from the GunController, since that cannot be a NetworkBehaviour. I tried doing that, but it told me the gun object didn’t have authority, so i tried adding AssignClentAuthority, which is run on pick-up and it says owner can’t be null. I’ll add that script in an edit in OP, maybe you’ll understand what I need…