Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

Resolved CharacterController NullReferenceException only in Windows Build

Discussion in 'Editor & General Support' started by AydnMedia, Apr 5, 2020.

  1. AydnMedia

    AydnMedia

    Joined:
    Nov 12, 2019
    Posts:
    2
    Hi,

    I've been running into an issue when attempting to build my game.

    The game runs perfectly in the Unity Editor on both Windows and MacOS. The MacOS build of the game also runs perfectly without issue. However, for some reason in the Windows standalone build, when I enter my main game scene I encounter a NullReferenceException when attempting to access the CharacterController on my player in order to move it.

    NullReferenceException: Object reference not set to an instance of an object
    at PlayerController.Update () [0x0004c] in ...\Reef Rally 2019.2.7\Assets\Scripts\PlayerController.cs:111


    I have attached the editor log from the most recent build run.

    Here is my PlayerController script where the error is originating. I should mention that the motion controller referenced within the script should have no effect on ability to find the CharacterController.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Leap;
    5.  
    6. /*
    7.     This script controls the movement mechancics of the player when using both a keyboard or motion controller. The main function of this script
    8.     determines whether or not the player is dead or alive. Then, depending on if a hand is detected by the controller it decides whether the game will be
    9.     controlled by the keyboard or by the motion controller.
    10. */
    11.  
    12. public class PlayerController : MonoBehaviour
    13. {
    14.     //Define External Scripts
    15.     [HideInInspector] HandController handPosition;
    16.     [HideInInspector] public CharacterController controller;
    17.     [HideInInspector] public GameplayController gameplayController;
    18.  
    19.     //Define GameObjects
    20.     [HideInInspector] public GameObject player;
    21.     [HideInInspector] private GameObject mainCamera;
    22.  
    23.     //Define player states
    24.     [HideInInspector] public enum State { None, Alive, Dead };
    25.     [HideInInspector] public State playerState;
    26.  
    27.     //Add ranged slider to inspector for camera distance from player
    28.     [Range(0.0f, 20.0f)] [SerializeField] float cameraOffsetZ;
    29.     [Range(-5.0f, 5.0f)] [SerializeField] float cameraOffsetY;
    30.  
    31.     //Define Leap Motion Interaction Box Vector
    32.     Vector normalized;
    33.  
    34.     //Define input axis variables
    35.     float leapHorizontal;
    36.     float leapVertical;
    37.     float horizontal;
    38.     float vertical;
    39.  
    40.     //Create inspector input for Movement variables
    41.     [SerializeField] float controlSpeed = 10f; //Speed in m/s^-1
    42.     //[SerializeField] float leapControlSpeed = 15f; //Speed in m/s^-1
    43.     [SerializeField] public float forwardVelocity = 5.0f;
    44.     [SerializeField] float waterGravity = 3.0f;
    45.     [SerializeField] float leapMovementScale = 1.5f;
    46.  
    47.     //Throw is 1 > -1 offset from centre of controller
    48.     float xThrow;
    49.     float yThrow;
    50.  
    51.     //Create inspector input for Player Rotation Variables
    52.     private float controlPitchFactor = -30f;
    53.     private float controlRollFactor = -20f;
    54.     private float leapRotationFactor = 50;
    55.  
    56.     //Define Character postion as Vector3
    57.     Vector3 characterPos;
    58.  
    59.     //Create floats for player movement restrictions
    60.     [SerializeField] public float xClamp = 4f;
    61.     [SerializeField] public float yClamp = 3f;
    62.     private float xLeapClampMin = -3.5f;
    63.     private float xLeapClampMax = 3.5f;
    64.     private float yLeapClampMin = 1f;
    65.     private float yLeapClampMax = 6f;
    66.  
    67.     private void Awake()
    68.     {
    69.         //Access Game Objects
    70.         mainCamera = GameObject.FindGameObjectWithTag("MainCamera");
    71.  
    72.         //Access External Scripts
    73.         handPosition = GameObject.FindGameObjectWithTag("HandController").GetComponent<HandController>();
    74.         gameplayController = mainCamera.GetComponent<GameplayController>();
    75.     }
    76.  
    77.     // Start is called before the first frame update
    78.     void Start()
    79.     {
    80.         //Set Player to dead, is change to alive by GameplayController after start delay
    81.         gameplayController.playerState = GameplayController.State.Dead;
    82.  
    83.         player = GameObject.FindGameObjectWithTag("Player");
    84.  
    85.         cameraOffsetY = 0.8f;
    86.         cameraOffsetZ = 6f;
    87.     }
    88.  
    89.     // Update is called once per frame
    90.     void Update()
    91.     {
    92.         //Get HandController Data from current frame
    93.         Frame frame = handPosition.GetFrame();
    94.         //Define hand as most prominent hand detected in the frame by Leap Motion
    95.         Hand hand = frame.Hands.Frontmost;
    96.  
    97.         controller = player.GetComponent<CharacterController>();
    98.         //controller.detectCollisions = false;
    99.  
    100.         AccessInputVariables(frame, hand);
    101.  
    102.         //Run if player is not Dead
    103.         if (gameplayController.playerState != GameplayController.State.Dead)
    104.         {
    105.             //Move player forward at specified speed m/s
    106.             controller.Move((Vector3.forward * forwardVelocity) * Time.deltaTime);
    107.             controller.Move((Vector3.down * waterGravity) * Time.deltaTime);
    108.  
    109.             //If hand is detected by Motion Controller
    110.             if (hand.IsValid)
    111.             {
    112.                 UseHandControls(frame, hand, leapHorizontal, leapVertical);
    113.             }
    114.             //else if no hand is detected
    115.             else
    116.             {
    117.                 UseKeyControls(horizontal, vertical);
    118.             }
    119.         }
    120.  
    121.         //Camera follows the player
    122.         CameraFollow();
    123.  
    124.     }
    125.  
    126.     private void AccessInputVariables(Frame frame, Hand hand)
    127.     {
    128.         //Access Leap Motion Interaction Box
    129.         normalized = frame.InteractionBox.NormalizePoint(hand.PalmPosition, true) * 2;
    130.  
    131.         //Access input axis and Interaction Box axis
    132.         leapHorizontal = normalized.x - 1;
    133.         leapVertical = normalized.y - 1;
    134.         horizontal = Input.GetAxis("Horizontal");
    135.         vertical = Input.GetAxis("Vertical");
    136.     }
    137.  
    138.     public void UseKeyControls(float horizontal, float vertical)
    139.     {
    140.         xPlayerMovement(controlSpeed, horizontal);
    141.         yPlayerMovement(controlSpeed, vertical);
    142.         PlayerRotation(horizontal, vertical);
    143.     }
    144.  
    145.     public void UseHandControls(Frame frame, Hand hand, float horizontal, float vertical)
    146.     {
    147.         //Interaction Box Hand Controls
    148.         //xPlayerMovement(leapControlSpeed, horizontal);
    149.         //yPlayerMovement(leapControlSpeed, vertical);
    150.         //PlayerRotation(horizontal, vertical);
    151.  
    152.         //Legacy Hand Controls
    153.         PlayerMovement(hand);
    154.         PlayerRotation(hand);
    155.     }
    156.  
    157.     private void CameraFollow()
    158.     {
    159.         //Define characterPos as current world position of the character model
    160.         characterPos = player.transform.position;
    161.  
    162.         //Set camera position to player position with a defined offset behind the player
    163.         mainCamera.transform.position = new Vector3(characterPos.x, characterPos.y + cameraOffsetY, characterPos.z - cameraOffsetZ);
    164.     }
    165.  
    166.     private void xPlayerMovement(float SpeedFactor, float inputAxis)
    167.     {
    168.         //Horizontal input from controller/keyboard - joystick/a-d
    169.         xThrow = inputAxis;
    170.  
    171.         //Time.deltaTime = time passed since last frame. Allows for constant velocity with varying fps distance = speed x Velocity
    172.         float xOffset = xThrow * controlSpeed * Time.deltaTime;
    173.  
    174.         //Change player x-axis position with offset included
    175.         float xPos = player.transform.localPosition.x + xOffset;
    176.  
    177.         //Restrict how far player can move
    178.         xPos = Mathf.Clamp(xPos, -xClamp, xClamp);
    179.  
    180.         //Change position on x-axis without altering y and z axes
    181.         player.transform.localPosition = new Vector3(xPos, player.transform.localPosition.y, player.transform.localPosition.z);
    182.     }
    183.  
    184.     private void yPlayerMovement(float SpeedFactor, float inputAxis)
    185.     {
    186.         //Vertical input from controller/keyboard - joystick/w-s
    187.         yThrow = inputAxis;
    188.  
    189.         //Time.deltaTime = time passed since last frame. Allows for constant velocity with varying fps distance = speed X Velocity
    190.         float yOffset = yThrow * SpeedFactor * Time.deltaTime;
    191.  
    192.         //Change player y-axis position with offset included
    193.         float yPos = player.transform.localPosition.y + yOffset;
    194.  
    195.         //Restrict how far player can move
    196.         yPos = Mathf.Clamp(yPos, -yClamp, yClamp);
    197.  
    198.         //Change position on y-axis without altering y and z axes
    199.         player.transform.localPosition = new Vector3(player.transform.localPosition.x, yPos, player.transform.localPosition.z);
    200.     }
    201.  
    202.     private void PlayerRotation(float xRotation, float yRotation)
    203.     {
    204.         //Define Roll and Pitch multiplied by their control factor
    205.         float roll = xRotation * controlRollFactor;
    206.         float pitch = yRotation * controlPitchFactor;
    207.  
    208.         //Transform rotation based on factored proportions in relation to position of player
    209.         player.transform.localRotation = Quaternion.Euler(pitch, 0, roll); //x, y, z
    210.     }
    211.  
    212.     private void PlayerMovement(Hand hand)
    213.     {
    214.         Vector3 getHandPosition = handPosition.transform.TransformPoint(hand.PalmPosition.ToUnityScaled());
    215.  
    216.         //Define X and Y axes of hand position and mulitply by leapMovementScale
    217.         float xPosHand = getHandPosition.x * leapMovementScale;
    218.         float yPosHand = getHandPosition.y * leapMovementScale;
    219.  
    220.         //Set clamps for hand position
    221.         float clampedXPos = Mathf.Clamp(xPosHand, xLeapClampMin, xLeapClampMax);
    222.         float clampedYPos = Mathf.Clamp(yPosHand, yLeapClampMin, yLeapClampMax);
    223.  
    224.         //Transform position of Player with position of user's hand
    225.         player.transform.position = new Vector3(clampedXPos, clampedYPos, player.transform.position.z);
    226.     }
    227.  
    228.     private void PlayerRotation(Hand hand)
    229.     {
    230.         float pitch = hand.Direction.Pitch * -leapRotationFactor;
    231.         float roll = hand.PalmNormal.Roll * leapRotationFactor;
    232.  
    233.         player.transform.rotation = Quaternion.Euler(pitch, 0, roll);
    234.     }
    235. }
    236.  
    237.  
    This is my first time posting on these threads so apologies if I have not uploaded everything in the correct format.
     
    Last edited: Apr 9, 2020
  2. RLord321

    RLord321

    Joined:
    Feb 25, 2017
    Posts:
    28
    You probably should put your file path in the post as everyone now knows you are in your 3rd year in college :)

    NullReferenceExceptions are a pain - especially when it works in the editor and not on a certain build. I had this problem many times and EVERY SINGLE TIME it was because I was using one of the Find methods like you are. Apparently, different platforms don't maintain the same order of GameObjects... For instance, if you have two objects that have the same tag and you do the statement in line 73, FindGameObjectWithTag, it may pick up the 1st object in your list in the Unity Editor but on a different platform (Windows, XBOX, etc), it may pick up the 2nd one. If you don't have the right setup on that object, you may receive this error.

    Not sure if that's your problem but just check and see if you have multiple objects with the same tag unintentionally (maybe you duplicated an object to test something?).
     
    AydnMedia likes this.
  3. AydnMedia

    AydnMedia

    Joined:
    Nov 12, 2019
    Posts:
    2
    Hey, thanks for taking the time to respond!

    I managed to eventually trace it back to exactly how you had described. I had moved my the colliders from my character to a separate object within the parent and I had left the same tag on this new child object as the parent. And then yes, for whatever reason in the way the platform builders work, the Windows build appeared to go directly for the child object as opposed to the parent which contained the characterController.
     
  4. RLord321

    RLord321

    Joined:
    Feb 25, 2017
    Posts:
    28
    No problem - I'm glad you were able to solve it!