On unity using C# I made this jump script to control a player. When I run the code below I get the errors shown below
using UnityEngine;
public class PlayerScript : MonoBehaviour
{
public float JumpForce;
[SerializeField]
bool isGrounded = false;
Rigidbody2D RB;
private void Awake()
{
RB = GetComponent<Rigidbody2D();
}
// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(KeyCode.Space))
{
if(isGrounded == true)
{
RB.AddForce(Vector2.up*JumpForce);
isGrounded = false;
}
}
}
O refrences
private void OnCollisionEnter2D(Collision2D collision)
{
if(collision.gameObject.CompareTag("ground"))
{
if(isGrounded == false)
{
isGrounded = true;
}
}
}
}
For some reason, I get no error inside of vs code but when I to the game it says what the picture below says. If you have an answer it would really help thanks.
Make sure you have configured everything correctly. An in-depth tutorial can be found here.
https://code.visualstudio.com/docs/other/unity
The warnings can happen when you change the name of a class or file and don't fix the script component on the scene game object. It can also give that warning if you change the code while in playmode.
Related
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 1 year ago.
For some reason when I'm in the normal view in-game I am able to link the scripts that I need to call in order to make an animation like so
however, whenever I start the game it automatically removes them from the slots, and it doesn't work
I am completely clueless as to why this may be happening and unity keep giving me errors that say that I'm not setting an instance to my script I really have no clue why this may be happening.
I have 3 scripts that I'm working with that is giving me the problem
one is the main script for the enemy vision (I am referencing the other scripts in this one)
the second is the enemy animation script which makes him go from idle to attack and the third is an animation for the gun model since I had to make it follow the hands of the enemy
scripts attached bellow
1st script(enemyAI):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyAi : MonoBehaviour
{
public bool detected;
GameObject target;
public Transform enemy;
public GameObject Bullet;
public Transform shootPoint;
public float shootSpeed = 10f;
public float timeToShoot = 1f;
public EnemyAni Animation;
public GunAni GunAnimation;
void Start()
{
Animation = GetComponent<EnemyAni>();
GunAnimation = GetComponent<GunAni>();
}
public void Update()
{
//makes the enemy rotate on one axis
Vector3 lookDir = target.transform.position - transform.position;
lookDir.y = 0f;
//makes enemy look at the players position
if (detected)
{
enemy.LookAt(target.transform.position, Vector3.up);
enemy.rotation = Quaternion.LookRotation(lookDir, Vector3.up);
}
if (detected == true)
{
Animation.LookPlayer = true;
GunAnimation.ShootPlayer = true;
}
if (detected == false)
{
Animation.LookPlayer = false;
GunAnimation.ShootPlayer = false;
}
}
//detects the player
void OnTriggerEnter(Collider other)
{
if (other.tag == "Player")
{
detected = true;
target = other.gameObject;
}
}
void OnTriggerExit(Collider other)
{
if (other.tag == "Player")
{
detected = false;
}
}
}
2nd Script (EnemyAnimation):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyAni : MonoBehaviour
{
public Animator animator;
public bool LookPlayer;
public void Start()
{
animator = GetComponent<Animator>();
}
public void Update()
{
if (LookPlayer == true)
{
animator.SetBool("IsShootingStill", true);
}
else
{
animator.SetBool("IsShootingStill", false);
}
}
}
3rd script (GunAnimation):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GunAni : MonoBehaviour
{
public Animator animator;
public bool ShootPlayer;
public void Start()
{
animator = GetComponent<Animator>();
}
public void Update()
{
if (ShootPlayer == true)
{
animator.SetBool("IsShooting", true);
}
else
{
animator.SetBool("IsShooting", false);
}
}
}
Your code:
void Start()
{
Animation = GetComponent<EnemyAni>();
GunAnimation = GetComponent<GunAni>();
}
Searches the GameObject that holds the EnemyAI script for EnemyAni and GunAni. If the GameObject doesn't have those it will return null.
Sounds like you want to remove that code.
Note that if the scripts exist on a child of that GameObject you will need to use GetComponentInChildren
There are some things to review, good practices:
GameObject target is private for C#, but it is better to put private before.
variable names like Bullet Animation GunAnimation should always begin with lowercase, because they might be confused with a Class Name (search in internet for CamelCase and PascalCase).
Name should be clear. EnemyAni Animation is not clear enough, because Animation maybe any animation (player, enemy, cube, car, etc.).
It is better enemyAnimation to be clear, as you did with GunAnimation (only just with lower case at beginning)
As slaw said, the Animation must be in the GO attached.
about last item
Let's say you have an empty GO (GameObject) called GameObject1 and you attach EnemyAi script to it.
In Runtime (when game mode begins), it will try to find Animation = GetComponent<EnemyAni>();, but it won't find it
Why?
Because GetComponent<> searches for the Component(Class) that is in the <> (in this case EnemyAni) in its GO (in this case, GameObject1), but the unique script attached to GameObject1 is EnemyAI.
So, you have 3 options:
Attach EnemyAni to GameObject1
Create another GO (for example, GameObjectEnemyAni), attach the script EnemyAni and drag and drop GameObjectEnemyAni to GameObject1 and delete Animation = GetComponent<EnemyAni>(); in Start
Keep in mind: if you leave that line of code, instead of getting the script EnemyAni from GameObjectEnemyAni, it will run the code Animation = GetComponent<EnemyAni>(); in Start, and obviously, it won't find it
Create events. It's a really good practice for avoiding code tight coupling, but that is more advanced stuff.
For my health system in a Unity game, I have a script that is accountable for my in-game "enemy" hit-points. The game runs just fine, but the script doesn't seem to be doing anything. I'm not getting any error messages, but the fact that it's not working and Debug.Log statements aren't popping up in console seem to be that functions aren't being called properly or that something else is awry. Here is my script:
using System.Diagnostics;
using UnityEngine;
public class Health : MonoBehaviour {
private float hitPoints = 5;
// Health popup
void announceUp()
{
UnityEngine.Debug.Log("If this message shows in Debug.Log, the script should be working.");
}
// Update is called once per frame
void Update()
{
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Bullet")
{
UnityEngine.Debug.Log("The enemy has been hit!");
hitPoints = hitPoints - 1f;
if (hitPoints == 0f)
{
UnityEngine.Debug.Log("The enemy has been eliminated!");
Destroy(gameObject);
}
}
}
}
}
I've poked around the internet to see what's wrong, but I couldn't find anything. Could someone inform me on what could be wrong with my programming?
Your scrpt is currently not working, because you are defining the OnTriggerEnter() Method inside the Update() Method. When you do that you are defining a local function and Unity then can't call that function when actual collision happens. So your OnTriggerEnter() Function never get's called.
Example:
using System.Diagnostics;
using UnityEngine;
public class Health : MonoBehaviour
{
private float hitPoints = 5;
// Health popup
void announceUp() {
UnityEngine.Debug.Log("If this message shows in Debug.Log,
the script should be working.");
}
// Update is called once per frame
void Update() {}
void OnTriggerEnter(Collider other) {
if (other.gameObject.tag == "Bullet") {
UnityEngine.Debug.Log("The enemy has been hit!");
hitPoints = hitPoints - 1f;
if (hitPoints == 0f) {
UnityEngine.Debug.Log("The enemy has been eliminated!");
Destroy(gameObject);
}
}
}
}
I have 2 script, playerMachanics and enemyBehavior. My enemyBehavior has a boolean that when the boolean is true it moves away from the player. Instead i'm getting the error: "object reference not set to an instance of an object".
I'm sure it means the script can't find the component but i can't quite figure out what's wrong.
public class enemyBehavior : MonoBehaviour
{
public bool evade = false;
public GameObject Player;
public float movementSpeed = 4;
// Start is called before the first frame update
void Start()
{
Player = GameObject.FindGameObjectWithTag("Player");
}
// Update is called once per frame
void Update()
{
transform.LookAt(Player.transform);
transform.position += transform.forward * movementSpeed * Time.deltaTime;
if (evade == true)
{
movementSpeed = -4;
}
}
}
public class playerMechanics : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
void OnCollisionEnter(Collision collision)
{
enemyBehavior evade = gameObject.GetComponent<enemyBehavior>();
if (collision.gameObject.name == "coin")
{
Destroy(collision.gameObject);
enemyBehavior script = GetComponent<enemyBehavior>();
script.evade = script.evade == true;
}
}
}
I expected that the movementSpeed would go to -4 but now i'm just getting an error.
Calling getComponent by itself will look for the component attached to the parent object of the script, which is the player in this case I think. So it will always return null.
Add
Public GameObject enemy;
to the playerMechanics class and then go into the designer and drag the game object that has the enemyBehavior script attached into it. There are several problems with the onCollisionEnter method. Something like this
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.name == "coin")
{
Destroy(collision.gameObject);
enemyBehavior script = enemy.GetComponent<enemyBehavior>();
script.evade = false;
}
}
should get you going in the right direction.
Is the enemy behavior on the player object? See here
enemyBehavior evade = gameObject.GetComponent<enemyBehavior>();
and here
enemyBehavior script = GetComponent<enemyBehavior>();
You need to implement a way to track which enemy instance you are grabbing. Do this by making a variable to hold the enemy script, or by using a singleton on the enemy script (if there is one enemy).
Variable:
public enemyBehaviour enemy;
Singleton:
(enemyBehaviour)
public static enemyBehaviour instance = null;
private static readonly object padLock = new object();
void Awake(){
lock(padLock){
if(instance == null)
instance = this;
}
}
(player)
enemyBehaviour.instance.evade = false;
Look up singletons if you want to learn more.
If I'm right, I think your game mechanics works like this: The player's objective is to collect coins. When they collect one, the enemy near it will come and evade the player.
If that's the case, you should use this:
public class enemyBehavior : MonoBehaviour
{
public bool evade = false;
public GameObject Player;
public float movementSpeed = 4;
void Start()
{
Player = GameObject.FindGameObjectWithTag("Player");
}
void Update()
{
transform.LookAt(Player.transform);
transform.position += transform.forward * movementSpeed * Time.deltaTime;
if (evade)
{
movementSpeed = -4;
}
}
}
public class playerMechanics : MonoBehaviour
{
[SerializeField] enemyBehvaior enemy;
void OnCollisionEnter(Collision collision)
{
if (collision.collider.name == "coin")
{
Destroy(collision.collider.gameObject);
enemy.evade = true;
}
}
}
In your code, you wrote 'collision.gameObject.' This refers to the object the script is attached to. If you want to reference to the object that we hit, use 'collision.collider'.
'[SerializeField]' is a unity attribute, which is used to make a field show up in the inspector without making it public.
Just a heads up, if you're using 2D, make sure the method is signatured 'OnCollisionEnter2D(Collision2D collision)'.
I hope I answered your question. :)
I'm trying to have an if condition to do something if the sprite renderer of another object is enabled, but it won't work.
Here's the code I tried:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PickUpReCharge : MonoBehaviour
{
public Animator anim;
public Animator animc;
public Animator anime;
public GameObject neon;
public GameObject chargesprite;
public AudioSource recharge;
public BoxCollider2D collision;
public SpriteRenderer blackout;
public AudioSource ambient;
public AudioSource music;
void Start()
{
anime.Play("Pickup", 0, 1f);
}
private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Player")
{
neon.GetComponent<PlayerMovement>().enabled = true;
chargesprite.GetComponent<SpriteRenderer>().enabled = false;
collision.GetComponent<BoxCollider2D>().enabled = false;
anim.SetBool("IsDead", false);
anim.Rebind();
animc.Rebind();
anime.Rebind();
recharge.Play();
Destroy(gameObject, 3.0f);
//activate blackout
blackout.GetComponent<SpriteRenderer>().enabled = false;
if (blackout.enabled)
{
ambient.Play();
music.Play();
}
}
}
}
The public blackout has a sprite renderer that is disabled. When enabled, I want the last bit of code to run but it won't.
What's wrong with it?
Prodian asked if I tried gameobject.activeself, and I want to thank you for the advice. It works perfectly! I changed the reference type to gameobject and reaasigned it and made the necessary and it works like a charm now!
Here's the full new code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PickUpReCharge : MonoBehaviour
{
public Animator anim;
public Animator animc;
public Animator anime;
public GameObject neon;
public GameObject chargesprite;
public AudioSource recharge;
public BoxCollider2D collision;
public GameObject blackout;
public AudioSource ambient;
public AudioSource music;
void Start()
{
anime.Play("Pickup", 0, 1f);
}
void Update()
{
}
private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Player")
{
neon.GetComponent<PlayerMovement>().enabled = true;
chargesprite.GetComponent<SpriteRenderer>().enabled = false;
collision.GetComponent<BoxCollider2D>().enabled = false;
anim.SetBool("IsDead", false);
anim.Rebind();
animc.Rebind();
anime.Rebind();
recharge.Play();
Destroy(gameObject, 3.0f);
if (blackout.gameObject.activeSelf)
{
ambient.Play();
music.Play();
}
blackout.gameObject.SetActive(false);
}
}
}
EDIT: One more thing to note! The location of the if statement WAS important. It should have been before the code that makes the sprite false. This means the previous code would've worked if that had been done, but the gameobject code is much better for me because the blackout layer is one that I need to be OFF all the time.
Basically, my old code works! Just move the if statement before the "getcomponent......enabled = false" because the script is read in order.
Your blackout is SpriteRenderer so calling GetComponent on it is invalid. Change that to:
blackout.enabled = true;
Or use:
anotherGameObject.GetComponent<SpriteRenderer>().enabled = true;
Calling SetActive on a GameObject will disable not only the SpriteRenderer component! In some cases this changes your desired behaviour.
When my Player (GameObject) meets Lava, they should respawn in a specific scene.
This is the code I have assigned to the Player:
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Lava")
{
GameObject.Find("Controller").GetComponent<Controller>().Respawn();
}
}
Controller is a GameObject, that I don't want to Destroy by Changing level, so this is the code for my Controller GameObject:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Controller : MonoBehaviour
{
private static bool created = false;
public static Controller instance;
GameObject Player;
Vector3 respawnPoint;
void Awake()
{
if (instance = null)
{
instance = this;
}
else
{
Destroy(this.gameObject);
return;
}
if (!created)
{
DontDestroyOnLoad(this.gameObject);
created = true;
Player = GameObject.Find("Player");
respawnPoint = GameObject.Find("RespawnPoint").transform.position;
}
}
public void Respawn()
{
SceneManager.LoadScene(0);
Player.transform.position = respawnPoint;
}
}
RespawnPoint is just an invisible Cube GameObject, where I want the player to respawn.
Let's say the Game Starts with Scene "0" (this is where the RespawnPoint is, too.)
Then the Player goes to Scene "1" and dies (meets Lava). Then I want the Game to change back to Scene "0" and teleport the Player to the RespawnPoint.
The Scene-Change works good, but the player always starts at the same position, where he starts the first time and he's not teleported to the RespawnPoint.
What am I doing wrong?!
First of all you lack the "==" in the first 'if' from the Awake: if (instance == null
The code is fine or it does seem so to me, but the RespawnPoint should be in the Scene your Player meets the lava not in the Scene you are loading. If not the starting position of the player will always be (0,0,0).
I would recommend coming to this in a completely different way. I would make a public Transform[] Spawnpoints. Since the transform is public you can assign different objects to it. Make an empty game object and position it where you want to spawn. Then use
Void OnTriggerEnter(collider2D, other){
if(other.gameObject.tag == lava) {
transform.position = spawnpoints[0].position;
}
}
In the inspector set the Transform to be a size of 1 and set the respawn GameObject as the one transform.
Thanks to your answers, they helped me solving this problem.
I added a "DontDestroyOnLoad" to the RespawnPoint and than i changed the Controller Code to this:
{
private static bool created = false;
public static Controller instance;
void Awake()
{
if (instance == null)
{
instance = this;
}
else
{
Destroy(this.gameObject);
return;
}
if (!created)
{
DontDestroyOnLoad(this.gameObject);
created = true;
}
}
public void Respawn()
{
SceneManager.LoadScene(0);
GameObject.Find("Player").transform.position = GameObject.Find("RespawnPoint").transform.position;
}
}
now the player gets teleported to the correct RespawnPoint. Thanks for your help!