Why using getComponent to call objects in Unity? - unity3d

I am new in unity, I'm just wondering why we call the player object like this :
private void OnTriggerEnter(Collider other)
{
// if the player hit the enemy then destroy the ememy
if (other.tag == "PLAYER" ) {
// like this
other.transform.GetComponent<Player>().damage();
}
while we can make the damege method static and call it like this :
private void OnTriggerEnter(Collider other)
{
// if the player hit the enemy then destroy the ememy
if (other.tag == "PLAYER" ) {
//other.transform.GetComponent<Player>().damage();
Player.damage();
}
why we call the object like this what the point
other.transform.GetComponent<Player>().damage();
does it effect performance ? or is it just another available way to call objects

I will try to explain this the best I can. This explanation isn't perfect, but I worded it so it makes the most sense.
A class is a file that contains code. There are two "types" of classes, static and non-static. Static classes can be accessed anywhere, but there is only ever 1 copy. For example, use UnityEngine.Mathf. That is a static class, so you can just do Mathf.(whatever).
The non-static class can have multiple copies. Non-static classes can have static methods and fields, which can be accessed like you would a static class. For most basic applications, these classes just use normal methods. These methods are instance-dependent.
For example, take a non-static Player class.
public class Player : MonoBehaviour {
//This is accessed using Player.instance
public static Player instance;
//This function only runs on the script you place on a GameObject
public void Start(){
//Sets the static instance to this instance
instance = this;
}
}
You can then access the active player instance with any other script (as long as the instance variable was set before)
public Player GetPlayer() {
//As you can see, you don't need a reference to a Player; you can just use the static instance.
Player instance = Player.instance;
return instance;
}
In conclusion, using Player.Whatever references the static version. Using playerInstance.Whatever references a runtime instance. If you will only have one runtime instance of a class, you can use the example above to allow other classes to access the instance.

Related

How to reference a gameObject inside a prefab? Using GameObject.Find does not work

I am trying to use GameObject.Find within a prefab to reference an object that exists in the scene. The name of the object is exactly the same as the actual object.
LoseLives loseLives;
GameObject loseLivesing;
private void Awake()
{
loseLivesing = GameObject.Find("MasterManager");
}
private void Start()
{
loseLives = loseLivesing.GetComponent<LoseLives>();
target = Waypoints.waypoints[0];
}
loseLives.LoseLife();
Null Reference
I get a null reference when "loseLives.LoseLife();" runs.
Any help with solving the no reference problem would be greatly appreciated!
If you think there is a better way to create the connection between a script on a prefab and a script on a in-scene gameObject could you please explain it or point me to a tutorial, because in all my research I did not have any luck.
Thank you!
It seems like your LoseLives is a singular, constant object.
First Method
Simply making use of the inspector by exposing the fields.
public class YourScript : MonoBehaviour {
[SerializeField]
private LoseLives loseLives;
// ..
private void Start() {
loseLives.LoseLife();
}
// ..
}
It comes with the problem of needing to constantly drag your constant object into the inspector whenever you need it.
For a Prefab, it works if the target object is part of the Prefab, or the Prefab is generated in the same scene as the targeted object.
Second Method
Using singletons.
LoseLives.cs
public class LoseLives : MonoBehaviour {
public static LoseLives Instance {
get => Instance;
}
private static LoseLives instance;
private void Start() {
instance = this;
}
public void LoseLife() {
// ...
}
}
YourScript.cs
public class YourScript : MonoBehaviour {
// ..
private void Start() {
LoseLives.Instance.LoseLife();
}
// ..
}
This works if you have a global, singular instance of LoseLives object.
Even though it might not be the best approach, I found a workaround for my issue.
I am using a static variable that resides in the other script (CurrencyManager), calling it from the LoseLives script.
Instead of:
loseLives.LoseLife();
I do:
CurrencyManager.playerHealth -= 1;
Where CurrencyMananger is the other script and playerHealth is a static variable that is in the CurrencyManager script. This works because a static variable does not require the objects to be referenced in the inspector.
From now on, when I have a problem where I want to reference a gameObject within a script that is on a prefab, I will consider using static variables in my solution.

how to access multiple instantiated object in unity?

when I'm instantiate some object and I create a reference for I destroy which destroy the only first object in instantiating, my goal is to declare how to create multiple references of instantiated object?, I'm trying this
instiatedobject = GameObject.Instantiate(realobject, realobject.position, real.rotation);
You could use any generic collection type like List, Queue etc. For example
private List<GameObject> runtimeCreatedObjects;
private void Awake() {
runtimeCreatedObjects = new List<GameObject>();
}
public void CreateObject() {
GameObject instiatedobject = GameObject.Instantiate(realobject, realobject.position, real.rotation);
runtimeCreatedObjects.Add(instiatedobject);
}
Here every time we instantiate new object we add it to our list and use them elsewhere as per our requirement.

Exception in OnStartServer:Object reference not set to an instance of an object

public class GameControl : NetworkBehaviour {
public GameObject localPlayer;
[TargetRpc]
public void TargetGetLocalPlayer(NetworkConnection conn)
{
localPlayer = GameObject.Find("Local");
}
public override void OnStartServer()
{
base.OnStartServer();
TargetGetLocalPlayer(connectionToClient);
}
}
i have a script attached to a server object which should be able to grab the local player GameObject (which i denoted by changing it's name to 'Local' once it's spawned in another script) from the client but when i try to call TargetGetLocalPlayer , i get the following error :
Exception in OnStartServer:Object reference not set to an instance of an object at
UnityEngine.Networking.NetworkBehaviour.SendTargetRPCInternal
(UnityEngine.Networking.NetworkConnection conn, UnityEngine.Networking.NetworkWriter writer,
System.Int32 channelId, System.String rpcName) [0x0002e]
i am totally new to networking in unity and i feel like i should have gone with photon instead of unet , it seems like no one is interested in unet anymore and the docs suck at explaining anything and i will be very grateful if anyone could answer me , thanks in advance
I think a better solution would be to attach a script to each player. and make it so that when a "new" player joins it runs a method in your GameControl to add the player to a player list. like this:
//this is on your gameControl.
public List<Player> players;
public void AddPlayer(Player player)
{
players.Add(player);
}
this is working if you have your GameControl as a singleton. if you do not know how to do that check the last piece of code.
//this is on your Player script called player(if you have another name change all
//Player scripts in here to that name
public void Start()
{
GameControl.AddPlayer(this);
}
Or
Instead of making the players list a List you can make it a dictionary and make a key for each player who joins to make it more accesible.
How to make a script a singleton and why.
why:
if you have a manager class/script you always want there to only be ONE instance of it so you can call its methods easily and without problems.
How:
Basically you make it so that Only THIS script can change values and variables in the manager, and other scripts can get/call methods and functions. this makes it easily accesible and you will have less problems.
private static GameControl _GameControl;
private Player player;
public static GameControl gameControl
{
get
{
if(_GameControl == null)
{
Debug.LogError("Game Control is null");
}
return _GameControl;
}
}
void Awake()
{
_GameControl = this;
player = GameObject.Find("Player").GetComponent<Player>();
}
Well i see what you mean, well create a method that can be run by any script like a singleton. then you pass in the gameobject that you want to add like this:
public class GameManager
{
public GameObject _player;
//this is a singleton.
private static GameManager _gm;
public static GameManager gameManager
{
get
{
if(_gm == null)
{
Debug.LogError("Game manager is null");
}
return _gm;
}
}
void awake()
{
_gm = this;
}
void GetPlayer(GameObject player)
{
_player = player;
}
void AddPlayer(GameObject player)
{
//add it to whatever you want to.
}
}
call the method this way:
public class Player : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
GameManager.gameManager.GetPlayer(this.gameObject);
}
}

'PlaySounds.audio' hides inherited member 'Component.audio'. Use the new keyword if hiding was intended

I have seen a similar error to this but for Video, however I can not find anywhere that explains my current error.
I will attach my code below for reference, does anyone know what the error means here?
using UnityEngine;
using System.Collections;
public class PlaySounds : MonoBehaviour {
public AudioClip SoundToPlay;
public float Volume;
AudioSource audio;
public bool alreadyPlayed = false;
void Start()
{
audio = GetComponent<AudioSource>();
}
void OnTriggerEnter2D(Collider2D other)
{
if (!alreadyPlayed)
{
audio.PlayOneShot(SoundToPlay, Volume);
alreadyPlayed = true;
}
}
}
The MonoBehaviour class is already presenting a member called "audio" so your PlaySounds class has that member already. If you want to ignore the one from the base class you should declare it like so:
private new AudioSource audio;
But if you want the inherited member to be available as well as the one in your class simply give it a name other than "audio". To be honest unless you have a particular reason you want to override the inherited member I'd do the latter.

Global Scriptable Object

Suppose I have this ScriptableObject to represent a list of cards:
using UnityEngine;
using System.Collections;
[CreateAssetMenu(fileName = "CardList", menuName = "Inventory/List", order = 1)]
public class CardList : ScriptableObject {
public string[] cardName;
public Sprite[] cardSprite;
}
Then I create the ScriptableObject and fill it with all my cards information.
Is there a way to modify this code so that any script have access to it statically? For example, is it possible to give CardList a singleton behaviour?
I don't want to create another class, it would be easy to create a ScriptableObjectManager that could reference CardList. I'd rather call something like CardList.instance.cardName[i] directly.
Definitely, you can create it as singleton so for this.
Suppose that we have Unity Project that has file hierarchy like
UnityProject
- Assets (directory)
Scripts
SampleScriptableObject.cs
- Resources (directory)
SampleScriptableObject.asset
- Project
- ..etc
in "SampleScriptableObject" class will be like
public class SampleScriptableObject<T> : ScriptableObject where T : ScriptableObject
{
private static T _instance;
public T GetInstance()
{
if (_instance == null)
{
_instance = Resources.Load(typeof(T).Name) as T;
}
return _instance;
}
}
you can use scriptable object as singleton as you want.