See child gameObjects from code - unity3d

Is it possible to put parent gameObject in UnityEditor and see child gameObjects from code? I tried to create custom class with necessary structure, nut unity doesn't understand it.
public Path Path1;
public Path Path2;
public Path Path3;
public Path Path4;
[Serializable]
public class Path : MonoBehaviour
{
public List<Way> Ways;
public Path ()
{
}
}
Way class
[Serializable]
public class Way : MonoBehaviour
{
public Transform StartPoint { get; set;}
public Transform[] EndPoints { get; set;}
public Transform[] AngleWaypoints { get; set;}
public Way ()
{
}
public Way (Transform startPoint, Transform[] endPoints, Transform[] angleWaypoints)
{
this.StartPoint = startPoint;
this.EndPoints = endPoints;
this.AngleWaypoints = angleWaypoints;
}
}

Your class needs to inherit from MonoBehaviour, maybe it is it that your missing.
It should look like
class myClass : MonoBehaviour{
}
You have selected your GameManager script. Try selecting Path_1, all public variables of Path class should appear in the UnityEditor.
Also you can change the UnityEditor Mode to Debug, which will show much more information UnityEditor Debug Mode

Related

Calling protected variable from another class

I need to call a protected variable from a public class into an if statement in a private method of another public class
I am programing a video game in unity and I need to use a bool variable (that shows if the character is out of stamina) in an if statement to determine whether or not the character can run
This is what my code looks like excluding everything unrelated to the problem
Public class CharacterStats : MonoBehaviour
{
[SerialzeField] protected bool Tired;
}
Public class PlayerMovement : MonoBehaviour
{
Private void HandleRunning()
{
If (Input.GetKeyDown(KeyCode.LeftShift) && X != True)
{
Speed = RunSpeed;
}
}
}
X is where I want the Tired variable to be.
Use a public readonly property like e.g.
public class CharacterStats : MonoBehaviour
{
// Keep you serialized field protected
[SerialzeField] protected bool tired;
// Have a public read-only accessor property
public bool Tired => tired;
}
and then e.g.
public class PlayerMovement : MonoBehaviour
{
// Somehow you will need to get a reference to the CharacterStats instance
// e.g. via the Inspector
[SerializeField] private CharacterStats stats;
[SerializeField] private float RunSpeed;
private float Speed;
private void HandleRunning()
{
if (Input.GetKeyDown(KeyCode.LeftShift) && !stats.IsTired)
{
Speed = RunSpeed;
}
}
}
Alternatively (and my apologies to #aybe who had answered this) you can actually directly serialize a property using explicitely
[field: SerializeField] public bool Tired { get; protected set; }
this is a property which can be accessed by everyone but only this and inherited classes (and due to the serialization now the Inspector) have the permission to set the value.
In general: Fix your casing! In c# all keywords are lower key!

Unity - issue with AudioClip array

I'm trying to make an audio player in Unity.
I first created a ResourceManager, that has a
AudioClip[] array.
public class ResourceManager : MonoBehaviour
{
public AudioSource audioSrc;
public AudioClip[] clips;
private int trackNum = 0;
public void Awake()
{
audioSrc = GetComponent<AudioSource>();
audioSrc.Stop();
...omitted...
public void LoadClip()
{
audioSrc.clip = clips[trackNum];
}
}
So that they appear in the Clips drag-and-drop box.
However, I want to make the AudioClip array static in ResourceManager static, so other scripts (e.g. PlayPause.cs can access clips statically (via function calls).
But the problem is once I make clips static, the drag-and-drop for disappears.
Is there a way to fix that? Or are there some better design patterns? Thanks.
You can e.g. simply do
public class ResourceManager : MonoBehaviour
{
...
// This is the one in the Inspector
// Usually I keep the Inspector private and only provide public access
// where needed via properties
[SerializeField] private AudioClip[] clips;
// This will be set in Awake to the ones from the Inspector
// readonly for others, only this class can assign it
public static AudioClip[] Clips { get; private set; }
public void Awake()
{
Clips = clips;
...
}
}
The alternative suggested is make the ResourceManager a so called singleton like e.g.
public class ResourceManager : MonoBehaviour
{
// Here you store your own instance reference
// and provide public readonly access
public static ResourceManager Instance { get; private set; }
[SerializeField] private AudioClip[] clips;
public AudioClip[] Clips => clips;
...
public void Awake()
{
// Make sure only one instance exists at a time
if(Instance && Instance != this)
{
Destroy(gameObject);
return;
}
_instance = this;
// optional: Don't destroy this instance when the scene is switched
// Careful: Make sure this applies also to the AudioSource instance!
// For now I assume it is either attached to this object or a child
// if not simply do the same DontDestroyOnLoad on it as well
DontDestroyOnLoad (this.gameObject);
...
}
public void LoadClip()
{
audioSrc.clip = clips[trackNum];
}
}
And then access everywhere ReaourcesManager.Instance.Clips
Or a built-in alternative to the singleton is using FindObjectOfType so any other script in the Scene can actually simply access
FindObjectOfType<ResourcesManager>().clips
without you having to change anything at all ;)
Except as said I would make it
[SerializeField] private AudioClip[] clips;
public IReadonlyList<AudioClip> Clips => clips;
depending a bit of course what exactly you want to do with the clips but this way the array can not be altered by any other script

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);
}
}
}

Can't draw Serializable class on Unity Inspector

This is my Example class and MonoBehaviour script:
using UnityEngine;
using System;
[Serializable]
public class TestSerializableClass
{
public int a;
public string b;
}
public class TestScript : MonoBehaviour
{
public TestSerializableClass field1;
[HideInInspector] public TestSerializableClass field2;
}
and this is the editor script for the MonoBehaviour Script
using UnityEditor;
[CustomEditor(typeof(TestScript))]
public class TestScriptEditor : Editor
{
SerializedProperty testClass;
public override void OnInspectorGUI()
{
DrawDefaultInspector();
SerializedProperty testField = serializedObject.FindProperty("field2");
EditorGUILayout.PropertyField(testField, true);
}
}
This is how my inspector for TestScript looks.
Why doesn't it draw the "field2" varialble like the first one?
Can I do it with Editor script and property field? How?
(the includeChildre flag is true)
Remove the HideInInspector attribute from field2

Unity3D: UnityEvent with inputs does not appear in editor

Does anyone know how make complex UnityEvent appear in editor?
public class Test : MonoBehaviour
{
public UnityEvent myEvent;
public UnityEvent<string> myAnotherEvent;
}
myEvent appears just fine, but myAnotherEvent does not.
Thanks in advance.
UPD Also tried to override the UnityEvent like:
public class NewEvent : UnityEvent<string>
{
}
public class Test : MonoBehaviour
{
public UnityEvent myEvent;
public NewEvent myAnotherEvent;
}
didn't seem to help.
[System.Serializable]
public class NewEvent : UnityEvent<string>
{
}
public class Test : MonoBehaviour
{
public NewEvent myAnotherEvent;
}
You need to inform that your new class is serializable.