How to have custom script icons other than using "Assets/Gizmos" in Unity3D - unity3d

I know this was asked a lot of times probably .. but it is very often answered wrong.
What I want is:
Use a custom icon for specific components/scripts in the Inspector (e.g. Figure 2 and Figure 3) and the ProjectView (e.g. Figure 1)
What I do so far:
For each component/class that shall have the icon I have an accroding Icon file in the folder
Assets/Gizmos/<Path>/<To>/<Namespace>/<ClassName> icon
and in the Import Settigns set TextureType to Editor GUI and Legacy GUI
This is working fine .. and until now the only way how I could achieve that (having in mind the below section What I definitely do NOT want).
But
However, I wondered if there is really no better way having to have a unique Icon file for each script. This makes the project/UnityPackage unnecessarily huge. Also if I rename a class I always have to rename the according icon file as well ... This imply doesn't feel right!
Most Unity build-in Behaviours and Components have a unique icon. But also external Packages coming from the new PackageManager have built-in icons and sometimes a Gizmos folder but it is not following the above naming rule ... so apparently the icon is configured somehow else for them.
Therefore my questions:
Is there any better way to have those icons for scripts/components?
Preferably scripted and reusing ONE single icon file instead of having the same icon in multiple differently named files.
And/or also Where/How are those icons defined for the scripts coming from the PackageManager?
!NOTE! What I definitely do NOT want:
Show the Icon also in the SceneView for all GameObjects having those components attached (e.g. Figure 4). This is caused by either selecting the icon for this script via the Inspector as in Figure 5 (as allways suggested e.g. in this post or here and even by Unity - Assign Icons ) or using OnDrawGizmos or DrawGizmo. This is not happening using the approach I use currently with the Gizmos folder!
Update
Because this was suggested in this answer: I also know that I could do that and turn them off via the Gizmos settings of the SceneView. But imagine I have like 25 different modules and various different icons each. I don't want to have to disable their Gizmos in the SceneView settings one by one on a per project basis! Even the provided script seems like a vast hackaround. Reflection would be the very last resort I would ever take. Also I'ld prefer to not even have those icons appear as possible Gizmos at all instead of disabling them all.

You can set the icon with figure 5 and then turn the gizmos for that icon off from the gizmos drop down.
Edit: Injunction with the step above you could try this script derived from here it uses reflection to find the class responsible for turning off the the gizmos and icons. This would execute any time your scripts recompiled to keep those icons off or if you added any new icons to the autohide icon file. Note: scriptClass will be an empty string for built in components eg.Camera, AudoSource
using UnityEditor;
using System;
using System.Reflection;
public class DisableAllGizmos
{
[UnityEditor.Callbacks.DidReloadScripts]
private static void OnScriptsReloaded()
{
var Annotation = Type.GetType("UnityEditor.Annotation, UnityEditor");
var ClassId = Annotation.GetField("classID");
var ScriptClass = Annotation.GetField("scriptClass");
var Flags = Annotation.GetField("flags");
var IconEnabled = Annotation.GetField("iconEnabled");
Type AnnotationUtility = Type.GetType("UnityEditor.AnnotationUtility, UnityEditor");
var GetAnnotations = AnnotationUtility.GetMethod("GetAnnotations", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
var SetIconEnabled = AnnotationUtility.GetMethod("SetIconEnabled", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
Array annotations = (Array)GetAnnotations.Invoke(null, null);
foreach (var a in annotations)
{
int classId = (int)ClassId.GetValue(a);
string scriptClass = (string)ScriptClass.GetValue(a);
int flags = (int)Flags.GetValue(a);
int iconEnabled = (int)IconEnabled.GetValue(a);
// this is done to ignore any built in types
if (string.IsNullOrEmpty(scriptClass))
{
continue;
}
// load a json or text file with class names
const int HasIcon = 1;
bool hasIconFlag = (flags & HasIcon) == HasIcon;
// Added for refrence
//const int HasGizmo = 2;
//bool hasGizmoFlag = (flags & HasGizmo) == HasGizmo;
if (/*Compare class names in file to scriptClass == true*/)
{
if (hasIconFlag && (iconEnabled != 0))
{
UnityEngine.Debug.LogWarning(string.Format("Script:'{0}' is not ment to show its icon in the scene view and will auto hide now. " +
"Icon auto hide is checked on script recompile, if you'd like to change this please remove it from the config",scriptClass));
SetIconEnabled.Invoke(null, new object[] { classId, scriptClass, 0 });
}
}
}
}
}
Shown in the inspector with a gizmo
Hide Icon from gizmos dropdown
Icon still appears in the inspector and in the project view but not in the scene

So I did a bit more research about built in types as well as packages coming from the package manager and the asset store. Anything that is external (packagemanager or assetstore) if it has a custom icon for the script and inspector it will Always have a gizmo in the scene view. As it has its icon set using your figure 5 example, as seen in the screenshots with the debug inspector.
Also if you want to set the icon with a script or hide it ,currently reflection is your only option as these APIs are not publicly accessible.
My Script showing the debug inspector for its script
PixelPerfect package script from the packagemanager in the debug inspector
PixelPerfect Icon showing in the scene
I was hoping to add this as a comment to your original question but not enough rep yet.

Related

Where is the camera component located for ACharacter?

So I just started playing around with Unreal Engine 4. I would like to learn as much as I can, so I started with a blank C++ project.
I created a new Character class for my player character, then created a Blueprint based on this class.
The character Blueprint (or some of it's components seem to have a UCameraComponent attached to it, since after making the keybindigs for movement and look up/turn I could already use my mouse to navigate the camera.
My question is, where is this UCameraComponent located? When I open the Blueprint, it seems like it doesn't have a CameraComponent in there. I also tried searching for it in the source code of ACharacter, but couldn't find anything.
I would like to adjust the camera position related to the character because right now this camera is right inside my character mesh.
You have to add it to your class manually.
In YourCharacter.h:
UPROPERTY(EditAnywhere, Category = "Components")
USpringArmComponent* SpringArm = nullptr;
UPROPERTY(EditAnywhere, Category = "Components")
UCameraComponent* Camera = nullptr;
In YourCharacter.cpp constructor:
SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("Spring Arm"));
SpringArm->SetupAttachment(RootComponent);
Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
Camera->SetupAttachment(SpringArm);

Unity editor - How to stop field from turning blue when its edited

I am making a tool in Unity to build your project for muliple platforms when you press a button.
I started with the preferences window for the tool, and came up with an anoying thing. Whenever I change the enum value of the EnumPopup field, the field turns blue in the editor window. Is there a way to disable this?
See how in the 2nd picture the field is not blue, and in the 3rd picture the field has changed to blue? How do I prevent this from happening?
Thanks in advance!
Difficult to help without having the rest of your code.
This is Unity built-in behaviour. I tried a lot of stuff see here to disable / overwrite the built-in coloring of prefix labels but had no luck so far.
A workarround however might be to instead use an independent EditorGUI.LabelField which will not be affected by the EnumPopup together with the EditorGUIUtility.labelWidth:
var LabelRect = new Rect(
FILEMANAGEMENT_ENUMFIELD_RECT.x,
FILEMANAGEMENT_ENUMFIELD_RECT.y,
// use the current label width
EditorGUIUtility.labelWidth,
FILEMANAGEMENT_ENUMFIELD_RECT.height
);
var EnumRect = new Rect(
FILEMANAGEMENT_ENUMFIELD_RECT.x + EditorGUIUtility.labelWidth,
FILEMANAGEMENT_ENUMFIELD_RECT.y,
FILEMANAGEMENT_ENUMFIELD_RECT.width - EditorGUIUtility.labelWidth,
FILEMANAGEMENT_ENUMFIELD_RECT.height
);
EditorGUI.LabelField(LabelRect, "File relative to");
QuickBuilder.Settings.Relation = (QuickBuilder.Settings.PathRelation)EditorGUI.EnumPopup(EnumRect, QuickBuilder.Settings.Relation);
As you can see the label is not turned blue while the width keeps being flexible
Sidenotes
Instead of setting values via edito scripts directly like
QuickBuilder.Settings.Relation = you should always try and use the proper SerializedProperty. It handles things like Undo/Redo and also marks the according objects and scenes as dirty.
Is there also a special reason why you use EditorGUI instead of EditorGUILayout? In the latter you don't need to setup Rects.
EditorGUILayout.BeginHorizontal();
{
EditorGUILayout.LabelField("File relative to", GUILayout.Width(EditorGUIUtility.labelWidth));
QuickBuilder.Settings.Relation = (QuickBuilder.Settings.PathRelation)EditorGUILayout.EnumPopup(QuickBuilder.Settings.Relation);
}
EditorGUILayout.EndHorizontal();

Expand Unity Text Window Size In Inspector

I have a custom string field in the inspector and I want to give it a large box.
Currently its this:
and I want it to be this:
I looked through https://docs.unity3d.com/ScriptReference/EditorGUILayout.html but didn't seem to find anything that increases inspector window size.
Since you didn't mention what type of Input field you are using for the custom Editor and no code at-all, I will provide the possible solution. You sort it out yourself.
Simply enable wordWrap.
Depending on what you are using:
GUI.skin.textArea.wordWrap = true;
or
EditorStyles.textField.wordWrap = true;
You can even do this with the TextArea attribute.
[TextArea(3,10)]
public string text = "blah blah blah";

Show/ hide Unity 3D elements

I hope I am posting in the correct section. I know that it is possible to write a custom code in Unity so I have the following questions:
Imagine a house model in Unity. Would it be possible to have a code which helps to hide/unhide certain objects? For example, letter "W" would hide/unhide all windows, letter "C" would hide/unhide all columns etc.
If it would be possible to develop a code for that, what would be the workflow? How would Unity know what is window and what is door?
Taking one step further.. Would it be possible to have a code that unhides the next step of the project. For example, the first step would be building foundations. Would it be possible to have a code that would unhide the next step, say, 1st floor floor element, with a klick of a keyboard key? And then with the same key unhide the next step which might be 1st floor walls. And would it be possible with another key go backwards?
If such code would be possible, what do you think would be the workflow? How would Unity know which element is in which step?
Yes just have a class with an array of objects to show/hide and another property for what button will do it. Then just have a method that will hide/unhide each object in that class. In the update method of a behavior just check the input and call the method of the class based on what button was pressed.
Would it be possible to have a code which helps to hide/unhide?
Yes, you can do that by calling GameObject.SetActive() function
door.SetActive(true); // door is a game object;
How would Unity know what is window and what is door?
You can give the window/door a name, then access the game object by name
var door = GameObject.Find("MyDoor") as GameObject;
Would it be possible to have a code that would show the next step, say, 1st floor floor element, with a klick of a keyboard key?
Yes, you can do that with code snippet below:
int step = 1;
void Update() {
if (Input.GetKeyDown("space")){
print("space key was pressed");
step++;
}
if(step == 1) {
// do sth
}
else if(step == 2) {
// do sth
}
}
Given the above snippet, your last answer can be easily deduced.
I see 2 ways of doing what you asked.
1st way
GameObject[] walls;
walls = GameObject.FindGameObjectsWithTag("Wall");
foreach (GameObject wall in walls)
{
wall.setActive(true);
}
What you will have to do, besides the code, is to assign to those object a correct tag (like "Wall" "Window" "WatheverYouWillNeed"). So you can easily find all objects by giving them some kind of order (with tags).
Best practice tip
You may want to create a static class "Tags", and set public constants string inside the class, with all tag names.
public static class Tags
{
public static const WINDOW_TAG = "Window";
// ... more tags
}
2nd way
If what you want to set is only "visibility", you may want to modify only camera tag rendering. It doesn't even require any cycle at all. When you want to view windows, you just tell your camera to render the tag "Window".
// Turns on Windows Layer on mask using an OR operation
private void Show()
{
camera.cullingMask |= 1 << LayerMask.NameToLayer("Window");
}
// Turn off the bit using an AND operation with the complement of the shifted int:
private void Hide()
{
camera.cullingMask &= ~(1 << LayerMask.NameToLayer("Window"));
}
It may look odd the second option, but keep in mind that the cullingMask is composed of bits, and every bit is a Layer defined by your tags. The "Everything" culling mask is 111111. If you want to see only Window, for example, and window is the last element, your culling mask would look something like 0000001
Hope it helped! :)

open and play a scene in Unity3d

I have done a project with many scenes in Unity3D.
In the first scene there are buttons, each of them will play a scene when clicked.
For example, if the player clicks the button “Show the balloon”, then the scene called Balloon (which contains a balloon object and its animation) will be opened.
How can I do it using JavaScript code?
See Application.LoadLevel(...).
From the documentation:
[...]. Before you can load a level you have to add it to the list of levels
used in the game. [...]
// Loads the level with index 0
Application.LoadLevel (0);
// Load the level named "HighScore".
Application.LoadLevel ("HighScore");
First thing you have to do is add all the levels you want into the Build Settings Property.
Go to Unity or File Menu, Build Settings, and drag and drop your scenes into the scroll window. Then it'll assign them a logical number (or you can reference by name).
Application.LoadLevel(0); // this loads the first level in the list
Application.LoadLevel("nameoflevel"); //does the same thing numerically except by name
Application.LoadLevel(Application.loadedLevel); //reloads current level
Application.LoadLevel(Application.loadedLevel + 1); //loads the next level in order
Application.LoadLevel(Application.loadedLevel - 1); //loads the prior level in order
Application.LoadLevel(Application.levelCount - 1); //loads the last level in list
The int version of LoadLevel takes the id from build settings.
You can also call the string version, which takes the scene name from the project view (Though it still has to be in build settings for it to be found)
Go to File->Build Settings and drag your scenes there then use following.
Application.LoadLevel("Ballon");
If you want to reload the current level, you can use
Application.LoadLevel (Application.loadedLevel);
You'll, of course, need to make sure to manually reset or destroy anything that was created by the scene and marked as DontDestroyOnLoad.
And yes, the only way to put levels in any order in your build is from the build settings menu. You can jump around to which level is loaded by specifying its name or build order, but if you wanted to insert your levels in order in the build sequence and just want to jump from one level to the next (ie, Menu->Level1->Level2->EndGame), you can use
Application.LoadLevel (Application.loadedLevel + 1);