Assetbundles: How-To

And other useful bits and bobs.

Why assetbundles? Assetbundles allow us to "pre-make" things we can use in the game without having to create them when the game is loaded. Things like converting embedded sprites into usable textures during runtime take a very small amount of time, but when you have over a thousand sprites and VERY large sprites, like bosscards, it adds up *very* fast. Step 0: Install Unity Version 2017.4.40. From what I understand, Gungeon uses this version of Unity specifically and loading assetbundles from different versions of Unity doesn't work from what I've tried. Step 0.1: Download this boilerplate Unity project, which should have a lot of tools deemed useful for advanced things, like custom shaders. Download it here. Note, do NOT use this project for anything else. I WILL kill you otherwise (I'll get executed). Step 0.2: Open the Unity version you just installed, and select the "Open" option.

If everything was done right, it should start processing it, and after a bit, open the project.

Now, we need some extra code in your mod project. That's right, we're not done yet!

Step 0.3: Add this class to your mod, either by just copypasting the code into a fresh class or whatever, and change things as needed. This is a simple class that will let you load your assetbundle by just sticking it in the same folder as your mods DLL.

If you don't have a FilePathFolder, set this up in your module.

You should also create a static reference to your Assetbundle, so when you load it, you can load anything from it from anywhere. Make it a habit to load your assetbundle before anything else.

Alternatively, you can load your assetbundle directly through an embedded resource.

using (Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream("file path in your project to your bundle with . instead of /"))
{
     yourAssetbundleReference = AssetBundle.LoadFromStream(s);
}

If "Stream" shows up white and has an error, add " using System.IO; " to the top of your class. Now that we have set this up, we can now actually work inside of the Unity Editor.

Assetbundles and nearly everything about them.

This will go over how to actually make, add to, generate, and access things from your assetbundle. With your template, it should be quite easy as you don't have to add anything yourself.

Making a new bundle

Simply clicking on any object in your explorer tab will put an option in the Inspector window to put it in an assetbundle.

Note the highlighted area.

Click on the dropdown tab and a few options should appear (as part of this demonstration I already have an assetbundle called example_bundle) Click on "New..." and create a new assetbundle with whatever name you want. This will be the name you will use when loading the assetbundle.

And voila, you now have a new assetbundle. You can have multiple assetbundles if you want to keep things organized.

Adding Objects to your Bundle.

Selecting None will not put the object into the assetbundle when it's generated. By default, objects will not be in any assetbundle until assigned one, so remember to assign things to assetbundles.

Once you did that, you've now added an object to your assetbundle. You can add as many objects and bundles as you like, but do note it will take longer to generate depending on how much stuff needs to be added to a bundle / bundles generated. Try do things in batches, but considering the asset sizes we will likely be using are small, it shouldn't be too bad.

Generating your Assetbundle.

Right click and select "Build Assetbundles". That's it.

This will build all of your assetbundles, and package anything assigned to a bundle, into one.

Your generated bundles will appear in the appropriately named "Assetbundles" folder. Once they're generated, you can simply drag it out of there and into where-ever you want the file. Note that your assetbundle will look like the file in the Green square.

Accessing objects from your Assetbundle.

The other generated file with the same name as your bundle/s is a manifest file, while its not needed, it is a very good reference for loading things from the assetbundle. It will usually have some useless garbage data at the start but under "Assets" it shows you what assets are in your bundle. Heres a very short list as an example.

Keep this in mind. To load an asset from your bundle, you simply run this line of code.

Using the Modular mod as an example, here it loads a GameObject by the name of "ModularGunClip_Atlas" from the assetbundle. Depending on the file ending, you put different things into the green part. For example: Assets that end with .prefab are loaded as GameObjects. Assets that end with .mat are loaded as Materials. Assets that end with .shader are loaded as Shaders. And simple image files, like .pngs as loaded as Texture2Ds or just Textures. As for the red part, its just simply the name of your asset.

The Tools at your disposal.

The template unity project has a few but useful tools at your disposal, with the main version being a similar version of the sprite building assets that Gungeon uses. The main tools are:

  1. Sprite Collection and Sprite Animation tools.

  2. DFGUI, mainly used for building DFAtlases for custom UIs.

  3. Shader Forge, a tool used for making completely custom shaders.

This guide will only go over using the Sprite Collection and Animation tools. DFGUI stuff is nearly the same as the Sprite Collection stuff and Shader Forge is its own beast you'll have to explore by yourself.

Creating a sprite collection.

You can create a new sprite collection from your Project window in the Editor (it will have all of your folders visible), by right clicking, then following: Create > tk2d > Sprite Collection

This will create a new Sprite Collection asset in the folder you created it. You can rename the Collection by clicking on the name. To actually add sprites to your image, you click on your Sprite Collection asset and press the "Open Editor" button.

This will open a new window, and to add sprites to it you can simply just drag them in, as long as you have added the sprites to the Unity project. (Remember, for good organization, create new folders for your sprites in the Unity Editor, don't just have 700 sprites in a random folder for your own sanity) The order doesn't really matter. However, there are a few important steps to follow before you can commit your Collection, or it will generate not to Gungeon specifications.

  1. When adding sprites, their Anchor MUST be set to "Lower Left". This anchor is used by just about all sprites in Gungeon so not using it where its usually used (Like items and guns) will make it look VERY offset. You can select multiple sprites by holding shift and selecting the first and last sprite in the collection to modify them in batches.

    1.5: Set "Pad method" to "Black Zero Alpha". Although very minor, in Gungeon if this is not set to "Black Zero Alpha", if these sprites are outlined, they will look weird / wrong. Make sure to set this for all of your sprites.

  2. Under Settings, Set "Pixels Per Meter" to 16. Gungeon uses the same P.P.M so if you don't set this your sprites will look VERY small ingame.

  3. Tick "Disable Trimming" and set Pad amount to at least 2. If your sprites utilize empty space, Disabling the trimming will keep said empty space. The padding is to prevent weird overlapping.

You will only have to repeat point 1, as your settings will save once you Commit the Collection.

Once you have commited your collection, a new folder with the same name as your Sprite Collection will appear. This folder will have 3 things, all 3 which are important in some way.

The item in the Green Square is the material of your Sprite Collection. You can rename this as you please. This item is required to go into your Assetbundle. The item in the Blue Square is your Sprite Collection Data. This item is also required to go into your Assetbundle. The file in the Red Square is the sprite atlas. When generated, it will look slightly weird, but to get it to good condition, click on it and:

1. Set its "Texture Type" to "Sprite (2D and UI)" 2. Set its Pixels Per Unit to 16. 3. Tick the "Alpha Is Transparency".

Once you did that, click "Apply". Once you have done this, every time you Commit your sprite collection you will not have to do this, except for Ticking "Alpha Is Transparency", though not much changes if you don't. Once you have finished up, you can build your Assetbundle and load it into the game. To Note: You can add as many sprites to your collection as you want, though it will take longer and longer to generate. You can also go back into the Collection and add new sprites / remove sprites if you've commited a Collection, as long as you Commit it again, and follow the required steps. To be able to actually use it in the game, you'll first have to run a tiny bit of code. Add this method somewhere where you can run it.

 public static tk2dSpriteCollectionData DoFastSetup(AssetBundle bundle, string CollectionName, string MaterialName)
        {
            tk2dSpriteCollectionData Colection = bundle.LoadAsset<GameObject>(CollectionName).GetComponent<tk2dSpriteCollectionData>();
            Material material = bundle.LoadAsset<Material>(MaterialName);
            Texture texture = material.GetTexture("_MainTex");
            texture.filterMode = FilterMode.Point;
            material.SetTexture("_MainTex", texture);
            Colection.material = material;

            Colection.materials = new Material[]
            {
                material,
            };
            Colection.materialInsts = new Material[]
            {
                material,
            };
            foreach (var c in Colection.spriteDefinitions)
            {
                c.material = Colection.materials[0];
                c.materialInst = Colection.materials[0];
                c.materialId = 0;
            }
            return Colection;
        }
 

It intakes the Assetbundle in which your Sprite Collection Data and material is in, and the name of the material and sprite collection data assets. It is VERY advised to create a class from where you initialise all of your sprite collection datas, for cleanliness. There, you can do something like this, as an example.

This will load, process and return a usable sprite collection that you can access from anywhere. How do you actually use it? The most common use will likely be items, as they only require one sprite (unless they use VFX), and ItemAPI already has a method for using pre-built sprite collections.

Using Planetside as an example, it accesses a pre-defined sprite collection, and feeds the sprite collection and the sprite ID from the collection.

You can get the ID of the sprite you want by using multiple ways, but running GetSpriteIdByName is a favourite of mine as you just need to insert the sprites name into it and nothing else. You can also use GetSpriteById(), if you know the ID of the sprite. You can find the ID of your sprite by opening your sprite collection and clicking on the sprite.

For uses outside ItemAPI, here is an example:

Simply getting the sprite component in your object is more than enough to be able to use bundled sprites., as long as you set the sprite collection to the correct one and use the pre-existing SetSprite method to set a sprite to your one.

Creating a Sprite Animation

Tired of assigning hundreds of sprite numbers in a row to create one goddamn animation? This is the perfect thing for you then!

You can create a new sprite collection from anywhere in the Unity Editor, by right clicking, then following: Create > tk2d > Sprite Animation

This will create a new Sprite Animation component. You can rename this to whatever you please.

Click on it, and press the "Open Editor" button. This will open up a somewhat complicated looking UI, but once you get used to it, its very helpful.

Here is an overview of every thing in here, that I know of.

Name: The name of your animation clip. VERY important. Frames: Non-changable, shows how many frames long your animation is. Frame Rate: Self explanatory, the amount of frames per second your animation plays at. Wrap Mode: the way in which your animation plays.

  • Loop: Loops your animation once it reaches its end. Example: idle animations.

  • Loop Section: Plays your animation normally, but once it finishes, it loops again starting from the frame where you set the Loop Start option. This option only appears with Loop Section selected. Example: Charge animations for guns.

  • Once: Plays your animation once. Example: Firing animations in guns.

  • Ping Pong: Once it finishes playing your animation, plays the animation again but with the frames reversed. Repeats forever.

  • Random Frame: Genuinely no idea. Probably just picks a random frame from your clip to set its sprite to.

  • Random Loop: Same as Loop, but instead of playing from the start of the clip, starts the animation from a random point in the animation clip.

The rest I dont know about or dont really care about.

The Reverse Button here reverses all the frames currently in your clip. The Trigger button allows you to add a trigger to a frame. This is only really used in code. Remind me to show it off sometime.

These 2 buttons are fairly self-explanatory. Play plays the current animation in the clip while active. Repeat, while active, repeats the animation regardless if its a looping animation or not. If the animation doesn't loop by default, it will pause for a second before playing it again.

This is your frame timeline. You can add frames by pressing the [+] button. I will mention it a few times during the next section.

Time for the fun stuff.

Collection makes you select a pre-existing sprite collection in your Unity Project to use sprites from. In other words, you'll need to make a sprite collection to be able to use this tool. Sprite lets you change the current sprite of the selected frame on the timeline. This can be either from a dropdown menu or a large menu with every sprite visible. You likely won't be using this much.

Frames lets you stretch how how many frames in the animation a sprite is. For example:

Autofill [1...9] will automatically place all sprites into your clip in numerical order, as long as the sprites names are identical. Very practical for making simple animations quickly.

Autofill [9...1] likely does the same as above but in reverse numerical order, I don't really know. Insert > adds a sprite in front of the selected sprite into the clip with the same sprite as the currently selected frame.

Insert < adds a sprite behind the selected sprite into the clip with the same sprite as the currently selected frame. Delete deletes the currently selected sprite.

Delete > removes all frames that are in front of the currently selected frame.

Delete < removes all frames that are behind the currently selected frame.

To Note: You can have as many unique clips in the Sprite Animator as you want, as long as every animation clip has unique names. Once you are done, press "Commit", and it'll save your clips into the component.

To actually use it in your code, add the component to your Assetbundle, and build your bundle to put it in. As mentioned above, you can do something similar to this to create an animation library accessible anywhere.

Then, whereever you use a SpriteAnimator component, set the Library variable to your new Tk2dSpriteAnimation, like this:

Then, as long as the animation is in the Library, you can play it through code.

And for example: setting up an enemy that uses bundled sprites:

https://github.com/Some-Bunny/Modular/blob/master/Code/Enemies/BigDrone.cs

ADDITIONAL TOOLS

Not everything we have is built for assetbundle usage, so heres some replacements to older things that use the new assetbundle stuff. NOTE: If you are using the Alexandria dependancy mod (which most mods do as it's part of the template mod), you will not need to add these, as they are already a part of Alexandria.

ProjectileToolbox adds 3 new methods: SetProjectileCollisionRight(), AnimateProjectileBundle(), and AddTrailToProjectileBundle(). The arguments required for these should be self explanatory.

Mainly just a re-used BeamToolbox from Alexandria with some changes, the main difference being the new method: GenerateBeamPrefabBundle()

A replacement to GunExt used for custom guns, its slightly modified to allow for all the GunExt features to work with assetbundled sprites. The SetupSprite() is nearly the same, save for the sprite collection data you have to feed it now.

Very important for bundled guns. This allows you to embed all of your Gun Jsons into your DLL directly, as the old method will NOT work for bundled gun sprites.

Using the Modular mod as an example, this uses your current Assembly, the sprite collection in which all of your gun sprites are stored, and a file path to all of your embedded gun jsons.

Last updated