I'm new to Unity but have development experience. I'd like to know whether I should be using the inherited properties in my MonoBehaviour scripts, or if I should be injecting everything from the inspector instead.
I'm following a tutorial that has suggested writing some code like this:
public class BirdScript : MonoBehaviour
{
public Rigidbody2D myRigidbody;
So that the Inspector can inject the component's Rigidbody2D into it:
When playing with the code, I noticed that MonoBehaviour extends Component and I can do this.rigidbody2D instead. I got told off by Intellisense for this, but it suggested instead using: GetComponent<Rigidbody2D>().
Using this, instead of my code reading:
void Update()
{
myRigidbody.velocity = Vector2.up * 10;
}
I can write:
void Update()
{
GetComponent<Rigidbody2D>().velocity = Vector2.up * 10;
}
But which is better? I'm thinking GetComponent<Rigidbody2D>() because it makes sure that I'm directly referencing the current rigid body that my script is attached to, instead of requiring me to apply things in the Inspector, but maybe this is too inflexible for Unity? In general, the style seems more lenient towards making things public instead of private for the sake of the Inspector.
Any advice on some best practices I can use to make these kinds of decisions?
Related
So I was looking into implementing the new Unity input system into my game by reworking my code in my PlayerController script and got stuck pretty early on.
Here is the code that causes issues:
private PlayerInput playerInputController;
private void Awake()
{
playerInputController = new PlayerInput();
}
A green scribbly line appears under the 'Awake()' bit.
The code itself actually works, but it causes a lof of other issues, which makes a bunch of error messages appear saying:
NullReferenceException: Object reference not set to an instance of an object
The error messages all lead to places where I've used lines of code like this one in other scripts, to get variables and methods from my PlayerController script:
if (PlayerController.instance.isGroundedPhys)
Lastly, here's my singleton script, since it's likely relevant, as it's connected to my PlayerController script and allows it to be accessible from other scripts:
using UnityEngine;
public class Singleton<Instance> : MonoBehaviour where Instance : Singleton<Instance>
{
public static Instance instance;
public virtual void Awake()
{
if (!instance)
{
instance = this as Instance;
}
else
{
Destroy(gameObject);
}
}
}
This bit is at the top of my PlayerController script to make it accessible from other scripts:
public class PlayerController : Singleton<PlayerController>
{
I've been looking around and can't find anybody talking about similar issues. I think it's related to my singleton script, but I can't figure it out. :[
[Edit]:
I just found out it also gives this warning in the Unity console:
warning CS0114: 'PlayerController.Awake()' hides inherited member 'Singleton<PlayerController>.Awake()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.
PlayerInput is a MonoBehaviour!
No seriously, this is "Not Allowed" and you should actually give you an according warning in the console.
A MonoBehaviour "can"/should only exist attached to an according GameObject and always be created by the underlying c++ framework. It's a c# thing that Unity can't fully prevent you from using new to create one.
The only valid way of creating an instance of a MonoBehaviour are
Instantiate a prefab that has the component attached
use AddComponent on an existing GameObject
use the constructor of GameObject and pass in the according component type(s)
Or you probably rather want to use e.g. GetComponent or FindObjectOfType in order to get a reference to an already existing instance of PlayerInput.
And then the other warning means you implemented
public void Awake()
{
// ...
}
or similar in your PlayerController class. The warning already tells you exactly what to rather do:
// Use "override" in order to not hide the already existing implementation
// of "Awake" in the base class
public override void Awake()
{
// Make sure the base class behavior is executed
// this will initialize the Singleton thing
base.Awake();
// ... your additional behavior here
}
I am new to Unity 3D development and I wanted to know what is the best way to declare attributes of a class to be assigned later from the editor.
I have seen mainly two:
public class MyObject : MonoBehavour {
public GameObject relatedObect;
}
and
public class MyObject : MonoBehavour {
[SerializeField]
private GameObject relatedObect;
}
I understand that it is of the second form because the encapsulation is maintained, but I am not sure.
Please consider that in the example you declared class fields, and not properties.
They are both members of a class, but they are quite different.
For the sake of this answer I'll focus on your example, so I'll talk about fields.
Both public and [SerializeField] private let you inject a value in the Unity Inspector, but they act differently in the scripts.
1 - public field
You declare a public field when you want it to be used or set from another class. This choice goes against encapsulation, because other script may access it. It still might be an intended behaviour if you require the field to be accessible.
2 - [SerializeField] private field
You use this when you want to set the item in the inspector, but you do not want the other classes to see it. This option is better for encapsulation, because in this way no other script may access or change this field.
Second is the way to go if you want to do things "properly". But unfortunately there is a "bug" that throws warning on every private you set via the editor. I saw on github that it is finally getting fixed, but in the meantime if you want to remove the warning you can put your variables between pragma warning disable 0649 and pragma warning restore 0649
In addition to Jack Mariani's answer, I want to mention RangeAttribute and HideInInspectorAttribute.
[Range (min, max)]
If there's one, the inspector will show a slider instead of just a number. You move a slider and the value changes in specified range.
[SerializeField] [Range (0, 5)] private float _speed;
Documentation
[HideInInspector]
You should use it when you do not want a public variable to show up in the inspector (they are shown by default):
[HideInInspector] public float X;
Documentation
I am making a game in Unity C# where the character will have different characterstics and movement functions in each scene. So I am trying to have different scripts for a player in different scenes, while all of them inheriting from the same base class. The definition will be something like below
public class PlayerScript1 : PlayerBase { /* for scene 1*/
public void Move(){
/* my movement code*/
}
}
Similarly, I have a separate class for Scene2 as
public class PlayerScript2 : PlayerBase { /* for scene 2*/
public void Move(){
/* my movement code*/
}
}
Now the problem is, my other scripts, like HealthScript,ScoreScript etc they do not change with scene. But they do access PlayerScript1 script. And thats why, I have the PlayerScript1 declaration in them. Like below:
public class HealthScript : MonoBehaviour {
PlayerScript1 playerScript;
void Start(){
/*accessing the script attached to game object*/
}
}
So how can I have my Health Script access different instances of my PlayerScript based on the scene? I know I could use delegates to call different methods in runtime, but how can I do the same with classes?
So how can I have my Health Script access different instances of my PlayerScript based on the scene?
Well first, you'll want to declare that object as of Type PlayerBase as you will be unable to assign an instance of PlayerScript2 to a variable of type PlayerScript1: those classes might inherit from the same parent, but they are not the same and you cannot convert from one to the other.
After that you will need to search for the player object in the scene, something like...
void Start(){
playerScript = GameObject.Find("Player").GetComponent<PlayerBase>();
}
Assuming, of course, that PlayerBase extends MonoBehaviour. If it doesn't you can't get a reference this way (as it won't exist in the scene at all). Additionally if you want this health object to persist from scene to scene, you need to call DontDestroyOnLoad() for it (as well as remembering that if you don't start testing from Scene 1 where this object is, it won't exist at all, or if you have a copy in every scene, you'll have duplication problems).
Someone answered to my question on the Unity forum which cleared all my doubts:
The key was using the below line in my HealthScript :
PlayerBase player = (PlayerBase)FindObjectOfType(typeof(PlayerBase));
http://answers.unity3d.com/answers/1348311/view.html
I'm trying to write a little mod for Kerbal Space Program a game which uses Unity. I've got a class that is a child of MonoBehaviour which loads correctly and all. Part of this mod involves creating a new light source in the current scene. My question is as follows: is it possible for me to create a new Unity light source in the current scene using a script rather then the unity engine scene editor (which I obviously don't have access too as a modder).
Example of the sort of thing I'm looking for (I know it won't actually look anything like this but just to give you an idea of what I need)
UnityEngine.getCurrentScene().createObject(new Light(pos, direction, color, strength));
Create the gameobject and add the light component:
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour {
void Start() {
GameObject lightGameObject = new GameObject("The Light");
Light lightComp = lightGameObject.AddComponent<Light>();
lightComp.color = Color.blue;
lightGameObject.transform.position = new Vector3(0, 5, 0);
}
}
I'm currently working on an inventory system in Unity3D, and came upon a weird problem. I have created non-MonoBehaviour classes for my inventory system (in case that matters), so that I have an Inventory class which holds a list of Slot objects, which in turn holds a list of Item objects.
Then I added a component script to my "HudInventoryPanel", called "HudInventoryController", which looks like this:
using UnityEngine;
using System.Collections;
public class HudSlotController : MonoBehaviour {
private InventoryController ic;
// Use this for initialization
void Start () {
ic = GetComponent<InventoryController>();
}
// Update is called once per frame
void Update () {
}
}
However, inside the Start() method, the InventoryController (part of my Player) hasn't been created yet, and it seems to me like the gameobjects are created in alphabetical order...?
How should I deal with this problem?
You can specify script execution order in the project settings (Edit -> Project settings -> Script execution order), so use that to make sure your scripts are executed in the correct order. In addition to that, you can use the Awake() method as all Awakes are executed before any Start() method. Hope a combination of these helps you!
I solved this by creating an intermediate variable in my InventoryController script, plus creating a "manual" getter; https://gist.github.com/toreau/f7110f0eb266c3c12f1b
Not sure why I have to do it this way, though.