Hey all!
I’m a starting developer, been having fun with Unity, C# and the tutorials from Brackeys for a few weeks now. Enjoying the hell out of the Making a Multiplayer FPS tutorials from Brackeys! With help from the 14th episode, I tried to implement an UI bar to show the players stamina, instead of the fuel from the tutorial. Turns out I get a “NullReferenceException: Object reference not set to an instance of an object PlayerUI.Update () (at Assets/Scripts/PlayerUI.cs:19)”. It’s driving me crazy since the code doesn’t give any errors while building, plus, yeah I made sure the right prefabs are connected in the inspector. Still, the stamina for the sprinting works, but the bar doesn’t. Been trying a few days now, but I don’t have much hair left. So I would like some help from any of you super smart people. Anyway, this is my PlayerController:
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
[RequireComponent(typeof(PlayerMotor))]
public class PlayerController : MonoBehaviour {
[SerializeField]
private float speed = 5f;
[SerializeField]
private float defaultSpeed = 5f;
[SerializeField]
private float runspeed = 10f;
[SerializeField]
private float staminaStopSpeed = 1f;
[SerializeField]
private float lookSensitivity = 3f;
private bool cantSprint = false;
private PlayerMotor motor;
private Animator animator;
[SerializeField]
private float staminaAmount = 1f;
private float staminaBurn = 0.3f;
private float staminaRegen = 0.1f;
private float staminaStopSec = 3f;
//getter stamina
public float GetStaminaAmount () {
Debug.Log (staminaAmount);
return staminaAmount;
}
void Start () {
motor = GetComponent<PlayerMotor>();
animator = GetComponentInChildren<Animator>();
}
void Update () {
//movement 3d vector
float xMov = Input.GetAxis("Horizontal");
float zMov = Input.GetAxis("Vertical");
Vector3 movHorizontal = transform.right * xMov;
Vector3 movVertical = transform.forward * zMov;
//final movement vector
Vector3 velocity = (movHorizontal + movVertical) * speed;
//animate movement
animator.SetFloat("ForwardVelocity", zMov);
//apply movement in player motor script
motor.Move (velocity);
float yRot = Input.GetAxisRaw("Mouse X");
Vector3 rotation = new Vector3 (0f, yRot, 0f) * lookSensitivity;
//apply rotation
motor.Rotate(rotation);
// CAMERA rotate
float xRot = Input.GetAxisRaw("Mouse Y");
float cameraRotationX = xRot * lookSensitivity;
//apply camerarotation
motor.RotateCamera(cameraRotationX);
//apply run
if (Input.GetButton ("Sprint") && cantSprint == false && staminaAmount > 0.05f) {
//stamina burn
staminaAmount -= staminaBurn * Time.deltaTime;
speed = runspeed;
animator.speed = 2f;
} else {
//stamina regen
staminaAmount += staminaRegen * Time.deltaTime;
speed = defaultSpeed;
animator.speed = 1f;
}
//clamp stamina
staminaAmount = Mathf.Clamp (staminaAmount, 0f, 1f);
if (staminaAmount <= 0.05f) {
cantSprint = true;
Invoke("StaminaStop", staminaStopSec);
animator.speed = 0.2f;
cantSprint = false;
}
if (staminaAmount >= 1f) {
speed = defaultSpeed;
animator.speed = 1f;
}
//just to test if the stamina calculations are working
GetStaminaAmount();
}
//stamina invoke method
void StaminaStop() {
speed = staminaStopSpeed;
}
}
Then the playerSetup script:
using UnityEngine;
using UnityEngine.Networking;
[RequireComponent(typeof(PlayerManager))]
[RequireComponent(typeof(PlayerController))]
public class PlayerSetup : NetworkBehaviour {
[SerializeField]
Behaviour[] componentsToDisable;
[SerializeField]
string remoteLayerName = "RemotePlayer";
[SerializeField]
string dontDrawLayerName = "DontDraw";
[SerializeField]
GameObject playerGraphics;
[SerializeField]
GameObject playerUIPrefab;
private GameObject playerUIInstance;
Camera sceneCamera;
void Start() {
if (!isLocalPlayer) {
DisableComponents();
AssignRemoteLayer();
} else {
sceneCamera = Camera.main;
if (sceneCamera != null) {
sceneCamera.gameObject.SetActive(false);
}
//disable player graphics for local player
SetLayerRecursively (playerGraphics, LayerMask.NameToLayer(dontDrawLayerName));
//create player UI
playerUIInstance = Instantiate (playerUIPrefab);
playerUIInstance.name = playerUIPrefab.name;
//configure player UI
PlayerUI ui = playerUIInstance.GetComponent<PlayerUI>();
if (ui == null)
Debug.LogError ("No player UI component on player prefab");
ui.SetController (GetComponent<PlayerController>());
}
GetComponent<PlayerManager>().Setup();
}
void SetLayerRecursively (GameObject obj, int newLayer) {
obj.layer = newLayer;
foreach (Transform child in obj.transform){
SetLayerRecursively (child.gameObject, newLayer);
}
}
public override void OnStartClient() {
base.OnStartClient();
string netID = GetComponent<NetworkIdentity>().netId.ToString();
PlayerManager player = GetComponent<PlayerManager>();
GameManager.RegisterPlayer(netID, player);
}
void AssignRemoteLayer() {
gameObject.layer = LayerMask.NameToLayer(remoteLayerName);
}
void DisableComponents () {
for (int i = 0; i < componentsToDisable.Length; i++) {
componentsToDisable*.enabled = false;*
}
}
//when destroyed
void OnDisable () {
Destroy (playerUIInstance);
if (sceneCamera != null) {
sceneCamera.gameObject.SetActive(true);
}
GameManager.UnRegisterPlayer(transform.name);
}
}
And last but not least, the playerUI script:
using UnityEngine;
public class PlayerUI : MonoBehaviour {
[SerializeField]
RectTransform StaminaFill;
private PlayerController controller;
public void SetController (PlayerController _controller) {
controller = _controller;
}
void Start () {
controller = GetComponent();
}
void Update () {
SetStaminaAmount(controller.GetStaminaAmount());
}
void SetStaminaAmount (float _amount) {
StaminaFill.localScale = new Vector3 (1f, _amount, 1f);
}
}
So once again, the stamina calculates correct. It works. The prefabs are linked in the inspector correctly (the colored bar rect transform in the playerUI). Still, the bar doesn’t empty/ refill and I get this nullreference at the “SetStaminaAmount() in the PlayerUI Update()”, so I guess the script can’t find the right controller? Or it can’t receive the float amount from the public float in the controller OR the configure playerUI in the setup script doenst work… pff. I don’t get it! It should work right? I hope someone has the answer! Thanks in advance!