As of today, all of your purchases paid through stripe will have 1% of their total redirected to carbon offset. You can read more about how it works at stripe.com/climate. This is one more way I am doing my part to help ensure sustainability of the planet.
How To Make a Unity Property Drawer Using IMGUI
First a definition. Drawer (noun) – One that draws. Property drawers draw properties. We are not talking about that thing in your furniture holding all your nicely folded outfits.
Don’t look at the image at the top of this post. Those are drawers, we are talking about drawers. Wait, don’t tell me. You looked at the image at the top of this post.
Use Case
With that out of the way, we can cover a brief overview of the use case of property drawers. The Unity editor uses a very naive algorithm for generating the UI in the inspector. After all, there are a lot of possible ways you could be making your MonoBehaviours, ScriptableObjects, and Serializable classes and structs. The approach is very flexible, which makes it great as a general purpose implementation for the editor, but sometimes this can result in big, bulky inspectors that are hard to use. This is especially true when using arrays since you need to expand two levels just to see the properties of elements.
Unity’s initial solution to this was Custom Editors. A custom editor is C# code in your project which draws an entire editor window, like Project, Hierarchy, or Console. These editors could also replace the inspector for MonoBehaviour and ScriptableObject classes. This is great when you want your entire class to have a custom inspector.
But what about Serializable classes? They can exist in many MonoBehaviours. In the distant past, if you wanted all MonoBehaviours using a particular serializable class to have a non-default inspector you needed to make a custom editor for each one. This was quite tedious, error prone, and impossible for plugins.
Property Drawers solved all of this. Property drawers enable you to specify how the inspector should look for your serializable classes. This way all MonoBehaviours and ScriptableObjects with fields of your type will have the fancy inspector without having to make a custom editor for every one.
So how do we make one of these? Specifically how do we make one of these using the editor’s old UI framework known as IMGUI short for Immediate Mode GUI? (We will cover using UI Toolkit in another post)
Basic Example
The first time I ever wanted to do this was back before property drawers were a feature, so that’s the example I am going to implement here. I had a list of key value pairs in the unity inspector associating a string to an AudioClip
. It was a simple way to store named sound effects as data. Here is the basic data class.
[System.Serializable]
public class NamedAudioClip
{
public string key;
public UnityEngine.AudioClip value;
}
Now let’s make a MonoBehaviour using this so we can see it in the inspector.
public class ExampleInspector : UnityEngine.MonoBehaviour
{
public NamedAudioClip[] sounds = new NamedAudioClip[3];
}
Here’s how this MonoBehaviour looks in the default inspector.
Notice how the fields need expanded and how each one takes up three lines. This is not as convenient as all fields on a single line. We can use a drawer to put all the fields on a single line that doesn’t require expanding every time we want to edit it.
Now let’s make the drawer for the NamedAudioClip
class. It is just a C# script inherited from PropertyDrawer
and overriding the OnGUI
method. This class is an editor script and therefore needs placed inside a folder named Editor (or similarly, inside an arbitrarily named folder with an asmdef excluding runtimes and including the editor).
Another common pattern is to put the editor class in the same file it applies to, but place it inside
#if UNITY_EDITOR
preprocessor conditionals. I won’t be doing that here for the sake of clarity.
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(NamedAudioClip))]
public class NamedAudioClipDrawer : PropertyDrawer
{
private const int ColumnCount = 2;
private const int GapSize = 4;
private const int GapCount = ColumnCount - 1;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
var x = position.x;
var y = position.y;
var width = (position.width - GapCount * GapSize) / ColumnCount;
var height = EditorGUIUtility.singleLineHeight;
var offset = width + GapSize;
EditorGUI.PropertyField(new Rect(x, y, width, height), property.FindPropertyRelative("key"), GUIContent.none);
EditorGUI.PropertyField(new Rect(x + offset, y, width, height), property.FindPropertyRelative("value"), GUIContent.none);
EditorGUI.EndProperty();
}
}
This uses a general column based approach to making two columns using some simple math. You can use the same logic to make any number of columns by changing the ColumnCount
constant at the top of the class. After the math for calculating column sizes, it puts the fields in each column. The first field, for key
, ends up being a string field. The second, for value
, ends up being an AudioClip
field. Here is a screenshot.
This setup works great for an array of instances which can then be queried for particular values. It is much easier to work with in an array versus the expanded form without a drawer seen above. When a list like this grows it will be easier to manage since you no longer need to expand each item, and more fit on screen. The additional advantage of Property Drawers is that now, every use of this class will also get this new inspector. If you put another of the NamedAudioClip
in a different class, it will look the same without you having to make a custom editor for that class.
In an upcoming post I will demonstrate the same property drawer using the new UI Toolkit in the Unity editor. It is the preferred way of building UI going forward.
Gem City Shine Prints Fundraiser
One year ago the city of Dayton came together to show their love and support for one another following the tragic shooting. Today, I am launching a fundraiser to support the Oregon District Business Association by selling prints of the iconic photo of the crowd at Gem City Shine. Seeing the people of Dayton at one of their greatest moments always gives me pause. Memories like those made that evening are rare, and I want people to have something to remember all the performers, friends, and neighbors from that night. The best way I can do that is with the photo all of Dayton knows. The one shared all across social media the week following the event.
These prints are on high quality photo paper intended to last longer than photos printed at home or the convenience store. The wall prints are also printed with archival ink, resisting fade over time. All prints come in standard sizes and should fit frames advertised for that size.
The fundraiser will last until at least Friday September 11. And in an effort to maximize the benefit to the ODBA, shipping will not have tracking.
-
Gem City Shine Photo Print$5.00 – $7.00
-
Gem City Shine Square Print$4.00 – $6.00
-
Gem City Shine Wall Print$30.00 – $67.00
I also want to thank Parabo Press for providing discounted printing services to help raise funds. If you are looking for a way to display your print they have compatible frames.
Stay #DaytonStrong
Using those pointers
In my last post I outlined a way to manage native object lifecycle from C# in Unity. But I skipped one of the conveniences of calling native functions. You can call a function without matching the declared type of the pointer parameters. That means you don’t need to use CFTypeRef
everywhere.
The pointer you have in C# is untyped, it is void *
. That’s the same as CFTypeRef
. But you can declare and call native functions which are your type. Let’s take a look at one of the classes we could build from the last post.
// nativeClass.h
@interface NativeClass
- (instancetype) init;
@end
// nativeClass.m
#import "nativeClass.h"
@implementation NativeClass
- (instancetype) init
{
// omitted for brevity
}
@end
#if __cplusplus
extern "C" {
#endif
CFTypeRef _createNativeClass()
{
return CFBridgingRetain([[NativeClass alloc] init]);
}
void _destroyNativeClass(CFTypeRef nativeClassInstance)
{
CFRelease(nativeClassInstance);
}
#if __cplusplus
}
#endif
// NativeClass.cs
using System;
using System.Runtime.InteropServices;
public class NativeClass : IDisposable
{
[DllImport("__Internal")]
static extern IntPtr _createNativeClass();
[DllImport("__Internal")]
static extern void _destroyNativeClass(IntPtr nativeClassInstance);
IntPtr m_Instance;
public NativeClass()
{
m_Instance = _createNativeClass();
}
public void Dispose()
{
_destroyNativeClass(m_Instance);
}
}
This is a very basic native class which has its lifecycle controlled from C#. But we can take things a step further with our own functions. Let’s add a method to our objective-c interface.
// nativeClass.h
@interface NativeClass
- (instancetype) init;
- (void)doSomeStuff;
@end
Now we can add an implementation, and provide a C function wrapper. Remember, C# can call C functions, but not objective-c. So we need to write a simple C wrapper for any methods we want to call from C#.
// nativeClass.m
#import "nativeClass.h"
@implementation NativeClass
- (instancetype) init
{
// omitted for brevity
}
- (void)doSomeStuff
{
// Only the best algorithm
}
@end
#if __cplusplus
extern "C" {
#endif
CFTypeRef _createNativeClass()
{
return CFBridgingRetain([[NativeClass alloc] init]);
}
void _destroyNativeClass(CFTypeRef nativeClassInstance)
{
CFRelease(nativeClassInstance);
}
void _doSomeStuffNativeClass(const NativeClass * instance)
{
[instance doSomeStuff];
}
#if __cplusplus
}
#endif
Notice the declared pointer type in the function parameters. It is NativeClass *
instead of CFTypeRef
which was used last time. Yes, this actually works. Finally, let’s add the C# code for this method.
// NativeClass.cs
using System;
using System.Runtime.InteropServices;
public class NativeClass : IDisposable
{
[DllImport("__Internal")]
static extern IntPtr _createNativeClass();
[DllImport("__Internal")]
static extern void _destroyNativeClass(IntPtr nativeClassInstance);
[DllImport("__Internal")]
static extern void _doSomeStuffNativeClass(IntPtr instance);
IntPtr m_Instance;
public NativeClass()
{
m_Instance = _createNativeClass();
}
public void Dispose()
{
_destroyNativeClass(m_Instance);
}
void DoSomeStuff()
{
_doSomeStuffNativeClass(m_Instance);
}
}
In C#, the pointer remains an IntPtr
which is essentially a void *
or CFTypeRef
. But we can call functions with the proper type declared in the function parameters. That means no casting is needed when we marshal our pointer into native objective-c.
Unity iOS Native Pointer Pattern
One common situation I find myself in when developing for Unity on iOS is having to integrate with native APIs. Integrating native features is a nice touch for your apps and makes them feel at home running in iOS. It keeps your users familiar with platform conventions instead of having to learn some UI or workflow specific to your app.
When doing this, you inevitably want to use an API which requires you to hold a reference to a pointer. Let’s say you want to use iCloud ubiquity containers in your app. You need to subscribe to changes in the cloud. This requires a persistent object on the native side to receive notifications from the operating system. The information then needs sent up to Unity and processed by your app. You may start with something like this on the native side.
@interface iCloudMonitor : NSObject @end
@implementation iCloudMonitor { NSMetadataQuery * documentStoreMonitor; } -(instancetype)init { if (!(self = [super init])) { return nil; } [self startSearch]; return self; } -(void)queryDidUpdate:(NSNotification *)sender { // Do what you need to when iCloud updates, this is just an example UnitySendMessage("iCloudMonitor", "DocumentsUpdated", ""); } -(void)startSearch { documentStoreMonitor = [NSMetadataQuery new]; documentStoreMonitor.searchScopes = [NSArray arrayWithObjects:NSMetadataQueryUbiquitousDataScope,nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(queryDidUpdate:) name:NSMetadataQueryDidUpdateNotification object:documentStoreMonitor]; [documentStoreMonitor startQuery]; } @end extern "C" { void _createICloudMonitor() { [[iCloudMonitor alloc] init]; } }
This lets you call _createICloudWrapper()
from Unity to start monitoring for iCloud changes. But there is a problem. iOS uses a system called Automatic Reference Counting, or ARC, to keep track of when to deallocate objects from memory. I don’t want to go into great depth about ARC here as there are many articles covering it in great detail such as https://www.raywenderlich.com/2992-beginning-arc-in-ios-5-tutorial-part-1. To summarize and simplify, when an object has zero strong references it get deallocated.
The call inside _createICloudMonitor()
creates an object, but doesn’t hold a reference to it. As soon as the function returns, ARC will see the object has zero references and deallocate it. You need to keep a reference to the object so it stays around. One option is to make a global variable to keep ARC happy with a reference. This brings all the issues of global variables with it. Another option is to use a singleton, which is slightly better than a global. It keeps ARC happy with a reference, but still has many of the issues of a global variable. A third option is to use the -fno-objc-arc
compiler flag to disable ARC on the entire file. But that means we can’t use ARC any where in the file at all. The best option is to transfer the variable out of ARC entirely. This is done through bridging.
Bridging allows us to give the ARC system more information than it can gather on its own. Namely, whether or not the system should deallocate an object. There are two things you can tell the system. One, you can tell it to stop monitoring an object which it previously was. And two, you can tell it to start monitoring an object it wasn’t. Basically you can move ownership of objects between Objective-C land with references and reference counting, and plain old C land with pointers. The function CFBridgingRetain(id)
takes a reference and converts it to a CFTypeRef
, which is just an alias for void *
, and adds one to the retain count. Lets see how to change our code to use this.
CFTypeRef _createICloudMonitor() { return CFBridgingRetain([[iCloudMonitor alloc] init]); }
Since we have stopped ARC from deallocating this object we need to do it ourselves. Just like in the time before ARC existed, every call to retain
required a corresponding call to release
. Luckily That function is provided as well. Lets make a function to access it.
void _destroyICloudMonitor(CFTypeRef monitor) { CFRelease( monitor ); }
And that’s everything we need in objective-c land. Now we can make a C# class to use this code. Here is an example of using MonoBehaviour
to control the native object. When the MonoBehaviour
instance is first loaded it will call into C land to make the native object. And when it is destroyed, it will call to C land again to destroy the native object. This means the native object’s lifecycle follows the MonoBehaviour instance.
using System; using System.Runtime.InteropServices; using UnityEngine; public class iCloudMonitorBehaviour : MonoBehaviour { [DllImport("__Internal")] private static extern IntPtr _createICloudMonitor(); [DllImport("__Internal")] private static extern void _destroyICloudMonitor(); private IntPtr NativeObject; void Awake() { NativeObject = _createICloudMonitor(); } void OnDestroy() { _destroyICloudMonitor(NativeObject); } }
All of this lets us use persistent native objects whose lifecycle is controlled by an object in Unity all without needing extra variables in native land to store the variables. The basics are as follows:
- Have a create function to make the object instance we need which bridges that variable out of ARC and returns the pointer to it.
- A corresponding destroy function which releases the variable sent to it.
- In the C# class have an
IntPtr
to hold the reference to the object. - Inside
Awake
call the create function and assign the value to our pointer field. - Inside
OnDestroy
call the destroy function and send the pointer.
This is applicable anywhere you need to use a persistent native object. Besides that, you can add all the other functions you want.
Alternate C# class
If you want something a bit more flexible than a MonoBehaviour
to control the native object, implementing the IDisposable
interface works really well too.
using System; using System.Runtime.InteropServices; public class iCloudMonitor : IDisposable { [DllImport("__Internal")] private static extern IntPtr _createICloudMonitor(); [DllImport("__Internal")] private static extern void _destroyICloudMonitor(); private IntPtr NativeObject; public iCloudMonitor() { NativeObject = _createICloudMonitor(); } public void Dispose() { _destroyICloudMonitor(NativeObject); } }
Common WWW
Unity’s WWW class is quite powerful. Give it a URL and it will download that file in the background. Provide it with some form data and it will encode it properly and post it for you. It can even load files from inside your APK on Android.
As powerful as the WWW class is, there is really only one way to use it, in a coroutine. Start the download, yield until it finishes, and finally process the error or payload. I found that nearly all times I used the WWW class the coroutine followed this pattern. So instead of rewriting it again, I made a library of the pattern.
I present the WWWNetworking library. It implements the most common WWW use patterns so you can use callbacks instead of implementing coroutines. You can also queue up multiple downloads and control the amount of concurrent downloads. It even provides singleton access to a default instance.
using UnityEngine; using WWWNetworking; public class FloatingImage : MonoBehaviour { void Start() { NetworkingEngineSingleton.Instance.Download("http://images.earthcam.com/ec_metros/ourcams/fridays.jpg", www => { GetComponent<Renderer>().material.mainTexture = www.texture; }); } }
The core of the library is the NetworkingEngine
component. It is essentially a queue of tasks to run. When there are fewer than the maximum amount of allowed concurrent tasks running it starts one from the queue. The maximum is user configurable so you can dynamically change the amount of resources to consume. There is also a singleton-like default instance available for when you don’t want to deal with adding components. The example above shows the singleton-like default instance.
Unity iOS Plugin Basics
One of my favorite things about Unity is how easy it is to port games to multiple platforms. The simplest of games require no work to target a new platform. Literally none. This makes developing in Unity a time saver because there are very small porting costs.
However keeping the game purely within the engine comes with drawbacks. Primarily, little system integration. Many platforms have features outside of the game which you might want to take advantage of. For instance, iOS has twitter sharing built in to the OS. This is a feature Unity does not implement. So how do we use it? Through the use of plugins.
Plugins allow you to call into code written and potentially compiled outside of Unity. This is extremely powerful because it allows you to do pretty much anything the platform you’re targeting can do. Going back to the iOS twitter example, you can call into the native Cocoa Touch APIs.
Let’s try this out by writing a simple plugin to show a dialog to post to twitter. This API is built into iOS versions 5 and newer. I will be assuming you are targeting at least that version. If you are targeting something older you will need to include checks for the iOS version before calling the API. We need two functions. The first will check whether we can post to twitter. The second to do the posting. The social sharing API is documented at https://developer.apple.com/library/ios/documentation/NetworkingInternet/Reference/SLComposeViewController_Class/Reference/Reference.html. It will come in handy.
The mono runtime makes calls into native code using C standards. Any language that follows the C calling convention can be called. Unfortunately Objective-C does not follow this convention. We will have to wrap Objective-C APIs with C code to make it available to Unity. this is done by putting our calls inside C functions and using a C compiler to compile it. Our file will contain calls into C++ so we need to use a .mm
file with Extern "C" {
at the top and }
at the bottom to avoid name mangling issues.
// Check if c++ compiler #if __cplusplus Extern "C" { // Avoid name mangling issues #end if #if __cplusplus } // Close Extern C #endif
Put this file in the Assets/Plugins/iOS/
folder in your project. This is a special folder. When you build for iOS, any native libraries or code in this folder are copied to the Xcode project where they are compiled and linked with the rest of Unity.
Now, in Unity create a new C♯ file. This file will act as the Unity side to the plugin.
// Notice it doesn't extend MonoBehaviour public class TwitterSharing { }
Let’s start by adding a simple call to find out if Twitter is available. SLComposeViewController
contains a class method called isAvailableForServiceType
to check the availability of a given service. The constant for Twitter is SLServiceTypeTwitter
.
// In Social.framework, imports social sharing classes and constants #import <Social/Social.h> #if __cplusplus Extern "C" { #end if bool _isTwitterAvailable() { // Returns true when Twitter is available return [SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter]; } #if __cplusplus } #endif
When calling native code, mono “marshals” the parameters and return values. Basically it copies stuff. This is needed because C and C♯ have different memory management. Primitive types, integer, floating point, and boolean, are automatically converted to and from their respective types. Because of this we can use a bool in C♯ just as we would in C. Strings work a little differently as we will see later.
using System.Runtime.InteropServices; // For calling into native code public class TwitterSharing { // The plugin is only compiled for the iOS platform, check if Unity is compiling for it. #if UNITY_IPHONE // Specifies which binary file contains the function. // For plugins you write the library is always "__Internal". [DllImport("__Internal")] // Has the same signature as in the C file private extern static bool _isTwitterAvailable(); #endif public bool IsTwitterAvailable() { #if UNITY_IPHONE // Calls into native code return _isTwitterAvailable(); #else // The method needs to always return something. return false; #endif } }
Now you can check whether Twitter is available from game code. Debug.Log(TwitterSharing.IsTwitterAvailable());
will print whether twitter is available when running on iOS. But this is no fun. We want to post to Twitter. Let’s add a function to do just that. But first, let’s cover how mono marshals strings from C♯ to C. When you send a string
as a parameter mono converts it into a null terminated UTF8 character array (char[]
ending with \0
) for native code. The sharing service expects an NSString
so we have to convert it using stringWithUTF8String
.
#import <Social/Social.h> // Contains functions to call into Unity #include "UnityInterface.h" #if __cplusplus Extern "C" { #end if bool _isTwitterAvailable() { return [SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter]; } void _postToTwitter(char* text) // Make note of the signature { // Create a view for Twitter sharing SLComposeViewController* shareSheet = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter]; // Convert characters into NSString. [shareSheet setInitialText:[NSString stringWithUTF8String:text]]; // Get the Unity native view and tell it to show the twitter view. [UnityGetGLViewController() presentViewController:shareSheet animated:YES completion:NULL]; } #if __cplusplus } #endif
Now to make the unity side.
using System.Runtime.InteropServices; public class TwitterSharing { #if UNITY_IPHONE [DllImport("__Internal")] private extern static bool _isTwitterAvailable(); // This specifies which binary file contains the function. // For plugins you write the library is always "__Internal". [DllImport("__Internal")] // Notice here we say the parameter is a string private extern static void _postToTwitter(string text); #endif public bool IsTwitterAvailable() { #if UNITY_IPHONE return _isTwitterAvailable(); #else return false; #endif } public void PostToTwitter(string text) { #if UNITY_IPHONE // Call native function _postToTwitter(text); #endif } }
Now we can do something like the following from within the game.
if (TwitterSharing.IsTwitterAvailable()) { TwitterSharing.PostToTwitter("Tweet!"); }
This will bring up a twitter share dialog for the user to tweet with the text “Tweet!” already filled in. Some things to go over in the future include performing an action when the player successfully tweets and attaching a screenshot/image.
More information is available at http://www.mono-project.com/Interop_with_Native_Libraries.
Unity Property Drawer Attributes
The Unity editor is a really useful tool when making a game. A lot of its power comes from how customizable it is. If you want to make a new window to do some custom action it is as easy as writing code like you would for the game. Custom inspectors and property drawers are the most common form of customization. These work in the inspector to simplify working with your components.
There are preexisting property drawer attributes you can use to simplify your inspector. Recently, I wanted to find if there was one I could use for a script I was working on. Unfortunately there wasn’t a comprehensive list of attributes built in to Unity. So I went ahead and made a list for future reference.
Range
Since 4.0
This changes a float
or int
to a slider. The parameters are the lowest and highest allowed values.
[Range(0, 100.5f)] public float range; [Range(0, 5)] public int moreRange; [Range(0, 10)] public float[] rangeArray;
Multiline
Since 4.0
Changes a string to use multiple lines in the input field. The optional parameter is the number of lines.
[Multiline] public string multiline; [Multiline(6)] public string moreMultiline; [Multiline] public string[] multilineArray;
Textarea
Since 4.5
Changes a string to a multiple line text area with scroll bars when the text doesn’t fit.
[TextArea] public string textArea; [TextArea(3, 6)] public string moreTextArea; [TextArea] public string[] textAreaArray;
There are other attributes which do not alter behavior or appearance I will likely go over later.
Unity Android Plugin Environment
I’ve recently begun work on android platform integrations into Crowman & Wolfboy. We’ve had a playable build of the game on Android for a while now, but some parts need more integration than others. I ended up having to write a java library for inclusion in the project.
This posed a new problem for us. All our iOS native plugins were included as objective-c files. Unity then copied those source files into the compiled project for XCode to build. This made it easy to include the source files in version control while keeping the build process simple. Android plugins aren’t so simple.
Unity requires android plugins be precompiled JAR files. I think it has something to do with Unity’s build process for android apps, but that doesn’t really matter. Those JAR files must be in the ‘Special Folder’ at the path Assets/Plugins/Android/. I wanted a way to easily keep the java source files in the same repository as the main project, but also keep the build process for the plugin simple.
The first thing I tried was putting the whole Eclipse workspace under versio control. That didn’t work because a lot of paths are saved as part of the workspace. The JDK path is different for different developers. The Android SDK path is different too.
I ended up making an Eclipse workspace adjacent to the main project folder. This workspace contained java projects as usual. Those java projects then used linked source folders. The source files were in a sub folder of the special android plugin folder. Each eclipse project then linked to its specific source folder. Then I can export the JAR to an external location (that being the special android plugin folder).
This setup will requires each developer configure their own eclipse workspace. Other than that the build process for a change to java code is easy as an export in Eclipse followed by a build in the Unity Editor. Not quite the ideal one-click-build, but java code shouldn’t be changed very often anyway.
XKCD Colors
I was working on a post about integrating the TestFlight SDK into Unity, but since it is no more I’ll have to skip that topic.
Instead let me introduce, XKCD Colors as less mixins.
I am an avid reader of the XKCD comics. If you haven’t read it take a minute right now to go read some. It is a staple of internet culture.
Well, a little while ago Randall held a survey about color names. The survey showed a color on screen and asked the user to name it. The names for each hex code were compiled into a list. I converted the list into LESS mixins to make them more useful. You are free to download and us the file yourself.
Some color names contained characters not allowed in CSS. I converted spaces to dash (‘ ‘ to ‘-‘) slashes to double dashes (‘/’ to ‘–‘) and removed apostrophes. I also prefixed each color name with “xkcd-” to prevent conflicts. In total there are 949 colors.
Here’s a sample.
@xkcd-fern-green: #548d44; @xkcd-bright-lilac: #c95efb; @xkcd-weird-green: #3ae57f; @xkcd-peacock-blue: #016795; @xkcd-avocado-green: #87a922; @xkcd-faded-orange: #f0944d; @xkcd-grape-purple: #5d1451; @xkcd-hot-green: #25ff29; @xkcd-lime-yellow: #d0fe1d; @xkcd-mango: #ffa62b;