Method in Script is never called - c#

I have a Projectile Script attached to a GameObject. Now i want to access the LinearProjectile() method in Projectile Script from Script A attached to GameObject A. Here i made a public field of type Projectile in Script A and passed in one GameObject where Projectile Script is attached.
To access LinearProjectile() method i just did.
projectile.LinearProjectile(transform.position, transform.rotation, this.direction, this.shotPower);
//Here is my method defination..
public void LinearProjectile(Vector3 position, Quaternion rotation, Vector2 direction, float force)
{
Debug.Log("called");
this.direction = direction;
this.force = force;
this.projectileType = ProjectileType.Linear;
}
All the field value assigned in this method are in default state since this method is never called. How can I access this method from other GameObject Script.
I tried GetComponent().method() but even though i can't acess what is the error here? i spent alot of time to find out but no success.. Help me out

Provided a scenario like this:
We have a GameObject in scene, let's call it Item
We have ProjectileScript attached to Item
We have a A script attached to Item
All we need to do is to call inside A script:
gameObject.GetComponent<ProjectileScript>().LinearProjectile();
If it's on another GameObject, I would personally create field in script A to be used in Inspector, for example: public GameObject ProjectileScriptHolder and then just drag GameObject from scene that holds ProjectileScript into that variable in Inspector and the access it that way:
ProjectileScriptHolder.GetComponent<ProjectileScript>().LinearProjectile();
I would also check every GetComponent<T> before calling method as it might return null, ie:
ProjectileScript script = ProjectileScriptHolder.GetComponent<ProjectileScript>();
if (script != null)
script.LinearProjectile();
If you can't attach item through Inspector, you can use FindWithTag() and find GameObject in scene provided it has proper Tag attached. FindWithTag() takes string as parameter and will look for GameObject with such tag in scene.

I understand that you want to access a script from another script on another gameobject!
Way 1
There is a simple way to do that, caching the script. (Assuming the name of the script is: "ProjectileScript")
On ScriptA you create a
public ProjectileScript pS;
and you need to initialise it, there is two ways:
1- on the inspector of GameObjectA, drag the GameObject with the projectileScript.
or
2.1- if the script is in the same game object:
pS = GetComponent<ProjectileScript> ();
2.2- if it is on another gameobject you might need to find this object somehow. Consider using a tag
pS = GameObject.FindGameObjectWithTag("projectile").GetComponent<"ProjectileScript">();
And cast it inside Script A:
pS.LinearProjectile();
Way 2
Or you can make a generic tag on the GameObject with the ProjectileScript and find it that way:
GameObject.FindGameObjectWithTag("projectile").GetComponent<"ProjectileScript">.LinearProjectile();
This make sense for you? Sorry my english.

Related

How to: Get instance of gameObject

Looking to get an instance of this game object so I can successfully use .enabled to hide it in a scene.
PlayPortalLoginButton loginButton = gameObject.GetComponent<PlayPortalLoginButton>();
Fairly new to C# and I believe I am close to achieving my goal with the line above. What needs changed? Want to understand how to correctly do this.
Here is one way you could find a component on a GameObject in the scene, where "PortalLoginButton" is the name of the GameObject as seen in the editor:
var loginButton = GameObject.Find("PortalLoginButton");
loginButton.enabled = false;
However, GameObject.Find("...") searches the name of every GameObject in the scene, and this is not usually the best way to reference a GameObject since it is not very efficient. So make sure not to use GameObject.Find("...") or similar function calls in the Update() function because it will execute every frame and slow your game down. If the GameObject is not instantiated while the game is running, it is usually better to make a global reference to any GameObject or Component that you use in your script and then drag-and-drop the GameObject with the Component you are looking for into the field in the editor. Alternatively, you can use GameObject.Find("...") in the Start() or Awake() functions to store a reference to the GameObject that you are looking for, so that the search only happens once at the start of your game.
Here is an example of how to store the reference in global field (it will show up in the editor and you can drag-and-drop the GameObject into it). The differences between using a public field vs a private field are explained in the comments (you can decide on using public or private):
// By default, private fields are not viewable in the editor,
// but the [SerializeField] attribute, placed before
// the field declaration, allows them to be visible.
[SerializeField]
private GameObject loginButtonPrivateReference;
// If you need to access loginButton from another script,
// you can make it a public field.
// Public fields are viewable in the editor by default.
public GameObject loginButtonPublicReference;
Here is an example of how you can use GameObject.Find("...") in the Awake() function:
private GameObject loginButton;
private void Awake() {
loginButton = GameObject.Find("PortalLoginButton");
}
If you need to search for GameObjects in your scene by type or by tag name, see the GameObject documentation here for more information. Searching by type is less efficient and searching by tag is more efficient than searching by name because type searches check each component on each GameObject, and tag searches search only an organized GameObject subset.
GameObject button;
void Start() {
button = GameObject.Find ("yourButtom");
}
void SomeEvent() {
button.SetActive(false);
}
I think you have to help to you
There are several ways to get access to a gameObject in a script depending on exactly which gameObject you are trying to get.
If you are trying to access a GameObject of a behavior in the behavior script then simply using gameObject should suffice since that is the gameObject that behavior is attached to.
Accessing a script that is attached to another GameObject is where it can be tricky. For scenes such as a MainMenu, there is nothing wrong with giving it a public reference as an example:
public PlayPortalLoginButton loginButton;
void setLoginState(bool activate) {
loginButton.enabled = activate;
}
With this example you would just drag and drop the gameObject with the PlayPortalLoginButton script on your manager script, the script that would control whether it is enabled or not.
If you need a more modular approach to it for example in a gameplay scene where you are populating objects at run time the approach you can take is:
PlayPortalLoginButton loginButton;
void setLoginState(bool activate) {
if(loginButton == null)
{
loginButton = FindObjectOfType<PlayPortalLoginButton>();
}
// Requires the correct version of .net otherwise you can reuse the check above...
loginButton?.enabled = activate;
}
In the above script if you needed to gameObject of loginButton, now you can access it through loginButton.gameObject.
There are some more examples you could use and other approaches however I feel the above should suffice if for a menu.
I will also mention I am avoiding example of GameObject.Find and GameObject.FindGameObjectsWithTag as those are more prone to error. They will only work if your name or tag are correctly marked, if you rename them for any reason then your scripts will fail to find the Object, and this can cause an issue with troubleshooting.
Using FindObjectOfType, you are less likely to have an error, and if you remove that script type these scripts will populate an error indicating the script no longer exists. When refactoring, if you right click on the behaviors name and use the rename option it will automatically update references to the script throughout your code.

Unity - How do I instantiate an asset?

void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Instantiate(Resources.Load("Objects/Level"), transform.position, Quaternion.identity);
}
}
This is my code. I have an object named Level.obj inside of a folder named "Objects" inside of my Assets. I attempt to spawn it on top of the parent object of this script with Resources.Load("Object/Level"). I believe this code itself is correct because the console returns with "The Object you want to instantiate is null." upon pressing the spacebar. What's probably wrong is my parameters, specifically how I attempted to find the object. I have also tried Assets/Objects/Level as opposed to what's above.
Add a public field public GameObject myPrefab; to your monobehavior.
Set it in the editor by selecting your gameobject and using the inspector.
Instantiate it like Instantiate(myPrefab, transform.position, Quaternion.identity);
You only need Resources.Load if your asset doesn't exist at compile time. And like the documentation says, Resources.Load needs the asset to be in the Resources folder.
https://docs.unity3d.com/ScriptReference/Resources.Load.html
I never used Resources.Load() so you may try to achieve something different, but what I do to "spawn" objects is to make them into a prefab (just drag/drop your object to your assets). Then declare a public GameObject field on your script, drag/drop the prefab in it in the inspector and then Instantiate it like you did.
Hope it helped !

What is better: link to a GameObject or to a Class in Unity?

Example: GameObject A has a script attached to it called MakeItRain. Inside that script is a public void Drizzle();
GameObject B also has a script and wants to tell MakeItRain to do Drizzle();
Inside the script of GameObject B, I can do this:
public GameObject makeitrain;
and then I have to use GetComponent to reach Drizzle(); in my code.
In the inspector, I drop GameObject A into the slot of makeitrain and I'm done.
However, I could also do this in the script of GameObject B:
public MakeItRain makeitrain;
and then just call makeitrain.Drizzle(); in my code of GameObject B's script, without GetComponent.
In both cases, in the Inspector, I have to drag and drop GameObject A into the slot of GameObject B.
Is there a difference or reason why I should definitely not do the last option? I understand that the first method gives me more flexibility because I could call other components of GameObject A as well and not just the script's stuff. Just wondering if there is any other rationale for not doing the second method.
The answer depends if you need to call any function or use variable from the MakeItRain script.
If you don't need to to call any function in the MakeItRain script or access any variables from it then it is better to use GameObject as the reference. Also, if what you need to do is activate, de-active, rotate the GameObject then use the GameObject as reference.
On the other hand, if you need to be able to call a function such as Drizzle or access a variable from the MakeItRain script from multiple places, then you need to use the MakeItRain reference. At this time, it doesn't make sense to use the GameObject reference since by using it, it's required to use GetComponent every-time you need to call a function or access a variable from the MakeItRain script attached to it.
Finally, when using the MakeItRain script to reference your object, you can directly and easily access the GameObject it is attached to without using the makeitrain.gameObject. This doesn't require the use of the GetComponent function.
Just wondering if there is any other rationale for not doing the
second method.
Performance issue due to the required use of the GetComponent function is the reason. Using it once in the Start or Awake function and initializing your MakeItRain variable is better.
For example, this is better:
public MakeItRain makeitrain;
void Start()
{
makeitrain = GetComponent<MakeItRain>();
}
void Update()
{
makeitrain.Drizzle();
}
than this:
public GameObject makeitrain;
void Update()
{
makeitrain.GetComponent<MakeItRain>().Drizzle();
}
And should be used to avoid having to search for the component on the native side every frame.
Using MakeItRain and explicitly defining the type is better than using GameObject.
As #hacksalot commented, using MakeItRain offers strong typing. One of the benefits of this is related to your comment:
In both cases, in the Inspector, I have to drag and drop GameObject A
into the slot of GameObject B.
If you explicitly set the public variable type to MakeItRain rather than GameObject, it is not possible to drag and drop a GameObject A into the slot of GameObject B unless GameObject A is has a script of the correct type. This gives you a compile-time/editor-time check that you are linking to the correct GameObject in the Unity Editor inspector.
Also, while not necessarily so, using GameObject references often encourages messier code, whether because of unnecessary chaining of methods together (e.g. GetComponent) just because the type wasn't specified, or because it adds a bit of friction to writing & using helper methods. Consider even in a simple example which one reads better:
makeitrain.Drizzle()
makeitrain.GetComponent<MakeItRain>().Drizzle()
I understand that the first method gives me more flexibility because I
could call other components of GameObject A as well and not just the
script's stuff.
Note that you still have the flexibility to access GameObject, it's just a bit more verbose (which is one downside of this approach):
public MakeItRain makeitrain;
void Start()
{
makeitrain.gameObject.SetActive(false)
}
However, you'll likely be using helper methods anyway (for anything more than basic calls), or even wrapper methods (which are inconvenient to write but sometimes helpful for readability).
In most cases, the benefits of linking to the class rather than the GameObject outweigh the downsides.
If u don't want to use GetComponent(), you can simply use SendMeassage(), like this
public Gameobject makeItRain;
void Start(){
makeitrain.SendMeassage("Drizzle");
}
Another way to link a script is that use FindObjectOfType(), which do not need to drag and drop GameObject into the slot, here is the sample
void Start(){
MakeItRain makeitrain = FindObjectOfType("MakeItRain");
}
Also you can use Gameobject.Find() to link a GameObject instead of dragging into slot, but I don't recommand this way, it cost a lot performance since you need to find every single GameObject in scene.

How to prevent "public" in Unity?

Being a student and having finished my school year I studied the development of Unity in C # to learn how to use the engine but also and above all to have fun.
One of the advantages of Unity is that you can pass a game object parameter directly in drag/drop, but for this to be possible it is necessary that the said variable is in public, which goes against what I have learned in class (the attributes must be private as often as possible).
My question was, how to make sure to have the same result with private attributes, i.e., recovered the game object manually without using the drag/drop system?
Thanks in advance and sorry for my English level.
It is not necessary to mark the variable as public in order to make it appear in the Editor. Just just put the SerializeField attribute on top of the private variable and it should show up in the Editor.
[SerializeField]
private GameObject cam1;
You can also do the opposite which is make public variable not show in the Editor. This can be done with the HideInInspector attribute.
[HideInInspector]
public GameObject cam1;
But there is another method in Unity to get a GameObject, by avoiding
drag/drop ?
Yes. Many ways.
If the GameObject already exist in the scene then You can with one of the GameObject.FindXXX functions such as GameObject.Find, GameObject.FindGameObjectWithTag
For example,
[HideInInspector]
public GameObject cam1;
// Use this for initialization
void Start()
{
cam1 = GameObject.Find("Name of GameObject");
}
If the GameObject is just a prefab then put the prefab in a folder named Resources then use Resources.Load to load it. See this for more thorough examples.
Finally if you just want to get the component of that GameObject, just like your cam1 variable which is not a GameObject but a component, First, find the GameObject like I did above then use the GetComponent function to get the component from it.
private Camera cam1;
// Use this for initialization
void Start()
{
GameObject obj = GameObject.Find("Main Camera");
cam1 = obj.GetComponent<Camera>();
}

Pointer to a script in Unity3d

I have a gameObject and I want to get a value from one of the scripts. How would I point to the script? At the moment I am calling the gameObject from a script named Body and I want to get the script named RightArm.
Inside your Body script you can do this, assuming that the Arm is inside the Body.
RightArm rArm = GetComponentInChildren<RightArm>();
It will look through all the Children and find the correct component you want. You can use this to find all sorts of Components, such as Rigibodies.
Assuming the RightArm is somewhere else, maybe on the floor outside the body. Then you can do this:
RightArm rArm = GameObject.Find("RightArm").GetComponent<RightArm>();
Let "RightArm" be the name of the GameObject containing the RightArm Script.
This second implementation will look through in the scene for the GameObject named "RightArm" then look at the components in that gameObject and return you the RightArm script. If there is no gameObject named "RightArm" then you will get an exception when trying to get a component of null.

Categories

Resources