Unity Inspector: require elements when boolean checked - unity3d

How do I automatize the inspector such that if you don't click a serialized boolean, a component doesn't show up, when you click it, the corresponding component automatically shows up (as if it was required)?
Dropping journal not checked
You see I have not checked the boolean and the other component is not showing up indeed.
But when I click on the boolean I'd like that automatically this script shows up on the inspector.
Like this:
Dropping journal checked image
How can I do this?

You need to create custom editor.
Official documentation
using UnityEngine;
public class MyScript : MonoBehaviour
{
public bool Checked = false;
public GameObject SomeField;
}
Editor script.
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(MyScript))]
[CanEditMultipleObjects]
public class MyScriptEditor : Editor
{
SerializedProperty Checked;
SerializedProperty SomeField;
void OnEnable()
{
Checked = serializedObject.FindProperty("Checked");
SomeField = serializedObject.FindProperty("SomeField");
}
public override void OnInspectorGUI()
{
var myScript = (MyScript)target;
serializedObject.Update();
EditorGUILayout.PropertyField(Checked);
if(myScript.Checked)
EditorGUILayout.PropertyField(SomeField);
serializedObject.ApplyModifiedProperties();
}
}

You can use Attribute ExecuteInEditMode and then check in update function if boolean is true then just Add the second script to base component Here I attached simple script that give you idea
[ExecuteInEditMode]
public class TestScript : MonoBehaviour
{
public bool show = false;
void Update()
{
if (show)
{
base.gameObject.AddComponent<objectyouwanttoadd>();
}
}
}
Also you can implement logic that if other object is already attached or not also if you uncheck show bool then remove added object, also if current platform is unity Editor then only attach other component etc...

Related

Not able to change text from another script

How it should work - when i click on the UI button, the score increases and is displayed using text.
How it's working - An error that says 'NullReferenceException: Object reference not set to an instance of an object'
There are two scripts on two different game objects.
Player Script
using UnityEngine;
public class Player : MonoBehaviour
{
ScoreManager scoreManager;
private void Start()
{
scoreManager = new ScoreManager();
}
public void UpdateScore()
{
scoreManager.IncrementScore();
}
}
ScoreManager Script
using UnityEngine;
using TMPro;
public class ScoreManager : MonoBehaviour
{
private int score = 0;
public TextMeshProUGUI scoreText;
public void IncrementScore()
{
score++;
scoreText.text = score.ToString();
}
}
When I use Debug.Log(score.ToString()), it displays the score in the console. But when I use textmeshprougui, it gives an error.
Also, I've dragged the text into the inspector, so that cannot be a problem for the null referrance. I've checked it multiple times.
Why am I not able to update the text from another script?
Null reference exception is in your Player.cs script and caused because of the code in your Start() method
ScoreManager scoreManager;
private void Start()
{
scoreManager = new ScoreManager();
}
Remove the code in your Start() method. Because there is a field ScoreManager scoreManager;, you drag the gameobject which has the script ScoreManager.cs into its slot in the Player.cs script. Now you have the reference of the ScoreManager.cs script in your Player.cs script.
Now, you are resetting its reference in your Start() method. This caused the null reference exception.

Photon, RPC not working, how can I fix my code?

I'm trying to synchronize text in a unit between players, but I'm getting an error.
I just need to sync the text
[1]: https://i.stack.imgur.com/0l98U.png
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Photon.Pun;
using UnityEngine.UIElements;
public class Sync : MonoBehaviourPunCallbacks
{
private PhotonView view;
public Text textGame;
public Text copied;
void Start()
{
view = GetComponent<PhotonView>();
}
public void sync()
{
if(view.IsMine)
view.RPC("ViewAll", RpcTarget.AllBuffered, textGame.text);
}
[PunRPC]
public void ViewAll(string tG)
{
tG = copied.text;
Debug.Log(tG);
}
}```
пппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп
The error is telling you that the "view" variable has not been assigned and is therefore null.
To assign it you can make that field public, and in the inspector you
assign the photonView you want, I guess that of the player.
Alternatively you can assign "view" not from the inspector but in a
Start() or Awake() method. If the photonView you want to associate is
on the same GameObject as the script, you can write like this:
void Awake()
{
view = GetComponent();
}
However, the easiest answer is to replace "view" with "photonView".
It will have the same result as the solutions described above, but it will be very simple.
enter code here
public void sync()
{
if(photonView.IsMine)
view.RPC("ViewAll", RpcTarget.AllBuffered, textGame.text);
}
I have not directly given you the simple slogan to make you fully understand the problem and to help you solve it.

Correct way to serialized in custome editor?

this is test script
public class Test : MonoBehaviour
{
public int something;
}
1.if i directly set the value without use serializedProperty
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
private Test test;
private void OnEnable()
{
test = target as Test;
}
public override void OnInspectorGUI()
{
test.something = EditorGUILayout.IntField("Something", test.something);
if (GUI.changed)
EditorUtility.SetDirty(this);
}
}
value is saved successfully in editor
result
but if i restart unity,the value will be reset,this means the value is not serialized to disk?
2.if use serializedProperty
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
public override void OnInspectorGUI()
{
serializedObject.Update();
var something = serializedObject.FindProperty("something");
something.intValue = EditorGUILayout.IntField("Something", something.intValue);
serializedObject.ApplyModifiedProperties();
}
}
everything is right
my question
why first way can save value in editor but not serilized to disk? is my script something wrong?
what's the true difference bewtween them?
second way is the correct way to serilized?
You should use SerializedProperty class for editing properties on objects in a completely generic way that automatically handles undo and styling UI for Prefabs.
[CustomEditor(typeof(Test))]
public class TestEditor : Editor
{
SerializedProperty something;
void OnEnable()
{
/* Fetch the objects from the GameObject script to display in the inspector */
something = serializedObject.FindProperty("something");
}
public override void OnInspectorGUI()
{
/* Update the serializedProperty - always do this in the beginning of OnInspectorGUI. */
serializedObject.Update();
/* Display your field in the inspector */
EditorGUILayout.PropertyField(something);
/* Apply changes to the serializedProperty - always do this in the end of OnInspectorGUI. */
serializedObject.ApplyModifiedProperties();
}
}

Custom onClick list

Can i create custom region with grouped methods for list onClick like dynamic and statics?
like this
Yes and no! ^^
Yes, you can create your own event type taking a parameter and assign dynamic callbacks to it. What you are looking for is UnityEvent.
For the dynamic parameterized ones see UnityEvent<T0> to UnityEvent<T0, T1, T2, T3> depending on how many parameters you need.
For the example with a single int it would be (exactly as in the API example)
// Since Unity doesn't support direct serialization of generics you have to implement this [Serializable] wrapper
[Serializable]
public class MyIntEvent : UnityEvent<int>
{
}
public class ExampleClass : MonoBehaviour
{
public MyIntEvent m_MyEvent;
}
No, you can not simply change the existing implementation of UI.Button.onClick which is parameterless.
What you could do, however, is build a new component and attach it on a button like
[RequireComponent(typeof(Button))]
public class ExampleClass : MonoBehaviour
{
[SerializeField] private Button _button;
public MyIntEvent onClickWithIntParameter;
private void Awake()
{
if(!_button) _button = GetComponent<Button>();
_button.onClick.AddListener(HandleOnClick);
}
private void HandleOnClick()
{
// Wherever you get your int from
var value = 123;
onClickWithIntParameter.Invoke(value);
}
}
In the case that [Serializable] isn't working for you try [System.Serializable] or using System; at the top.
For Those who want to create a custom event Script:
I made a collision detection script. The events set in the inspector are called when a collision is detected. Just like a button.
https://i.stack.imgur.com/r4epP.png
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEngine.Events;
public class CollisionCallFunc : MonoBehaviour {
[System.Serializable]
public class CollisionEvent : UnityEvent<object> {
public object value;
}
[SerializeField]
private CollisionEvent collisionEvents = new();
private void OnCollisionEnter(Collision collision) {
try {
collisionEvents.Invoke(collisionEvents.value);
} catch(System.Exception exception) {
Debug.LogWarning("Couldn't invoke action. Error:");
Debug.LogWarning(exception.Message);
}
}
private void OnCollisionEnter2D(Collision2D collision) {
try {
collisionEvents.Invoke(collisionEvents.value);
} catch(System.Exception exception) {
Debug.LogWarning("Couldn't invoke action. Error:");
Debug.LogWarning(exception.Message);
}
}
}

Unity scriptable object only serializing the unity objects

I am trying to make a spell system. My base class for the system looks like this:
public abstract class MagicBook : ScriptableObject {
public Sprite bookSprite;
public float manaCost;
public float coolDown;
public bool rapidFire;
[HideInInspector] public bool coolDownElapsed;
public virtual void OnActivate() {
}
public virtual void OnActivate(Vector3 position, Quaternion rotation) {
}
}
Then I have another class extending from MagicBook where I override the OnActivate function. My problem now is that in the inspector only the variable bookSprite is showing and all the other values are not there. I tried adding an [SerializeField] in front of the variables and define them new in the extending class. But they still dont show. Has anyone an idea why they are not showing or how I can fix this?
Thanks for your help and time.
Did you create Asset for ScriptableObject?
Add attribute to extended class:
[CreateAssetMenu(fileName = "Data", menuName = "ScriptableObjects/NewBook", order = 1)]
And then create asset with
Another idea:
Probably you have custom drawer for this object, but...
Turn your inspector into debug mode and check if properties are visible there.
Cannot reproduce this issue with Unity 2020.1.0f1.
public class NewBook : MagicBook
{
}