Category Archives: Unity3D-tips

Configuring Cross-platform DLL’s in #Unity3d automatically #UnityTips

Many Unity devs don’t use DLL’s, but they save a lot of time and effort. Unity hasn’t documented much of the process, but it’s surprisingly easy when you know how.

Previously, I showed how to use MonoDevelop to make C# DLL’s that work in all versions of Unity, and intelligently switch between different versions of the Unity SDK’s.

Today we’re going to finish by automating the setup, so that you can edit source code and ship C# DLL’s from any version of Unity, on any computer, on any Operating System – and they seamlessly interact with all the other people on your project (no conflicts, no errors).

Continue reading

A safe and accurate .gitignore for #unity3d (Unity5 onwards)

Github has a website for hosting gitignores. I learnt the hard way that they are NOT vetted, they can lose critical data from your project if you use them blindly.

But Unity doesn’t provide a standard gitignore for Unity projects, so people often ask: Well, OK, so what should my gitignore contain?

I’ve screwed it up a few times over last 8 years, but my current approach seems to work well. This may work for you, or not. Either way: read the notes, understand each line, and be sure you know what it’s doing before you adopt this yourself!

Problem summary/recap

Unity creates a LOT of temp files. Some of those can speed up loading time on your computer. But many of these cannot be used on other computers. e.g. Macs make incompatible files from the ones Windows PCs make. Even different Windows PCs can make incompatible versions with each other (off the top of my head: e.g. pre-compiled shaders for your current platform).

Unity also creates temp files in bad locations (e.g. the root) that follow naming conventions of critical source files (e.g. C# projects).

If you want to share your code with other projects, Unity has zero backwards compatibility, and so you MUST maintain complete separate copies of your project for every version of Unity you might ever want to use that code/unitypackage with. In most hobby game projects, you don’t care, this isn’t a problem – but we’ll go with a general solution since it’s actually no extra effort.

Finally: given Unity puts some files in the root, and it creates magic metafiles for every file it can see, you want to keep your files and Unity’s files separate. If you share the root, you’ll never know what it’s safe to delete. And if you put your non-Unity files in the Unity folder, Unity will waste time constantly indexing and interpreting them.

Solution part 1: Folder structure

Here’s the simplest correct structure for a two new Unity projects, one called “Game 42” and the other called “Some Other Game”:

/[My Game Projects]/
[Game 42]/        <- this is the folder you add to git
UnityProjects/        <- this is the Unity project folder
Game42-Unity-5.1.3/
Game42-Unity-5.3.0/
Game42-Unity-5.5.5/
[Some Other Game]/        <- this is the folder you add to git
UnityProjects/        <- this is the Unity project folder
SomeOtherGame-Unity-5.1.3/
SomeOtherGame-Unity-5.3.0/
SomeOtherGame-Unity-5.5.5/

Key points:

  • Each game has its own repository in git (this should be obvious)
  • You do NOT use the Unity folder as the root – you make it a subfolder (this allows us to know, in git, whether a file is a Unity file or not, just by looking at the parent folder)
  • You can have MULTIPLE unity folders per project, one for each version of the Unity Editor
  • Each Unity-folder is named after the Unity version it contains AND after the project; this way you get all the info you need both inside Unity and outside it to know which folder is which, e.g. when deleting files, or packaging them

Solution part 2: .gitignore

Now we build a gitignore that uses its knowledge of Unity to exclude Unity-temp files, but keep all other files. Note the [syntax] in case Unity uses different case in the folder names. I’ve never had this cause a problem, but it’s a clever feature of gitignore and I see no harm in keeping it in. Note that Unity is NOT compatible with case-sensitive file-systems.

/UnityProjects/*/[Ll]ibrary/
/UnityProjects/*/[Tt]emp/
/UnityProjects/*/[Oo]bj/
/UnityProjects/*/[Bb]uild/
/UnityProjects/*/[Bb]uilds/
/UnityProjects/*/Assets/AssetStoreTools*
# OPTIONAL: if you have huge assets you’re not ready to commit to source-control yet:
/UnityProjects/*/Assets/UNCOMMITTED.*
/UnityProjects/*/Assets/UNCOMMITTED/*

# Autogenerated VS/MD solution and project files
/UnityProjects/*/ExportedObj/
/UnityProjects/*/*.csproj
/UnityProjects/*/*.unityproj
/UnityProjects/*/*.sln
/UnityProjects/*/*.suo
/UnityProjects/*/*.tmp
/UnityProjects/*/*.user
/UnityProjects/*/*.userprefs
/UnityProjects/*/*.pidb
/UnityProjects/*/*.booproj
/UnityProjects/*/*.svd

# Unity3D generated meta files
/UnityProjects/*/*.pidb.meta

# Unity3D Generated File On Crash Reports
/UnityProjects/*/sysinfo.txt

Key points:

  • DO NOT EXCLUDE .sln, .csproj etc from your whole project! If you create any DLLs (speeds up your Unity development time, and makes it easier to share code), you NEED those files in source control.
  • …unless they are Unity’s internal ones, in which case: ignore them
  • The “OPTIONAL” line is for when e.g. you add a 4 gigabyte texture pack, and not sure you want to keep it in your project. Before blowing your git-lfs budget, you can keep those files in Assets/UNCOMMITTED, and they will be ignored by git. When you’re ready to keep them in your project, move the folder into Assets. This is slightly tricky because it needs two lines to support the existence of a possibly-empty folder, hence I kept it in.

Changing scene/level smoothly in Unity 5 (5.5+) #unitytips

Changing scenes in Unity is harder than I expected. Since version 2 of Unity, we’ve had a deceptively simple and easy to use API call:

Application.LoadLevel() // Easy to use, but wrong name, wrong parameter, no status

It’s easy, but the player-experience was horrible. Unity Pro users had access to a better API. Then, in Unity 5.3, they added the new SceneManager class, and deprecated all the old methods.

So … what’s the best practice for loading a level / changing a scene in Unity 5?
Continue reading

A real IDE for #unity3d: how to install JetBrains Rider C# editor on Mac (2017) #unitytips

I joined the EAP for Rider about a year ago, but it had too many problems for me (personally) to make it my main editor on Mac (mostly: it coped poorly with running on non-Windows machines, integration with Unity was wonky). These were all workaroundable, but life’s too short to use a wonky IDE, so I waited, and periodically re-tested to see if it was easy yet.

That day has come! Installing the C# IDE on Mac is finally quick and easy.

August 2017 update: if you’re using Unity v2017, Rider is now supported by Unity directly, so you shouldn’t need to do most/any of this!

Pre-requisites

  1. A Mac, running a recent-ish copy of OS X (I tested on latest: 10.12.3)
  2. A copy of Unity 5.5.0 or later installed on your machine

If you only make games, you probably have 5.5.x or 5.6 installed by now. My game is built in 5.4, and Unity’s backwards compatibility is non-existent (my experience so far: most versions of Unity 5 seem to corrupt each other’s project files), but you only need a copy of 5.5.x+ installed, you don’t need to be actually using it.

(as an Asset Store developer, I have copies of: 4.6, 5.0, 5.1, 5.2, 5.3, 5.4, 5.4.3, 5.4.4, 5.5.0, 5.5.2 currently installed. Unity is cool with this – no problems. Everything “Just Works”)

Alternatively, you can download and install a separate version of Mono, for your Mac, but I had a lot of problems when I did this – it got MonoDevelop confused, it got Rider confused, it got OS X confused. My advice: just don’t. Mono is not supported well enough on OS X yet.

Steps

This bit was confusing. There is no documentation anywhere from Rider explaining how to install Rider with Unity. Instead, there are partial docs, in different places, which pretend that you know everything and that you will read the minds of JetBrains dev-team and guess what to do.

So, to be really clear:

  1. Install Rider (obviously)
  2. Install the Resharper-Unity plugin (not obvious: you’re not using Resharper, and the docs suggest you don’t need it. But you do. NB: this is “auto suggested” by the installer – the installer is great)
  3. Configure Unity to use Rider
  4. Configure Rider to use Unity
  5. Install the Unity3DRider plugin

Every step is required! (as of April 2017) Do not be fooled into thinking you need fewer than “all” of them. i.e. “don’t do what I did the first time round”.

Install Rider

Easy … https://www.jetbrains.com/rider/download/

Install Resharper-Unity plugin

For me, this was automatically offered during the install process, so I accepted it. It Just Works, so I recommend you accept it too.

Configure Unity to use Rider

From the official Jetbrains instructions at bottom of this page:

Set Rider as the default External Script Editor

“This only needs to be done once.

  1. Open Unity.
  2. Go to Edit → Preferences → External Tools.
  3. Select “Browse” in the External Script Editor dropdown and select the Rider application.
  4. On Windows, navigate to %APPDATA%\Microsoft\Windows\Start Menu\Programs\JetBrains Toolbox and select “Rider”
  5. On Mac, select ~/Applications/Jet Brains/Toolbox/Rider.app or /Applications/Rider.app
  6. On Linux, select rider.sh

Install the plugin into your project

From the same official page – except their instructions are slightly wrong (they work, but are overkill).

This needs to be done for each project.

Copy the folder Assets/Plugins/Editor/JetBrains from this repository into Assets/Plugins/Editor/JetBrains in your project.

…Note: you do NOT need to copy the linked files (currently: two .cs files) into “Assets/Plugins/Editor/JetBrains”. The code works fine if you follow whatever standard you’re using in your project. The only requirement is that ONE of the parent/grandparent/etc folders is named “Editor” (this is a Unity feature).

e.g. I put mine in: Assets/Plugins/3rd-party/RiderEAP/Editor/

Configure Rider to use Unity

Tricky. First of all:

Quit Rider and restart it via Unity

Do this by finding any of your scripts in Unity Editor and double-clicking them. If you’ve done the steps above correctly, a new copy of Rider will open, and will open the script automatically.

If you don’t do this, Rider will try and get you to create a new project, which is a road of pain and suffering you want to avoid (you want Unity to managing the project, not Rider).

Nothing works; Fix the bug

If you wait a bit, and watch the status-bar at bottom of the screen, you’ll see an error appear. Click on the status bar for more info (this is standard JetBrains IDE behaviour). You’ll see this error:

Solution ‘MY GAME HERE’ load failed
Rider was unable to detect a Mono runtime on this machine.

Don’t click the link in the error message! The error comes because OS X doesn’t include Mono, and nor does Rider. But this is where your copy of Unity 5.5+ comes in handy. Courtest of this Rider bug report, we learn that we can use the copy of Mono in Unity 5.5, and how.

Open up Rider’s preferences (cmd-, as normal for OS X):

UPDATE June 2017: Jetbrains has made a breaking-change to Rider, and this setting no longer exists. If the old way was working for you, you must now re-do it with the following setting instead:

…thanks to Ilya for figuring this out, and Kirill from JetBrains for telling us the new setting-name.

…hit the button on the right to browse, and navigate to the folder: " /Applications/Unity/Unity.app/Contents/MonoBleedingEdge" (NB: if you have different versions of Unity installed, you’ll want to navigate to /Applications/Unity-5.5, or Unity5.6, instead – wherever you installed your 5.5+ version to).

Rider will think for a bit – watch that status bar – and you should see the left-hand pane auto-update to look exactly like it does in MonoDevelop (sorry no “before” screenshot, I didn’t think to capture it in time):

Party

Final step: realise you now have a real IDE, with wonderful, 21st-century, source control options, formatting THAT WORKS (@MonoDevelop/Xamarin: don’t call us, we’ll call you…never), intelligent code-hints and auto-fixes, etc. Knock yourselves out…

Correct code to add a mouseover/mouse-hover/pointer-enter to #unity3d

This should be a 1-line feature, but Unity screwed it up. You can do it in approx. 12 lines of code, but I couldn’t find anywhere showing how, so I’ve written it up and you can copy/paste.

This is missing from the Unity docs (as of summer 2016).

This is missing from the Unity API’s and SDK (they implemented the code for “onClick” but failed to implement the code for the other GUI events – onHover / onEnter / onExit – etc).

The most-popular code on the internet is much too long and over-complicated, and requires creating new classes (that you don’t need) which pollute your code-base.

The less-popular but mostly correct code only works for Unity 4.6, and has some bugs that will prevent it working in most cases.

So I fixed it…

How it should work – but doesn’t

This is Unity’s code for adding a “click” handler to a button in their new (post-4.5) GUI:

Button b = ... // your button, from your code
b.onClick.AddListener( () => { YOUR_CODE_HERE } );

So the code for adding a “hover” handler (or, in 99% of SDK’s and platforms, an “enter/exit” pair of handlers) should be:

Button b = ... // your button, from your code
b.onEnter.AddListener( () => { YOUR_CODE_HERE } );
b.onExit.AddListener( () => { YOUR_CODE_HERE } );

Or, if they wanted to go with the 1% solution, that is only used by CSS:

b.onHover.AddListener( () => { YOUR_CODE_HERE } );

None of these work, because Unity’s API is incomplete.

Correct solution, Unity v5.0 – v5.4

Instead, you have to implement the missing code from Unity yourself. You can use this to do manual click detection, and to distinguish between mouse down and mouse up (a “click” is traditionally a pair of events: down followed by up. This is standard in all windowing systems and GUI API’s).

The most commonly needed case is hovering, so you’ll need two pieces of code, one for “mouse moves over” (enter) and one for “mouse moves away” (exit).

/**
 * replace the code "YOUR_CODE_HERE_1" and "YOUR_CODE_HERE_2"
 */
Button b = ... // your button, from your code

EventTrigger trigger = b.GetComponentInParent<EventTrigger>();
if( trigger == null ) trigger = b.gameObject.AddComponent<EventTrigger>();

EventTrigger.Entry entryEnter = new EventTrigger.Entry();
entryEnter.eventID = EventTriggerType.PointerEnter;
entryEnter.callback.AddListener( (eventData) => { YOUR_CODE_HERE_1(); } );
trigger.triggers.Add(entryEnter);

EventTrigger.Entry entryExit = new EventTrigger.Entry();
entryExit.eventID = EventTriggerType.PointerExit;
entryExit.callback.AddListener( (eventData) => { YOUR_CODE_HERE_2(); } );
trigger.triggers.Add(entryExit);

#unity3d #missingdocs: CanvasRenderer.SetMesh() – making it work (mostly)

This once-obscure method, that – I guess – is the low-level call used by most of the new Unity GUI … is now the only way of drawing meshes in GUIs. The previous options have been removed, with brief comments telling you to use .SetMesh instead. Half of the DrawMesh / DrawMeshNow methods have also been removed (no explanation given in docs), which were my other go-to approach.

Unfortunately, no-one has documented SetMesh, and it has significant bugs, and breaks with core Unity conventions. This makes it rather difficult to use. Here’s the docs I’ve worked out by trial and error…

Continue reading

#unity3d remove yellow warnings you don’t need #unitytips

Screen Shot 2016-04-16 at 11.48.08

Warnings are very, very important in any compiled language: they tell you that the computer has checked your code and realised you “probably” created a bug; they even tell you something about what the bug might be.

..but the computer isn’t sure – if it could be sure, it would be a compiler Error (in red). So (in Unity) it’s yellow, and “optional”. But in those cases where it’s not a bug – and you know it! – it’s very annoying. Most IDE’s let you turn them on and off, Unity doesn’t … here’s how to fix it.
Continue reading

What makes a great #Unity3d asset? Which do you recommend?

Unity is still the only major game-engine with an effective, established Asset Store. This is an enormous benefit to game developers – but do you feel you’re making full use of it?

I’ve bought and used hundreds of Unity plugins, models, scripts, etc from 3rd parties. I’ve found some amazing things that transformed my development.

TL;DR: please share your recommended assets using this form: http://goo.gl/forms/G3vddOdRL3

Things we want to improve

This is a shortlist; if you’ve got areas you want to improve, please add a comment.
Continue reading

#unity3d missing docs: EditorWindow lifecycle

If you do any non-trivial customization of Unity Editor, you’ll almost certainly extend EditorWindow. But Unity (to date) refuses to tell anyone how to do this legally, or what the contracts you’re being held to are. Without that, many plugins on the Unity Asset Store are wrong and buggy, and sooner or later accidentally cause problems for users.

Their fault? Partly, but I don’t blame them too much – rather: Unity’s fault for failing to document (and failing to test assets before approving them!).

For those of you who aren’t happy shipping crappy, broken, buggy plugins (And charging for them), here’s a guide / reference for the lifecycle of EditorWindow. Extra info, explanations, and gotchas welcome!

Docs-UnityEditorWindow

I’m working on my own Entity System for Unity; want to follow it?

…Sign up here to be kept up-to-date on the project’s upcoming Kickstarter / Patreon / whatever-it-ends-up-being (if you’re already signed up, it won’t add you again)

Use shift-N to create new scripts in Unity Project Window, fast

In Unity, you create new scripts many times per day, and folders but there’s no keyboard shortcuts. I fixed this, and made the popup rather more intelligent than Unity’s built-in one. I’ve decided to make the basic version available for free here:

UPDATE: there’s a bug in the 1.0 version – it WILL NOT WORK if you set your Project window to 2-column layout. This is due to BUGS IN UNITY (not my code!). I have a workaround that’s in the Asset Store version, but is missing from the free version. I’ll patch it later

FreeIntelligentNew.dll – I’m not supporting this; it’s free: use at your own risk.

Or, for $2, you can get the latest version with full source code from Asset Store – I’m supporting + updating this.

Installation

Drag/drop the DLL into any folder named “Editor” in your project.

(required by Unity; this is how they make sure that Editor scripts aren’t accidentally included in your final game)

Usage

  1. Select the Project panel
  2. Hit shift-N
  3. By default, it intelligently guesses if you wanted a new Folder or a new Script. If it guessed wrong, hit “tab” to cycle through the options
  4. Choose a name and hit Enter (like normal in Unity). Done!

How…?

This works by peeking into some of Unity’s internals and detecting which EditorWindow has focus. If it’s the Project window, it uses some hardcoded constants (which differ between Unity versions, due to bugs they gradually fix, I think) to get the positions right, and offer you the popup.

I did it this way because Unity currently provides NO PUBLIC API for reproducing some of their core Editor features (e.g. where they temporarily change the render-style of the “newly-created item” in a Unity windowpane, so that you can edit the name in-line. Not possible for you or I!)

With a bit more hacking, I might be able to hook Unity’s own code and enable / trigger / alter the hidden features from keyboard, but … that’s on the wrong side of “Fragile; would probably break unexpectedly in a future version”.

How I’ve done it so far it sits independently of Unity’s code, and is very unlikely to stop working, or to cause bugs later on. YMMV…

(if you want to know more, get the Asset Store version, read the source. I’m happy to answer quetsions via the support links or in the Unity Forums page for this)

Intelligent “new (thing)” control for #unity3d

In Unity, hundreds of times a day you do “new (folder)” or “new (C# script)” etc. But Unity makes this ridiculously hard: you have to hunt and peck a tiny button and then hunt-peck a tiny item in a huge dropdown that is very easy to miss.

And you can’t do any of this from the keyboard. Even though you’re fully in keyboard mode and about to write the name of the New Thing (required!) and if it’s a script: type in the source code.

Screw that.

UPDATE: Now available in Asset Store – get the source

For a mere $2, I will Intelligent New you long time:

Source is included. If you want to see how I did it, knock yourselves out…

My context-sensitive New for Unity

So, what I’ve made today:

intelligent-new-demo-1
intelligent-new-demo-1

  • Select any folder or object in the Project window
  • Hit “shift-N” (because Unity sucks and steals Ctrl-N and refuses to let you choose a better one. Stupid stupid stupid.)
  • A popup appears pre-filled with a sensible new file name OR folder name
    1. If you were on a folder, it prepares to auto-create a new folder
    2. If you were on a script file, it prepares to auto-create a new script
    3. The name is pre-selected and editable, exactly as with Unity built-in
  • Sometimes that intelligent guess above will be wrong, so … hit Tab, and it switches type, while keeping the text selected and editable

Net result: super-fast workflow for creating new scripts and organizing your project.

(This required an ungodly amount of hacking and trial and error to work around bugs, bad documentation, and obvious missing core features from Unity APIs. But it works, and seems to be pretty seamless now)

Implementation Notes

A subset of the things I discovered / re-discovered on the journey to this one small fix / improvement:

  1. AssetDatabase.CreateAsset is basically broken: can’t create C# scripts at all. Don’t try.
  2. ScriptableWizard is unusable in Unity less than 5.0, because they made a core method private / non-overridable. Don’t bother.
  3. You can find the Project window and others by doing a reflection on the Assembly to find the magic C# Type of known Unity private classes (that SHOULD BE public!) and comparing at runtime. Hoops? Jumping through? Because an API has something private that should have always been public? Welcome to Unity customization! :)
  4. You can find the exact position of the selected row by adding yourself as a callback on Unity’s own row-by-row rendering of their built-in windows, and saving the data every frame. Sounds scary; works great (one of the few bits here that is a perfect hack with no downsides)
  5. Popups need you to create a new class, and that class MUST BE in file of its own or you will break Unity (internal bugs in Unity window management that trigger when you reload/restart Unity)
  6. …if you trigger that bug (or in any way end up with floating, non-closeable windows), go to the Layout menu and re-select the layout you’re already using. It will kill any unexpected windows. Phew!
  7. Unity still hasn’t made the Indent width (in pixels) public. The documentation insults you by saying that when you hardcode the number 20 this will break your code in future. YES, WE KNOW. SO MAKE THE DAMN NUMBER PUBLIC, YOU BASTARDS.
  8. There is a 2 pixel top and bottom padding needed to surround textfields in 1-line popups. I hardcoded this, it may have a number somewhere in the API. Good frickin’ luck trying to find it. Given the taunt about indents above, I very much doubt it is public.
  9. If you have a button or non-editable textfield with a changeable title, or anything that can be changed by a keypress during rendering, it is critical that in OnGUI you read Event.current.type and switch() on it. As far as I can tell, this has never been documented except in forum threads and blog posts by Unity staff. Once you know about it, you can sort of guess it from reading the undocumented bits of the API, but it’s damn hard to find references to it online. (I found it years ago by trial and error and blind luck). Until you do this you get race conditions when changing GUI based on keypresses. Ugh.

    Compatibility

    Critically, this (should) work no matter how much I customized Unity elsewhere. It’s peeking into the actual window and render areas to decide what to popup and where on screen.

    The only conflict I expect is one that – thanks to some brainfart design at Unity corp – we can’t workaround: I had to hardcode “shift N” as the keyboard shortcut :(.

    Want it yourself?

    I thought it would take me about 10-20 minutes to do. HAHAHAHAHAHAAHAH! If I’d done this as a client project, I worked out it cost almost $1500 in billable hours. Ugh.

    I’m going to use this in production for a while. If it continues not to break or corrupt anything, I’ll put it on the Asset Store.

    Next up…

    …I’m going to do some context-sensitive New for the Hierarchy window, I think. Now that I have these hacks working, that’ll be quite a lot easier.

Fix #Unity3d’s broken OnMouseDown

This one has annoyed me for years: Unity’s OnMouseDown has never really worked. (NB: it works perfectly if you make a scene with a single cube; but that is not a game. It breaks completely as soon as you add multiple objects, colliders, etc to a scene)

The main reason to use a 3rd party engine is to avoid re-inventing the wheel; it’s tragic that Unity can’t even do mouse-input out of the box. Let’s fix it!

Continue reading

Unity3D: display a variable instantly on screen

You need this ALL THE TIME when developing, and Unity lacks it as a core feature:

  1. Create a Text label on your GUI
  2. Drag/drop a variable onto the label, and it will automatically display the value

Completely impossible, due to short-sighted design decisions in the Unity Editor from 10 years ago that never got changed. So, let’s fix it. It’s hugely annoying not being able to do this!

Continue reading

Easy parametric animations in #Unity3d with code and curves

iOS forces you to use pretty animations: if you don’t tell it otherwise, it will use “ease-in/ease-out” curves to make things feel … smoother, less jerky.

Unity is made for programmers; changes you make to position, size, rotation, etc all happen instantaneously. By default, they won’t even animate, will teleport instead.

So … moving from “prototype with no animation” to “prototype that won’t hurt people’s eyes, and I can share”, what are some tips and gotchas?

Continue reading

Debugging A* Pathfinding in Unity

I needed fast, efficient, … but powerful, adaptable … pathfinding for my hobby project. My minions have to fly, walk, crawl, teleport, tunnel their way across a procedural landscape. Getting to that point has been tricky, but the journey’s been interesting.

We want something that intelligently routes creatures around obstacles, and picks “shallow” routes instead of scaling cliffs (or vice versa for Giant Spiders etc). Something like this:

Screen Shot 2014-08-10 at 20.09.36

Continue reading

How to tidy your Unity code by putting it in a DLL

The importance of Re-use

Here’s a story that may sound familiar:

You downloaded Unity, watched some tutorials on YouTube, and had a physics “game” running the same day. Excited, you started writing the game you’ve always wanted to make. Possibly – bitten before when trying this with GameMaker etc – you thought to organize your source code: folders, subfolders, logically-named scripts, etc.

Fast-forward a few months, and you have 50 scripts in 40 sub-folders, some of it re-usable, some of it hardcoded for your game. Hoooo-Kayyyy… Well, it’s not too bad. And then a new opportunity comes along – a paid contract, a game-jam, a collaboration with a friend – and you want to re-use some code from your main project. You look at the folder structure, you look at how intertwined it’s all become … and you weep.

Without re-use, what seemed like an “easy” project becomes just a little too much work, and you never finish it. Back to square one :(.

Code re-use in Unity

There are five major aspects to code re-use when making Unity apps. Most of these are shared with general programming, but these are the ones I’ve found *especially* important when doing Unity development.

Good names

The best way to get good at naming things in a program is to focus on “what makes a bad name”, and “Don’t do that”. e.g.

  • If you have to open a Script to remember what it does … it has the wrong name.
  • If you keep typo’ing the script when referencing it in other scripts … it’s the wrong name
  • If your script is more than a thousand lines long … it’s the wrong name AND you’ve put too much junk in there; split it!
  • If you can’t find a script, because you can’t remember which folder it’s in … the folder name is wrong, AND the script name is wrong (should have been a name that forced you to put it in the right place first time!)
  • …etc

Renaming scripts in Unity is a minor pain: you rename it, then you have to close the file in MonoDevelop, re-open it, and (assuming it was a C# class) rename the class in source-code too. (I keep hoping latest Unity will do this automatically, but I’m a version behind at the moment).

We need Sub-folders. Lots of Sub-Folders

… you can never have too many. Give them good names, though!

De-couple your code

Ah, now it gets tricky. The art of decoupling takes much practice to master.

Decoupling is why C# (and Java) has the “interface” keyword. The concept is much easier to understand after you cocked it up, written code you can’t re-use, because everything’s too inter-dependent.

“I can’t just copy/paste that script to my new project, because it references 3 other scripts. Each of which … references another 12. ARGH!”

Unity itself doesn’t use Interfaces (though it really ought to!) – and you have to use a little ingenuity to use them yourself (Google it, it’s only a few small caveats). But C#-interfaces simply give you a compiler-compatible way of decoupling: you have to design your classes as decoupled to start with. Again, google this and ask around – it’s too big a topic for me to do justice to here!

Package your code, so you can re-use it

Libraries. This is why The God Of Programming invented Libraries. So, how do you do a Library in Unity?

Libraries in Unity: the easy DLL

There are two kinds of DLL’s:

  1. Real DLL’s, as used by Real Men, who write all their code in C++
  2. Fake DLL’s, as used by the rest of us, who just want an easy life so we can focus on making our game

A DLL is a great way of packaging code – it’s a very widely-used standard. So, Unity uses DLL’s for this (good move) – but if you google “Unity make DLL” you’ll get distracted by the huge complexity and depth of C++/Unity integration, and you don’t need any of it. Instead, you’ll be doing “DLL light”, which is easy.

But, as with most Unity features, it’s almost entirely undocumented. And, out of the box, it will fail. For bonus points, Unity will give you completely the wrong error message when it goes wrong. Yay!

Step 1: write a Unity script in Unity

Do something simple. I wrote a class that makes random numbers, following XKCD’s advice:

using UnityEngine;

/** In Unity 3, you cannot have namespaces. So comment out this next line. Unity 4 is fine */
namespace MyTestDLL
{
	public class DLLClass
	{
		public static int GetRandom()
		{
			return 4;
		}
	}
/** In Unity 3, you cannot have namespaces. So comment out this next line. Unity 4 is fine */
}

Make a second script that uses that first one, e.g.

using UnityEngine;

public class TestScript : MonoBehaviour
{
	void Start()
	{
		print( DLLClass.GetRandom() );
	}
}

…attach it to a GameObject, check it works.

Step 2: follow Unity’s docs on creating and using a DLL

You’d think this would be enough, but it isn’t. However, the docs are simple, direct, and I found them easy to follow.

So http://docs.unity3d.com/Documentation/Manual/UsingDLL.html = read this and do what it says

NB: they write a slightly more complex script to use than mine, with but whatever. The idea is the same.

Step 3: Use the namespace, Luke. And Interfaces. And …

Now that your DLL is compiling/building in MonoDevelop … you are no longer stuck with Unity’s arbitrary rules and restrictions! The world is yours!

(so, even in Unity 3, you can now use the namespace. Which makes it MUCH easier to keep your code well-organized ;))

Step 4: What about the [square brackets]?

These Just Work ™ exactly as they did in Unity scripts. e.g.

using UnityEngine;

namespace MyTestDLL
{

/** Hey! Look! Unity editor-features ... coded outside of Unity */
[ExecuteInEditMode]
[System.Serializable]
	public class DLLClass
	{
...

Step 5: Editor extensions, editor scripts, editor GUIs, etc

This is where it breaks. If you had any Editor scripts (which, in Unity, MUST be stored in the “Editor” root folder, or one of its subfolders), you can include them in your DLL – but they won’t work.

Worse, when you trigger them (e.g. by selecting a GameObject that did custom editor rendering), you’ll get:

Error: multi-object editing not supported !

…at least, you do in Unity 3.x. Fixed in 4.x, I suspect? But I haven’t gone back to try it since I fixed the bug :).

There is some mumbo-jumbo on the internet (and Unity forums) about complicated workarounds, notably courtesy of AngryAnt (with a Jan 2014 post here, with some extra info worth reading but NOT required!). But these are long-since outdated and unnecessary. The fix is very simple: we must create TWO DLL’s!

  1. DLL #1: the one we already had
  2. DLL #2: will contain ONLY the editor-scripts, and we’ll drag/drop it into Unity’s “Editor” folder.

This is extremely logical, simple, and easy to remember. And it works beautifully! But .. how?

Step 5a: Upgrade MonoDevelop project to output not one, but two, DLL’s

First, right-click on the top-most item in MonoDevelop’s “Solution” panel, and select “Add New Project…”:

Screen Shot 2014-05-24 at 20.54.53

As you did earlier, choose “Library (C#)”. I recommend naming this “SomethingSomethingEditorScripts” (where “SomethingSomething” is your library name, which you used for the first DLL).

Second, you need to edit the References (as you did with first DLL), and this time repeat the steps and add ALL of:

  • UnityEngine.dll
  • UnityEditor.dll
  • AND: instead of the “.Net Assembly” tab, use the “Projects” tab and select your main DLL/library. It should be the only option

That gives you something like this:

Screen Shot 2014-05-24 at 20.58.22

…see how I have two “projects” in MonoDevelop, one which just uses normal Unity stuff, the other which additionally uses Unity Editor stuff? And the second one “references” the first, so it can see/use/create the classes and methods from the first one.

Step 5b: Put the DLL’s in different places

Build, and find the output files. The first project/DLL will still only be making one DLL, but the folder for the SECOND project/DLL will conveniently build BOTH projects and contain BOTH DLL’s.

Make sure you put one DLL “anywhere except Editor” and the other one “in Editor, or a subfolder of Editor”.

Finally, create some GameObject’s, open up the DLL’s in Unity’s Project view (expand the triangle) and drag/drop the Scripts onto your objects as desired. Click on them in the Scene view, and all your OnGUI, OnGizmos etc methods should run exactly as normal.

Step 6: Rejoice!

Now you can share your code with other Unity projects simply by drag/dropping the 2 x DLL’s into a new Unity project. BOOM!

Beautiful! Easy, simple, impossible-to-screw-up ;). That’s how I like my code re-use…