BetterUnity

Better Unity

openupm

A collection of modifications/additions (scripts/prefabs) which enhance [for me] the overall flow of using the Unity Engine.

Philosphy

A tool that is robust but minimal. Modularly modifiable with minimal cross-dependencies. Avoiding frankensteinian architecture and preferring a simpler, familiar interface and codebase.

Purpose

There are some key features pan other game engines that seem to be lacking in Unity and this is a package to resolve some of those problems while adding some new ones to their already very solid game engine.

Installation

You can download the latest .unitypackage through Releases and double-click to import it.

or

You can import it through Unity’s package manager using the url:

https://github.com/sudotman/BetterUnity.git

Installation instruction: "Installation Demo"

Contribute to the project

Click here to see general collaboration information and the star history.

Contents / Documentation

Table of Contents:

1. Inspector Additions

1.1 CallInEditor

Allows you to call/execute functions in your script from your inspector.

You can expose normally to the inspector in Unity and it works great. Sometimes, you would want to have a button set to call a function of your liking from the inspector and people tend to use workarounds (such as, setting a boolean and then calling a function after checking the boolean from Update) or creating your custom inspector and having a button there.

This is a much more easier and simpler addition to your existing scripts and can be called using a simple attribute.

Usage:

[CallInEditor]
void HelloGitFunction(){
    ....

"1.1 Demo - Call in Editor"

You may want finer control over your button that appears in the inspector in the terms of the size, the label or the place it appears at. In that case, you can use the alternative attribute field described below.

Usage:

[InspectorButton("funcToBeCalled")]
public char random;

The above snippet will create a button named Random and will call funcToBeCalled function from inside your script when pressed. The public character can be any variable type, I prefer char for saving miniscule memory.

You can also specify the size of the button (by default, it will try to scale your button size to your text size):

[InspectorButton("funcToBeCalled",100)]
public char myButton;

"1.1 Demo - Inpsector Button"

You can also specify a custom text for your button (by default, it takes button name from the variable name below it [the aforementioned variable will still be required in the script regardless of if we use this]):

[InspectorButton("funcToBeCalled",100,"Custom Name Here!")]
public char myButton;

For dynamic size:

[InspectorButton("funcToBeCalled","Custom Name Here!")]
public char myButton;

*The extra step to create a character and invoke the function through specifying the name is because of trying to workaround OnGUI/OnInspectorGUI; this is the only workaround as of now due to the way Unity is built - the CallInEditor attribute relies on reflection to find the proper function, too.

1.2 Better Decoration

Various inspector fields which can be used to output text to the Inspector without having to write a custom editor GUI for simple text labels or to have more pleasing looking headers.

Usage:

[Optional]
public int additionalPoints;

// Standard Variable
public float mainPoints;

[Label("This is a normal label")]

[BetterHeader("Main Header")]

[BetterHeader("Main Header aligned to the left", true)]

[BetterHeader("Sub Heading aligned to the left",true,true)]

[SerializeField, Layer]
int layer;

[NullCheck]
public Transform myField;

"1.2 Demo - Inspector Fields"


For a starting point getting familiar with the fields, check the test script out: TestScript.cs

1.3 Tidbits

These are attachable objects/components to GameObjects as opposed to the inspector additions which get injected into the inspector directly.


1.3.1 BetteRename

A lot of the times when developing, you have similar children which you want to be named incrementally with your desired prefix. Instead of manually going in and doing it, this module allows me to do more it quickly and effeciently, by attaching a script to the parent.

Further, when duplicating objects and creating new ones, Unity appends (x) [x being the current duplicate] and sometimes you would want the objects to be named differently. All new objects will also be renamed appropriately, automatically.

Attach ‘BetteRename’ to any game object.



1.3.2 BetterScale

Allows you to always have uniform scaling on any GameObject. Works similar to the BetterTransform component but given incase you dont wish to override default transform and just want the uniform scaling on one object.

Attach ‘BetterScale’ to any game object.


2. Helpers

A collection of extension functions which can be called in other scripts for ease-of-use.

2.1 Scale Range

Scale a value from a previous range to a new range (remap it linearly).

myFloatValue.ScaleRange(0,100,10,30);


2.2 Destory Children

Destroy all children of a parent.

transform.DestroyChildren();

When calling the function from the editor:

transform.DestroyChildrenEditor();


2.3 Minus/Plus Float Vector 3

Subtract one float value from x, y, z components of a Vector3.

myVector3.MinusFloatVector3(2.5f);

Add one float value to x, y, z components of a Vector3.

myVector3.PlusFloatVector3(4.2f);


2.4 LookAtY

Look at but rotate only across the Y axis (say, for an enemy that needs to turn to you at all times).

transform.LookAtY(player.position);


2.5 Grounded/Distance From Ground

Returns distance between two vectors but its grounded. (ignoring their Y-position during calculation)

player.position.DistanceFromGround(objective.position);


2.6 Return a random item from a list

Get a random item from a list

currentItem = myList.RandomItem();


2.7 Ease In Interpolation

Performs a Ease-In Interpolation on our specified Vector3.

myVector3.EaseInLerp(myFinalVector3,currentTime);


2.8 Ease Out Interpolation

Performs a Ease-Out Interpolation on our specified Vector3.

myVector3.EaseOutLerp(myFinalVector3,currentTime);


2.9 Smooth Step Float Interpolation

Returns a smooth stepping interpolation between two floats.

HelperFunctions.SmoothStep(currentTime,startFloat,EndFloat);


2.10 Hex To Color

Allows you to pass a Hexadecimal color string and use in the native Unity’s RGB color system.

Color myColor;
myColor = myColor.HexColor("#60c47e");

"2.10 - Hex to Color"

If an incorrect hex string is passed and/or it can’t be parsed, a warning is logged while a default black color is returned.

"2.10 - Hex to Color Error" "2.10 - Hex to Color Error"

There are plenty more functions which are not mentioned here because of their usages being quite insigniicant. Look through HelperFunctions.cs for all the remaining functions, they are aptly documented.


2.11 Serializers

Gives you different serializers which allows you to easily pass common Unity data structures into files and vice versa.

SerializedVector3 serializedVector3;
SerializedQuaternion serializedQuaternion;

Quick code to get started with conversion of Vector3 into Serialized JSON data:

List<SerializedVector3> anchorPositions = new List<SerializedVector3>();
List<SerializedQuaternion> anchorRotations = new List<SerializedQuaternion>();

foreach (var gameObjects in arrayOfGameObjects)
{
    Vector3 currentPositionData = anchorGameObject.transform.position;

    Quaternion currentRotData = anchorGameObject.transform.rotation;

    anchorPositions.Add(Vector3Extensions.FromVector3(currentPositionData));
    anchorRotations.Add(QuaternionExtensions.FromQuaternion(currentRotData));
}

SerializedVector3[] actualPositions = anchorPositions.ToArray();
SerializedQuaternion[] actualRotations = anchorRotations.ToArray();

string jsonPositions = JsonConvert.SerializeObject(actualPositions);
string jsonRotations = JsonConvert.SerializeObject(actualRotations);

byte[] dataPos = Encoding.ASCII.GetBytes(jsonPositions);
byte[] dataRot = Encoding.ASCII.GetBytes(jsonRotations);

UnityEngine.Windows.File.WriteAllBytes(localJSONPath, dataPos);
UnityEngine.Windows.File.WriteAllBytes(localJSONPath, dataRot);

Serializables.cs has more information about every function/class and extensions. Deserialization/Serialization is also available in the same script.


2.12 BetterRaycast

A simple one-liner to allow a better raycast function. Usually, when Raycasting, we also like to Debug and see the visual output of our raycast being hit. This encapsulates it all into one single line.

The hit is passed by reference and is updated automatically.

RaycastHit hit;
hit.BetterRaycast(startPosition, direction, raycastDistance);

2.13 Vector3FromString

Is able to parse a Vector3 from a string.

string s = "(-2.24,3.92,0.00)";
Vector3 test = s.StringToVector3();


3. Toolbar Tools

Tools to do various functions, called by menus.

3.1 Rename Suite

Works similar to BetterRename except its for remaining them only once. [We can attach the script, do the rename, and then remove it if we would want but this has a much cleaner UX]. Further, it allows you to rename any random [from anywhere to anywhere] selection at any place in the heirarchy.

3.2 Setup Default Project

A one click button that set-ups directories in our project folder in a standardish way.

"3.2 Demo - Default"

3.3 Select All With

Another wizard to select all the objects with the specified:

"3.3 Demo - Select"

3.3.1 Select All with Generic

Often times we end up with frankenstienian structure in the heierarchy of our project. Imagine a dashboard inside of a car being setup using a canvas with various TextMeshPro’s being nested inside more Canvas Elements until there are atleast 20-30 elements inside other sub components. The normal search function (including the aforementioned BetterUnity’s select all with) ends up showing objects in the entire heirarchy during a search even if we search by type.

‘Select all with generic’ allows you to select any object type that exists below the currently selected object - allowing faster modifications of components at the same time.

"3.3 Demo - Select Generic"

3.4 Mesh Combine Wizard Tool

Made from taking the tool by @sirgru as the base of it. Allows you to combine multiple meshes into one in one easy click. Allows the generation of Secondary Meshes too if needed. Combines mesh renderer and the mesh filter together of any two meshes into one also making it into prefab.

"3.4 Demo - Mesh Combine Wizard"

4. BetterContext

A collection of additions to various context menus throughout Unity.

4.1 Move ATB

Right click on any two GameObjects in the heirarchy and move the objects to each other as needed.

4.2 Solve Import

Right click on any GameObject in the heirarchy to “Resolve Import Issues”. A lot of times when importing 3D models, we tend to get empty objects, cameras, lights etc [usually dependent on the way the modeller exports them] and hence this button gets rid of them in one-go.

"4.1 Demo - Solve Import"

4.3 Other Contexts

"4.2 - AudioSource"

5. Debug Tools

Some small tools to allow for more effecient debugging.

5.1 BetterDebug:

BD (BetterDebug) is a bunch of extensions to the default Debug class which allows greater control over Debugging/Logging.

BD.Log("Test");
int testCounter = 0;
float testTimer = 0.6f;
BD.Log2(testCounter,testVar);

5.2 BD Universal:

Unity has a great Debug system but lacks in outputting it while full-screened/inside VR and hence this is an Unreal-Inpsired simple way to display all Debug Log messages on the screen. All messages fade away after a while and also start replacing old logs if too many are outputted quickly.

How to use: Add LogToScreen as a component to any GameObject in your scene. And, every log subsequently called using ‘Debug.Log’ will be automatically outputted to both the console and the screen.

"3.1 Demo - Debug To Screen"


5.3 Simple FPS Counter

A very simple skeletal frames-per-second counter. Inverses unscaled delta time to output fps on the screen.

"3.2 Demo - FPS Counter"


6. Better Transform

An extension of the existing Transform component to include some ease-to-use features.

"6 Demo - Better Transform Overview"

6.0 Local/Global Switch

"6 Demo - Better Transform Overview"

6.1 Lock Scale Ratio (Uniform Scale):

Maintain the ratio of the scaling in an object’s axes when scaling a GameObject up/down. Gives a slider with an option to configure the ceiling value for the slider.

"6.1 Demo - Lock Scale"

6.2 Reset Position, Rotation, Scale:

Reset the position, rotation and scale of any GameObject locally/globally individually.

6.3 Visibility Toggle:

Sometimes you would want to only disable the Mesh Renderers and not Disable the object so that the scripts/components on them still execute. This disables all the Mesh Renderers in this GameObject and all the children renderers.

"6.3 Demo - Visibility"

6.4 Make Unit Scale Parent:

For a lot of use-cases in Unity [wanting to have a unit scale or have positioning, rotation start from zero], we tend to create new objects and then assign it as a parent. This button does that.

"6.4 Demo - Unit Scale"

6.5 Unreal-Styled Camera Bookmark Hotkeys

Unreal offers a way in the scene to set “camera” position/rotation as bookmarks with “Ctrl+1/Ctrl+2/Ctrl+3” to set the bookmarks and then “1,2,3” respectively to jump to those bookmarks. [This shortcut might already be bound to something else. Resolve any conflicts as you please]

"6.5 Demo - Unreal"

6.6 Visualize Normals

We need to visualize normals plenty of times for multiple of reasons when working in 3D. This simple click will start visualizing the normals in the sceneview on the currently selected object.

You can define ‘normal length’ to define the size with which normals are displayed.

"6.6 Visualize Normals"

6.7 Metrics Information

One of the most essential information is the number of vertices/triangles in our current scene or in our current object. Unity’s ‘Stats’ window displays only the vertices visible in the current POV and not the entire number of vertices/triangles currently existing.

The global information is cached to save performance - whenever new object is deleted/added and you want the change to instantly reflect, press the ‘Refresh Scene Vertices’ button to reflect that change in the global stats.

"6.7 Metrics Information"


7. Better Hierarchy

A few extensions to the hierarchy window that aids in the better usage of it.

7.1 Headers/Folders

An all encompassing Header/Folder system.

To create a header/folder, right click and click on ‘Create Header’ or rename any empty game object to have a prefix of "= " so for example, the name could be "= My Header".

A header is essentially just an empty game object drawn differently. You could also use it as a folder and put objects in the child of this ‘folder’.

"7.1 BetterHierarchy - Header/Folders"

7.2 Toggle Object

A lot of times, there is a need to quickly enable disable objects directly from the hierarchy - this helps in that. Adds a toggle button next to every element in the hierarchy.

"7.2 BetterHierarchy - Toggle"

7.3 Go To Parent

Ending up with heavily nested hierarchies is very common. This tool simplifies one pain point of wanting to select the parent object without disturbing the heirarchy - as the LArrow Key closes the hierarchy while selecting the parent.

"7.3 BetterHierarchy - Go To Parent"

8. World Settings

A bunch of world settings inspired by the same-name Unreal settings which have a bunch of functionalites missing in Unity.

8.1 KillY (KillZ from UE)

The value of KillY dictates the Y-Position threshold of any object below which it gets automatically destroyed.

9. VR Scripts

Useful scripts that aid in my VR development.

9.1 Head Level

Make an object always align with our headset’s level.

Mainly derived from MRTK’s head aligning script with some extra small modifications to the whole script that best suits my (and hopefully, other developers’) needs.

"8.1 Demo - HeadLevel"

"8.1 Demo - HeadLevel"

10. Miscellaneous

10.1 Controllers

Various basic controller templates, such as FPS, VR.

10.2 Navigation System

A NPC walking/navigation system which is modular and fully configurable.

Demo:

"7.1 Demo - HeadLevel"


You can reconfigure individual points/characters after using the Master Creator or you can choose to attach scripts individually and configure settings manually - both would work, and that would also work in conjunction to both approaches.

Import the sample from the package manager to get a preconfigured scene if needed.


Doing it manually: Group all the points you wish to navigate into one parent and drop the parent into the points prefab and configure everything accordingly. You can keep the PointParnet’s children messy and maybe use BetterRename to organize them (wink, wink).

Individual scripts: "8.2 - Navigation System"


A quick guiding GIF on a quick setup is given below: "8.2 - Navigation System"

General Information:


Navigation System working as it should:

"8.2 - Navigation System"


10.3 Flow Controller

A lot of times, there is a need to script events linearly (usually to follow a particular storyboard in a particular order). This scripts entails having multiple variables, multiple functions and in general just a very messy frankensteinian codebase.

This hopes to alleviate some of those messyness - trying to make a more generic flow controller which allows for triggering of events with ease also eliminating the need to do this everytime.

Also, has a Custom Inspector GUI that streamlines it some more.

"9.3 Demo - Flow Controller"

General outline:

The script would look this with sample data of a storyboard: "9.3 Demo - Flow Controller"


Contribution

Generate a pull request for whatever change you feel is necessary and I will be happy to review and add them.

The project should be good to go as is on most modern Unity versions. Prefer to not update any dependencies or any other prompts auto-detected by Unity.

Star History

Star History Chart

Current to-do:

Main Changes: