Add float number to another script, c# unity [duplicate] - c#

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 4 years ago.
I need help, i'am trying to add float number from a script to another script but it does not work. I'am new to c# and coding in general if somebody code fix the script and explained whats wrong with this i would be very thankful. This is the error i am getting.
"NullReferenceException: Object reference not set to an instance of an object
Resources.Die () (at Assets/Resources.cs:42)
Resources.Update () (at Assets/Resources.cs:22)"
Here is my scripts:
1st
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Resources : MonoBehaviour {
public float maxHealth = 5;
public float currentHealth;
public float ResourceCounter;
public Texture stoneIcon;
public Texture woodIcon;
void Start ()
{
currentHealth = maxHealth;
ResourceCounter = 0;
}
void Update ()
{
Die();
}
public void OnMouseOver()
{
if(Input.GetButtonDown("Fire1"))
{
Debug.Log("Loosing one health");
currentHealth = currentHealth - 1f;
}
}
public void Die()
{
if(currentHealth <= 0)
{
Destroy(gameObject);
Inventory inventory = GetComponent<Inventory>();
inventory.ResourceStone = inventory.ResourceStone + 1;
}
}
}
2nd
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour {
public float ResourceStone;
// Use this for initialization
void Start ()
{
ResourceStone = 0;
}
// Update is called once per frame
void Update () {
}
}

By looking at your code i think you never defined the inventory instance for your "resources" script. If you are using a getcomponent both the resources and the inventory script must be on the same gameobject to be found.
If what you want requires both scripts to be on other gameobjects you need a reference to the inventory in your resources script.
You can do this several way (like making a static reference and refering to it or defining inventory as a public variable and then adding the inventory reference in the unity editor)
This is how the first case would look:
First Script -
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
public static Inventory instance;
private void Awake()
{
instance = this;
}
public float ResourceStone;
// Use this for initialization
void Start()
{
ResourceStone = 0;
}
}
Second Script -
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Resources : MonoBehaviour
{
public float maxHealth = 5;
public float currentHealth;
public float ResourceCounter;
public Texture stoneIcon;
public Texture woodIcon;
void Start()
{
currentHealth = maxHealth;
ResourceCounter = 0;
}
void Update()
{
Die();
}
public void OnMouseOver()
{
if (Input.GetButtonDown("Fire1"))
{
Debug.Log("Loosing one health");
currentHealth = currentHealth - 1f;
}
}
public void Die()
{
if (currentHealth <= 0)
{
Destroy(gameObject);
Inventory.instance.ResourceStone++;
}
}
}
This is how the code would look if you did the second one:
first script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
public float ResourceStone;
// Use this for initialization
void Start()
{
ResourceStone = 0;
}
// Update is called once per frame
void Update()
{
}
}
second script-
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Resources : MonoBehaviour
{
public float maxHealth = 5;
public float currentHealth;
public float ResourceCounter;
public Inventory inventory;
public Texture stoneIcon;
public Texture woodIcon;
void Start()
{
currentHealth = maxHealth;
ResourceCounter = 0;
}
void Update()
{
Die();
}
public void OnMouseOver()
{
if (Input.GetButtonDown("Fire1"))
{
Debug.Log("Loosing one health");
currentHealth = currentHealth - 1f;
}
}
public void Die()
{
if (currentHealth <= 0)
{
Destroy(gameObject);
inventory.ResourceStone++;
}
}
}
Just take in account two things to decide if you will use the first or the second one. The first one is a static reference, that means that you can't make more that one inventory. In the second one you need to manually drag the reference in the editor. Just in case you don't know, writing ++ after an integer does the same as integer = integer + 1;
EDIT: There, that's better looking :D

Related

Why is this health bar not working in Unity2d [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 1 year ago.
My HealthBar script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class HealthBar : MonoBehaviour
{
public Slider slider;
public Gradient gradient;
public Image fill;
public void SetMaxHealth(int health)
{
slider.maxValue = health;
slider.value = health;
fill.color = gradient.Evaluate(1f);
}
public void SetHealth(int health)
{
slider.value = health;
fill.color = gradient.Evaluate(slider.normalizedValue);
}
}
My Player script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public int maxHealth = 100;
public int currentHealth;
public HealthBar healthBar;
private void Start()
{
currentHealth = maxHealth;
healthBar.SetHealth(maxHealth);
}
private void Update()
{
if (currentHealth == 50)
{
healthBar.SetHealth(currentHealth);
}
if (currentHealth == 0)
{
Die();
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Enemy"))
{
TakeDamage(50);
}
}
void TakeDamage(int damage)
{
currentHealth -= damage;
}
void Die()
{
Destroy(gameObject);
LevelManager.instance.Respawn();
healthBar.SetHealth(maxHealth);
}
}
My LevelManager script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
public class LevelManager : MonoBehaviour {
public static LevelManager instance;
public Transform respawnPoint;
public GameObject playerPrefab;
public CinemachineVirtualCameraBase cam;
[Header("Currency")]
public int currency = 0;
private void Awake() {
instance = this;
}
public void Respawn() {
GameObject player = Instantiate(playerPrefab,
respawnPoint.position, Quaternion.identity);
cam.Follow = player.transform;
}
public void IncreaseCurrency(int amount) {
currency += amount;
}
}
The errors that I am getting:
NullReferenceException: Object reference not set to an instance of an object
Player.Start () (at Assets/Scripts/Player.cs:15)
NullReferenceException: Object reference not set to an instance of an object
Player.Update () (at Assets/Scripts/Player.cs:22)
NullReferenceException: Object reference not set to an instance of an object
Player.Die () (at Assets/Scripts/Player.cs:49)
Player.Update () (at Assets/Scripts/Player.cs:27)
I have been trying to figure the problem out for a while. It works, when I die once. unfortunately, when I try die again,it doesn't work . The error message pops up, when I collide with the enemy.
How do I fix these errors pls help.
Is the healthBar being destroyed on death? It makes sense since we want to make the health bar disappear when the player dies but make sure to instantiate it again on respawn.
You should assign a HealthBar component to PlayerScript's healthBar property from inspector.

Is there a way to have Delay timer or cutscene? Unity March 28/21 update

What I'm trying to do is have my player stop moving so I can play animation through a trigger-event or just a custscene.
What I expect was for one of them to trigger the timer then play animation>player move.. like a cut-scene
Also there are no errors In any of them They just didn't stop player from moving or just stop the player when starting the game(or when I press play it just set forwardMovement to 0)
Here's the code I use:
public class Player_controls : MonoBehaviour
{
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class Player_controls : MonoBehaviour
{
public int forwardMovement = 1000;
public void Update()
{
rb.AddForce(0, 0, forwardMovement * Speed * Time.deltaTime);
}
}
}
Things that I tried:
public void ForwardMovement()
{
forwardMovement = 0;
Invoke("Action", 2f);
}
public void Action ()
{
forwardMovement = 1000 ;
}
Which only works for ForwardMovement(); method nothing else
I tried these two things also:
Public static class MonoExtensions
{
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public float Delayer = 10f;
public static class MonoExtensions
{
public static void Timed_delay(this MonoBehaviour mono,Action function, float Delayer)
{
mono.StartCoroutine(Timed_delayRoutine(function,Delayer));
}
static IEnumerator Timed_delayRoutine(Action function, float Delayer)
{
yield return new WaitForSeconds(Delayer);
function();
}
public class `Player_Controls`: MonoBehaviour
{
public void PM ()
{
forwardMovement = 0;
}
void OnTriggerEnter(Collider other)
{
if (CompareTag("Power_up"))
{
this.Timed_delay(PM, Delayer);
}
}
}
Which just stop the player from moving an nothing else.
What I also tried was:
public class Player_Controls : MonoBehaviour
{
void Start()
{
StartCoroutine(ForwardMovement());
}
IEnumerator ForwardMovement()
{
forwardMovement = 0;
yield return new waitforseconds(Delayer);
forwardMovement = 1050;
}
void OnTriggerEnter(collider other)
{
if (CompareTag("Power_up"))
{
ForwardMovement();
}
}
}
Which did not work as in(it works but the timer part does nothing, so the player can't move when started the game )
Different way I tried
public class Player_Controls : MonoBehaviour
{
OnTriggerEnter(collider other)
{
Startcroutine(ForwardMovement ));
}
}
it didn't work but no Errors.
I tried this one by jazzhar:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class Player_controls : MonoBehaviour
{
// Drag the player in the inspector here;
public Rigidbody rb;
// Youre speed variable for movement.
public float Speed = 5;
// Youre speed variable for movement.
public int forwardMovement = 1000;
// Set this "stopmoving" bool to true to prevent movement.
public bool stopMoving = false;
// Create and select the right layer in the inspector.
public LayerMask WichObjectStopsMovement;
public void Update()
{
// if stopMoving = true than Dont Add force.
if (stopMoving == false)
{
rb.AddForce(0, 0, forwardMovement * Speed * Time.deltaTime);
}
}
private void OnCollisionEnter(Collision collision)
{
// if you're player touches a object and that object's layer
// is the same as "WichObjectStopsMovement" than disable Movement.
if (collision.collider.gameObject.layer == WichObjectStopsMovement)
{
stopMoving = false;
}
}
}
It sorta works in a way if you set if
if (stopMoving == true)
{
rb.AddForce(0, 0, forwardMovement * Speed * Time.deltaTime);
}
and
if (collision.collider.gameObject.layer == WichObjectStopsMovement)
{
stopMoving = true;
}
then the player would be able to move but it will not trigger if hit the cube
it didn't work either but no Errors.
And some other timers I did but forgotten....
_________________________________________________________________March/6/21
public float Delayer = 10.0f;
I think found solution by doing this
private void OnTriggerEnter(Collider other)
{
if (CompareTag("Power_up"))
{
Delayer -= Time.deltaTime; <- this part giving me the error
if (Delayer => 0)
{
forwardMovement = 0;
}
}
}
but their one problem it giving me the this error Cannot convert lambda expression to type 'bool' because it is not a delegate type [Assembly-CSharp]csharp(CS1660) I don't know much about this even searching about doesn't help either
__________________________________________________________________March 28/21
this script is under player controls
this one works I made sure by doing Debug.Log("test");
void OnTriggerExit(Collider collision)
{
if (collision.gameObject.CompareTag("Power_up"))
{
forwardMovement = 0;
}
if (forwardMovement <= 0)
{
Debug.Log("test");
}
This might be a solution to you're problem, Fire-Source!:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class Player_controls : MonoBehaviour
{
// Drag the player in the inspector here;
public Rigidbody rb;
// Youre speed variable for movement.
public float Speed = 5;
// Youre speed variable for movement.
public int forwardMovement = 1000;
// Set this "stopmoving" bool to true to prevent movement.
public bool stopMoving = false;
// Create and select the right layer in the inspector.
public LayerMask WichObjectStopsMovement;
public void Update()
{
// if stopMoving = true than Dont Add force.
if (stopMoving == false)
{
rb.AddForce(0, 0, forwardMovement * Speed * Time.deltaTime);
}
}
private void OnCollisionEnter(Collision collision)
{
// if youre player touches a object and that object's layer
// is the same as "WichObjectStopsMovement" than disable Movement.
if (collision.collider.gameObject.layer == WichObjectStopsMovement)
{
stopMoving = false;
}
}
}
This code uses a LayerMask, to create 1 click on any object and in the inspector go:
Click on Layer:
Add Layer:
Write in User Layer 6, StopMovement (or anything else).
Than in the object that should stop player movement:
Click on layer:
Than select the Layer that says StopMovement.
And in you're player's script drag the object into the rb variable.
and in "WichObjectStopsMovement" assign the StopMovement layer.
This should take care of everything is that ok?

How can I make a public "enemyDamage" integer from 1 script, communicate with another script?

I am new to coding and am not quite sure how to add context from 1 script to another. For my game so far, I have been Frankensteining code from multiple sources and have head into a dead end. I want my player to take the same amount of damage as stated by enemyDamage in the 'Enemy' script. I'm not too sure what other context to give you, but if you know how you could help me out, that would be awesome!
Enemy Script
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using UnityEngine;
public class Enemy : MonoBehaviour
{
public int health = 100;
public int enemyDamage = 10;
public GameObject deathEffect;
public void TakeDamage (int damage)
{
health -= damage;
if (health <= 0)
{
Die();
}
}
void Die ()
{
Instantiate(deathEffect, transform.position, Quaternion.identity);
Destroy(gameObject);
}
}
PlayerHealth Script
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
public class PlayerHealth : MonoBehaviour
{
public int maxHealth = 10;
public int currentHealth;
public int damage = 1;
public HealthBar healthBar;
// Start is called before the first frame update
void Start()
{
currentHealth = maxHealth;
healthBar.SetMaxHealth(maxHealth);
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.R))
{
TakenDamage(1);
}
if (currentHealth <= 0)
{
PlayerDeath();
}
}
public void TakenDamage(int damage)
{
currentHealth -= damage;
healthBar.SetHealth(currentHealth);
}
void PlayerDeath()
{
UnityEngine.Debug.Log("bean guy");
}
public void OnTriggerEnter2D(Collider2D hitInfo)
{
UnityEngine.Debug.Log("We did it boys");
PlayerHealth player = hitInfo.GetComponent<PlayerHealth>();
{
UnityEngine.Debug.Log("beans");
TakenDamage(enemyDamage); // I need this to update with enemyDamage 's value
}
}
}
There are multiple ways:
Make EnemyDamage a Static Variable
public static int enemyDamage = 10;
Then you can call it in other scripts with Enemy.enemyDamage
Be aware that you can't set static variables in the Inspector.
Use GetComponent
Enemy enemy = gameObject.GetComponent(typeof(Enemy )) as Enemy;
enemy.enemyDamage
Create a GameManager
GameManager.CS:
#region Singelton
public static GameManager instance;
void Awake()
{
if (instance != null)
{
Debug.LogWarning("More than one Instance of Inventory found");
return;
}
instance = this;
}
#endregion
public int enemyDamage = 10;
Referencing the GameManager Script:
GameManager gm;
void Start()
{
gm = GameManager.instance;
}
//Calling Function in GameManager
gm.EndGame();
// Getting Value from GameManager
gm.enemyDamage();
When to use what?
If you want a more short term solution I would use a static variable, not advised with multiple enemies (different enemyDamage Values are now immosible)
If you have more variables or even functions that need to be accessible from multiple scripts I would advise you to use a Game Manager instead
You need to get a reference of the Enemy to use GetComponent, but makes it possible to add multiple different enemyDamage Values

Unity Highscore reset at respawn

I'm trying to be able to respawn as well as reset the score counting as soon as i walk into my "Gold" Object.
As for now i'm not even able to respawn which was possible earlier before trying to implement the "Score-Stuff" (at first the "FoundGold" Script was only used to be able to respawn). Also i'm trying to make the lowest Score the High-Score.
Note that im new to C# and i kinda put everything together from the tutorials i needed so a answer with some actual code/stating where something went wrong would be much appreciated.
//GoldFound Code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GoldFound : MonoBehaviour
{
private ScoreManager theScoreManager;
public Transform target;
[SerializeField] private Transform player;
[SerializeField] private Transform respawnpoint;
private void Start()
{
theScoreManager = FindObjectOfType<ScoreManager>();
}
private void OnTriggerEnter(Collider other)
{
theScoreManager.scoreIncreasing = false;
player.transform.position = respawnpoint.transform.position;
theScoreManager.scoreCount = 0;
theScoreManager.scoreIncreasing = true;
}
}
other code
//ScoreManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ScoreManager : MonoBehaviour
{
public Text scoreText;
public Text hiScoreText;
public float scoreCount;
public float hiScoreCount;
public float pointPerSecond;
public bool scoreIncreasing;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
if (scoreIncreasing)
{
scoreCount += pointPerSecond * Time.deltaTime;
}
if(scoreCount > hiScoreCount)
{
hiScoreCount = scoreCount;
}
scoreText.text = "Score: " + Mathf.Round (scoreCount);
hiScoreText.text = "High Score: " + Mathf.Round (hiScoreCount);
}
}
If you want to save your highscore in-between play sessions, then the easiest way to do so is to save the value to PlayerPrefs. If you want to start saving more / more complex stuff you really should save it in a file you generate yourself. But in your case, PlayerPrefs is fine.
Here's a Unity tutorial on the subject:
https://unity3d.com/learn/tutorials/topics/scripting/high-score-playerprefs
Otherwise, you can just do it like this:
public void SetHighscore (float currentScore)
{
if (PlayerPrefs.HasKey("highscore"))
{
float highscore = PlayerPrefs.GetFloat("highscore");
if (highscore > currentScore)
{
PlayerPrefs.SetFloat("highscore", currentScore);
PlayerPrefs.Save();
}
}
else
{
PlayerPrefs.SetFloat("highscore", currentScore);
PlayerPrefs.Save();
}
}
Then just write PlayerPrefs.GetKey("highscore") whenever you need it.
(Though I'd also recommend you check if it exists by using the PlayerPrefs.HasKey("highscore"))
https://docs.unity3d.com/ScriptReference/PlayerPrefs.html

Identifier Expected error on 2D Collision Code?

I am trying to make a oncollision2D EnemyDamage is done removing health from playerStats.health, unfortunately I got the error, "Identifier expected" does anyone know what I need to put there to get the code to work? Thanks error on Collision (8,41).
Collision damage code:
using UnityEngine;
using System.Collections;
public class Collision : MonoBehaviour {
int EnemyDamage = 1;
void OnCollisionEnter2D(Collision2D)
{
playerStats.Health -= EnemyDamage;
}
}
Player Health Code:
using UnityEngine;
using System.Collections;
public class Player : MonoBehaviour {
[System.Serializable]
public class PlayerStats {
public int Health = 100;
}
public PlayerStats playerStats = new PlayerStats();
public int fallBoundary = -20;
void Update () {
if (transform.position.y <= fallBoundary)
DamagePlayer (9999999);
}
public void DamagePlayer (int damage) {
playerStats.Health -= damage;
if (playerStats.Health <= 0) {
GameMaster.KillPlayer(this);
}
}
}
Collision2D is a class and is used to return collision information when used with the OnCollisionEnter2D callback function. If you are going to use it, you have to put a variable after it.
void OnCollisionEnter2D(Collision2D)
{
}
should be
void OnCollisionEnter2D(Collision2D col)
{
playerStats.Health -= EnemyDamage;
}
If you don't need to get information about the collison, you can just use the OnCollisionEnter2D function without Collision2D parameter at-all.
void OnCollisionEnter2D()
{
playerStats.Health -= EnemyDamage;
}

Categories

Resources