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'm a beginner developper and I just started making my own game but in my advancement I got stuck with the creation of an enemy.
The goal of this script is to move the enemy, catch the player and most of all making damages to the player, but in this case, I cannot make link between my player health and my enemy controller script because of the NullReferenceException error that haunts me. It's the only error I have and I've searched everywhere to fix my error but don't find anything.
This is my EnemyController script which I know is not really optimized but whatever.
The real problem is right here at the line 49 in the Update function (if(playerHealth == null){})
All of my scripts are connected, here are all scripts I used for this.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class EnemyContoller : MonoBehaviour
{
public float lookRadius = 10f;
public float maxHealth = 100f;
public float currentHealth;
Transform target;
NavMeshAgent agent;
public HealthBarScript healthBar;
public Animator anim;
EnemyAttack attack;
PlayerHealth playerHealth;
// Update is called once per frame
void Start()
{
attack = GetComponent<EnemyAttack>();
anim = GetComponent<Animator>();
gameObject.layer = 6;
currentHealth = maxHealth;
healthBar.SetMaxHealth(maxHealth);
target = PlayerManager.instance.player.transform;
agent = GetComponent<NavMeshAgent>();
playerHealth = GetComponent<PlayerHealth>();
}
void Update()
{
float distance = Vector3.Distance(target.position, transform.position);
if(distance <= lookRadius)
{
anim.speed = agent.speed;
anim.SetBool("isRunning",true);
agent.SetDestination(target.position);
}else{
anim.speed = 0;
anim.SetBool("isRunning",false);
}
if(distance <= agent.stoppingDistance)
{
if(playerHealth != null)
{
attack.MakeDamage(attack.damages, playerHealth);
Debug.Log(playerHealth.currentHealth);
}
else if(playerHealth == null)
{
Debug.Log("Player Health = null");
}
FaceTarget();
}
}
public void TakeDamage(float amount){
currentHealth -= amount;
healthBar.SetHealth(currentHealth);
if(currentHealth <= 0)
{
Die();
}
}
void Die()
{
Destroy(gameObject);
}
void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, lookRadius);
}
void FaceTarget()
{
Vector3 direction = (target.position - transform.position).normalized;
Quaternion lookRotation = Quaternion.LookRotation(new Vector3(direction.x, 0, direction.z));
transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Time.deltaTime * 3f);
}
}
This is my Enemy Attack script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyAttack : MonoBehaviour
{
public float damages = 10f;
public float damageRate = 1f;
private float damageCooldown = 0f;
PlayerHealth pH;
void Update()
{
damageCooldown -= Time.deltaTime;
}
public void MakeDamage(float amount, PlayerHealth health)
{
if(damageCooldown <= 0f)
{
pH.TakeDamage(damages);
Debug.Log(health);
damageCooldown = 1f / damageRate;
}
}
}
This my PlayerHealth script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerHealth : MonoBehaviour
{
public float currentHealth;
public float maxHealth = 50f;
public HealthBarScript healthBar;
// Start is called before the first frame update
void Start()
{
currentHealth = maxHealth;
healthBar.SetMaxHealth(maxHealth);
}
public void TakeDamage(float amount)
{
currentHealth -= amount;
healthBar.SetHealth(currentHealth);
Debug.Log(currentHealth);
if(currentHealth <= 0)
{
Debug.Log("You're Dead.");
Time.timeScale = 0;
}
}
}
If someone could help me that would be great I don't know what to do to fix this bug that lasts for 2 days.
Related
so first time learning C# for my team studio class. I found this video which I was able to get my player moving and jumping perfectly, https://www.youtube.com/watch?v=3GtQ2yQX2kU&t=569s however after I added a health/can die system to the script, now the player refuses to jump no matter what I do. Since I am a newbie at this, I am just going to post the whole thing here if anyone can point me in the right direction. I've played with the box colliders, added the layers to the platforms like the tutorial said... please, if anyone can help. I know I'm a newbie to this :(
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public HealthBar healthBar; //Communicates with the healthbar script
public float moveSpeed;
public float jumpForce;
public int jumpsAmount;
int jumpsLeft;
public Transform GroundCheck;
public LayerMask GroundLayer;
public int maxHealth = 3;
public int currentHealth;
bool isGrounded;
float moveInput;
Rigidbody2D rb2d;
float scaleX;
// Start is called before the first frame update
void Start()
{
healthBar.SetMaxHealth(maxHealth); //Sets healthbar to max health
currentHealth = maxHealth;
rb2d = GetComponent<Rigidbody2D>();
scaleX = transform.localScale.x;
}
public void TakeDamage(int damage)
{
currentHealth -= damage;
if (currentHealth <= 0) //When Health is zero the player is destroyed
{
Destroy(gameObject);
}
healthBar.SetHealth(currentHealth); //Updates Healthbar when damgage is taken
}
// Update is called once per frame
void Update()
{
moveInput = Input.GetAxisRaw("Horizontal");
Jump();
}
private void FixedUpdate()
{
Move();
}
public void Move()
{
Flip();
rb2d.velocity = new Vector2(moveInput * moveSpeed, rb2d.velocity.y);
}
public void Flip()
{
if (moveInput > 0)
{
transform.localScale = new Vector3(scaleX, transform.localScale.y, transform.localScale.z);
}
if (moveInput < 0)
{
transform.localScale = new Vector3((-1) * scaleX, transform.localScale.y, transform.localScale.z);
}
}
public void Jump()
{
if (Input.GetKeyDown(KeyCode.Space))
{
CheckIfGrounded();
if (jumpsLeft > 0)
{
rb2d.velocity = new Vector2(rb2d.velocity.x, jumpForce);
jumpsLeft--;
}
}
}
public void CheckIfGrounded()
{
isGrounded = Physics2D.OverlapCircle(GroundCheck.position, GroundCheck.GetComponent<CircleCollider2D>().radius, GroundLayer);
ResetJumps();
}
public void ResetJumps()
{
if (isGrounded)
{
jumpsLeft = jumpsAmount;// jumpsAmount =2;
}
}
}
I put the groundcheck collider where the video wanted me to, even played around having different locations too. Nothing is working... tried changing the jump force too to see if it needs to be higher. I am at a complete loss.
I'm trying to make it so that every time I kill an enemy, my player's speed increases by 1. I've been trying to do this but I don't really know what I'm doing. Can somebody help me?
Here is my player movement script
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public float MovementSpeed = 5;
public float JumpForce = 5;
private Rigidbody2D _rigidbody;
private void Start()
{
_rigidbody = GetComponent<Rigidbody2D>();
}
private void Update()
{
//Movement
var movement = Input.GetAxis("Horizontal");
transform.position += new Vector3(movement, 0, 0) * Time.deltaTime * MovementSpeed;
if (Input.GetButtonDown("Jump") && Mathf.Abs(_rigidbody.velocity.y) < 0.001f)
{
_rigidbody.AddForce(new Vector2(0, JumpForce), ForceMode2D.Impulse);
}
}
}
Here is my Enemy script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class enemyScript : MonoBehaviour
{
public int health = 100;
private static float speed;
private static float jump;
public void TakeDamage(int damage)
{
health -= damage;
if (health <= 0)
{
Die();
speed += 1.0f;
jump += 1.0f;
}
}
void Die()
{
Destroy(gameObject);
speed = GetComponent<PlayerMovement>().MovementSpeed;
jump = GetComponent<PlayerMovement>().JumpForce;
}
}
Sorry, my question didn't have all the details, the player is not gaining any speed. I tried using
GetComponent<PlayerMovement>().MovementSpeed += 1.0f;
GetComponent<PlayerMovement>().JumpForce += 1.0f;
and now I'm getting this error message
NullReferenceException: Object reference not set to an instance of an object
Sorry for the inconvenience
First of all it makes no sense to use GetComponent since the PlayerMovement is not attached to your enemy objects.
Then
speed = GetComponent<PlayerMovement>().MovementSpeed;
jump = GetComponent<PlayerMovement>().JumpForce
is also the wrong way round .. what use would it be to take the value from the player and store it in a field of the enemy?
If there is only one player anyway you could simply use FindObjectOfType and do
void Die()
{
Destroy(gameObject);
FindObjectOfType<PlayerMovement>().MovementSpeed += 1.0f;
FindObjectOfType<PlayerMovement>().JumpForce += 1.0f;
}
Or alternatively use a Singleton Pattern as actually even suggested by before mentioned docs like e.g.
public class PlayerMovement : MonoBehaviour
{
public static PlayerMovement Instance { get; private set;}
private void Awake ()
{
if(Instance && Instance!= this)
{
Destroy(gameObject);
return;
}
Instance = this;
}
...
}
and then simply do
void Die()
{
Destroy(gameObject);
PlayerMovement.Instance.MovementSpeed += 1.0f;
PlayerMovement.Instance.JumpForce += 1.0f;
}
I am assuming you want to increase the jumpforce and speed of your player when the player kills an enemy. Also, Could you please elaborate the question if you are getting any error or just the speed is not increasing?
Please find the inline response for the Enemy Script.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class enemyScript : MonoBehaviour
{
public int health = 100;
private static float speed;//This is enemy speed variable that you have declared
private static float jump;//This is enemy jump variable that you have declared
public void TakeDamage(int damage)
{
health -= damage;
if (health <= 0)
{
Die();
//speed += 1.0f; Here you are increasing enemy speed and not playerspeed.
//jump += 1.0f; Same goes for jump.
}
}
void Die()
{
Destroy(gameObject);
//speed = GetComponent<PlayerMovement>().MovementSpeed; here you are assigning Player movement speed to enemy speed.
//jump = GetComponent<PlayerMovement>().JumpForce; here you are assigning Player movement jump to enemy jump.
//Instead try
GetComponent<PlayerMovement>().MovementSpeed += 1.0f;
GetComponent<PlayerMovement>().JumpForce += 1.0f;
}
}
Also you can use
Debug.Log(your movementspeed variable);
to check if the player speed is being increased or not.
This question already has an answer here:
invoke() Function in unity [duplicate]
(1 answer)
Closed 2 years ago.
Hi I'm very new to unity and C# so any help at all is greatly appreciated! I am trying to make my enemy (prefab is named snowman) and my player (prefab is named Santa) collide. When this happens, the player should lose damage in its healthbar. The healthbar is showing up but I just am so lost on how to make it lose health when it collides with the snowman.
Here is the script:
using UnityEngine;
using System.Collections;
using Mirror;
using UnityEngine.UI;
public class Player : NetworkBehaviour {
CharacterController characterController;
public float speed = 6.0f;
public float jumpSpeed = 8.0f;
public float gravity = 20.0f;
public int maxHealth = 30;
public int currentHealth;
//private HealthBar healthBar;
private Vector3 moveDirection = Vector3.zero;
void TakeDamage(int damage) {
currentHealth -= damage;
FindObjectOfType<HealthBar>().SetHealth(currentHealth);
// healthBar.SetHealth(currentHealth);
}
void Start() {
characterController = GetComponent<CharacterController>();
currentHealth = maxHealth;
FindObjectOfType<HealthBar>().SetMaxHealth(maxHealth);
// healthBar.SetMaxHealth(maxHealth);
}
void Update() {
if (isLocalPlayer) {
if (characterController.isGrounded) {
// We are grounded, so recalculate
// move direction directly from axes
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0.0f, Input.GetAxis("Vertical"));
moveDirection *= speed;
if (Input.GetButton("Jump")) {
moveDirection.y = jumpSpeed;
}
}
// if ()
// {
// TakeDamage (10);
// }
void OnCollisionEnter(Collision collision) {
TakeDamage (10);
}
moveDirection.y -= gravity * Time.deltaTime;
characterController.Move(moveDirection * Time.deltaTime);
transform.rotation = Quaternion.LookRotation(moveDirection);
}
void TakeDamage(int damage) {
currentHealth -= damage;
FindObjectOfType<HealthBar>().SetHealth(currentHealth);
// healthBar.SetHealth(currentHealth);
}
}
public override void OnStartLocalPlayer() {
Camera.main.GetComponent<CameraFollow>().setTarget(gameObject.transform);
}
}
Move TakeDamage and OnCollisionEnter to the class scope. Also I suggest to remove network features for the moment. Suggested code to meve on below:
using UnityEngine;
using System.Collections;
using Mirror;
using UnityEngine.UI;
public class Player : Monobehaviour {
CharacterController characterController;
public float speed = 6.0f;
public float jumpSpeed = 8.0f;
public float gravity = 20.0f;
public int maxHealth = 30;
public int currentHealth;
//private HealthBar healthBar;
private Vector3 moveDirection = Vector3.zero;
void Start() {
characterController = GetComponent<CharacterController>();
currentHealth = maxHealth;
FindObjectOfType<HealthBar>().SetMaxHealth(maxHealth);
// healthBar.SetMaxHealth(maxHealth);
}
void Update() {
if (isLocalPlayer) {
if (characterController.isGrounded) {
// We are grounded, so recalculate
// move direction directly from axes
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0.0f, Input.GetAxis("Vertical"));
moveDirection *= speed;
if (Input.GetButton("Jump")) {
moveDirection.y = jumpSpeed;
}
}
// if ()
// {
// TakeDamage (10);
// }
moveDirection.y -= gravity * Time.deltaTime;
characterController.Move(moveDirection * Time.deltaTime);
transform.rotation = Quaternion.LookRotation(moveDirection);
}
}
void OnCollisionEnter(Collision collision) {
TakeDamage (10);
}
void TakeDamage(int damage) {
currentHealth -= damage;
FindObjectOfType<HealthBar>().SetHealth(currentHealth);
// healthBar.SetHealth(currentHealth);
}
public void Start() {
Camera.main.GetComponent<CameraFollow>().setTarget(gameObject.transform);
}
}
For a start remove the OnCollisionEnter and the TakeDamage from the Update, you need them to be in the class scope.
On the other hand take into account the code format for the code readability. If the format is messy and the code not readable you are discouraging potential helpers to help you out! good luck
I am trying to make my enemy object turn and start moving towards my player object when the player comes within a certain vicinity.
For the turning I have been testing the transform.LookAt() function although it isn't returning the desired results as when the player is too close to the enemy object the enemy starts to tilt backwards and I only want my enemy to be able to rotate along the y axis, thanks in advance.
using UnityEngine;
using System.Collections;
public class EnemyController : MonoBehaviour {
public Transform visionPoint;
private PlayerController player;
public Transform Player;
public float visionAngle = 30f;
public float visionDistance = 10f;
public float moveSpeed = 2f;
public float chaseDistance = 3f;
private Vector3? lastKnownPlayerPosition;
// Use this for initialization
void Start () {
player = GameObject.FindObjectOfType<PlayerController> ();
}
// Update is called once per frame
void Update () {
// Not giving the desired results
transform.LookAt(Player);
}
void FixedUpdate () {
}
void Look () {
Vector3 deltaToPlayer = player.transform.position - visionPoint.position;
Vector3 directionToPlayer = deltaToPlayer.normalized;
float dot = Vector3.Dot (transform.forward, directionToPlayer);
if (dot < 0) {
return;
}
float distanceToPlayer = directionToPlayer.magnitude;
if (distanceToPlayer > visionDistance)
{
return;
}
float angle = Vector3.Angle (transform.forward, directionToPlayer);
if(angle > visionAngle)
{
return;
}
RaycastHit hit;
if(Physics.Raycast(transform.position, directionToPlayer, out hit, visionDistance))
{
if (hit.collider.gameObject == player.gameObject)
{
lastKnownPlayerPosition = player.transform.position;
}
}
}
}
change the look at target:
void Update () {
Vector3 lookAt = Player.position;
lookAt.y = transform.position.y;
transform.LookAt(lookAt);
}
this way the look at target will be on the same height as your object.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class EnemyMovement : MonoBehaviour
{
public Transform Player;
public float MoveSpeed = 4;
int MaxDist = 10;
int MinDist = 5;
void Update()
{
transform.LookAt(Player);
if (Vector3.Distance(transform.position, Player.position) >= MinDist)
{
transform.position += transform.forward * MoveSpeed * Time.deltaTime;
if (Vector3.Distance(transform.position, Player.position) <= MaxDist)
{
// Put what do you want to happen here
}
}
}
}
Im currently working on a TurretAi. I have it so that when the enemy is within a certain range the turret targets the enemy but I'm unable to get the turret to shoot the projectiles toward the enemy. this is currently what i have this is turret class.
using UnityEngine;
using System.Collections;
public class Defence : MonoBehaviour {
public float DistanceFromCastle,CoolDown;
public GameObject enemy;
public GameObject Bullet;
public int protectionRadius,bulletSpeed;
// Use this for initialization
void Start ()
{
protectionRadius = 35;
bulletSpeed = 50;
CoolDown = 5;
}
// Update is called once per frame
void Update () {
enemy = GameObject.FindGameObjectWithTag("Enemy");
if(enemy != null)
{
DistanceFromCastle = Vector3.Distance(GameObject.FindGameObjectWithTag("Enemy").transform.position,GameObject.FindGameObjectWithTag("Defence").transform.position);
//print (DistanceFromCastle);
if(DistanceFromCastle <= protectionRadius)
{
attackEnemy();
}
}
}
void attackEnemy()
{
transform.LookAt(enemy.transform);
CoolDown -= Time.deltaTime;
if (CoolDown <= 0)
{
Debug.DrawLine(transform.position,enemy.transform.position,Color.red);
Instantiate(Bullet,Vector3.forward,Quaternion.identity);
print("attack Enemy");
CoolDown = 5;
}
}
}
I also already have a cool down var so that it only shoot every 5 second any help would be awesome.
You were fairly close, you need to change this line:
Instantiate(Bullet, Vector3.forward, Quaternion.identity);
To this:
private const int SPAWN_DISTANCE = 5;
Instantiate(Bullet, transform.position + SPAWN_DISTANCE * transform.forward, transform.rotation);
Quaternion.identity refers to:
This quaternion corresponds to "no rotation".