"Object reference is not set to an instance of an object" error in my code

I’m working on my base weapon system for my game, and i got the error in the title at line 102 in the following script:

PlayerController.cs:

using UnityEngine;
using System.Collections;


public class PlayerController : MonoBehaviour
{

    [SerializeField]
    private float speed;
    public bool onGamepad = false;

    private Vector3 moveData = Vector3.zero;
    private Rigidbody playerRB;
    private Camera mainCam;


    public CombatItem primary;
    public CombatItem secondary;
    private CombatItem current;
    private bool onPrimary = true;
 

    void Start()
    {
        playerRB = GetComponent<Rigidbody>();
        mainCam = FindObjectOfType<Camera>();
    }

 
    void FixedUpdate ()
    {                      
        checkConrolMethod();
        setCurrentItem();
        Move();                      

        if (onGamepad)
        {
            GamepadRotate();
            GPAction1(current);    
        }
        else
        {
            Rotate();
            Action1(current);              
        }                                      
    }    

    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 = mainCam.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.name == "laserBullet(Clone)")
        {
            transform.position = new Vector3(0, transform.position.y, 0);
        }
    }

    void Action1(CombatItem c)
    {
        if (Input.GetAxisRaw("Fire") != 0) c.Action1(true);    
        else c.Action1(false);
    }

    void GPAction1(CombatItem c)
    {
        if (Input.GetAxisRaw("GPFire") == -1) c.Action1(true);
        else c.Action1(false);
    }

    void setCurrentItem()
    {
        if(!onPrimary) current = secondary;
        else current = primary;
    }
}

Here are all the related scripts, in case the error is somewhere in them.

CombatItem.cs:

using UnityEngine;
using System.Collections;

public interface CombatItem
{
    void Action1(bool on);
    void Action2(bool on);  
}

GunController.cs:

using UnityEngine;
using System.Collections;
using System;

public class GunController : MonoBehaviour
{
    public Bullet b;
    protected float speed;
    protected float rateOfFire;

    protected bool singleShot;
    protected Transform origin;

    protected float ROFCountDown;
    protected bool canFire;
    protected bool isFiring; 
   
   
    public void Fire(bool canFire, bool firing, bool singleShot)
    {
        if (canFire)
        {
            canFire = false;
            ROFCountDown -= Time.deltaTime;
            if (ROFCountDown <= 0)
            {
                ROFCountDown = rateOfFire;
                Bullet newBullet = Instantiate(b, origin.position, origin.rotation) as Bullet;
                newBullet.speed = speed;
                canFire = true;
            }
        }
        else ROFCountDown = 0;
    }
}

and AssaultRifle.cs

using UnityEngine;
using System.Collections;
using System;

public class AssaultRifle : GunController, CombatItem {

    // Use this for initialization
    void Start ()
    {
        b = Resources.Load("Assets/Prefabs/laserBullet") as Bullet;
    }

    void FixedUpdate()
    {
        Fire(isFiring, canFire, singleShot);
    }

    public void Action1(bool on)
    {
        isFiring = on;     
    }

    public void Action2(bool on)
    {

    }
}

Note that there might be a number of unrelated bugs, so don’t mind them…

Might be a bit obvious answer, but just to ensure you made everything. Did you assign the variable “Primary” for PlayerController in the inspector?

You are right, that’s the problem. However, it doesn’t appear in the PlayerController inspector… I tried with [SerializeField], even though it’s public, but nada…

EDIT: To point out, I found this new problem after your answer…

Yeah, I didn’t notice that you use interfaces. Unfortunately, Unity by itself does not serialise Interfaces. However, you can make your own editor extension to handle it.

I am not a pro in editor extensions, but I found this code:

[Assets/MyScript.cs]:
using UnityEngine;
public class MyScript : MonoBehaviour
{
   public ILight m_Light;
   public Transform m_TheTransform;
   public Rigidbody m_LaserBlastingRocketOfDoom_prefab;
}



[Assets/Editor/MyScriptInspector.cs]:
using UnityEngine;
using UnityEditor;
[CustomEditor (typeof (MyScript))]
public class MyScriptInspector : Editor
{
   void OnInspectorGUI ()
   {
      MyScript script = (MyScript)target;
      script.m_Light = EditorGUILayout.ObjectField ("Light", script.m_Light, typeof (ILight));
      DrawDefaultInspector ();
   }
}

(Retrieved from here)

It seems reasonable to me, but I dont know if it works. If it not, google, maybe you will find other options. Hope you are skilled enough to shape this code for your purposes.

Much easier solution would be to make a public variable of type GameObject, but later in awake, for example, manually transfer it into a private variable of interface type. The only disadvantage of this is that you can in the future ocasionally put into the variable a wrong GameObject without interface extension. So, it will just throw an error. However, it is not a big deal, in my opinion.

Thanks for the reply, I actually slightly changed the code, I turned the interface into a class with virtual methods, because it turned out, that I would need a few fields in there as well, so now it works fine. Thanks anyway!