Search code examples
libgdxdependenciesproject-structure

Bundle assets with libGDX dependency


I'm making a card game engine on top of libGDX for many similar games I plan to make. Here's how I plan to structure this: each game is a separate project and the engine is a dependency added to the core module. The engine itself will have a lot of assets like card sprites and other UI elements, and they need to be included too.

How can I make that structure work? Is there any way to make a dependency include its assets? The alternative is to duplicate all assets for each game which I don't think is very efficient. Also the assets are in the android module by default, which the engine dependency doesn't have (the engine is a single module). Where do I put the assets in the engine module?


Solution

  • We have a setup that seems similar to what you've outlined above with a "many to one" relationship of projects to assets. Here's a potential way to go about it.

    The basic idea is:

    1. Have a single, authoritative assets folder
    2. Have individual projects copy this folder to their build output at build time
    3. Accomplish this by having a project's compile task dependsOn or be finalizedBy a copy task.
    4. Ensure that the Android and other projects are happy by copying the assets to the place that libgdx's internal File APIs look for that particular type of project. (For example, android projects automatically get an assets/ prepended to the URI provided to Gdx.files.internal(). This step is more dependent on your personal file structure, so it may take a little tweaking to get the pathing right for all projects, but don't get discouraged!

    Side-note: Gradle should automatically track whether or not the assets dir actually changed. If nothing's been updated, then the copy tasks will effectively become no-ops, which speeds up the build quite a bit for non-first runs. Obviously if you do a cleanAssets like I mention below, then this won't apply.

    The advantage of this approach (to me anyway) is that it no longer relies on cross-project links or funky classpath manipulation. It's just real files in real directories. The downside is that it increases the disk space used because there can be multiple physical copies of the assets in the various projects.

    The following is not a complete example, but should hopefully give you enough to go by.

    Example of a copy task in action. This particular one takes an assets dir from a "core" project and copies it into an android project.

    android/build.gradle
    
    task copyAssets(type: Copy) {
        from "../core/assets"
        into "./assets"
    }
    

    Example of how to make the android project's build depend on this task:

    android/build.gradle
    
    afterEvaluate { project ->
        project.tasks.preDebugBuild {
            dependsOn copyAssets
        }
    
        project.tasks.preReleaseBuild {
            dependsOn cleanAssets
            finalizedBy copyAssets
        }
    }
    

    You'll notice in the preReleaseBuild I added a cleanAssets task as well. It's always a good idea to clean up any junk and do a fresh copy during a production build. cleanAssets is just a basic Delete task.

    Example of a copy task dependency for a non-android project:

    build {
        finalizedBy copyAssets
    }
    

    If you're still stuck, let me know where and I'll try to help.