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/project
for 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Â
Other
on the left side - Choose
Library
on the right side - Change the
Library
drop down to “F#” - Click the
Next
button - Enter your project and solution name to your liking
- Change
Location
to your project:/path/to/project
- Click the
Create
button
Make the Project Use .NET 3.5 and Deploy to Assets
- From the top bar, click
Project
- Click
YourProjectName Options
from the drop-down - Under
Build
on the left side, clickGeneral
- On the right side, change
Target framework
toMono/.NET 3.5
- Under
Build
on the left side, clickOutput
- On the right side, change
Output path
to/path/to/project/Assets
- Click OK
Make the Project Use FSharp.Core.dll
and UnityEngine.dll
- In the
Solution
pane, click the triangle next toReferences
- Right-click on
FSharp.Core
and clickDelete
- Right-click on
System.Numerics
and clickDelete
- Right-click on
References
itself and clickEdit References...
- Click the
.NET Assembly
tab - Click the
Browse...
button - Navigate to
/path/to/project/FSharp
- Click on
FSharp.Core.dll
- Click the
Open
button - Click the
Browse...
button - Navigate to
/Applications/Unity/Unity.app/Contents/Frameworks/Managed
- Click on
UnityEngine.dll
- Click the
Open
button - Click the
OK
button - In the
Solution
pane underReferences
, right-clickUnityEngine
and clickLocal Copy
to uncheck it
Create a Simple Script
- Replace the contents of the
Component1.fs
file 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
Project
pane, click the triangle next toYourProjectName
- Drag
SimpleScript
ontoMain Camera
in theHierarchy
pane - Save the scene
- Press the play button to play the scene
- Observe that the
Console
pane 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#.