Using the Package with Unity Game Engine¶
This is a sort of experiment I did while developing this package, which I focused in making a simple working example in Unity and make it work with a build. I executed all necessary functions to check which python interpreter and where the module is being loaded. And they returned that they were loaded from the game build path, which it’s important when you ship your game so you don’t need to ask for the user to install python together with your game.
However I did not try to execute it in a machine that doesn’t have Python, so if you want to use it in production that test must be made.
So in this example we will learn how to:
- Configure a Unity project
- Use Python using Unity
- Learn how to install a package using pip and use inside Unity
- Code C# using python modules and Python.Net
Note
You can’t use yaml if you use Unity because PyYaml raises errors, so you have to use json raws.
Setting a Unity Project¶
For this we are using Unity 2019.02.0f1 but it would probably work with any Unity that is able to execute .net framework 4.x.
So, create a new Unity project as normal, for learning purposes let’s name the project core_data. Then set the API compatibility to framework 4.x you can read how to in this link: https://docs.microsoft.com/en-us/visualstudio/cross-platform/unity-scripting-upgrade?view=vs-2019#enabling-the-net-4x-scripting-runtime-in-unity which will inform a couple more things about the difference between the versions.
Note
I tested with netstandard 2.0 however it did not work because dynamic fields needs a microsoft dll which is not referenced.
Installing Python.net¶
The easiest way that I found how to set everything up, is first of all, install python 3.7 64 bits, or 32 depending on the final build you desire and then install virtualenv with this command:
pip install virtualenv
If you fell with a parachute here. The command above installs packages from the Python Library Index (PyPI) and virtualenv let you create a python interpreter that is not linked to the one installed into the system. So, pretty much we will create a virtualenv, cd to the root of your project and run this code:
virtualenv Packages/python_net
Wait for the command to execute. Then activate the virtualenv with:
./Packages/python_net/Scripts/activate
Then simply install Python.Net with:
pip install pythonnet
Lastly create a file inside core_data/Packages/python_net named package.json with this contents:
{
"name": "com.company.package_name",
"version": "0.0.1",
"displayName": "Example",
"description": "Any Description"
}
Unity just needs those fields, the contents can be almost anything, but version and name fields needs to follow the pattern above.
Installing PandaCoreData¶
The Python interpreter needs to load the module, but Unity compacts everything, but it doesn’t compact anything inside the folder Assets/StreamingAssets so create that folder if it doesn’t exist, then cd to that folder. Then execute this command:
pip install --ignore-installed git+https://github.com/Cerberus1746/PandaCoreData.git --install-option="--prefix=absolute_folder"
And replace absolute_folder with the absolute folder to your streaming assets folder. Wait the command to execute and you are done.
Follow this tutorial Getting Started and create the file structure with the command in there but inside Assets/StreamingAssets folder. Probably you would need to use the quickstart command like this:
./Script/panda_core_data_commands -o . -re json
Considering that you are executing that command inside the streaming folder, it will create a mods folder using json raws. Again, yaml won’t work. Then follow Getting Started as normal, of course, you won’t need to install again the package. But delete the main.py file, you won’t be needing it because we use a:
C# Main File¶
And here’s the final working example, the results will be the same as the Getting Started but this file will need to be inside the Assets folder, outside StreamingAssets folder. For convenience sake, let’s call it main.cs
using UnityEngine;
using Python.Runtime;
using System.IO;
using System.Collections.Generic;
namespace PythonTest {
public class PythonTest : MonoBehaviour {
void Start() {
using(Py.GIL()) {
// Let's import sys
dynamic py_sys = Py.Import("sys");
// We need this so we add the python modules from the streaming assets.
// Otherwise the module won't load.
string site_pkg = "Lib\\site-packages";
py_sys.path.insert(0, Path.Combine(Application.streamingAssetsPath, site_pkg));
// Now we can import all necesary modules for the example.
dynamic py_panda_core_data = Py.Import("panda_core_data");
dynamic py_dataclasses = Py.Import("dataclasses");
dynamic py_builtin = Py.Import("builtins");
// Now we get the mods folder from streaming assets
string mods_folder = Path.Combine(Application.streamingAssetsPath, "mods");
// And now we can use the data_core just like we do in python.
// List type is automatically converted to python equivalent with Pyton.Net
py_panda_core_data.data_core(mods_folder, templates_folder: false,
excluded_extensions: new List<string>(){"meta"});
// Now we iterate along all model instances
dynamic item_model = py_panda_core_data.data_core.get_model_type("items");
foreach(dynamic instance in item_model) {
// And we can iterate along all fields
foreach(dynamic field in py_dataclasses.fields(instance)) {
// And show the field name and field value
Debug.Log($"{field.name}: {py_builtin.getattr(instance, field.name)}");
}
}
}
}
}
}
Then attatch this script to the camera or any object that you prefer. Then all you need to do is hit play or build the project if you want.