Contents

1
.
Brief Introduction to Unity
2
.
Hands-on Demonstrations
2
.
1
.
Wrecking Ball Simulation
2
.
2
.
Playable Piano
2
.
3
.
Polyhedron Dodger Game

What is Unity?

Unity is a world-leading game engine using by millions of developers.
Supports both 2D and 3D games for a large variety of platforms.

What does Unity Provide?

Industry Standard Physics Engine

Unity uses PhysX for its physics engine. PhysX is a scalable multi-platform real-time physics solution supporting a wide range of devices, from smartphones to high-end multicore CPUs and GPUs. Unity supports a wide range of physical colliders, joints and other components, both in 2D and 3D.

Lighting & Rendering

Unity provides options for both performant and high fidelity rendering. Many rendering effects run at real-time, but more complex lighting calculations can be baked to avoid running heavy calculations at runtime. Their more recent shader pipelines support shader authoring through a graph GUI.

Extensive Built-In Utilities

Unity also provides numerous tools for tasks such as terrain generation and navigation. In addition to the built-in tools, Unity provides a simple package system that allows users to import both Unity-made standard assets or user-made assets from the AssetStore.

What does the WL Provide?

Scripting Environment

The Wolfram Language provides a unique powerful scripting environment for the Unity engine and the Unity editor. A Unity project can be created, launched, modified, monitored, and built – all from within a single Wolfram notebook. Users may also run Unity as a background process and use a notebook as the sole interface.

Content Creation

The Wolfram Language allows for the easy creation of synthesized audio, colorful visuals and procedural geometric content. Wolfram Language users also have access to the Wolfram Knowledgebase – an extensive repository of curated data, including 3D models and textures. The Wolfram Language also contains numerous functions for processing this content and exporting it into all common file formats.

Introduction to Unity

Before diving into Unity, let’s quickly review the four (4) key topics in Unity.

Scenes

◼
  • The 3D environment which contains everything you see from UI to 3D objects (terrain, buildings, players, etc.).
  • Game Objects

    ◼
  • Exists within a single scene.
  • ◼
  • Act as containers for components, which implement the real functionality.
  • ◼
  • Everything in a scene is either a game object or attached to one.
  • Game Object Components

    ◼
  • Control lighting, physics, audio, rendering, and more.
  • ◼
  • Must be attached to game objects.
  • Assets

    ◼
  • Any file that can be used within your game.
  • ◼
  • Exist within the Assets folder of your project.
  • ◼
  • Can be referenced by components in one or more scenes.
  • ◼
  • Examples: 3D models, audio files, images
  • Introduction to Unity II

    In the Unity Editor, these can be found in the following areas.

    Creating a Unity Project

    1. Download Unity Hub from the official Unity website.
    2. Choose a version of the Unity Editor to install.
    3. Once installed, load the UnityLink paclet.
    In[]:=
    Needs["UnityLink`"]
    4. Create a new Unity project.
    In[]:=
    UnityOpen["/Users/alecs/Desktop/UnityDemos"]

    Demo - Wrecking Ball

    In this first demo, we will create a wall of cubes to be knocked down by a swinging wrecking ball. This will require:
    ◼
  • Creating scenes, game objects, and assets.
  • ◼
  • Adding and modifying components.
  • ◼
  • Using Unity’s physics engine (PhysX).
  • Falling Cube Test

    Let’s start with something simple – making a cube fall.
    1. Create a cube game object.
    In[]:=
    gameObject=CreateUnityCube["MyCube"]
    Out[]=
    UnityGameObject
    GameObject
    : MyCube
    position: {0.,0.,0.}
    
    2. Show the default components on Unity’s cube primitive.
    In[]:=
    gameObject["Components"]
    Out[]=
    UnityTransform
    Transform
    : MyCube
    position: {0.,0.,0.}
    ,UnityMeshFilter
    Mesh Filter
    : MyCube
    shared mesh: Cube
    ,UnityBoxCollider
    Box Collider
    : MyCube
    size: {1.,1.,1.}
    ,UnityMeshRenderer
    Mesh Renderer
    : MyCube
    receive shadows: True
    
    3. Apply physics to the cube using a Rigidbody component.
    In[]:=
    CreateUnityRigidbody[gameObject]
    Out[]=
    UnityRigidbody
    Rigidbody
    : MyCube
    use gravity: True
    
    4. Create a plane for the cube to land on.
    In[]:=
    CreateUnityPlane["Plane"]
    Out[]=
    UnityGameObject
    GameObject
    : Plane
    position: {0.,0.,0.}
    
    5. Move and rotate the cube so it sits above the plane.
    In[]:=
    (*UsethePartassignmentsyntaxtosetpropertiesofUnityobjectsfromtheWolframLanguage*)​​gameObject[["Position"]]={0,8,0};​​gameObject[["EulerAngles"]]={30,45,90};
    6. Switch the Unity Editor to Play mode.
    In[]:=
    UnityPlay[]
    7. Exit Play mode.
    In[]:=
    UnityStop[]

    Organizing the Project

    Before going any further, it’s good practice to keep your Unity project organized.
    1. Create some folders in the Assets directory.
    In[]:=
    CreateUnityAssetDirectory[{"Scenes","Materials","Prefabs","Scripts","Meshes","Audio"}]
    Out[]=
    {Scenes,Materials,Prefabs,Scripts,Meshes,Audio}
    2. Create a new scene for the wrecking ball demo.
    In[]:=
    CreateUnityScene[File["Scenes/WreckingBall"]]
    Out[]=
    UnityScene
    Scene
    : WreckingBall
    path: Assets/Scenes/WreckingBall.unity
    
    Now all of our changes can be saved to this scene file.
    3. Create some Material assets. Materials are used to determine the appearance of rendered game objects (similar to graphics directives in the WL).
    In[]:=
    redMat=CreateUnityMaterialFile["Materials/Red"],
    ​​grayMat=CreateUnityMaterialFile["Materials/Gray"],
    ​​blueMat=CreateUnityMaterialFile["Materials/Blue"],
    
    Out[]=
    UnityMaterial
    Material
    : Red
    shader: Standard
    
    Out[]=
    UnityMaterial
    Material
    : Gray
    shader: Standard
    
    Out[]=
    UnityMaterial
    Material
    : Blue
    shader: Standard
    

    Creating a Prefab

    Our goal is to build a wall of identical cube game objects. We could do this by copying a single game object in the scene.
    However, a better solution is to create a Prefab, which allows us to store a game object as an asset. Once the prefab is created, we can easy create instances of it in our scene.
    1. Create another default cube game object.
    In[]:=
    gameObject=CreateUnityCube["Cube"]
    Out[]=
    UnityGameObject
    GameObject
    : Cube
    position: {0.,0.,0.}
    
    2. Add a Rigidbody component.
    In[]:=
    CreateUnityRigidbody[gameObject]
    Out[]=
    UnityRigidbody
    Rigidbody
    : Cube
    use gravity: True
    
    3. Assign the blue material to the cube.
    In[]:=
    gameObject["MeshRenderer"][["Material"]]=blueMat;
    4. Create the prefab asset from the game object.
    In[]:=
    prefab=CreateUnityPrefab[File["Prefabs/Cube"],gameObject]
    Out[]=
    UnityGameObject
    GameObject
    : Cube
    position: {0.,0.,0.}
    
    5. Delete the original game object.
    In[]:=
    DeleteUnityGameObject[gameObject]

    Constructing a Wall

    1. Generate the positions of the cubes.
    In[]:=
    cubePositions=Flatten[Table[{x,y+1/2,z},{x,-4,4},{y,0,5},{z,0,1}],2];​​cubePositions//Short
    Out[]//Short=
    -4,
    1
    2
    ,0,-4,
    1
    2
    ,1,-4,
    3
    2
    ,0,102,4,
    9
    2
    ,1,4,
    11
    2
    ,0,4,
    11
    2
    ,1
    In[]:=
    (*Note:Unityconsidersthey-axistobevertical*)​​Graphics3D[{Cube/@cubePositions}]
    Out[]=
    2. Create a wall game object to act as the parent for all the cubes.
    In[]:=
    wall=CreateUnityGameObject["Wall"]
    Out[]=
    UnityGameObject
    GameObject
    : Wall
    position: {0.,0.,0.}
    
    3. Instantiate the Cube prefab for each position.
    In[]:=
    cubes=Table[​​gameObject=CreateUnityGameObject["Cube",prefab];​​gameObject[["Position"]]=pos;​​gameObject[["Parent"]]=wall;​​gameObject,​​{pos,cubePositions}​​];​​cubes//Length
    Out[]=
    108
    4. Create a plane for the wall to rest on.
    In[]:=
    floor=CreateUnityPlane["Floor"];​​floor[["LocalScale"]]={10,10,10};​​floor["MeshRenderer"][["Material"]]=grayMat;

    Wrecking Ball

    1. Create a Unity mesh asset from the “Spikey” polyhedron.
    In[]:=
    spikey=RegionResize[PolyhedronData["Spikey","MeshRegion"],{5}]
    Out[]=
    In[]:=
    mesh=CreateUnityMesh[File["Meshes/Spikey"],spikey]
    Out[]=
    UnityMesh
    Mesh
    : Spikey
    vertices: 180
    
    2. Create the wrecking ball game object using the spikey.
    In[]:=
    wreckingBall=CreateUnityGameObject["Wrecking Ball",mesh]
    Out[]=
    UnityGameObject
    GameObject
    : Wrecking Ball
    position: {0.,0.,0.}
    
    3. Add a Rigidbody component with significant mass.
    In[]:=
    rb=CreateUnityRigidbody[wreckingBall]​​rb[["Mass"]]=100;
    Out[]=
    UnityRigidbody
    Rigidbody
    : Wrecking Ball
    use gravity: True
    
    In[]:=
    (*Rigidbodiesrequiremeshcolliderstobeconvex*)​​wreckingBall["MeshCollider"][["Convex"]]=True;
    4. Add a Hinge Joint component to swing the wrecking ball.
    In[]:=
    wreckingBall[["Position"]]={0,20,16};
    In[]:=
    joint=CreateUnityHingeJoint[wreckingBall]
    Out[]=
    UnityHingeJoint
    Hinge Joint
    
    In[]:=
    joint[["Anchor"]]={0,0,-16}
    5. Create a cylinder to act as a support pole.
    In[]:=
    pole=CreateUnityCylinder["Pole"];​​pole[["Parent"]]=wreckingBall;​​pole[["LocalPosition"]]={0,0,-8};​​pole[["LocalScale"]]={0.2,8,0.2};​​pole[["EulerAngles"]]={90,0,0};
    6. Apply materials.
    In[]:=
    pole["MeshRenderer"][["Material"]]=grayMat​​wreckingBall["MeshRenderer"][["Material"]]=redMat

    Wall Destruction

    1. Adjust the camera to give us a better view of the destruction.
    In[]:=
    camera=FindUnityComponent["Main Camera","Camera"]
    Out[]=
    UnityCamera
    Camera
    : Main Camera
    position: {0.,1.,-10.}
    
    In[]:=
    (*Movethecameratoabetterspot*)​​camera["Transform"][["Position"]]={24,6,-3};​​camera["Transform"][["EulerAngles"]]={0,-90,0};
    In[]:=
    (*Useasolidlightgraycolorforthebackground*)​​camera[["ClearFlags"]]="SolidColor";​​camera[["BackgroundColor"]]=LightGray;
    2. Save our progress.
    In[]:=
    SaveUnityScene[];
    3. Start the simulation.
    In[]:=
    UnityPlay[]

    Demo - Piano

    In this demo, we will create a playable piano. This will require:
    ◼
  • Importing audio assets into Unity.
  • ◼
  • Adding custom scripts to game objects.
  • Scene Setup

    1. Create a new scene for our piano.
    In[]:=
    CreateUnityScene[File["Scenes/Piano"]]
    Out[]=
    UnityScene
    Scene
    : Piano
    path: Assets/Scenes/Piano.unity
    
    2. Adjust the camera.
    In[]:=
    camera=FindUnityComponent[All,"Camera"];​​camera[["Transform","Position"]]={3.75`,6.75`,-3.5`};​​camera[["Transform","EulerAngles"]]={45.`,0.`,0.`};​​camera[["ClearFlags"]]="SolidColor";​​camera[["BackgroundColor"]]=GrayLevel[0.15];
    3. Adjust the light.
    In[]:=
    light=FindUnityComponent["Directional Light","Light"];​​light[["Transform","EulerAngles"]]={90,0,0};
    4. Prepare some material assets for the keys.
    In[]:=
    whiteMat=CreateUnityMaterial[File["Materials/White"],White]​​blackMat=CreateUnityMaterial[File["Materials/Black"],Black]
    Out[]=
    UnityMaterial
    Material
    : White
    shader: Standard
    
    Out[]=
    UnityMaterial
    Material
    : Black
    shader: Standard
    

    Interactivity with Scripts

    In Unity, we can write custom components using scripts. Each script defines a C# class that let’s us add unique behaviors to our game objects.
    I have written a script below called PianoKey, which checks if the player clicked on its attached game object. If so, it will play an audio clip and a short animation.
    In[]:=
    pianoKeyScriptText//displayScript
    Out[]=
    using UnityEngine;
    public class PianoKey : MonoBehaviour
    {
    // Settings
    public string key;
    public AudioClip clip;
    public float pressDuration = 0.1f;
    public float unpressDuration = 0.2f;
    // State
    private enum State { Pressing, Unpressing, Idle }
    ...
    }
    1. Manually add the script to our project.
    In[]:=
    filepath=FileNameJoin[{$UnityAssetsDirectory,"Scripts","PianoKey.cs"}];​​Export[filepath,pianoKeyScriptText,"String"]
    Out[]=
    /Users/alecs/Desktop/UnityDemos/Assets/Scripts/PianoKey.cs
    2. Force the Unity scripts in our scene to recompile.*
    In[]:=
    UnityTokenExecute[{"Assets","Refresh"}]
    * This is only necessary if you don’t bring focus back to Unity before adding the script.

    Anatomy of a Piano

    The modern piano has a total of 88 keys, 52 of which are white and are used to play the natural notes (A, B, C, D, E, F and G). The remaining 36 keys are black and are used to play the accidentals (A♯/B♭, C♯/D♭, D♯/E♭, F♯/G♭ and G♯/A♭).
    The notes can be further divided into octaves, each of which contains 12 keys. Two keys with the same note but in different octaves will have different pitches.
    For this demo, we’re only going to recreate the C major scale for simplicity.
    To generate the notes, we can simply use the SoundNote function.
    In[]:=
    Audio[SoundNote["C4",3,"Piano"]]
    Out[]=
    00:00
    00:03
    cloud object
    We can get all the natural notes in the 4th octave by appending “4” to the note names.
    In[]:=
    naturalNotes={"C","D","E","F","G","A","B"};​​Table[Audio[SoundNote[note<>"4"]],{note,naturalNotes}]//AudioJoin
    Out[]=
    00:00
    00:07
    We can then do the same for the accidentals.
    In[]:=
    accidentalNotes={"C♯","D♯","F♯","G♯","A♯"};​​Table[Audio[SoundNote[note<>"4"]],{note,accidentalNotes}]//AudioJoin
    Out[]=
    00:00
    00:05

    Audio Assets

    In order to play audio in our game, we need to generate Audio Clip assets. We can import Audio objects directly from the WL into Unity.
    1. Define the notes we want to generate.
    In[]:=
    notes={"C4","D4","E4","F4","G4","A4","B4","C#4","D#4","F#4","G#4","A#4","C5"};
    2. Create an Audio Clip asset for each note.
    In[]:=
    clips=Association[Table[​​audio=Audio[SoundNote[note,2.5,"Piano"]];​​noteCreateUnityAudioClip[File["Audio/note_"<>note],audio],{note,notes}]​​];
    In[]:=
    clips//Short
    Out[]//Short=
    C4UnityAudioClip
    AudioClip
    : note_C4
    length: 2.53
    ,11,C5UnityAudioClip
    AudioClip
    : note_C5
    length: 2.53
    

    Key Mesh Assets

    The piano keys could be built from cube primitives, however I found that they’re simple enough to specify manually.
    1. Define the dimensions of the keys.
    In[]:=
    whiteWidth=7/8;​​whiteLength=6;blackWidth=15/32;blackLength=4;height=7/8;gap=1/16;
    2. Generate the base shape for each key type.
    In[]:=
    coordinates=
    ;​​coordIndices={​​{1,2,3,4},{1,2,3,5,6,7},{1,2,8,9,10,4},{1,2,8,9,10,5,6,7},{9,11,12,10}​​};​​polygons=Table[Polygon[coordinates[[indices]]],{indices,coordIndices}];​​GraphicsRow[Graphics/@polygons,ImageSizeSmall]
    Out[]=
    3. Extrude the key shapes to create mesh regions.
    In[]:=
    line=BoundaryMeshRegion[{{0},{height}},Point[{{1},{2}}]];​​regions=Table[RegionBoundary[RegionProduct[BoundaryMeshRegion[polygon],line]],{polygon,polygons}];​​GraphicsRow[regions]
    Out[]=
    4. Create a Unity Mesh asset for each key mesh.
    In[]:=
    meshes=Table[CreateUnityMesh[File["Meshes/key_"<>ToString[i]],regions[[i]]],{i,Length[regions]}]
    Out[]=
    UnityMesh
    Mesh
    : key_1
    vertices: 24
    ,UnityMesh
    Mesh
    : key_2
    vertices: 36
    ,UnityMesh
    Mesh
    : key_3
    vertices: 36
    ,UnityMesh
    Mesh
    : key_4
    vertices: 48
    ,UnityMesh
    Mesh
    : key_5
    vertices: 24
    

    Putting it All Together

    Now that we’ve generated all the necessary assets, we can combine them to make our piano.
    To save time, I’ve defined the relevant properties for each key in two lists, which will allow us to generate all the keys at once.
    1. For each key, specify the computer keyboard key it corresponds to, the musical note it should play, and the index of the mesh it should use.
    In[]:=
    whiteKeys={​​"Keycode""q","Note""C4","Mesh"3,"Keycode""w","Note""D4","Mesh"4,"Keycode""e","Note""E4","Mesh"2,"Keycode""r","Note""F4","Mesh"3,"Keycode""t","Note""G4","Mesh"4,"Keycode""y","Note""A4","Mesh"4,"Keycode""u","Note""B4","Mesh"2,"Keycode""i","Note""C5","Mesh"1​​};​​​​(*Themeshindexfortheblackkeysareimplicitlyassumedtobe5*)​​blackKeys={​​<|"Keycode""2","Note""C#4"|>,​​<|"Keycode""3","Note""D#4"|>,​​Null,(*Representsthegapbetweenthe2ndand3rdblackkeys*)​​<|"Keycode""5","Note""F#4"|>,​​<|"Keycode""6","Note""G#4"|>,​​<|"Keycode""7","Note""A#4"|>​​};
    2. Create a parent game object to organize all the keys.
    In[]:=
    parent=CreateUnityTransform["Piano Scale"]
    Out[]=
    UnityTransform
    Transform
    : Piano Scale
    position: {0.,0.,0.}
    
    3. Iterate to generate all the white key game objects.
    In[]:=
    Do[​​key=whiteKeys[[i]];​​name="Key "<>key["Note"]<>" (White)";​​go=CreateUnityGameObject[name,meshes[[key["Mesh"]]]];​​go[["Transform","Position"]]={(i-1)*(whiteWidth+gap),0,0};​​go[["Transform","Parent"]]=parent;​​script=CreateUnityComponent[go,"PianoKey"];​​script[["Key"]]=key["Keycode"];​​script[["Clip"]]=clips[key["Note"]];​​,{i,Length[whiteKeys]}​​]
    4. Similarly generate the black keys.
    In[]:=
    Do[​​key=blackKeys[[i]];​​If[key===Null,Continue[]];​​name="Key "<>key["Note"]<>" (Black)";​​go=CreateUnityGameObject[name,meshes[[5]]];​​go[["Transform","Position"]]={(i-1)*(whiteWidth+gap),1/4,0};​​go[["Transform","Parent"]]=parent;​​script=CreateUnityComponent[go,"PianoKey"];​​script[["Key"]]=key["Keycode"];​​script[["Clip"]]=clips[key["Note"]];​​,{i,Length[blackKeys]}​​]
    5. Assign the materials we created earlier.
    In[]:=
    whiteMat=FindUnityAsset["White","Material"];​​blackMat=FindUnityAsset["Black","Material"];​​​​whiteMeshRenderers=FindUnityComponent["*White*","MeshRenderer",All];​​Do[wmr[["SharedMaterial"]]=whiteMat,{wmr,whiteMeshRenderers}]​​​​blackMeshRenderers=FindUnityComponent["*Black*","MeshRenderer",All];​​Do[bmr[["SharedMaterial"]]=blackMat,{bmr,blackMeshRenderers}]

    Play the Piano

    1. Save our scene for good measure.
    In[]:=
    SaveUnityScene[];
    2. Play the piano.
    In[]:=
    UnityPlay[]

    Demo - Polyhedron Dodger

    In this demo, we will create a simple game where the player tries to dodge large polyhedra falling from the sky.

    Scene Setup

    1. Create a new scene.
    In[]:=
    CreateUnityScene[File["Scenes/PolyhedronDodger"]]
    Out[]=
    UnityScene
    Scene
    : PolyhedronDodger
    path: Assets/Scenes/PolyhedronDodger.unity
    
    2. Create a floor game object.
    In[]:=
    floor=CreateUnityPlane["Floor"];​​floor[["LocalScale"]]={100,1,100};​​floor["MeshRenderer"][["Material"]]=FindUnityAsset["Gray","Material"];
    3. Adjust the camera.
    In[]:=
    camera=FindUnityGameObject["Main Camera"];​​camera[["Position"]]={0,20,-20};​​camera[["EulerAngles"]]={35,0,0};
    4. Adjust the light.
    In[]:=
    light=FindUnityGameObject["Directional Light"];​​light[["Position"]]={0,100,0};​​light[["EulerAngles"]]={90,0,0};

    Custom Scripts

    Once again, we’ll be using scripts to add custom behaviors to our game objects.

    PlayerController

    The PlayerController script does two main tasks:
    ◼
  • Apply physical forces to the player rigidbody to move it using WASD controls.
  • ◼
  • Checks if the player lost, and if so displays a game over message.
  • In[]:=
    playerControllerScript//displayScript
    Out[]=
    using UnityEngine;
    public class PlayerController : MonoBehaviour
    {
    private Rigidbody _rb;
    private float _speed = 1000f;
    private bool _gameOver;
    private GUIStyle _style;
    private void Awake()
    {
    _rb = this.GetComponent<Rigidbody>();
    ...
    }

    FallingObject

    The FallingObject script also has two main tasks:
    ◼
  • Reset the object to a random position in the sky when it falls too low.
  • ◼
  • Check if it collided with the player.
  • In[]:=
    fallingObjectScript//displayScript
    Out[]=
    using UnityEngine;
    public class FallingObject : MonoBehaviour
    {
    private float _spawnHeight = 25f;
    private float _opaqueHeight = 15f;
    private Material _material;
    private void Awake()
    {
    _material = this.GetComponent<MeshRenderer>().material;
    ResetPosition();
    ...
    }
    Create the PlayerController and FallingObject script assets.
    In[]:=
    filepath1=FileNameJoin[{$UnityAssetsDirectory,"Scripts","PlayerController.cs"}];​​filepath2=FileNameJoin[{$UnityAssetsDirectory,"Scripts","FallingObject.cs"}];​​​​Export[filepath1,playerControllerScript,"String"]​​Export[filepath2,fallingObjectScript,"String"]
    Out[]=
    /Users/alecs/Desktop/UnityDemos/Assets/Scripts/PlayerController.cs
    Out[]=
    /Users/alecs/Desktop/UnityDemos/Assets/Scripts/FallingObject.cs

    Create the Player

    1. Find the Spikey mesh asset we created earlier.
    In[]:=
    spikey=FindUnityAsset["Spikey"]
    Out[]=
    UnityMesh
    Mesh
    : Spikey
    vertices: 180
    
    2. Create the player game object with the mesh.
    In[]:=
    gameObject=CreateUnityGameObject["Player",spikey]
    Out[]=
    UnityGameObject
    GameObject
    : Player
    position: {0.,0.,0.}
    
    3. Adjust the size and position of the player.
    In[]:=
    gameObject[["Position"]]={0,0.7,0}​​gameObject[["LocalScale"]]={1/3,1/3,1/3}
    4. Add a Rigidbody component.
    In[]:=
    CreateUnityRigidbody[gameObject]
    Out[]=
    UnityRigidbody
    Rigidbody
    : Player
    use gravity: True
    
    In[]:=
    gameObject["MeshCollider"][["Convex"]]=True
    5. Add the PlayerController script.
    In[]:=
    CreateUnityComponent[gameObject,"PlayerController"]
    Out[]=
    UnityScript
    Player Controller
    
    6. Update the material.
    In[]:=
    gameObject["MeshRenderer"][["Material"]]=FindUnityAsset["Red","Material"];
    7. Set the tag so the falling objects know when they collide with the player.
    In[]:=
    gameObject[["Tag"]]="Player";

    Polyhedron Objects

    1. Generate some polyhedrons from PolyhedronData.
    In[]:=
    names={"RhombicHexecontahedron","SquareCupola","SnubCube","GyroelongatedPentagonalCupolarotunda",{"Antiprism",10},"PentagonalIcositetrahedron"};​​polyhedrons=Table[RegionResize[PolyhedronData[name,"MeshRegion"],{5}],{name,names}];​​GraphicsRow[polyhedrons]
    Out[]=
    2. Create a Mesh asset for each polyhedron.
    In[]:=
    meshes=Table[CreateUnityMesh[File["Meshes/polyhedron_"<>ToString[i]],polyhedrons[[i]]],{i,Length[polyhedrons]}]
    Out[]=
    UnityMesh
    Mesh
    : polyhedron_1
    vertices: 240
    ,UnityMesh
    Mesh
    : polyhedron_2
    vertices: 40
    ,UnityMesh
    Mesh
    : polyhedron_3
    vertices: 120
    ,UnityMesh
    Mesh
    : polyhedron_4
    vertices: 150
    ,UnityMesh
    Mesh
    : polyhedron_5
    vertices: 80
    ,UnityMesh
    Mesh
    : polyhedron_6
    vertices: 120
    
    3. Create the first falling object.
    In[]:=
    object=CreateUnityGameObject["Falling Object (1)",meshes[[1]]]
    Out[]=
    UnityGameObject
    GameObject
    : Falling Object (1)
    position: {0.,0.,0.}
    
    4. Update its material and renderer.
    In[]:=
    yellowMat=CreateUnityMaterialFile["Materials/Yellow"],
    ;
    In[]:=
    object["MeshRenderer"][["Material"]]=yellowMat;
    5. Add a Rigidbody.
    In[]:=
    rb=CreateUnityRigidbody[object];​​rb[["Drag"]]=1.0;
    In[]:=
    object["MeshCollider"][["Convex"]]=True​​(*Triggersdonotreacttocollision,butwilltriggeranevent*)​​object["MeshCollider"][["IsTrigger"]]=True
    6. Add the FallingObject script.
    In[]:=
    CreateUnityComponent[object,"FallingObject"]
    Out[]=
    UnityScript
    Falling Object
    
    7. Automatically generate game objects for the remaining polyhedrons, using the first one as a template.
    In[]:=
    Do[​​go=CreateUnityGameObject["Falling Object ("<>ToString[i]<>")",object];​​go["MeshFilter"][["SharedMesh"]]=meshes[[i]];​​go["MeshCollider"][["SharedMesh"]]=meshes[[i]];​​,{i,2,Length[polyhedrons]}​​]

    Play the Game

    1. Save the scene.
    In[]:=
    SaveUnityScene[];
    2. Play the game.
    In[]:=
    UnityPlay[]
    3. Build the game for my platform (MacOS).
    In[]:=
    UnityBuild[]
    Out[]=
    Success
    ✓
    ErrorCount: 0
    WarningCount: 1
    
    SystemOpen[...]
    Example of Piano WebGL build:
    https://blog.wolfram.com/2019/06/06/how-i-built-a-virtual-piano-with-the-wolfram-language-and-the-unity-game-engine/

    Thank You!

    Learn More About UnityLink

    Documentation
    ​https://reference.wolfram.com/language/UnityLink/guide/UnityLink.html
    Overview & Examples
    ​https://www.wolfram.com/language/12/built-in-interface-to-unity-game-engine/index.html?product=language

    Previous Talks on UnityLink

    https://www.youtube.com/watch?v=9wDoxSs68P0
    https://www.youtube.com/watch?v=Z_Tz95939Vw

    Questions?

    In[]:=
    go=FindUnityGameObject["Floor"]
    Out[]=
    UnityGameObject
    GameObject
    : Floor
    position: {1.,2.,3.}
    
    In[]:=
    go["Position"]
    Out[]=
    {1.,2.,3.}

    Library

    Scripts

    DisplayScript
    

    PianoKey
    

    PlayerController
    

    FallingObject
    

    CITE THIS NOTEBOOK

    Build your first game in the Wolfram Language with Unity game engine​
    by Alec Shedelbower​
    Wolfram Community, STAFF PICKS, May 18 2023
    ​https://community.wolfram.com/groups/-/m/t/2921593