Tutorial: Using F# with Unity3D
One of the advantages of Unity using Mono and IL2CPP as scripting engines is that any .NET language can be used to code your game or app. Today I’ll show an example of that in the form of F#. How do you go about using an unofficially supported language like this? Read on to for the step-by-step tutorial!
I’ll be using Unity 5.2.1f1 on Mac OS X 10.10.5 with Xamarin Studio 5.9.7 for this tutorial. The steps are likely to be the same for versions in the near future, the MonoDevelop IDE, and on Windows, but they’re not covered here. With that disclaimer out of the way, let’s dive in!
Create a Unity Project
- Create an new Unity project as normal. I’ll refer to its location as
/path/to/projectfor the rest of this tutorial. - Save the default scene as
TestScene
Download the F# Core Library
F# code relies on FSharp.Core.dll. The latest versions of Mono only build this library for .NET 4.0 and up, which Unity doesn’t support. So you’ll need to get the library from an older version of Mono. You can do that yourself, or use my snapshot from Mono 3.12.1. Either way, you’ll want the DLL and its related files:
- FSharp.Core.dll
- FSharp.Core.dll.mdb
- FSharp.Core.optdata
- FSharp.Core.sigdata
- FSharp.core.xml
If you want to get it from an older version of Mono yourself, those files can be found in /Library/Frameworks/Mono.framework/Versions/X.Y.Z/lib/mono/2.0/ where X.Y.Z is the version of Mono you have installed.
Once you have these files, put them in your Unity project: /path/to/project/FSharp.
Create a Xamarin Studio Project
- Open Xamarin Studio
- File > New > Solution…
- ClickÂ
Otheron the left side - Choose
Libraryon the right side - Change the
Librarydrop down to “F#” - Click the
Nextbutton - Enter your project and solution name to your liking
- Change
Locationto your project:/path/to/project - Click the
Createbutton
Make the Project Use .NET 3.5 and Deploy to Assets
- From the top bar, click
Project - Click
YourProjectName Optionsfrom the drop-down - Under
Buildon the left side, clickGeneral - On the right side, change
Target frameworktoMono/.NET 3.5 - Under
Buildon the left side, clickOutput - On the right side, change
Output pathto/path/to/project/Assets - Click OK
Make the Project Use FSharp.Core.dll and UnityEngine.dll
- In the
Solutionpane, click the triangle next toReferences - Right-click on
FSharp.Coreand clickDelete - Right-click on
System.Numericsand clickDelete - Right-click on
Referencesitself and clickEdit References... - Click the
.NET Assemblytab - Click the
Browse...button - Navigate to
/path/to/project/FSharp - Click on
FSharp.Core.dll - Click the
Openbutton - Click the
Browse...button - Navigate to
/Applications/Unity/Unity.app/Contents/Frameworks/Managed - Click on
UnityEngine.dll - Click the
Openbutton - Click the
OKbutton - In the
Solutionpane underReferences, right-clickUnityEngineand clickLocal Copyto uncheck it
Create a Simple Script
- Replace the contents of the
Component1.fsfile that’s already open with this simple script:namespace FSharpUnityTutorial open UnityEngine type SimpleScript() = inherit MonoBehaviour() member this.Start() = Debug.Log("Hello from F#")
- From the top bar, click
Build - Click
Build All
Try out the Simple Script
- Switch back to Unity with your project open
- In the
Projectpane, click the triangle next toYourProjectName - Drag
SimpleScriptontoMain Camerain theHierarchypane - Save the scene
- Press the play button to play the scene
- Observe that the
Consolepane has loggedHello from F#
(Optional) Do More in the Script
From here on it’s just a matter of doing more in your scripts to implement your game or app. Here’s a little script showing how to integrate with the editor’s Inspector pane and use the Unity API a little bit:
namespace FSharpUnityTutorial open UnityEngine type SimpleScript() = inherit MonoBehaviour() // Inspector pane property [<SerializeField>] let mutable numCubes = 3 // Use the Unity3D API let spawnCube x = let cube = GameObject.CreatePrimitive(PrimitiveType.Cube) cube.transform.position <- new Vector3(x, 0.0f, 0.0f) member this.Start() = // Spawn the number of cubes specified in the Inspector pane [1..numCubes] |> List.map (fun x -> float32 x * 1.5f) |> List.iter spawnCube
Remember to build the project each time you make changes to your F# scripts.
Conclusion
Integrating F# into Unity is pretty easy. The trickiest part is working around Unity’s old, forked version of Mono. Once you’ve got that one-time setup issue fixed, you’re off to using F# to code your game or app. To learn more about the language itself, I’d recommend checking out F# For Fun and Profit as well as the resources on FSharp.org.
Would you consider using F# in your games and apps? Have you actually used it before? What was your experience like? Let me know in the comments section below.
#1 by devboy_org on October 16th, 2015 ·
Did you actually manage to run FSharp.Core through IL2CPP?
I’ve been trying for ages and it still generates invalid C++ code for me….
IL_0071:
{
FSharpList_1_t3 * L_21 = V_3;
NullCheck(L_21);
FSharpList_1_t3 * L_22 = (FSharpList_1_t3 *)(L_21->___tail_1);
V_8 = (FSharpList_1_t3 *)L_22;
FSharpList_1_t3 * L_23 = V_4;
NullCheck(L_23);
FSharpList_1_t3 * L_24 = (FSharpList_1_t3 *)(L_23->___tail_1);
V_9 = (FSharpList_1_t3 *)L_24;
FSharpList_1_t3 * L_25 = V_8;
FSharpList_1_t3 * L_26 = V_9;
Object_t * L_27 = ___comp;
___comp = (Object_t *)L_27;
___obj = (Object_t *)L_26;
p-1 = (FSharpList_1_t3 *)L_25;
goto IL_0000;
}
#2 by devboy_org on October 16th, 2015 ·
p-1 is obviously not a valid name, let alone that p doesn’t exist in this scope…
#3 by jackson on October 17th, 2015 ·
While IL2CPP has gotten a lot better since its launch, it still has many issues. I recommend filing this one as a bug with Unity. As its name indicates, IL2CPP should be capable of using any IL, not just IL from C# or UnityScript.
#4 by devboy_org on October 17th, 2015 ·
I filed this like 4-5 months ago :(
#5 by jackson on October 17th, 2015 ·
That’s a shame. I suppose you could keep commenting on the issue to let them know it’s still occurring with each new release of Unity. Perhaps they think they fixed it in 5.1 or 5.2.
#6 by jackson on October 17th, 2015 ·
By the way, can you post a link to the issue you filed? I (and possibly other readers here) would like to vote for it.
#7 by pi on December 17th, 2015 ·
Hello and thanks for the article! I am particularly interested in running different languages in Unity. Specifically Swift and C#.
The one thing you haven’t mentioned is the debugging experience. Is it possible to use MD/VS to debug a .fs the same way we can currently debug a .cs?
That is really the deal breaker, because without integrated debugging, say goodbye to all the productivity gained from using better language!
Ï€
#8 by jackson on December 18th, 2015 ·
That’s a good question and one I haven’t personally tested. MonoDevelop was updated to a very current version with Unity 5.3 and the new version has official support for F#, so there’s a good chance it can also debug F#. I’m just not sure if it will also debug F# inside Unity and as a DLL.
#9 by Paul Blair on April 10th, 2017 ·
I recently filed a bug with Unity concerning another significant F#-related problem and received a response that indicated they’re not planning on fixing it, at least not unless they get a bigger show of support for F# in Unity. For details, see the blog post at http://seriouscodeblog.blogspot.ca/2017/04/no-virginia-you-cant-actually-write.html .
#10 by jackson on April 10th, 2017 ·
That’s a shame, but hopefully the feature voting will result in IL2CPP support for F#.