Destroy() method is not accessible in static method
public static void Die()
{
Destroy(gameObject);
}
But Destroy() is only accessible if:
public void Die()
{
Destroy(gameObject);
}
You can't call a non static function from a static function but you can do the opposite.
I need to make it accessible on another scripts
Make the Die function to be a non static function. Let's say that this script is named OtherScript.
public void Die()
{
Destroy(gameObject);
}
Then from another script, you can access it by finding the GameObject the OtherScript script is attached to with the GameObject.Find function then use the GetComponent function to get the OtherScript reference from the GameObject:
OtherScript otherScript;
void Awake()
{
GameObject obj = GameObject.Find("NameOfGameObjectOtherScriptIsAttachedTo");
otherScript = obj.GetComponent<OtherScript>();
}
You can now call the Die function with otherScript.Die(). Note that you must replace "NameOfGameObjectOtherScriptIsAttachedTo" with the name of GameObject the OtherScript script is attached to.
From your comments it looks more like you actually want to do what Programmer's answer shows.
I'm just adding this because your title asks How to Destroy Object from static method in Unity C#
If you really need it to be static (e.g. in a static class) you could use it like this
using UnityEngine;
public static class SomeStaticClass
{
public static void Die(GameObject obj)
{
Object.Destroy(obj);
}
}
but to be honest this is needed in very few cases. It might be helpful e.g. in an Editor script where you don't have any Component executing your code.
cannot kill a single static object, it dosnt work that way. please refer to the answer here.
the following excerpt is from the above link, and should explain for you...
*I think perhaps you've misunderstood the 'static' keyword a little bit.
To clarify, a bit... Imagine you have a class called 'Vehicle'.
A none-static variable means 'every vehicle has its own copy of this variable'. We might say 'every instance of vehicle has its own copy of the variable.
A static variable means 'there is only 1 of this value shared by all vehicles'. Here we'd say 'all instances of vehicle share the variable.
Following on from that, functions are a little harder to picture, but they work in much the same way:
A none-static function operates on an instance of the vehicle. The result is that it can use the 'this' operator (it makes sense!) and access both none-static member variables of it's instance, and the shared static ones
A static function isn't tied to an individual instance of a vehicle, so the 'this' operator doesn't make any sense (what would 'this' be?). It still makes sense for it to be able to access static variables, but again none-static ones don't make any sense - who's version of the variable would it be referring to?
Your 'Die' function looks like it is designed to operate on a given instance of your enemy. i.e. you are expecting calling 'Die' to mean 'kill this please'. As a result it should not be static. You'll also need to access the 'gameObject' variable, not the 'GameObject' type.*
Related
Maybe a silly question, but having difficulty understanding it.
public class A
{
public void Message()
{
Debug.Log("Some Message")
}
}
public class B: MonoBehaviour
{
A obj1 = new A(); //instance of object is made and constructor is called
A obj2; // object is made
obj1.Message();
obj2.Message();
void Start(){}
void Update(){}
}
What's the purpose of 'new' keyword if in both cases, the object is able to use methods of the class
A obj2; // object is made
The object is not instantiated at this time, you only told here that you have a variable with the name obj2, and it is hold reference to nothing, in case of class it is null. You have a class named A and in it, you have a method called Message() and compiler in compile-time have a signal you have Message method defined, and that it is. In this case, this code should throw an exception NullReferenceException
There are a few quirks to Unity which may be tripping you up here. Actually, obj2 is not null, because it is of type "A" (not a Monobehavior). Since Class B is derived from Monobehavior, all of its "class variables" (the ones defined in immediate scope) will be instanced by the Inspector automatically. You can read about that here.
In other words, obj2 will still be usable. This is a property of custom classes in regards to how they are loaded from MonoBehaviors. If class A was also a MonoBehavior, then it would be nullable here, and you would see it as an empty variable in your inspector when Class B is put onto a GameObject. This is the case where Message() would not work, since obj2 would actually be null. Note there are other complications though--if Class A is a MonoBehavior, then you shouldn't be using Constructors on it, you should be using AddComponent(). Also, you can't define two MonoBehaviors in the same script file.
Finally, I'm not sure of the specifics here since I haven't tested it, but obj1.Message() may not be able to be called from where you're currently doing it. Typically code is run using the Callback functions provided by the MonoBehavior inheritance, i.e. Start(), Update(), etc. In order to call obj1.Message() at the start of the game, you need to run it from the Start() method. Let me know if you have any questions and I can clear up anything you find confusing!
EDIT: This is only true if obj2 appears in the inspector--if it is public and the class A is tagged as Serializable.
I am trying to call a function in another c# script, that is attatched to another gameObject in my scene. I am creating an instance of the script LevelChanger in the Grounded one like this:
LevelChanger levelChanger;
Then, in the Awake() function:
GameObject gameObject = new GameObject("LevelChanger");
levelChanger = gameObject.AddComponent<LevelChanger>();
then calling like this in an IEnumerator:
levelChanger.FadeOut(true); // line 178
Then this is the LevelChanger class:
using System.Collections;
using UnityEngine;
public class LevelChanger : MonoBehaviour
{
public Animator animator;
public void FadeOut(bool fadeIn)
{
animator.SetBool("Fade", true); // line 10
if (fadeIn) StartCoroutine(FadeInAsWell());
}
IEnumerator FadeInAsWell()
{
yield return new WaitForSeconds(0.9f);
animator.SetBool("Fade", false);
}
}
I've been trying to solve this problem for quite a while now, I checked everywhere (here, here, here, here and on other sites). I saw that because my LevelChanger script is attatched to a gameobject, so it is MonoBehaviour, it is not possible to create an instance of the class from another script, like this:
LevelChanger levelChanger = new LevelChanger();
or either "normally" like I was doing at first like this:
LevelChanger levelChanger;
Then just calling its functions like
levelChanger.FadeOut(true);
Most of the time I was getting a NullReferenceException at runtime (at line 176), now directly in the LevelChanger script (at line 10).
At this moment, I truly have no idea how to fix this: does anybody know how?
(I'm still a beginner).
Thanks in advance!
Based on the conversation we've had in comments, I'll write an answer here to be more thorough.
So, let's recap. What you want to do is call a function from LevelChanger. But, you are unsure of how to get a reference to LevelChanger. This is the core problem every programmer faces: How do i get that stuff over there, and what's the best way to do?
Based on what you've said, your prefab exists in the scene, so you want to grab a reference to it.
One simple, lazy way is to call FindObjectOfType<LevelChanger>. This will search through the entire scene for components of that type, and will return your LevelChanger instance. I don't recommend this because it's pretty lazy and inefficient. This is only needed if one or both of your objects exist at run-time but not at edit-time
Another way is to treat LevelChanger like a singleton.
add a public static LevelChanger Instance; field to your LevelChanger. Then, on Awake() set Instance to this. ie Instance = this;
public static LevelChanger Instance;
public void Awake()
{
Instance = this;
}
Then, in any other script, you can call LevelChanger.FadeOut(false);
This is a similarly lazy way, but not quite inefficient. It does make your code a little harder to follow and there are a lot of devs that have problems with static instances like this. Just so you know.
One other way is to create an instance of the prefab using GameObject.Instantiate() and calling the function after getting a reference to the component. This is a bit more involved, but it might be a cleaner way for you.
There are two ways to do this, so lets do the cleanest way. In your project, create a folder called Resources if you don't already have one. Resources is a name unity will specifically look for when calling Resources.Load(). Drag your prefab object into that folder to create a new prefab. Call it LevelChanger
//Spawn the prefab gameobject
GameObject gameObject = GameObject.Instantiate(Resources.Load("LevelChanger")) as GameObject;
//Get a reference to its component LevelChanger
LevelChanger levelChanger = gameObject.GetComponent<LevelChanger>();
//Call the function
levelChanger.FadeOut(false);
After your prefab finishes the fade, you can have it destroy itself via Destroy(gameObject);
Finally, since you've indicated both scripts exist at edit time, you can simply add an inspector reference. This is the easiest way, but don't go crazy with inspector references. It makes the code difficult to follow.
public LevelChanger levelChanger;
Quick and dirty because little has been shared about the code and scene in question.
In Awake, get a reference to the gameObject with the already existing LevelChanger on it:
GameObject levelChangerGO = GameObject.Find("LevelChanger");
levelChanger = levelChangerGO.GetComponent<LevelChanger>();
then calling like this in an IEnumerator:
levelChanger.FadeOut(true); // line 178
I am having trouble getting one script to call an instantiation function from another script. The following image illustrates how I have my game objects set up.
I have 2 object things, Thing1 and Thing2, which move around the screen based on a movement script that is attached to each of them. Thing1 also has attached a reaction script. When Thing1 and Thing2 collide, Thing 3 should appear. Thing3 has an instantiation script attached to it that contains a function with an instantiation command.
When I call the instantiation function within the instantiation script (I put it in the Start function of Thing3), it works fine. However, when I take it out of there and try to put it in the Start function of the reaction script attached to Thing2 I cannot get it to work. Most currently, I get no error on compiling but as soon as the game starts I get is the following (The behavior of Thing1 and Thing2 also seems to be adversely affected):
"NullReferenceException: Object reference not set to an instance of an object"
When I look up the reason for that error I find that the most typical reason for that is a prefab object not being attached to the script. However, I DO have a prefab attached to the script. It is attached to the instantiation script that contains the instantiation function.
Below is the code for the instantiation script and the reaction script that is calling the instantiation function within the instatiation script.
//Instantiation
public class Thing3Instantiation : MonoBehaviour
{
public GameObject thing3Obj;
void Start()
{
//CreateThing3();
}
public void CreateThing3()
{
Instantiate(thing3Obj);
}
}
And
//Reaction
public class Reaction : MonoBehaviour
{
private Thing3Instatiation thing3instantiation;
void Awake()
{
thing3instantiation = GetComponent<Thing3Instantiation>();
}
void Start()
{
thing3instantiation.CreateThing3(); //This line triggers the null error
}
Any ideas on what I'm doing wrong?
If I understand your setup correctly:
Reaction is on Thing1
Thing3Instantiation is on Thing3
So when Reaction awakes, it tries to find the component called Thing3Instantiation on its own gameObject (Thing1). But it isn't on Thing1 it is on Thing3, so GetComponent returns null.
Hence, your NullReferenceException.
Your problem is actually at the line of Instantiate(thing3Obj);.
In other words... When you Instantiate a script, you won't have variables assigned, in your case thing3Obj. No matter if you've assigned them through Inspector, when Instanciated, you get a clean copy of that class, unallocated. You need to assign it before calling, that's why it's giving the Null exception.
I'm new to unit and i'm making this hack and slash game.
I'm having trouble with making one unit deal damage to another, though
EDIT: i forgot to mention the hit() method is being called from the animator.
public GameObject obj;
(...)
void OnTriggerEnter2D(Collider2D collider)
{
if(!collider.gameObject.GetComponent<floor>())
{
obj=collider.gameObject;
print(obj);
}
}
void hit()
{
print(obj);
if(kicked&&obj)
{
obj.GetComponent<health>().DealDamage(damage);
print(obj.GetComponent<health>().value);
}
}
the hit() method is being called by the animation (when the kick animation is performed). by the way, when you kick, the bool kicked becomes true. The hit method has been printing (null) every single time.
Change
GameObject obj=collider.gameObject;
to
obj=collider.gameObject;
You're declaring a second "obj" variable in your OnTriggerEnter2D method, local to that method, which is overriding the one you declared in your class. I should probably mention that your code (while it may work) is very poorly written. You should read up on OO design patterns.
multiple variable with same name .you have declare "obj" as public and than again want to Declare as local variable .change the name of obj if it is same remove "Gameobject" from inside function .
obj=collider.gameObject;
I'm making a little text game. The starting dialogue is in my main (static) method. From there, it sends you to other methods depending on your choices.
Now I think I need to have an instance of my class for this to work.
For example:
Program p = new Program();
if(stuff){
p.room1();
}
else{
p.room2();
}
Within those other methods there are global variables that will change.
So above the main method there is:
public bool hasItem = false;
So room1() would look like,
public void room1(){
if(stuff){
p.hasItem = true;
}
}
I know I'm screwing something up with the main method. Do I declare the instance "p" inside or outside of the main method? I've tried both but get errors both ways.
Edit: I ended up declaring a static "Program" outside of the main method to use elsewhere. Thanks for the help!
First off, you can either create a static Program outside of your main method, or declare a program inside your main method, depending on your architecture.
Second, you don't have to reference your instance from within your instance methods. Just use the field name. like so:
public void room1(){
if(stuff){
hasItem = true;
}
}
you can use this.hasItem if you want to be explicit about it.
Or better yet, make a brand new class to keep your state in. Having instance members in the class with the main method is awkward design.