This vignette supplements unifir 101 and unifir 102 to get into the weeds of how you can add assets – which is to say, any sort of object or event that isn’t specifically provided by the Unity engine itself – into your Unity scenes. If you’re trying to build scenes with unifir, I recommend checking out unifir 101 first; if you’re looking to extend unifir, I recommend reading both the other vignettes to start. This vignette will be a bit shorter than the other two, focused entirely on how to import and instantiate assets in your world.
An “asset” in Unity is a really vague category – it’s any item you’re including in a scene, be it 3D models, code, audio, or really any other type of data. To get away from this vagueness, unifir uses a slightly more pragmatic definition: an asset is any file or directory you want to include in your Unity project.
Unity provides a neat format for moving collections of assets around,
allowing you to compress folders into “unitypackage” files which can be
imported into other projects. Unfortunately, importing these packages
using Unity’s batchmode API currently does not work (and hasn’t worked
for a number of years). So rather than deal with this format and Unity’s
tools for moving data around, unifir just copies asset files directly
into your project when running scripts through
action()
.
That’s where the function import_asset()
comes in. This
function takes two main arguments: the script to add the prop to and the
path to the asset to copy (either a single file or a directory, to copy
recursively). For instance, let’s say we want to import all of the files
stored at example_asset
:
We can import that using import_asset()
as follows:
library(unifir)
script <- make_script(
project = file.path(tempdir(), "unifir"),
unity = waiver() # Makes it so make_script won't error if it can't find Unity
)
script <- import_asset(script, example_asset)
(For more information on waiver()
, check out unifir
102).
Now when we run action()
on this script, we’ll copy
example_asset
directly into the Assets
folder
of our Unity project. Note that this is done entirely in R, using
file.copy(..., recursive = TRUE)
, which has two main
implications: first, this copy step won’t be present in your C# code
anywhere, and secondly the original file structure will be preserved if
example_asset
points to a directory.
That second point is particularly important when it comes to actually using these objects in a scene, rather than just having them exist in your project. To talk about that, we should move along to:
There are a lot of ways to actually bring assets into a Unity scene as things that users will interact with or otherwise be affected by in your environment. The easiest one of those to work with, which is the only one unifir puts much thought into, is referred to as a “prefab”. A prefab is a Unity GameObject that incorporates external data and code, stored as a single file; for more information on prefabs and how to use them I’d recommend the official Unity documentation. For our purposes, I’m going to assume you’ve already got a prefab created and you want to import it into your scene.
The first step in doing so is to use import_asset()
in
order to bring your prefab file (along with all the external
files it relies on) into the Unity project. In order to turn that file
into an actual object in the environment, we can use the
instantiate_prefab()
function from unifir. This function
can work with just two arguments (though there are more, documented in
?instantiate_prefab
): the script object and the path to the
prefab you want to instantiate.
Importantly, that path is relative to the Unity project root
directory, not your current working directory. Since we used
import_asset()
to import our “asset” earlier, that means
our asset is inside the “Assets” directory inside our Unity project, and
we can instantiate it as follows:
If you used import_asset()
to import a directory, the
file structure of your directory will be preserved. That means that, if
example_asset
were a directory containing a prefab at
sub_directory/example.prefab
, we’d set
prefab_path = Assets/example_asset/sub_directory/example.prefab
instead.
We can use the other arguments to instantiate_prefab()
to customize our object further, specifying its location, rotation, and
scaling as desired.
Because prefabs can exist at different locations in imported assets,
and a single asset directory can contain multiple prefabs, unifir can’t
automatically infer what prefab you’re trying to create with
instantiate_prefab
. That means every time you want to add
GameObjects to a scene, you need to go through this two-step process
with import_asset
and instantiate_prefab
,
specifying the path to the asset to import and then the path to the
prefab itself.
For a small set of objects, however, unifir
makes things
a bit easier. A collection of permissively-licensed assets at https://github.com/mikemahoney218/unity_assets/
can be automatically added to the scene using the helper functions
add_default_player
and add_default_tree
. Those
functions will handle downloading assets, importing them into Unity, and
instantiating the prefabs, making it easy to add player controllers and
3D trees to your scene. These objects are also all permissively licensed
– the controllers are currently all MIT-licensed, while the trees are
CC-0 1.0 – making them free to use in any of your projects.
The functions – which I’m wrapping here in
if (interactive())
to prevent them from downloading files
on CRAN – take the same arguments as instantiate_prefab
to
let you specify position, scale, and rotation of your objects, but
handle all the file path trickiness for you:
if (interactive()) {
script <- add_default_player(script)
script <- add_default_tree(script, "tree_1")
}
If you have any (permissively-licensed – no GPL or CC-BY) assets you’d like to share as part of this set, open an issue on GitHub!