I keep getting the error Object reference not set to an instance of an object on line 64 and I can't figure out what I need to do
Everything is working like the lives are showing up and the timer and the score is but the score isn't increasing if you can tell me what is wrong I would be so thankful
Here's my code:
using UnityEngine;
using System.Collections;
public class Player : MonoBehaviour {
private CountdownTimer myTimer;
private int score = 0;
private int lives = 3;
private int DEATH_Y = -10;
public Texture2D LivesLeft1;
public Texture2D LivesLeft2;
public Texture2D LivesLeft3;
public int GetScore(){
return score;
}
public int GetLives()
{
return lives;
}
private void Start()
{
myTimer = GetComponent<CountdownTimer>();
}
private void Update()
{
float y = transform.position.y;
if (y < DEATH_Y) {
MoveToStartPosition();
lives--;
}
if (score == 10)
{
Application.LoadLevel("Level2");
}
if (lives == 0)
{
Application.LoadLevel("GameOver");
}
}
private void OnGUI()
{
GUILayout.BeginHorizontal ();
DisplayLives();
int secondsLeft = myTimer.GetSecondsRemaining();//this is line 64
string timeMessage = "Seconds left = " + secondsLeft;
GUILayout.Label(timeMessage);
string scoreMessage = "Score = " + score;
GUILayout.Label (scoreMessage);
}
private void DisplayLives()
{
int playerLives = GetLives();
if (1 == playerLives) {
GUILayout.Label(LivesLeft1);
}
if (2 == playerLives)
{
GUILayout.Label(LivesLeft2);
}
if(3 == playerLives){
GUILayout.Label(LivesLeft3);
}
}
private void MoveToStartPosition()
{
Vector3 startPosition = new Vector3(0,5,0);
transform.position = startPosition;
}
/**
* what increases the score
* anything with the tag Hidden
*/
private void OnTriggerEnter(Collider c)
{
string tag = c.tag;
if("Hidden" == tag)
{
score++;
}
}
}
Are you sure that your GameObject have the Component called CountdownTimer?
Also, change the Start function to Awake, because that line is not depending on anything else.
Related
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
In Unity (C#), why am I getting a NullReferenceException and how do I fix it? [duplicate]
(1 answer)
Closed 1 year ago.
I follow a Unity Tutorial to program a version of flappy bird but I get the error NullReferenceException: Object reference not set to an instance of an object
Parallaxer.Shift () (at Assets/scripts/Parallaxer.cs:130)
Parallaxer.Update () (at Assets/scripts/Parallaxer.cs:75)
uijk,hfgmjdcfmhfc,ghvkmbgµfhj,ddgxngsdfaf
This is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Parallaxer : MonoBehaviour
{
class PoolObject
{
public Transform transform;
public bool inUse;
public PoolObject(Transform t) { transform = t; }
public void Use() { inUse = true; }
public void Dispose() { inUse = false; }
}
[System.Serializable]
public struct YSpawnRange
{
public float min;
public float max;
}
public GameObject Prefab;
public int poolSize;
public float shiftSpeed;
public float spawnRate;
public YSpawnRange ySpawnRange;
public Vector3 defaultSpawnPos;
public bool spawnImmediate;
public Vector3 immediateSpawnPos;
public Vector2 targetAspectRatio;
float spawnTimer;
float targetASpect;
PoolObject[] poolObjects;
GameManager game;
private void Awake()
{
}
private void Start()
{
game = GameManager.Instance;
}
private void OnEnable()
{
GameManager.OnGameOverConfirmed += OnGameOverConfirmed;
}
private void OnDisable()
{
GameManager.OnGameOverConfirmed -= OnGameOverConfirmed;
}
void OnGameOverConfirmed()
{
for (int i = 0; i < poolObjects.Length; i++)
{
poolObjects[i].Dispose();
poolObjects[i].transform.position = Vector3.one * 1000;
}
if (spawnImmediate)
{
SpawnImmediate();
}
}
void Update()
{
if (game.GameOver) return;
Shift();
spawnTimer += Time.deltaTime;
if (spawnTimer > spawnRate)
{
Spawn();
spawnTimer = 0;
}
}
void Configure()
{
targetASpect = targetAspectRatio.x / targetAspectRatio.y;
poolObjects = new PoolObject[poolSize];
for (int i = 0; i < poolObjects.Length; i++)
{
GameObject go = Instantiate(Prefab) as GameObject;
Transform t = go.transform;
t.SetParent(transform);
t.position = Vector3.one * 1000;
poolObjects[i] = new PoolObject(t);
}
if (spawnImmediate)
{
SpawnImmediate();
}
}
void Spawn()
{
Transform t = GetPoolObject();
if (t == null) return;
Vector3 pos = Vector3.zero;
pos.x = defaultSpawnPos.x;
pos.y = Random.Range(ySpawnRange.min, ySpawnRange.max);
t.position = pos;
}
void SpawnImmediate()
{
Transform t = GetPoolObject();
if (t == null) return;
Vector3 pos = Vector3.zero;
pos.x = immediateSpawnPos.x;
pos.y = Random.Range(ySpawnRange.min, ySpawnRange.max);
t.position = pos;
Spawn();
}
void Shift()
{
for (int i = 0; i < poolObjects.Length; i++)
{
poolObjects[i].transform.position += -Vector3.right * shiftSpeed * Time.deltaTime;
CheckDisposeObject(poolObjects[i]);
}
}
void CheckDisposeObject(PoolObject poolObject)
{
if (poolObject.transform.position.x < -defaultSpawnPos.x)
{
poolObject.Dispose();
poolObject.transform.position = Vector3.one * 1000;
}
}
Transform GetPoolObject()
{
for (int i = 0; i < poolObjects.Length; i++)
{
if (!poolObjects[i].inUse)
{
poolObjects[i].Use();
return poolObjects[i].transform;
}
}
return null;
}
}
Thank you for your help.
I think you need to call Configure in Start or Awake. Otherwise the poolObjects array doesn't get initialized and trying to access poolObjects[i] in Shift will cause the NullRefrence error.
I've just updated to the new Input System from 2.7 to 2.8.
How the new Input System works is you create an input actions asset by going to Create-> Input Actions
.
This creates an asset where actions can be mapped to keys. One then create a C# script from this asset and use it in their code. Which is what I did. I called the Asset MyInput.inputactions and the C# script is MyInput.cs
When you use the generated C# script this way you need to reference the asset in your script. However, after the update, it seems this is impossible to do from the editor. When I define a public MyInput variable in my class, like so:
public class ShapeMover: MonoBehaviour
{
public MyInput controls;
private float _lastFallTime;
private float _fallSpeed;
private ShapeSpawner _spawn;
private GameObject _shapeToMove;
private Transform _shapeToMoveTransform;
private bool _isGameOver;
private const float _leftRotationAngle = (float) -1.57079633;
private const float _rightRotationAngle = (float) 1.57079633;
}
It isn't exposed in the inspector:
And I get an obvious NullReferenceExceptionerror when I try to access the controls variable.
Am I doing something wrong?
How can I reference the asset from the inspector? I have tried adding [SerializeField] to the public declaration, it didn't help.
I was following this video and it worked fine until I updated to a newer Input System version.
For reference, this is the full ShapeMover class:
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
namespace _Scripts
{
public class ShapeMover : MonoBehaviour
{
[SerializeField]
public MyInput controls;
private float _lastFallTime;
private float _fallSpeed;
private ShapeSpawner _spawn;
private GameObject _shapeToMove;
private Transform _shapeToMoveTransform;
private bool _isGameOver;
private const float _leftRotationAngle = (float) -1.57079633;
private const float _rightRotationAngle = (float) 1.57079633;
private void Awake()
{
_spawn = FindObjectOfType<ShapeSpawner>();
_lastFallTime = 0f;
_fallSpeed = GameGrid.Instance.GetFallSpeed();
_isGameOver = false;
Debug.Log("Registering controls callbacks...");
controls.Player.Movement.performed += ctx => Movement(ctx.ReadValue<Vector2>(), true);
controls.Player.Drop.performed += ctx => Drop();
controls.Menu.Reset.performed += ctx => Restart();
controls.Menu.Pause.performed += ctx => PauseToggle();
SetShapeToMove();
}
private void Restart()
{
GameGrid.Instance.ResetGame();
_isGameOver = false;
SetShapeToMove();
}
private void PauseToggle()
{
Debug.Log("Got Pause input");
var currentPauseState = GameGrid.Instance.IsPaused;
//If not paused, will pause
if (!currentPauseState)
{
// controls.Player.Movement.Disable();
// controls.Player.Drop.Disable();
// controls.Player.Menu.Disable();
// controls.Player.Disable();
GameGrid.Instance.IsPaused = true;
}
else
{
// controls.Player.Movement.Enable();
// controls.Player.Drop.Enable();
// controls.Player.Menu.Enable();
// controls.Player.Enable();
GameGrid.Instance.IsPaused = false;
}
}
private void Drop()
{
// Debug.Log("Should Drop Shape!");
bool didMove = true;
while (didMove)
{
didMove = Movement(new Vector2(0, -1), false);
}
}
private bool Movement(Vector2 direction, bool isFromInput)
{
if (isFromInput)
{
Debug.Log($"Got input {direction.ToString()}");
}
//Disable movement controls when game is over.
if (_isGameOver)
{
return false;
}
var oldPosition = _shapeToMoveTransform.position;
var oldRotation = _shapeToMoveTransform.rotation;
// Transform[] children = _shapeToMoveTransform.Cast<Transform>().ToArray();
var didMove = true;
var didEndMovement = false;
GameGrid.Instance.RemoveShapeFromGrid(_shapeToMoveTransform);
if (direction.x < 0)
{
didMove = MoveLeft();
}
else if (direction.x > 0)
{
didMove = MoveRight();
}
else if (direction.y > 0)
{
didMove = RotateLeft();
}
else if (direction.y < 0)
{
didMove = MoveDown();
if (!didMove)
{
didEndMovement = true;
}
}
//If Shape didn't move, restore previous position.
if (!didMove)
{
_shapeToMoveTransform.position = oldPosition;
_shapeToMoveTransform.rotation = oldRotation;
}
GameGrid.Instance.AddShapeToGrid(_shapeToMoveTransform);
// Debug.Log($"Shape {_shapeToMove.name} Position after movement Did Move: {didMove.ToString()}");
// Transform[] children = _shapeToMoveTransform.Cast<Transform>().ToArray();
// var lowestChild = children.OrderBy(x => x.position.y).First();
// Debug.Log($"{lowestChild.position.ToString()}");
if (didEndMovement)
{
GameGrid.Instance.ClearRows(_shapeToMoveTransform);
_isGameOver = GameGrid.Instance.IsGameOver(_shapeToMoveTransform);
if (!_isGameOver)
{
SetShapeToMove();
}
}
return didMove;
}
private void SetShapeToMove()
{
_shapeToMove = _spawn.SpawnShape();
_shapeToMoveTransform = _shapeToMove.transform;
}
private void Update()
{
if (_isGameOver)
{
return;
}
if (GameGrid.Instance.IsPaused)
{
return;
}
var time = Time.time;
if (!(time - (_lastFallTime + _fallSpeed) > 0))
{
return;
}
Movement(new Vector2(0, -1), false);
_lastFallTime = time;
_fallSpeed = GameGrid.Instance.GetFallSpeed();
}
private bool MoveLeft()
{
_shapeToMoveTransform.position += Vector3.right;
return GameGrid.Instance.CanMove(_shapeToMoveTransform);
}
private bool MoveRight()
{
_shapeToMoveTransform.position += Vector3.left;
return GameGrid.Instance.CanMove(_shapeToMoveTransform);
}
private bool MoveDown()
{
_shapeToMoveTransform.position += Vector3.down;
return GameGrid.Instance.CanMove(_shapeToMoveTransform);
}
private bool RotateLeft()
{
_shapeToMoveTransform.Rotate(0, 0, -90);
// foreach (Transform child in _shapeToMoveTransform)
// {
// RotateTransform(child, _leftRotationAngle);
// }
return GameGrid.Instance.CanMove(_shapeToMoveTransform);
}
private void RotateTransform(Transform transformToRotate, float rotationAngleRadian)
{
var currentLocalPosition = transformToRotate.localPosition;
var currentX = currentLocalPosition.x;
var currentY = currentLocalPosition.y;
var rotatedX = currentX * Mathf.Cos(rotationAngleRadian) - currentY * Mathf.Sin(rotationAngleRadian);
var rotatedY = currentX * Mathf.Sin(rotationAngleRadian) + currentY * Mathf.Cos(rotationAngleRadian);
transformToRotate.localPosition = new Vector2(rotatedX, rotatedY);
// Debug.Log($"Position after rotation is: {transformToRotate.localPosition.ToString()}");
}
private bool RotateRight()
{
_shapeToMoveTransform.Rotate(0, 0, -90);
return GameGrid.Instance.CanMove(_shapeToMoveTransform);
}
private void OnEnable()
{
Debug.Log("Controls Enabled...");
controls.Enable();
}
// private void OnDisable()
// {
// Debug.Log("Controls Disabled...");
// controls.Disable();
// }
}
}
Just as you said, you can't reference the new generated input class anymore.
To make it works, i instantiated the class, and use the SetCallbacks method, like this :
private MyInput _inputs;
public void Awake()
{
_inputs = new MyInput();
}
Truth be told, i don't know if it's the intended way of using the input class, but it works.
EDIT :
Starting from the 2.8 preview, an interface is automatically generated. I can only recommend it, cause it's very easy to use, you just need to inherits from IYourActionsSetNameActions and add the callbacks. (Also, you have to enable / disable the actions set, but you should be able to do it in another script)
Here is a complete base example, using your naming :
public class ShapeMover : MonoBehaviour, MyInput.IPlayerActions
{
private MyInput _inputs;
public void Awake()
{
_inputs = new MyInput();
_inputs.Player.SetCallbacks(this);
}
public void OnEnable()
{
_inputs.Player.Enable();
}
public void OnDisable()
{
_inputs.Player.Disable();
}
public void OnMovement(InputAction.CallbackContext context)
{
Vector2 delta = context.ReadValue<Vector2>();
transform.position += new Vector3(delta.x, 0, delta.y);
}
public void OnDrop(InputAction.CallbackContext context)
{
//TODO
}
// ...
}
I am building a game on unity on real old version like 5.3. I have a main scene and a menu scene.Each scene got an audio manager script which controls the audio. My problem is with this function called DontDestroyOnLoad. More specifically the problem is that when I build the game the game runs perfectly and the menu too but the menu got sounds and the game not.The game has only some sounds that is out of audio manager and I have put them by hand.
My code of audiomanager is here
using UnityEngine;
[System.Serializable]
public class Sound
{
public string name;
public AudioClip clip;
[Range(0f, 1f)]
public float volume = 0.7f;
[Range(0.5f, 1.5f)]
public float pitch = 1f;
[Range(0f, 0.5f)]
public float randomVolume = 0.1f;
[Range(0f, 0.5f)]
public float randomPitch = 0.1f;
public bool loop = false;
private AudioSource source;
public void SetSource(AudioSource _source)
{
source = _source;
source.clip = clip;
source.loop = loop;
}
public void Play()
{
source.volume = volume * (1 + Random.Range(-randomVolume / 2f, randomVolume / 2f));
source.pitch = pitch * (1 + Random.Range(-randomPitch / 2f, randomPitch / 2f));
source.Play();
}
public void Stop()
{
source.Stop();
}
}
public class AudioManager : MonoBehaviour
{
public static AudioManager instance;
[SerializeField]
Sound[] sounds;
void Awake()
{
if (instance != null)
{
if (instance != this)
{
Destroy(this.gameObject);
}
}
else
{
instance = this;
DontDestroyOnLoad(this);
}
}
void Start()
{
for (int i = 0; i < sounds.Length; i++)
{
GameObject _go = new GameObject("Sound_" + i + "_" + sounds[i].name);
_go.transform.SetParent(this.transform);
sounds[i].SetSource(_go.AddComponent<AudioSource>());
}
PlaySound("Music");
}
public void PlaySound(string _name)
{
for (int i = 0; i < sounds.Length; i++)
{
if (sounds[i].name == _name)
{
sounds[i].Play();
return;
}
}
// no sound with _name
Debug.LogWarning("AudioManager: Sound not found in list, " + _name);
}
public void StopSound(string _name)
{
for (int i = 0; i < sounds.Length; i++)
{
if (sounds[i].name == _name)
{
sounds[i].Stop();
return;
}
}
// no sound with _name
Debug.LogWarning("AudioManager: Sound not found in list, " + _name);
}
}
You need to specify that DontDestroyOnLoad will affect the gameObject itself, not only the MonoBehaviour.
void Awake()
{
if (instance != null)
{
if (instance != this)
{
Destroy(this.gameObject);
}
}
else
{
instance = this;
DontDestroyOnLoad(this.gameObject); // <-- Here
}
}
Im not really sure whats wrong, I'm pretty inexperienced with C#, and i posted this with everyone saying there isn't enough context, so Im posting the whole script. It isn't that long though, I just need this help!
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(AudioSource))]
public class MusicPlayer : MonoBehaviour {
public GUISkin skin;
public Song[] playlist;
public AudioClip mlgSong;
public AudioSource fastSource;
int currentSongID;
bool isPlaying;
[System.NonSerialized]
public bool fastMode = false;
string currentSongCredits;
//Song credits
float timer = 0;
float slidePosition;
float slidePositionMax = 20;
void Start() {
slidePosition = slidePositionMax;
ShuffleSongs();
audio.clip = playlist[0].clip;
currentSongID = 0;
isPlaying = audio.isPlaying;
if (!GameSettings.music) {
fastSource.Stop();
}
}
void Update() {
if ((!audio.isPlaying || GameSettings.keybinds.GetKeyDown("nextsong")) && isPlaying) {
if (currentSongID<playlist.Length-1) {
currentSongID++;
} else {
currentSongID = 0;
}
audio.clip = playlist[currentSongID].clip;
slidePosition = slidePositionMax;
Play (); //The error is here...
}
if ((!audio.isPlaying || GameSettings.keybinds.GetKeyDown("lastsong")) && isPlaying) {
if (currentSongID<playlist.Length+1) {
currentSongID++;
} else {
currentSongID = playlist.Length;
}
audio.clip = playlist[currentSongID].clip;
slidePosition = slidePositionMax;
Play (); //The error is also here.
}
//Timer
if (timer > 0) {
timer -= Time.deltaTime;
}
if (fastMode && fastSource.volume < 1) {
fastSource.volume = Mathf.Min(1,fastSource.volume + Time.deltaTime * 0.25f);
audio.volume = 0.5f - fastSource.volume/2;
}
if (!fastMode && fastSource.volume > 0) {
fastSource.volume = Mathf.Max(0,fastSource.volume - Time.deltaTime * 0.5f);
audio.volume = 0.5f - fastSource.volume/2;
}
if (timer > 0) {
slidePosition = Mathf.Lerp(slidePosition,0,Time.deltaTime);
} else {
slidePosition = Mathf.Lerp(slidePosition,slidePositionMax,Time.deltaTime);
}
}
public void Pause() {
Play (playlist[currentSongID].name);
}
public void Play(string credits) {
currentSongCredits = "Now playing: " + credits;
if (FindObjectOfType<MlgMode>() != null) {//IS MLG MODE
audio.clip = mlgSong;
currentSongCredits = "Now playing: xXxSW3GST3PxXx";
FindObjectOfType<MlgMode>().StartTheShit();//Start the wubs
}
isPlaying = true;
if (!audio.mute) {
timer = 8;
}
audio.Play();
}
void OnGUI() {
if (slidePosition < slidePositionMax-0.1f) {
GUI.skin = skin;
GUIStyle style = new GUIStyle(GUI.skin.label);
style.fontSize = 16;
style.alignment = TextAnchor.MiddleRight;
Rect rect = new Rect(0,Screen.height-30+slidePosition,Screen.width,30);
//GUIX.ShadowLabel(rect,currentSongCredits,style,1);
GUILayout.BeginArea(rect);
GUILayout.FlexibleSpace (); //Push down
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace(); //Push to the right
GUILayout.Label(currentSongCredits,GUI.skin.GetStyle("SoundCredits"),GUILayout.ExpandWidth(false));
GUILayout.EndHorizontal();
GUILayout.EndArea();
}
}
void ShuffleSongs() {
//Shuffle playlist using Fisher-Yates algorithm
for (int i = playlist.Length;i > 1;i--) {
int j = Random.Range(0,i);
Song tmp = playlist[j];
playlist[j] = playlist[i - 1];
playlist[i - 1] = tmp;
}
}
}
[System.Serializable]
public class Song {
public string name;
public AudioClip clip;
}
Your Play method is declared like this:
public void Play(string credits)
but you are calling it like this:
Play();
You need to include a string as a parameter when you call it.
Play("White and Nerdy - Weird Al Yankovic");
Your Play(string credits) method is expecting a string called credits. Since you call Play() without putting a string there, it is giving you an error.
What it is looking for is an overloaded method, another form of Play() without the string and when it doesn't find that you receive that error.
I want to display my health as the GUIText and decreasing when the player hits. How to code based on my health script?
Here is my healthscript
using UnityEngine;
using System.Collections;
public class HealthScript : MonoBehaviour {
public static HealthScript instance;
public int hp = 1;
private GUIText scoreReference;
private GUIText highscoreReference;
private static int _highscore = -1;
public int highscore {
get { if (_highscore == -1)
_highscore = PlayerPrefs.GetInt("Highscore", 0);
return _highscore;
}
set {
if (value > _highscore) {
_highscore = value;
highscoreReference.text = _highscore.ToString();
PlayerPrefs.SetInt("Highscore", _highscore);
}
}
}
public bool isEnemy = true;
private static int points;
public void Damage(int damageCount) {
hp -= damageCount;
if (hp <= 0)
{
// Dead!
Destroy(gameObject);
points++;
scoreReference.text = points.ToString();
}
}
public void gameEnd() {
highscore = points;
points = 0;
}
void Start()
{
scoreReference = GameObject.Find("Score").guiText;
highscoreReference = GameObject.Find("HighScore").guiText;
scoreReference.text = points.ToString();
highscoreReference.text = highscore.ToString ();
instance = this;
}
UPDATE: I DON'T WANT TO DISPLAY ENEMY HEALTH, THIS SCRIPT WAS ATTACHED TO EVERY ENEMY
I recommend you to use OnGui method always to show the interface of the game
void OnGUI(){
GUI.color = Color.red;
GUI.Label(new Rect (20,20,200,20), "Health = " + hp);
}
All the documentation you need to understand this code is here:
GUI.Label http://docs.unity3d.com/ScriptReference/GUI.Label.html
OnGui method: http://docs.unity3d.com/ScriptReference/MonoBehaviour.OnGUI.html
Hope this help you, ask if you have any troubles with this code!
You can use a variable to show on the GUI with C# easily by doing:
var myNiceVariable = "Showing the health values!";
var guiText = GameObject.Find("GUI Text").GetComponent(GUIText);
guiText.text = myNiceVariable;
Or you can use the OnGui method, you can add to your script:
void OnGui(){
GUI.Label(new Rect (5,5,10,100), "Health: " + hp);
}
Code taken from here and here.