<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://calamitysanctuary.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://calamitysanctuary.com/" rel="alternate" type="text/html" /><updated>2025-03-26T21:05:53+00:00</updated><id>https://calamitysanctuary.com/feed.xml</id><title type="html">Calamity Sanctuary</title><subtitle>Gamdev Articles</subtitle><author><name>Gregory Fournier</name><email>gregory.fournier@protonmail.com</email></author><entry><title type="html">Progress Post April</title><link href="https://calamitysanctuary.com/Progress-Post-April/" rel="alternate" type="text/html" title="Progress Post April" /><published>2022-04-21T00:00:00+00:00</published><updated>2022-04-21T00:00:00+00:00</updated><id>https://calamitysanctuary.com/Progress-Post-April</id><content type="html" xml:base="https://calamitysanctuary.com/Progress-Post-April/"><![CDATA[<p>This month was focused on adding bosses and adding a couple new assets. Progress has been a bit slow in April but things should pick up in June.</p>

<h3 id="new-bosses">New Bosses</h3>

<p>After all this time, we finally have 2 bosses : The Earth Golem and the Ice Golem.</p>

<h4 id="earth-golem">Earth Golem</h4>

<video autoplay="" loop="" src="../assets/april_earthGolem.webm"></video>

<p>Slow but a hard hitter, the Earth Golem excels at throwing rock based projectiles. Once it gets to half health, it’ll attack more frequently with tougher patterns to dodge.</p>

<h4 id="ice-golem">Ice Golem</h4>

<video autoplay="" loop="" src="../assets/april_iceGolem.webm"></video>

<p>The golem residing on the icy planet Izit. Bit faster than the Earth Golem, and some of his attacks will slow players down. When at half health, will turn the middle row into ice, making it harder for players to evade attacks.</p>

<h3 id="new-backgrounds">New backgrounds</h3>

<p><img src="../assets/april_mainMenu.png" alt="april_mainMenu" /></p>

<p>As you may have noticed in the previous images, the battle background has changed, with the capability implemented to easily replace this background with several other parallax backgrounds I have available.. Similarly, the main menu background has also changed.</p>

<h3 id="new-enemies">New Enemies</h3>

<p>Finally, I’ve started leveraging existing enemies and doing palette swaps with modified behaviors to create new enemies. For the Ice World, we have 2 enemies so far.</p>

<p><img src="../assets/april_coldey.png" alt="april_coldey" /><img src="../assets/worshipper_idle.gif" alt="worshipper_idle" /></p>

<video autoplay="" loop="" src="../assets/ice_enemies.webm"></video>

<h3 id="conclusion">Conclusion</h3>

<p>That’s it for this month! Short and sweet.</p>]]></content><author><name>Gregory Fournier</name><email>gregory.fournier@protonmail.com</email></author><summary type="html"><![CDATA[This month was focused on adding bosses and adding a couple new assets. Progress has been a bit slow in April but things should pick up in June.]]></summary></entry><entry><title type="html">Progress Post March</title><link href="https://calamitysanctuary.com/Progress-Post-March/" rel="alternate" type="text/html" title="Progress Post March" /><published>2022-03-28T00:00:00+00:00</published><updated>2022-03-28T00:00:00+00:00</updated><id>https://calamitysanctuary.com/Progress-Post-March</id><content type="html" xml:base="https://calamitysanctuary.com/Progress-Post-March/"><![CDATA[<p>A lot of things have changed since last year. Here’s an overview of all the major changes in the past couple of months</p>

<h3 id="removal-of-the-overworld-sections">Removal of the overworld sections</h3>

<p>I’ve gone back and forth on the idea of including an isometric overworld section in between battles reminiscent of Megaman Battle network, the main inspriation for Calamity Sanctuary. At first there was none out of simplicity, then at one point as an experiment I started tinkering around with implementing isometric sections in the game, for various reasons, mainly because I wanted to see if I was capable of not only implementing everything needed to handle isometric logic, but also create interesting procedural maps. I also thought it would be a great way to differentiate myself from popular card based roguelites such as Slay the Spire and Monster Train, which include node based traversal on a map between battles.<img src="..\assets\isometric-example-cs.png" alt="img" /></p>

<p>In the end, the isometric sections turned out to be too much of a headache. My collision detection code was always wonky, the procedural generation, while definetly servicable, was difficult to tweak into something interesting, and in the end I couldn’t see what the isometric traversal actually brought to the game. After much debate, I ended up scrapping the idea, and despite my quest to differentiate myself my avoiding a map with nodes, that’s what I ended up implementing.</p>

<h3 id="adding-a-map">Adding a Map</h3>

<video autoplay="" loop="" src="../assets/small_map_test.webm"></video>

<p>To put it simply, this is basically the same as the Slay the Spire map. Create a 5x20 array, iterate over it a bunch of times while linking nodes together, and finally clean up to make things more interesting. Set each node type based on probabilaty and certain rules (e.g. no shops on the first floor, no repeated rooms for certain types, etc.) I still need to make it prettier, especially the background, but I already have a couple of neat things in place, such as animated icons and links.</p>

<p>I’m still debating on keeping the information at the bottom of the screen. One one hand, I think be able to see your deck composition at a glance is great for deck building, but on the other the current implementation is pretty ugly and takes up a good amount of screen real estate.</p>

<h3 id="added-a-world-screen">Added a World Screen</h3>

<video autoplay="" loop="" src="../assets/world_test.webm"></video>

<p>This is something I’ve wanted to add ever since I saw the amazing <a href="https://deep-fold.itch.io/pixel-planet-generator">Pixel Planet Generator</a>. The idea is that after each area boss, players will have a choice between different worlds, each with their own enemies, unique events, etc. This is simply another layer of decision making for players : Do they choose the more difficult planet in hopes of obtaining better cards, or do they visit the ice planet, since they picked up a couple of fire cards in the previous world? (Elemental weakness hasn’t been implemented yet, but it’s something I’ve been thinking about more and more lately)</p>

<p>Right now it’s mostly just for show, as all planets have the same encounter and loot tables, but everything is in place to make them eventually unique. Once I have a bigger enemy pool and when I have a better idea of how difficult each of the enemies are I’ll be better equipped to separate them into different tables based on difficulty.</p>

<h3 id="removed-a-lot-of-copyrighted-material">Removed a lot of copyrighted material</h3>

<p>Given that Calamity Sanctuary is inspired by Battle Network and the fact that I have no artistic capabilities, it was only natural for me to borrow copyrighted sprites when this game was barely a project. However, I’m now well past that point, and if I want to be able to show off more of the game, I really couldn’t continue having a lot of the major sprites be copyrighted material. While there are still some copyrighted assets remaining, I feel like I’ve removed a good amount of the most prominent ones, such as the main character, enemies, and a bunch of the card art. For the rest, I try to keep a list updated of assets that need to be replaced, so I can go though it and remove items one by one.</p>

<p>I’ve also given myself as a rule to avoid adding any more copyrighted material. Like tech debt, replacing the assets just ends up costing more time in the end, and I wouldn’t want to include any assets I don’t own inadvertently into the final product.</p>

<h3 id="new-keyword---combo">New Keyword - Combo</h3>

<p>A new card keyword, “Combo” was added. When a card with Combo is played, it will add a new card to your hand. For example, the dagger card, when played, will not only swipe at the square in front of you, but will also add a “Throwing Dagger” card to your hand, which can deal damage across the screen. Combo cards incentivise build which want to play a lot of cards. There are also Combo specific cards and daemons, like the Specialist card, which increases the damage of cards created via Combo, and Resourceful, which will let you draw a card when you play a combo card.</p>

<p>The Combo keyword went through a couple of iterations before landing on it’s current implementation. The initial idea was that playing a Combo card would transform other identical cards in your hand into more powerful versions. There were however 2 major issues with this version :</p>

<ul>
  <li>There were a bunch of technical and gameplay side effects to consider and I didn’t have a good answer for any of them. Would transformed cards revert to their original form when discarded? Do transformed versions of cards also transform “original” versions of cards when played? Was transforming a card considered discarding a drawing a card?</li>
  <li>I felt that this version incentivised too much just trying to obtain copies of the same card. Since Combo cards wouldn’t be very useful without at least one or two other copies in your hand, it was in player’s best interest to simply avoid picking other cards and going “all in” on one card in particular. I don’t think these would lead to very interesting situations, which is why I abandoned the idea.</li>
</ul>

<h3 id="new-enemies-cards-and-more">New Enemies, Cards, and more</h3>

<p>A lot more content was added in these past months. Here are a couple new enemy sprites and animations</p>

<p><img src="..\assets\buzz-sheet.gif" alt="buzz-sheet" /><img src="..\assets\snakey" alt="idle" /><img src="..\assets\crow_idlew" alt="idle" /></p>

<h3 id="conclusion">Conclusion</h3>

<p>A lot has been done since the beginning of the year, but like always, I feel like I very far from an actual finished product. Hell, I’m probably still pretty far from an acceptable Alpha build of the game. However, for those of you who are curious, you can always find the latest build on my <a href="https://videogreg93.itch.io/calamity-sanctuary">Itch.io page</a>. Thanks for reading.</p>]]></content><author><name>Gregory Fournier</name><email>gregory.fournier@protonmail.com</email></author><category term="LibGDX" /><category term="Calamity-Sanctuary" /><category term="Progress" /><summary type="html"><![CDATA[A lot of things have changed since last year. Here’s an overview of all the major changes in the past couple of months]]></summary></entry><entry><title type="html">Generate Constant String Paths For Assets With Gradle</title><link href="https://calamitysanctuary.com/Generate-Constant-String-Paths-for-Assets-with-Gradle/" rel="alternate" type="text/html" title="Generate Constant String Paths For Assets With Gradle" /><published>2021-08-11T00:00:00+00:00</published><updated>2021-08-11T00:00:00+00:00</updated><id>https://calamitysanctuary.com/Generate-Constant-String-Paths-for-Assets-with-Gradle</id><content type="html" xml:base="https://calamitysanctuary.com/Generate-Constant-String-Paths-for-Assets-with-Gradle/"><![CDATA[<p>Unless you’ve created a fleshed out engine inside of LibGdx, chances are you’re manually providing asset paths for things like textures, sounds, etc. Here’s a typical example of creating a <code class="language-plaintext highlighter-rouge">Texture</code>.</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">val</span> <span class="py">texture</span> <span class="p">=</span> <span class="nc">Texture</span><span class="p">(</span><span class="s">"player/overworld/player.png"</span><span class="p">)</span>
</code></pre></div></div>

<p>There are many problems with this approach, notably :</p>

<ul>
  <li>
    <p>It’s easy to introduce a typo, which will probably crash at runtime when trying to fetch the asset.</p>
  </li>
  <li>
    <p>It’s hard to know if the asset is already being used somewhere else. Sure, you can <code class="language-plaintext highlighter-rouge">ctrl+f</code> “player/overworld/player.png” but if you did something like this you won’t find your asset :</p>

    <div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">const</span> <span class="kd">val</span> <span class="py">PLAYER_FOLDER</span> <span class="p">=</span> <span class="s">"player/"</span>
<span class="kd">val</span> <span class="py">texture</span> <span class="p">=</span> <span class="nc">Texture</span><span class="p">(</span><span class="s">"$PLAYER_FOLDER/overworld/player.png"</span><span class="p">)</span>
</code></pre></div>    </div>
  </li>
</ul>

<p>Since we know all of our assets at compile time, what if we could generate symbols to represent our asset paths? We could even keep the same hierarchy as our file system. Then, instead pf providing a hardcoded string, we could do something like this:</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">object</span> <span class="nc">Player</span> <span class="p">{</span>
    <span class="kd">object</span> <span class="nc">Overworld</span> <span class="p">{</span>
        <span class="k">const</span> <span class="kd">val</span> <span class="py">player</span> <span class="p">=</span> <span class="s">"player/overworld/player.png"</span>
    <span class="p">}</span>
<span class="p">}</span>
<span class="c1">// [...]</span>
<span class="kd">val</span> <span class="py">texture</span> <span class="p">=</span> <span class="nc">Texture</span><span class="p">(</span><span class="nc">Player</span><span class="p">.</span><span class="nc">Overworld</span><span class="p">.</span><span class="n">player</span><span class="p">)</span>
</code></pre></div></div>

<p>Let’s use Gradle to create a task that we can run whenever we add new assets to our project that will let us generate this file.</p>

<h3 id="creating-a-gradle-task">Creating a Gradle Task</h3>

<p>Creating a Gradle Task is as easy as writing <code class="language-plaintext highlighter-rouge">task yourTaskName() {}</code> in your <code class="language-plaintext highlighter-rouge">build.gradle</code> file. Gradle tasks let you do many powerful things, like generate code at compile time, publish your project to a service like Itch.io, and more. Leveraging Gradle can make routine tasks completely automated.</p>

<p>Lets create a dummy task to make sure everything is working correctly. Navigate to your top level <code class="language-plaintext highlighter-rouge">build.gradle</code> file, and inside the <code class="language-plaintext highlighter-rouge">project(":core") </code> section, write the following task</p>

<div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">task</span> <span class="nf">generateAssets</span><span class="o">()</span> <span class="o">{</span>
    <span class="n">println</span><span class="o">(</span><span class="s2">"Hello world!"</span><span class="o">)</span>
<span class="o">}</span>
</code></pre></div></div>

<p>You should see the ‘Load Gradle Changes’ button appear in the top right corner (it looks something like this <img src="..\assets\image-20210811152352131.png" alt="image-20210811152352131" />) Hit that button to let Gradle know you’ve made some changes. If everything goes well, you should be able to see your new task by navigating in the Gradle tab in the top right corner, and searching for your new task (regenerateImages in the pic below). Double click that and you should see “Hello world” print in the console below.</p>

<p><img src="..\assets\image-20210811152539276.png" alt="image-20210811152539276" /></p>

<h3 id="generating-some-code">Generating Some Code</h3>

<p>Code generation can seem like a daunting task, but in reality it’s just writing text to a file. Lets begin by declaring a couple of constants</p>

<div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">task</span> <span class="nf">generateAssets</span><span class="o">()</span> <span class="o">{</span>
    <span class="kt">def</span> <span class="n">project</span> <span class="o">=</span> <span class="s1">'../core'</span> <span class="c1">// Core project folder, should probably be kept as-is</span>
    <span class="kt">def</span> <span class="n">assetsFolder</span> <span class="o">=</span> <span class="s1">'../core/assets'</span> <span class="c1">// Assets folder, should probably be kept as-is</span>
    <span class="kt">def</span> <span class="n">source</span> <span class="o">=</span> <span class="s1">'src'</span> <span class="c1">// Source folder, should probably be kept as-is</span>
    <span class="kt">def</span> <span class="n">pack</span> <span class="o">=</span> <span class="s1">'com.mypack.assets'</span> <span class="c1">// package name of the file to be generate. Replace with your top level package name</span>
    <span class="kt">def</span> <span class="n">fileName</span> <span class="o">=</span> <span class="s1">'Assets.kt'</span> <span class="c1">// File name, feel free to rename as needed.</span>
    
    <span class="kt">def</span> <span class="n">newLine</span> <span class="o">=</span> <span class="n">System</span><span class="o">.</span><span class="na">getProperty</span><span class="o">(</span><span class="s2">"line.separator"</span><span class="o">)</span> <span class="c1">// OS-agnostic new line, will be used in code generation</span>
    <span class="kt">def</span> <span class="n">builder</span> <span class="o">=</span> <span class="k">new</span> <span class="n">StringBuilder</span><span class="o">()</span> <span class="c1">// This will be responsible for building up the 'Assets.kt' file</span>
<span class="o">}</span>
</code></pre></div></div>

<p>So far we’ve just defined a couple of things related to our project. Even if we end up only using these once, I like to declare them all at the beginning, so it’s easier if I end up wanting to move things around, or if I want to copy this for another similar task, just with different parameters.</p>

<p>Lets start generating out Kotlin code. We want to end up with something like this:</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="nn">com.mypack.assets</span>

<span class="c1">// Generated file, do not modify</span>

<span class="kd">object</span> <span class="nc">Assets</span> <span class="p">{</span>
    
<span class="p">}</span>
</code></pre></div></div>

<p>We could use a specialized library for code generation such as <a href="https://square.github.io/kotlinpoet/">Kotlin Poet</a> but for a simple case like this one, it’s a good idea to just write it out ourselves.</p>

<div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">task</span> <span class="nf">generateAssets</span><span class="o">()</span> <span class="o">{</span>
    <span class="kt">def</span> <span class="n">project</span> <span class="o">=</span> <span class="s1">'../core'</span> <span class="c1">// Core project folder, should probably be kept as-is</span>
    <span class="kt">def</span> <span class="n">assetsFolder</span> <span class="o">=</span> <span class="s1">'../core/assets'</span> <span class="c1">// Assets folder, should probably be kept as-is</span>
    <span class="kt">def</span> <span class="n">source</span> <span class="o">=</span> <span class="s1">'src'</span> <span class="c1">// Source folder, should probably be kept as-is</span>
    <span class="kt">def</span> <span class="n">pack</span> <span class="o">=</span> <span class="s1">'com.mypack.assets'</span> <span class="c1">// package name of the file to be generate. Replace with your top level package name</span>
    <span class="kt">def</span> <span class="n">fileName</span> <span class="o">=</span> <span class="s1">'Assets.kt'</span> <span class="c1">// File name, feel free to rename as needed.</span>
    <span class="kt">def</span> <span class="n">soundExtensions</span> <span class="o">=</span> <span class="o">[</span><span class="s1">'.mp3'</span><span class="o">,</span> <span class="s1">'.wav'</span><span class="o">]</span> <span class="c1">// Accepted sound types, feel free to modify</span>
    <span class="kt">def</span> <span class="n">imageExtensions</span> <span class="o">=</span> <span class="o">[</span><span class="s1">'.png'</span><span class="o">,</span> <span class="s1">'.jpg'</span><span class="o">,</span> <span class="s1">'.jpeg'</span><span class="o">]</span>  <span class="c1">// Accepted image types, feel free to modify.</span>
    <span class="kt">def</span> <span class="n">invalidChars</span> <span class="o">=</span> <span class="o">[</span><span class="s1">'-'</span><span class="o">,</span> <span class="s1">'.'</span><span class="o">,</span> <span class="s1">' '</span><span class="o">,</span> <span class="s1">','</span><span class="o">]</span>    
    <span class="kt">def</span> <span class="n">newLine</span> <span class="o">=</span> <span class="n">System</span><span class="o">.</span><span class="na">getProperty</span><span class="o">(</span><span class="s2">"line.separator"</span><span class="o">)</span> <span class="c1">// OS-agnostic new line, will be used in code generation</span>
    <span class="kt">def</span> <span class="n">builder</span> <span class="o">=</span> <span class="k">new</span> <span class="n">StringBuilder</span><span class="o">()</span> <span class="c1">// This will be responsible for building up the 'Assets.kt' file</span>
    
    <span class="n">builder</span><span class="o">.</span><span class="na">append</span><span class="o">(</span><span class="s2">"""package ${pack}

/** Generated from the assets folder. */
object Assets { 

"""</span><span class="o">)</span>
    <span class="c1">// TODO asset generation</span>
    <span class="n">builder</span><span class="o">.</span><span class="na">append</span><span class="o">(</span><span class="n">newLine</span><span class="o">).</span><span class="na">append</span><span class="o">(</span><span class="s2">"}"</span><span class="o">)</span>
<span class="o">}</span>
</code></pre></div></div>

<p>All there’s left to do to actually see this file is writing the contents of <code class="language-plaintext highlighter-rouge">builder</code> to an actual file.</p>

<div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">task</span> <span class="nf">generateAssets</span><span class="o">()</span> <span class="o">{</span>
    <span class="kt">def</span> <span class="n">project</span> <span class="o">=</span> <span class="s1">'../core'</span> <span class="c1">// Core project folder, should probably be kept as-is</span>
    <span class="kt">def</span> <span class="n">assetsFolder</span> <span class="o">=</span> <span class="s1">'../core/assets'</span> <span class="c1">// Assets folder, should probably be kept as-is</span>
    <span class="kt">def</span> <span class="n">source</span> <span class="o">=</span> <span class="s1">'src'</span> <span class="c1">// Source folder, should probably be kept as-is</span>
    <span class="kt">def</span> <span class="n">pack</span> <span class="o">=</span> <span class="s1">'com.mypack.assets'</span> <span class="c1">// package name of the file to be generate. Replace with your top level package name</span>
    <span class="kt">def</span> <span class="n">fileName</span> <span class="o">=</span> <span class="s1">'Assets.kt'</span> <span class="c1">// File name, feel free to rename as needed.</span>
    <span class="kt">def</span> <span class="n">soundExtensions</span> <span class="o">=</span> <span class="o">[</span><span class="s1">'.mp3'</span><span class="o">,</span> <span class="s1">'.wav'</span><span class="o">]</span> <span class="c1">// Accepted sound types, feel free to modify</span>
    <span class="kt">def</span> <span class="n">imageExtensions</span> <span class="o">=</span> <span class="o">[</span><span class="s1">'.png'</span><span class="o">,</span> <span class="s1">'.jpg'</span><span class="o">,</span> <span class="s1">'.jpeg'</span><span class="o">]</span>  <span class="c1">// Accepted image types, feel free to modify.</span>
    <span class="kt">def</span> <span class="n">invalidChars</span> <span class="o">=</span> <span class="o">[</span><span class="s1">'-'</span><span class="o">,</span> <span class="s1">'.'</span><span class="o">,</span> <span class="s1">' '</span><span class="o">,</span> <span class="s1">','</span><span class="o">]</span>
    <span class="kt">def</span> <span class="n">newLine</span> <span class="o">=</span> <span class="n">System</span><span class="o">.</span><span class="na">getProperty</span><span class="o">(</span><span class="s2">"line.separator"</span><span class="o">)</span> <span class="c1">// OS-agnostic new line, will be used in code generation</span>
    <span class="kt">def</span> <span class="n">builder</span> <span class="o">=</span> <span class="k">new</span> <span class="n">StringBuilder</span><span class="o">()</span> <span class="c1">// This will be responsible for building up the 'Assets.kt' file</span>
    
    <span class="n">builder</span><span class="o">.</span><span class="na">append</span><span class="o">(</span><span class="s2">"""package ${pack}

/** Generated from the assets folder. */
object Assets { 

"""</span><span class="o">)</span>
    <span class="c1">// TODO asset generation</span>
    <span class="n">builder</span><span class="o">.</span><span class="na">append</span><span class="o">(</span><span class="n">newLine</span><span class="o">).</span><span class="na">append</span><span class="o">(</span><span class="s2">"}"</span><span class="o">)</span>
    <span class="c1">// Write to file</span>
    <span class="kt">def</span> <span class="n">path</span> <span class="o">=</span> <span class="n">project</span> <span class="o">+</span> <span class="n">File</span><span class="o">.</span><span class="na">separator</span> <span class="o">+</span> <span class="n">source</span> <span class="o">+</span> <span class="n">File</span><span class="o">.</span><span class="na">separator</span> <span class="o">+</span> <span class="n">pack</span><span class="o">.</span><span class="na">replace</span><span class="o">(</span><span class="s2">"."</span><span class="o">,</span> <span class="n">File</span><span class="o">.</span><span class="na">separator</span><span class="o">)</span> <span class="o">+</span>
        <span class="n">File</span><span class="o">.</span><span class="na">separator</span> <span class="o">+</span> <span class="n">fileName</span> <span class="c1">// ../code/src/com/mypack/assets/Assets.kt</span>
    <span class="n">println</span><span class="o">(</span><span class="s2">"Saving Assets at ${path}..."</span><span class="o">)</span>
    <span class="kt">def</span> <span class="n">assetsFile</span> <span class="o">=</span> <span class="n">file</span><span class="o">(</span><span class="n">path</span><span class="o">)</span> <span class="c1">// Point to the file</span>
    <span class="n">delete</span> <span class="n">assetsFile</span> <span class="c1">// delete the existing file if there is one.</span>
    <span class="n">assetsFile</span><span class="o">.</span><span class="na">getParentFile</span><span class="o">().</span><span class="na">mkdirs</span><span class="o">()</span> <span class="c1">// Make the necessary directories if they haven't been created yet.</span>
    <span class="n">assetsFile</span><span class="o">.</span><span class="na">createNewFile</span><span class="o">()</span> <span class="c1">// Create a new file</span>
    <span class="n">assetsFile</span> <span class="o">&lt;&lt;</span> <span class="n">builder</span> <span class="o">&lt;&lt;</span> <span class="n">newLine</span> <span class="c1">// write the contents of 'builder' to the new file, ending with a newLine character.</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Hit the ‘Load Gradle Changes’ button, and rerun your task. If everything is correct, you should see your new <code class="language-plaintext highlighter-rouge">Assets.kt</code> generated file.</p>

<h3 id="walking-down-the-file-structure">Walking Down the File Structure</h3>

<p>We’re able to generate a Kotlin source file with an empty <code class="language-plaintext highlighter-rouge">Assets</code> object, now we need to add our asset paths to it. Before doing that, lets write a couple of useful local functions to make things clearer.</p>

<div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// previous lines ommited for clarity</span>
<span class="n">ext</span><span class="o">.</span><span class="na">capitalize</span> <span class="o">=</span> <span class="o">{</span> <span class="n">String</span> <span class="n">s</span> <span class="o">-&gt;</span>
    <span class="k">return</span> <span class="n">s</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">1</span><span class="o">).</span><span class="na">toUpperCase</span><span class="o">()</span> <span class="o">+</span> <span class="n">s</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span>
<span class="o">}</span>
<span class="n">ext</span><span class="o">.</span><span class="na">isImage</span> <span class="o">=</span> <span class="o">{</span> <span class="n">String</span> <span class="n">name</span> <span class="o">-&gt;</span>
    <span class="n">imageExtensions</span><span class="o">.</span><span class="na">any</span> <span class="o">{</span> <span class="n">name</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="n">it</span><span class="o">)</span> <span class="o">}</span>
<span class="o">}</span>
<span class="n">ext</span><span class="o">.</span><span class="na">isSound</span> <span class="o">=</span> <span class="o">{</span> <span class="n">String</span> <span class="n">name</span> <span class="o">-&gt;</span>
    <span class="k">return</span> <span class="n">soundExtensions</span><span class="o">.</span><span class="na">any</span> <span class="o">{</span> <span class="n">name</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="n">it</span><span class="o">)</span> <span class="o">}</span>
<span class="o">}</span>
<span class="n">ext</span><span class="o">.</span><span class="na">isValidAsset</span> <span class="o">=</span> <span class="o">{</span> <span class="n">String</span> <span class="n">name</span> <span class="o">-&gt;</span>
    <span class="k">return</span> <span class="nf">isImage</span><span class="o">(</span><span class="n">name</span><span class="o">)</span> <span class="o">||</span> <span class="n">isSound</span><span class="o">(</span><span class="n">name</span><span class="o">)</span>
<span class="o">}</span>
<span class="n">ext</span><span class="o">.</span><span class="na">cleanImage</span> <span class="o">=</span> <span class="o">{</span> <span class="n">String</span> <span class="n">name</span> <span class="o">-&gt;</span>
    <span class="kt">def</span> <span class="n">newName</span> <span class="o">=</span> <span class="n">name</span>
    <span class="o">(</span><span class="n">imageExtensions</span> <span class="o">+</span> <span class="n">soundExtensions</span><span class="o">).</span><span class="na">forEach</span> <span class="o">{</span>
        <span class="n">newName</span> <span class="o">=</span> <span class="n">newName</span><span class="o">.</span><span class="na">replace</span><span class="o">(</span><span class="n">it</span><span class="o">,</span> <span class="s2">""</span><span class="o">)</span>
    <span class="o">}</span>
    <span class="n">invalidChars</span><span class="o">.</span><span class="na">forEach</span> <span class="o">{</span>
        <span class="n">newName</span> <span class="o">=</span> <span class="n">newName</span><span class="o">.</span><span class="na">replace</span><span class="o">(</span><span class="n">it</span><span class="o">,</span> <span class="s2">"_"</span><span class="o">)</span>
    <span class="o">}</span>
    <span class="c1">// We cannot start a symbol with a number, so we add 'n' to the begining.</span>
    <span class="k">if</span> <span class="o">(</span><span class="n">Character</span><span class="o">.</span><span class="na">isDigit</span><span class="o">(</span><span class="n">newName</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="mi">0</span><span class="o">)))</span> <span class="o">{</span>
        <span class="n">newName</span> <span class="o">=</span> <span class="s2">"n$newName"</span>
    <span class="o">}</span>
    <span class="c1">// We append _sound to a sound, otherwise we would generate duplicate symbols if an image and sound shared the same filename</span>
    <span class="k">if</span> <span class="o">(</span><span class="n">isSound</span><span class="o">(</span><span class="n">name</span><span class="o">))</span> <span class="o">{</span>
        <span class="n">newName</span> <span class="o">=</span> <span class="n">newName</span> <span class="o">+</span> <span class="s2">"_sound"</span>
    <span class="o">}</span>
    <span class="k">return</span> <span class="n">newName</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Finally, we’re going to need to write the function that actually generates the strings that will contain the paths to our assets. We’re going to write a function called <code class="language-plaintext highlighter-rouge">printFiles(files: File[])</code> whose goal is to take a list of files (Note: A file can mean an actual file or a directory) and generate the corresponding code. Here’s the gist of it : The function iterates on each file:</p>

<ul>
  <li>If it’s an actual file, and it’s a valid asset, add a new string to the string builder.</li>
  <li>If it’s a directory, append the beginning of a new <code class="language-plaintext highlighter-rouge">object</code> to the string builder, call <code class="language-plaintext highlighter-rouge">printFiles</code> recursively with the files in this directory, and finally append a <code class="language-plaintext highlighter-rouge">}</code> to the string builder to complete the <code class="language-plaintext highlighter-rouge">object</code> definition.</li>
</ul>

<p>Here’s what that looks like :</p>

<div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// previous lines ommited for clarity</span>
<span class="n">ext</span><span class="o">.</span><span class="na">printFile</span> <span class="o">=</span> <span class="o">{</span> <span class="n">File</span><span class="o">[]</span> <span class="n">files</span> <span class="o">-&gt;</span>
    <span class="n">files</span><span class="o">.</span><span class="na">each</span> <span class="o">{</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">it</span><span class="o">.</span><span class="na">file</span> <span class="o">&amp;&amp;</span> <span class="n">isValidAsset</span><span class="o">(</span><span class="n">it</span><span class="o">.</span><span class="na">name</span><span class="o">))</span> <span class="o">{</span>
            <span class="c1">// This is an asset, create a new string constant</span>
            <span class="kt">def</span> <span class="n">varName</span> <span class="o">=</span> <span class="n">cleanImage</span><span class="o">(</span><span class="n">it</span><span class="o">.</span><span class="na">name</span><span class="o">)</span>
            <span class="kt">def</span> <span class="n">varPath</span> <span class="o">=</span> <span class="n">it</span><span class="o">.</span><span class="na">canonicalPath</span><span class="o">.</span><span class="na">split</span><span class="o">(</span><span class="s2">"assets"</span><span class="o">)[</span><span class="mi">1</span><span class="o">].</span><span class="na">replace</span><span class="o">(</span><span class="s1">'\\'</span><span class="o">,</span> <span class="s1">'/'</span><span class="o">).</span><span class="na">substring</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span>
            <span class="n">builder</span><span class="o">.</span><span class="na">append</span><span class="o">(</span><span class="n">newLine</span><span class="o">).</span><span class="na">append</span><span class="o">(</span><span class="s2">"const val $varName = \""</span><span class="o">).</span><span class="na">append</span><span class="o">(</span><span class="n">varPath</span><span class="o">).</span><span class="na">append</span><span class="o">(</span><span class="s1">'"'</span><span class="o">)</span>
        <span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">it</span><span class="o">.</span><span class="na">isDirectory</span><span class="o">())</span> <span class="o">{</span>
            <span class="c1">// Create a new object, and call this function recursively</span>
            <span class="n">builder</span><span class="o">.</span><span class="na">append</span><span class="o">(</span><span class="s2">"""
    object ${cleanImage(capitalize(it.name))} {"""</span><span class="o">)</span>
            <span class="n">printFile</span><span class="o">(</span><span class="n">it</span><span class="o">.</span><span class="na">listFiles</span><span class="o">())</span>
            <span class="n">builder</span><span class="o">.</span><span class="na">append</span><span class="o">(</span><span class="s2">"}"</span><span class="o">)</span>
        <span class="o">}</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>All that’s left now is to call this new function where we previously wrote <code class="language-plaintext highlighter-rouge">// TODO asset generation</code> 2 code blocks ago, and voilà, we’re done writing our Gradle task! Here’s what it looks like put all together :</p>

<div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">task</span> <span class="nf">generateAssets</span><span class="o">()</span> <span class="o">{</span>
    <span class="kt">def</span> <span class="n">project</span> <span class="o">=</span> <span class="s1">'../core'</span> <span class="c1">// Core project folder, should probably be kept as-is</span>
    <span class="kt">def</span> <span class="n">assetsFolder</span> <span class="o">=</span> <span class="s1">'../core/assets'</span> <span class="c1">// Assets folder, should probably be kept as-is</span>
    <span class="kt">def</span> <span class="n">source</span> <span class="o">=</span> <span class="s1">'src'</span> <span class="c1">// Source folder, should probably be kept as-is</span>
    <span class="kt">def</span> <span class="n">pack</span> <span class="o">=</span> <span class="s1">'com.mypack.assets'</span> <span class="c1">// package name of the file to be generate. Replace with your top level package name</span>
    <span class="kt">def</span> <span class="n">fileName</span> <span class="o">=</span> <span class="s1">'Assets.kt'</span> <span class="c1">// File name, feel free to rename as needed.</span>
    <span class="kt">def</span> <span class="n">soundExtensions</span> <span class="o">=</span> <span class="o">[</span><span class="s1">'.mp3'</span><span class="o">,</span> <span class="s1">'.wav'</span><span class="o">]</span> <span class="c1">// Accepted sound types, feel free to modify</span>
    <span class="kt">def</span> <span class="n">imageExtensions</span> <span class="o">=</span> <span class="o">[</span><span class="s1">'.png'</span><span class="o">,</span> <span class="s1">'.jpg'</span><span class="o">,</span> <span class="s1">'.jpeg'</span><span class="o">]</span>  <span class="c1">// Accepted image types, feel free to modify.</span>
    <span class="kt">def</span> <span class="n">invalidChars</span> <span class="o">=</span> <span class="o">[</span><span class="s1">'-'</span><span class="o">,</span> <span class="s1">'.'</span><span class="o">,</span> <span class="s1">' '</span><span class="o">,</span> <span class="s1">','</span><span class="o">]</span>
    <span class="kt">def</span> <span class="n">newLine</span> <span class="o">=</span> <span class="n">System</span><span class="o">.</span><span class="na">getProperty</span><span class="o">(</span><span class="s2">"line.separator"</span><span class="o">)</span> <span class="c1">// OS-agnostic new line, will be used in code generation</span>
    <span class="kt">def</span> <span class="n">builder</span> <span class="o">=</span> <span class="k">new</span> <span class="n">StringBuilder</span><span class="o">()</span> <span class="c1">// This will be responsible for building up the 'Assets.kt' file</span>
    
    <span class="n">builder</span><span class="o">.</span><span class="na">append</span><span class="o">(</span><span class="s2">"""package ${pack}

    /** Generated from the assets folder. */
    object Assets { 

    """</span><span class="o">)</span>
    <span class="n">ext</span><span class="o">.</span><span class="na">capitalize</span> <span class="o">=</span> <span class="o">{</span> <span class="n">String</span> <span class="n">s</span> <span class="o">-&gt;</span>
        <span class="k">return</span> <span class="n">s</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">1</span><span class="o">).</span><span class="na">toUpperCase</span><span class="o">()</span> <span class="o">+</span> <span class="n">s</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span>
    <span class="o">}</span>
    <span class="n">ext</span><span class="o">.</span><span class="na">isImage</span> <span class="o">=</span> <span class="o">{</span> <span class="n">String</span> <span class="n">name</span> <span class="o">-&gt;</span>
        <span class="n">imageExtensions</span><span class="o">.</span><span class="na">any</span> <span class="o">{</span> <span class="n">name</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="n">it</span><span class="o">)</span> <span class="o">}</span>
    <span class="o">}</span>
    <span class="n">ext</span><span class="o">.</span><span class="na">isSound</span> <span class="o">=</span> <span class="o">{</span> <span class="n">String</span> <span class="n">name</span> <span class="o">-&gt;</span>
        <span class="k">return</span> <span class="n">soundExtensions</span><span class="o">.</span><span class="na">any</span> <span class="o">{</span> <span class="n">name</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="n">it</span><span class="o">)</span> <span class="o">}</span>
    <span class="o">}</span>
    <span class="n">ext</span><span class="o">.</span><span class="na">isValidAsset</span> <span class="o">=</span> <span class="o">{</span> <span class="n">String</span> <span class="n">name</span> <span class="o">-&gt;</span>
        <span class="k">return</span> <span class="nf">isImage</span><span class="o">(</span><span class="n">name</span><span class="o">)</span> <span class="o">||</span> <span class="n">isSound</span><span class="o">(</span><span class="n">name</span><span class="o">)</span>
    <span class="o">}</span>
    <span class="n">ext</span><span class="o">.</span><span class="na">cleanImage</span> <span class="o">=</span> <span class="o">{</span> <span class="n">String</span> <span class="n">name</span> <span class="o">-&gt;</span>
        <span class="kt">def</span> <span class="n">newName</span> <span class="o">=</span> <span class="n">name</span>
        <span class="o">(</span><span class="n">imageExtensions</span> <span class="o">+</span> <span class="n">soundExtensions</span><span class="o">).</span><span class="na">forEach</span> <span class="o">{</span>
            <span class="n">newName</span> <span class="o">=</span> <span class="n">newName</span><span class="o">.</span><span class="na">replace</span><span class="o">(</span><span class="n">it</span><span class="o">,</span> <span class="s2">""</span><span class="o">)</span>
        <span class="o">}</span>
        <span class="n">invalidChars</span><span class="o">.</span><span class="na">forEach</span> <span class="o">{</span>
            <span class="n">newName</span> <span class="o">=</span> <span class="n">newName</span><span class="o">.</span><span class="na">replace</span><span class="o">(</span><span class="n">it</span><span class="o">,</span> <span class="s2">"_"</span><span class="o">)</span>
        <span class="o">}</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">Character</span><span class="o">.</span><span class="na">isDigit</span><span class="o">(</span><span class="n">newName</span><span class="o">.</span><span class="na">charAt</span><span class="o">(</span><span class="mi">0</span><span class="o">)))</span> <span class="o">{</span>
            <span class="n">newName</span> <span class="o">=</span> <span class="s2">"n$newName"</span>
        <span class="o">}</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">isSound</span><span class="o">(</span><span class="n">name</span><span class="o">))</span> <span class="o">{</span>
            <span class="n">newName</span> <span class="o">=</span> <span class="n">newName</span> <span class="o">+</span> <span class="s2">"_sound"</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">newName</span>
    <span class="o">}</span>
    <span class="n">ext</span><span class="o">.</span><span class="na">printFile</span> <span class="o">=</span> <span class="o">{</span> <span class="n">File</span><span class="o">[]</span> <span class="n">files</span> <span class="o">-&gt;</span>
        <span class="n">files</span><span class="o">.</span><span class="na">each</span> <span class="o">{</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">it</span><span class="o">.</span><span class="na">file</span> <span class="o">&amp;&amp;</span> <span class="n">isValidAsset</span><span class="o">(</span><span class="n">it</span><span class="o">.</span><span class="na">name</span><span class="o">))</span> <span class="o">{</span>
                <span class="c1">// This is an asset, create a new string constant</span>
                <span class="kt">def</span> <span class="n">varName</span> <span class="o">=</span> <span class="n">cleanImage</span><span class="o">(</span><span class="n">it</span><span class="o">.</span><span class="na">name</span><span class="o">)</span>
                <span class="kt">def</span> <span class="n">varPath</span> <span class="o">=</span> <span class="n">it</span><span class="o">.</span><span class="na">canonicalPath</span><span class="o">.</span><span class="na">split</span><span class="o">(</span><span class="s2">"assets"</span><span class="o">)[</span><span class="mi">1</span><span class="o">].</span><span class="na">replace</span><span class="o">(</span><span class="s1">'\\'</span><span class="o">,</span> <span class="s1">'/'</span><span class="o">).</span><span class="na">substring</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span>
                <span class="n">builder</span><span class="o">.</span><span class="na">append</span><span class="o">(</span><span class="n">newLine</span><span class="o">).</span><span class="na">append</span><span class="o">(</span><span class="s2">"const val $varName = \""</span><span class="o">).</span><span class="na">append</span><span class="o">(</span><span class="n">varPath</span><span class="o">).</span><span class="na">append</span><span class="o">(</span><span class="s1">'"'</span><span class="o">)</span>
            <span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">it</span><span class="o">.</span><span class="na">isDirectory</span><span class="o">())</span> <span class="o">{</span>
                <span class="c1">// Create a new object, and call this function recursively</span>
                <span class="n">builder</span><span class="o">.</span><span class="na">append</span><span class="o">(</span><span class="s2">"""
        object ${cleanImage(capitalize(it.name))} {"""</span><span class="o">)</span>
                <span class="n">printFile</span><span class="o">(</span><span class="n">it</span><span class="o">.</span><span class="na">listFiles</span><span class="o">())</span>
                <span class="n">builder</span><span class="o">.</span><span class="na">append</span><span class="o">(</span><span class="s2">"}"</span><span class="o">)</span>
            <span class="o">}</span>
        <span class="o">}</span>
    <span class="o">}</span>
    <span class="n">printFile</span><span class="o">(</span><span class="n">file</span><span class="o">(</span><span class="n">assetsFolder</span><span class="o">).</span><span class="na">listFiles</span><span class="o">())</span>
    <span class="n">builder</span><span class="o">.</span><span class="na">append</span><span class="o">(</span><span class="n">newLine</span><span class="o">).</span><span class="na">append</span><span class="o">(</span><span class="s2">"}"</span><span class="o">)</span>
    <span class="c1">// Write to file</span>
    <span class="kt">def</span> <span class="n">path</span> <span class="o">=</span> <span class="n">project</span> <span class="o">+</span> <span class="n">File</span><span class="o">.</span><span class="na">separator</span> <span class="o">+</span> <span class="n">source</span> <span class="o">+</span> <span class="n">File</span><span class="o">.</span><span class="na">separator</span> <span class="o">+</span> <span class="n">pack</span><span class="o">.</span><span class="na">replace</span><span class="o">(</span><span class="s2">"."</span><span class="o">,</span> <span class="n">File</span><span class="o">.</span><span class="na">separator</span><span class="o">)</span> <span class="o">+</span>
        <span class="n">File</span><span class="o">.</span><span class="na">separator</span> <span class="o">+</span> <span class="n">fileName</span> <span class="c1">// ../code/src/com/mypack/assets/Assets.kt</span>
    <span class="n">println</span><span class="o">(</span><span class="s2">"Saving Assets at ${path}..."</span><span class="o">)</span>
    <span class="kt">def</span> <span class="n">assetsFile</span> <span class="o">=</span> <span class="n">file</span><span class="o">(</span><span class="n">path</span><span class="o">)</span> <span class="c1">// Point to the file</span>
    <span class="n">delete</span> <span class="n">assetsFile</span> <span class="c1">// delete the existing file if there is one.</span>
    <span class="n">assetsFile</span><span class="o">.</span><span class="na">getParentFile</span><span class="o">().</span><span class="na">mkdirs</span><span class="o">()</span> <span class="c1">// Make the necessary directories if they haven't been created yet.</span>
    <span class="n">assetsFile</span><span class="o">.</span><span class="na">createNewFile</span><span class="o">()</span> <span class="c1">// Create a new file</span>
    <span class="n">assetsFile</span> <span class="o">&lt;&lt;</span> <span class="n">builder</span> <span class="o">&lt;&lt;</span> <span class="n">newLine</span> <span class="c1">// write the contents of 'builder' to the new file, ending with a newLine character.</span>
<span class="o">}</span>
</code></pre></div></div>

<p>You’ll notice that the indentation and general formatting in the generated code is a bit off. Personally I don’t think it matters since you’ll never really be looking directly at the code, but you could easily modify the previous code block to take indentation into account. Nonetheless, here’s what your generated code should look like (after applying auto formatting in IntelliJ) :</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">object</span> <span class="nc">Assets</span> <span class="p">{</span>
    <span class="kd">object</span> <span class="nc">Battle</span> <span class="p">{</span>
        <span class="k">const</span> <span class="kd">val</span> <span class="py">background</span> <span class="p">=</span> <span class="s">"battle/background.png"</span>
        <span class="k">const</span> <span class="kd">val</span> <span class="py">blue_bottom</span> <span class="p">=</span> <span class="s">"battle/blue_bottom.png"</span>
        <span class="k">const</span> <span class="kd">val</span> <span class="py">red_bottom</span> <span class="p">=</span> <span class="s">"battle/red_bottom.png"</span>
        <span class="k">const</span> <span class="kd">val</span> <span class="py">red_cracked_tile</span> <span class="p">=</span> <span class="s">"battle/red_cracked_tile.png"</span>
        <span class="k">const</span> <span class="kd">val</span> <span class="py">red_empty_tile</span> <span class="p">=</span> <span class="s">"battle/red_empty_tile.png"</span>
        <span class="k">const</span> <span class="kd">val</span> <span class="py">red_tile</span> <span class="p">=</span> <span class="s">"battle/red_tile.png"</span>

        <span class="kd">object</span> <span class="nc">Results</span> <span class="p">{</span>
            <span class="k">const</span> <span class="kd">val</span> <span class="py">background</span> <span class="p">=</span> <span class="s">"battle/results/background.png"</span>
            <span class="k">const</span> <span class="kd">val</span> <span class="py">background_big</span> <span class="p">=</span> <span class="s">"battle/results/background_big.png"</span>
            <span class="k">const</span> <span class="kd">val</span> <span class="py">failure</span> <span class="p">=</span> <span class="s">"battle/results/failure.png"</span>
            <span class="k">const</span> <span class="kd">val</span> <span class="py">success</span> <span class="p">=</span> <span class="s">"battle/results/success.png"</span>
        <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>You should now be able to use these paths anywhere in your project that uses assets.</p>]]></content><author><name>Gregory Fournier</name><email>gregory.fournier@protonmail.com</email></author><category term="LibGDX" /><category term="Gradle" /><category term="Gradle-Task" /><category term="Code-Generation" /><summary type="html"><![CDATA[Unless you’ve created a fleshed out engine inside of LibGdx, chances are you’re manually providing asset paths for things like textures, sounds, etc. Here’s a typical example of creating a Texture.]]></summary></entry><entry><title type="html">Making Remappable Controls</title><link href="https://calamitysanctuary.com/Making-Remappable-Controls/" rel="alternate" type="text/html" title="Making Remappable Controls" /><published>2020-11-18T00:00:00+00:00</published><updated>2020-11-18T00:00:00+00:00</updated><id>https://calamitysanctuary.com/Making-Remappable-Controls</id><content type="html" xml:base="https://calamitysanctuary.com/Making-Remappable-Controls/"><![CDATA[<p>Enabling remappable controls in your game is as simple as decoupling the player’s input from the actual action that they want to preform with said input. Let’s start by taking a look at a standard implementation of handling input in <strong>LibGDX</strong>, with the help of <a href="https://github.com/libktx/ktx">LibKTX</a>.</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">MenuScreen</span><span class="p">:</span> <span class="nc">KtxScreen</span><span class="p">,</span> <span class="nc">KtxInputAdapter</span> <span class="p">{</span>
  <span class="k">override</span> <span class="k">fun</span> <span class="nf">show</span><span class="p">()</span> <span class="p">{</span>
      <span class="k">super</span><span class="p">.</span><span class="nf">show</span><span class="p">()</span>
      <span class="kd">val</span> <span class="py">inputProcessor</span> <span class="p">=</span> <span class="nc">Gdx</span><span class="p">.</span><span class="n">input</span><span class="p">.</span><span class="n">inputProcessor</span>
      <span class="kd">val</span> <span class="py">multiplexer</span> <span class="p">=</span> <span class="nc">InputMultiplexer</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="n">inputProcessor</span><span class="p">)</span>
      <span class="nc">Gdx</span><span class="p">.</span><span class="n">input</span><span class="p">.</span><span class="n">inputProcessor</span> <span class="p">=</span> <span class="n">multiplexer</span>
  <span class="p">}</span>
  
  <span class="k">override</span> <span class="k">fun</span> <span class="nf">keyDown</span><span class="p">(</span><span class="n">keycode</span><span class="p">:</span> <span class="nc">Int</span><span class="p">):</span> <span class="nc">Boolean</span> <span class="p">{</span>
      <span class="k">when</span><span class="p">(</span><span class="n">keycode</span><span class="p">)</span> <span class="p">{</span>
        <span class="nc">Input</span><span class="p">.</span><span class="nc">Keys</span><span class="p">.</span><span class="nc">E</span> <span class="p">-&gt;</span> <span class="p">{</span>
          <span class="c1">// Do Something when 'e' key is pressed</span>
        <span class="p">}</span>
        <span class="k">else</span> <span class="p">-&gt;</span> <span class="k">return</span> <span class="k">false</span>
      <span class="p">}</span>
    <span class="k">return</span> <span class="k">true</span>
  <span class="p">}</span>
  
  <span class="k">override</span> <span class="k">fun</span> <span class="nf">hide</span><span class="p">()</span> <span class="p">{</span>
      <span class="k">super</span><span class="p">.</span><span class="nf">hide</span><span class="p">()</span>
      <span class="p">(</span><span class="nc">Gdx</span><span class="p">.</span><span class="n">input</span><span class="p">.</span><span class="n">inputProcessor</span> <span class="k">as</span><span class="p">?</span> <span class="nc">InputMultiplexer</span><span class="p">)</span><span class="o">?.</span><span class="nf">removeProcessor</span><span class="p">(</span><span class="k">this</span><span class="p">)</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>While this might be sufficient for a simple game, hardcoded key inputs into a screen gives us hardly any flexibility. If for example we wanted to replace all actions currently handled with the ‘e’ key by the ‘q’ key, we’d have to go over all of our screens and replace it. Even worse, this doesn’t allow users to remap keys themselves, since we’ve tightly coupled our desired action to the ‘se key.</p>

<p>How about if instead of listening to keys, we listened to actions instead? Let’s replace <code class="language-plaintext highlighter-rouge">keyDown</code> with <code class="language-plaintext highlighter-rouge">onAction</code> and turn it into something like this :</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">override</span> <span class="k">fun</span> <span class="nf">onAction</span><span class="p">(</span><span class="n">action</span><span class="p">:</span> <span class="nc">Action</span><span class="p">):</span> <span class="nc">Boolean</span> <span class="p">{</span>
      <span class="k">when</span><span class="p">(</span><span class="n">action</span><span class="p">)</span> <span class="p">{</span>
        <span class="nc">INTERACT</span> <span class="p">-&gt;</span> <span class="p">{</span>
          <span class="c1">// handle interact action</span>
        <span class="p">}</span>
        <span class="k">else</span> <span class="p">-&gt;</span> <span class="k">return</span> <span class="k">false</span>
      <span class="p">}</span>
  <span class="k">return</span> <span class="k">true</span>
  <span class="p">}</span>
</code></pre></div></div>

<p>Let’s see how to get something like this up and running.</p>

<h3 id="creating-our-own-inputprocessor">Creating our own InputProcessor</h3>

<p>We’re going to need to place something between LibGDX’s input processor and our screens to intercept user input and replace it with our actions. We’ll call this <code class="language-plaintext highlighter-rouge">InputActionManager</code>.</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">InputActionManager</span> <span class="p">:</span> <span class="nc">KtxInputAdapter</span> <span class="p">{</span>

    <span class="k">fun</span> <span class="nf">init</span><span class="p">()</span> <span class="p">{</span>
        <span class="nc">Gdx</span><span class="p">.</span><span class="n">input</span><span class="p">.</span><span class="n">inputProcessor</span> <span class="p">=</span> <span class="k">this</span>
    <span class="p">}</span>
  
  <span class="k">enum</span> <span class="kd">class</span> <span class="nc">InputAction</span> <span class="p">{</span>
        <span class="nc">UP</span><span class="p">,</span>
        <span class="nc">DOWN</span><span class="p">,</span>
        <span class="nc">LEFT</span><span class="p">,</span>
        <span class="nc">RIGHT</span><span class="p">,</span>
        <span class="nc">INTERACT</span><span class="p">,</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Screens won’t bind to the <code class="language-plaintext highlighter-rouge">Gdx.input.inputProcessor</code> anymore. Instead, the sole <code class="language-plaintext highlighter-rouge">InputAdapter</code> will be this class. Later on, we’ll add the screens as listeners of this class to be able to receive events.</p>

<p>We’ve also added an <code class="language-plaintext highlighter-rouge">InputAction</code> enum, which represent the different actions we want to handle.</p>

<h3 id="mapping-inputs-to-our-actions">Mapping Inputs to our Actions</h3>

<p>Let’s add a hash map to map Input to Actions :</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">private</span> <span class="kd">val</span> <span class="py">keyboardMappings</span> <span class="p">=</span> <span class="nc">HashMap</span><span class="p">&lt;</span><span class="nc">Int</span><span class="p">,</span> <span class="nc">InputAction</span><span class="p">&gt;().</span><span class="nf">apply</span> <span class="p">{</span>
        <span class="nf">put</span><span class="p">(</span><span class="nc">Input</span><span class="p">.</span><span class="nc">Keys</span><span class="p">.</span><span class="nc">UP</span><span class="p">,</span> <span class="nc">InputAction</span><span class="p">.</span><span class="nc">UP</span><span class="p">)</span>
        <span class="nf">put</span><span class="p">(</span><span class="nc">Input</span><span class="p">.</span><span class="nc">Keys</span><span class="p">.</span><span class="nc">DOWN</span><span class="p">,</span> <span class="nc">InputAction</span><span class="p">.</span><span class="nc">DOWN</span><span class="p">)</span>
        <span class="nf">put</span><span class="p">(</span><span class="nc">Input</span><span class="p">.</span><span class="nc">Keys</span><span class="p">.</span><span class="nc">LEFT</span><span class="p">,</span> <span class="nc">InputAction</span><span class="p">.</span><span class="nc">LEFT</span><span class="p">)</span>
        <span class="nf">put</span><span class="p">(</span><span class="nc">Input</span><span class="p">.</span><span class="nc">Keys</span><span class="p">.</span><span class="nc">RIGHT</span><span class="p">,</span> <span class="nc">InputAction</span><span class="p">.</span><span class="nc">RIGHT</span><span class="p">)</span>
        <span class="nf">put</span><span class="p">(</span><span class="nc">Input</span><span class="p">.</span><span class="nc">Keys</span><span class="p">.</span><span class="nc">E</span><span class="p">,</span> <span class="nc">InputAction</span><span class="p">.</span><span class="nc">INTERACT</span><span class="p">)</span>
    <span class="p">}</span>
</code></pre></div></div>

<p>Now we can map our input to our actions whenever the user presses an input.</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">override</span> <span class="k">fun</span> <span class="nf">keyDown</span><span class="p">(</span><span class="n">keycode</span><span class="p">:</span> <span class="nc">Int</span><span class="p">):</span> <span class="nc">Boolean</span> <span class="p">{</span>
    <span class="kd">val</span> <span class="py">action</span> <span class="p">=</span> <span class="n">keyboardMappings</span><span class="p">[</span><span class="n">keycode</span><span class="p">]</span>
    <span class="c1">// Notify listeners of action</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="introducing-the-action-listener">Introducing the Action Listener</h3>

<p>We need a way to notify screens of actions. We’ll create an interface called <code class="language-plaintext highlighter-rouge">ActionListener</code> which screens will be able to implement if they want to handle input.</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">interface</span> <span class="nc">ActionListener</span> <span class="p">{</span>
    <span class="k">fun</span> <span class="nf">onAction</span><span class="p">(</span><span class="n">action</span><span class="p">:</span> <span class="nc">InputAction</span><span class="p">):</span> <span class="nc">Boolean</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">InputActionManager</code> will keep a reference to all <code class="language-plaintext highlighter-rouge">ActionListeners</code> who have subscribed, and propagate the <code class="language-plaintext highlighter-rouge">Action</code> until an <code class="language-plaintext highlighter-rouge">ActionListener</code> handles the action.</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">InputActionManager</span> <span class="p">:</span> <span class="nc">KtxInputAdapter</span> <span class="p">{</span>
  <span class="k">private</span> <span class="kd">val</span> <span class="py">actionListeners</span> <span class="p">=</span> <span class="nc">ArrayList</span><span class="p">&lt;</span><span class="nc">ActionListener</span><span class="p">&gt;()</span>
  
  <span class="k">private</span> <span class="kd">val</span> <span class="py">keyboardMappings</span> <span class="p">=</span> <span class="nc">HashMap</span><span class="p">&lt;</span><span class="nc">Int</span><span class="p">,</span> <span class="nc">InputAction</span><span class="p">&gt;().</span><span class="nf">apply</span> <span class="p">{</span>
        <span class="nf">put</span><span class="p">(</span><span class="nc">Input</span><span class="p">.</span><span class="nc">Keys</span><span class="p">.</span><span class="nc">UP</span><span class="p">,</span> <span class="nc">InputAction</span><span class="p">.</span><span class="nc">UP</span><span class="p">)</span>
        <span class="nf">put</span><span class="p">(</span><span class="nc">Input</span><span class="p">.</span><span class="nc">Keys</span><span class="p">.</span><span class="nc">DOWN</span><span class="p">,</span> <span class="nc">InputAction</span><span class="p">.</span><span class="nc">DOWN</span><span class="p">)</span>
        <span class="nf">put</span><span class="p">(</span><span class="nc">Input</span><span class="p">.</span><span class="nc">Keys</span><span class="p">.</span><span class="nc">LEFT</span><span class="p">,</span> <span class="nc">InputAction</span><span class="p">.</span><span class="nc">LEFT</span><span class="p">)</span>
        <span class="nf">put</span><span class="p">(</span><span class="nc">Input</span><span class="p">.</span><span class="nc">Keys</span><span class="p">.</span><span class="nc">RIGHT</span><span class="p">,</span> <span class="nc">InputAction</span><span class="p">.</span><span class="nc">RIGHT</span><span class="p">)</span>
        <span class="nf">put</span><span class="p">(</span><span class="nc">Input</span><span class="p">.</span><span class="nc">Keys</span><span class="p">.</span><span class="nc">E</span><span class="p">,</span> <span class="nc">InputAction</span><span class="p">.</span><span class="nc">INTERACT</span><span class="p">)</span>
  <span class="p">}</span>
  
  <span class="k">fun</span> <span class="nf">subscribe</span><span class="p">(</span><span class="n">listener</span><span class="p">:</span> <span class="nc">ActionListener</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">actionListeners</span><span class="p">.</span><span class="nf">add</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">listener</span><span class="p">)</span> <span class="c1">// Latest subscribers get priority</span>
  <span class="p">}</span>
  
  <span class="k">fun</span> <span class="nf">unsubscribe</span><span class="p">(</span><span class="n">listener</span><span class="p">:</span> <span class="nc">ActionListener</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">actionListeners</span><span class="p">.</span><span class="nf">remove</span><span class="p">(</span><span class="n">listener</span><span class="p">)</span>
  <span class="p">}</span>
  
  <span class="k">override</span> <span class="k">fun</span> <span class="nf">keyDown</span><span class="p">(</span><span class="n">keycode</span><span class="p">:</span> <span class="nc">Int</span><span class="p">):</span> <span class="nc">Boolean</span> <span class="p">{</span>
      <span class="kd">val</span> <span class="py">action</span> <span class="p">=</span> <span class="n">keyboardMappings</span><span class="p">[</span><span class="n">keycode</span><span class="p">]</span>
      <span class="c1">// Notify listeners of action</span>
      <span class="n">action</span><span class="o">?.</span><span class="nf">let</span> <span class="p">{</span>
          <span class="k">if</span> <span class="p">(</span><span class="n">listener</span><span class="p">.</span><span class="nf">onAction</span><span class="p">(</span><span class="n">action</span><span class="p">))</span> <span class="k">return</span> <span class="k">true</span>
      <span class="p">}</span> <span class="o">?:</span> <span class="nf">debug</span> <span class="p">{</span> <span class="s">"No Action mapped to $keycode"</span> <span class="p">}</span>
      <span class="k">return</span> <span class="k">false</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>We’ve added methods for adding and removing subscribers, and we’ve created the missing link for notifying subscribers of user actions. We iterate over all subscribers, until we find one which handles the corresponding action. This lets us have multiple classes handling different inputs without the need for a multiplexer. I also added a debug message to notify the dev if they press a key that has no mapped <code class="language-plaintext highlighter-rouge">Action</code>.</p>

<h3 id="implementing-an-action-listener">Implementing an Action Listener</h3>

<p>The final piece of the puzzle : implementing an <code class="language-plaintext highlighter-rouge">ActionListener</code> and having it subscribe to our new <code class="language-plaintext highlighter-rouge">InputActionManager</code>. You’re going to need a way for your objects to access your <code class="language-plaintext highlighter-rouge">InputActionManager</code>. Here I’m using <a href="https://github.com/libktx/ktx/tree/master/inject">KTX-Inject</a> to inject it via dependancy injection, but you could also have it as a static object if you prefer.</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">MenuScreen</span><span class="p">:</span> <span class="nc">KtxScreen</span><span class="p">,</span> <span class="nc">ActionListener</span> <span class="p">{</span>
  <span class="k">private</span> <span class="kd">val</span> <span class="py">inputActionManager</span><span class="p">:</span> <span class="nc">InputActionManager</span> <span class="p">=</span> <span class="nc">MainContext</span><span class="p">.</span><span class="nf">inject</span><span class="p">()</span>
  <span class="k">override</span> <span class="k">fun</span> <span class="nf">show</span><span class="p">()</span> <span class="p">{</span>
      <span class="k">super</span><span class="p">.</span><span class="nf">show</span><span class="p">()</span>
      <span class="n">inputActionManager</span><span class="p">.</span><span class="nf">subscribe</span><span class="p">(</span><span class="k">this</span><span class="p">)</span>
  <span class="p">}</span>
  
  <span class="k">override</span> <span class="k">fun</span> <span class="nf">onAction</span><span class="p">(</span><span class="n">action</span><span class="p">:</span> <span class="nc">InputAction</span><span class="p">):</span> <span class="nc">Boolean</span> <span class="p">{</span>
      <span class="k">when</span><span class="p">(</span><span class="n">action</span><span class="p">)</span> <span class="p">{</span>
        <span class="nc">INTERACT</span> <span class="p">-&gt;</span> <span class="p">{</span>
          <span class="c1">// Handle interact action</span>
        <span class="p">}</span>
        <span class="k">else</span> <span class="p">-&gt;</span> <span class="k">return</span> <span class="k">false</span>
      <span class="p">}</span>
    <span class="k">return</span> <span class="k">true</span>
  <span class="p">}</span>
  
  <span class="k">override</span> <span class="k">fun</span> <span class="nf">hide</span><span class="p">()</span> <span class="p">{</span>
      <span class="k">super</span><span class="p">.</span><span class="nf">hide</span><span class="p">()</span>
      <span class="n">inputActionManager</span><span class="p">.</span><span class="nf">unsubscribe</span><span class="p">(</span><span class="k">this</span><span class="p">)</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Like with the input processor, we must subscribe when we want to receive actions, and unsubscribe when we’re done handling actions. in the <code class="language-plaintext highlighter-rouge">onAction</code> method, we can handle the actions we want, being sure to return <code class="language-plaintext highlighter-rouge">true</code> when we want to consume an action and <code class="language-plaintext highlighter-rouge">false</code> when we want to keep propagating the action to let others potentially handle it.</p>

<h3 id="so-what-was-the-point-of-it-all">So What was the Point of it all?</h3>

<p>By decoupling our input we’ve done many things. We now have one central point for input, instead of it being distributed everywhere. That lets us do neat things like disabling all or certain actions if need be, by adding logic in our <code class="language-plaintext highlighter-rouge">InputActionManager</code> to keep a list of disabled actions and avoid propagating them. We’ve also made it much easier to implement control remapping. Instead of hardcoding our <code class="language-plaintext highlighter-rouge">keyboardMappings</code> hash map, we could save that information to a local file, and add an option screen which lets us modify it.</p>

<p>Adding controller support will be much easier, since listeners don’t need to listen to both keyboard events and controller events. Just have your <code class="language-plaintext highlighter-rouge">inputActionManager</code> listen to controller input events and map those to the same Actions as before, that way your listeners don’t need to be made aware of the actual input device, just the desired action.</p>

<p>Do you want to show a demo screen where the player is automatically controlled? While out of scope for this article, here’s the general idea :</p>

<ul>
  <li>Hide the inputActionManager implementation behind an interface.</li>
  <li>Create a new implementation of this interface
    <ul>
      <li>This implementation will propage actions in a certain order, instead of mapping inputs to actions</li>
    </ul>
  </li>
  <li>Inject this new implementation in your “Demo Screen” instead of the default implementation</li>
</ul>

<p>You could even replace the demo <code class="language-plaintext highlighter-rouge">InputActionManager</code> by the real one when the player presses an input, letting them take control at any moment during the demo!</p>

<h3 id="things-to-improve">Things to Improve</h3>

<p>Here are a couple of things you could add to make the <code class="language-plaintext highlighter-rouge">InputActionManager</code> more feature complete :</p>

<ul>
  <li>Add the possibility to disable certain or all inputs</li>
  <li>Let listeners listen to both <code class="language-plaintext highlighter-rouge">onKeyDown</code> and <code class="language-plaintext highlighter-rouge">onKeyUp</code></li>
  <li>Add controller support</li>
</ul>]]></content><author><name>Gregory Fournier</name><email>gregory.fournier@protonmail.com</email></author><category term="LibGDX" /><category term="LibKTX" /><summary type="html"><![CDATA[Enabling remappable controls in your game is as simple as decoupling the player’s input from the actual action that they want to preform with said input. Let’s start by taking a look at a standard implementation of handling input in LibGDX, with the help of LibKTX.]]></summary></entry><entry><title type="html">Handle Asset Loading With Annotations</title><link href="https://calamitysanctuary.com/Handle-Asset-Loading-With-Annotations/" rel="alternate" type="text/html" title="Handle Asset Loading With Annotations" /><published>2020-11-09T00:00:00+00:00</published><updated>2020-11-09T00:00:00+00:00</updated><id>https://calamitysanctuary.com/Handle-Asset-Loading-With-Annotations</id><content type="html" xml:base="https://calamitysanctuary.com/Handle-Asset-Loading-With-Annotations/"><![CDATA[<p>The <strong>AssetManager</strong> handles loading and unloading various assets such as <em>Textures</em> and <em>Sounds</em>. Rather than loading them on use, you can use the Asset Manager to load all necessary assets at game launch, or at the beginning of a level. It also serves as a central point for all assets, making it easier to avoid reimporting the same asset multiple times.</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">val</span> <span class="py">manager</span> <span class="p">=</span> <span class="nc">AssetManager</span><span class="p">()</span>
<span class="n">manager</span><span class="p">.</span><span class="nf">load</span><span class="p">(</span><span class="s">"data/mytexture.png"</span><span class="p">,</span> <span class="nc">Texture</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">)</span>
<span class="cm">/*
 * Load all assets that we called 'load' on.
 * As long as update returns false, we havn't finished loading
 */</span>
<span class="k">while</span> <span class="p">(!</span><span class="n">manager</span><span class="p">.</span><span class="nf">update</span><span class="p">())</span> <span class="p">{</span>
  <span class="c1">// do nothing</span>
<span class="p">}</span>
<span class="c1">// Use the asset</span>
<span class="kd">val</span> <span class="py">texture</span><span class="p">:</span> <span class="nc">Texture</span> <span class="p">=</span> <span class="n">manager</span><span class="p">.</span><span class="k">get</span><span class="p">(</span><span class="s">"data/mytexture.png"</span><span class="p">,</span> <span class="nc">Texture</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">);</span>
</code></pre></div></div>

<p>While using the Asset Manager is much better than loading them on the fly, managing the <code class="language-plaintext highlighter-rouge">load</code> and <code class="language-plaintext highlighter-rouge">get</code> calls can very quickly start to get messy, not to mention all of the redundant code. Ideally, we would like to declare an asset once, and have the engine handle the loading and whatnot for us.</p>

<h1 id="proposed-solution">Proposed solution</h1>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Asset</span>
<span class="kd">val</span> <span class="py">textureAsset</span> <span class="p">=</span> <span class="nc">AssetDescriptor</span><span class="p">(</span><span class="s">"data/myTexture.png"</span><span class="p">,</span> <span class="nc">Texture</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">)</span>

<span class="kd">val</span> <span class="py">texture</span><span class="p">:</span> <span class="nc">Texture</span> <span class="p">=</span> <span class="n">texture</span><span class="p">.</span><span class="k">get</span><span class="p">()</span>
</code></pre></div></div>

<p>We’ve introduced the <code class="language-plaintext highlighter-rouge">@Asset</code> annotation, which will let us tell our engine that the following field is an asset to be loaded by our asset manager. Here is what the annotation declaration looks like.</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Target</span><span class="p">(</span><span class="nc">AnnotationTarget</span><span class="p">.</span><span class="nc">FIELD</span><span class="p">)</span>
<span class="k">annotation</span> <span class="kd">class</span> <span class="nc">Asset</span><span class="p">()</span>
</code></pre></div></div>

<p>By using this simple annotation we’ve done two things. We avoid having to drag along our asset manager wherever we want to declare assets, and we’ve created one single reference to handle both telling our asset manager to load the object and also serving as a reference point to obtain the actual asset.</p>

<p>However, simply adding the annotation won’t put everything into motion. Let’s see how we actually load the assets at startup.</p>

<h1 id="loading-the-assets">Loading the Assets</h1>

<p>Now that we’ve annotated our fields, we need to fetch this information and queue up the loading. Let’s take a look.</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">private</span> <span class="k">fun</span> <span class="nf">loadAllAssets</span><span class="p">()</span> <span class="p">{</span>
  <span class="kd">val</span> <span class="py">reflection</span> <span class="p">=</span> <span class="nc">MainContext</span><span class="p">.</span><span class="n">inject</span><span class="p">&lt;</span><span class="nc">Reflections</span><span class="p">&gt;()</span>
  <span class="kd">val</span> <span class="py">assets</span> <span class="p">=</span> <span class="n">reflection</span>
  <span class="p">.</span><span class="nf">getFieldsAnnotatedWith</span><span class="p">(</span><span class="nc">Asset</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">)</span>
  <span class="p">.</span><span class="nf">mapNotNull</span> <span class="p">{</span>
    <span class="n">it</span><span class="p">.</span><span class="n">isAccessible</span> <span class="p">=</span> <span class="k">true</span> <span class="c1">// Workaround for having this work despite wanting to limit scope of certain assets</span>
    <span class="n">it</span><span class="p">.</span><span class="k">get</span><span class="p">(</span><span class="k">null</span><span class="p">)</span> <span class="k">as</span><span class="p">?</span> <span class="nc">AssetDescriptor</span><span class="p">&lt;</span><span class="err">*</span><span class="p">&gt;</span>
  <span class="p">}</span>
  
  <span class="n">assets</span><span class="p">.</span><span class="nf">forEach</span> <span class="p">{</span>
    <span class="n">assetManager</span><span class="p">.</span><span class="nf">load</span><span class="p">(</span><span class="n">it</span><span class="p">)</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This basically replaces all of our <code class="language-plaintext highlighter-rouge">load</code> calls from the initial method. We’re using the <code class="language-plaintext highlighter-rouge">org.reflections:reflections</code> library to fetch all fields with the <code class="language-plaintext highlighter-rouge">@Asset</code> annotation as <code class="language-plaintext highlighter-rouge">AssetDescriptors</code> and loading them all. Although I haven’t talked about it so far, <code class="language-plaintext highlighter-rouge">AssetDescription</code> is an existing LibGDX class which basically holds the path and filetype information of an asset.</p>

<p>Once we’ve queued up the assets, we need to start loading them all. This hasn’t changed from before so we simply call <code class="language-plaintext highlighter-rouge">assetManager.update()</code> each frame, which returns <code class="language-plaintext highlighter-rouge">true</code> if we’re finished loading everything.</p>

<h1 id="obtaining-the-assets">Obtaining the Assets</h1>

<p>The final piece of the puzzle is the <code class="language-plaintext highlighter-rouge">get</code> extension function, which lets us obtain the actual asset via the same reference with annotated earlier.</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fun</span> <span class="p">&lt;</span><span class="nc">T</span><span class="p">&gt;</span> <span class="nf">AssetDescriptor</span><span class="p">&lt;</span><span class="nc">T</span><span class="p">&gt;.</span><span class="k">get</span><span class="p">():</span> <span class="nc">T</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">assetManager</span><span class="p">.</span><span class="k">get</span><span class="p">(</span><span class="k">this</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Using generics lets us omit the actual class name when permitted, which is useful in keeping things short and concise.</p>

<h1 id="putting-it-all-together">Putting it all together</h1>

<p>Let’s look at how it all comes together. For reuse in all my projects, I’ve wrapped everything found here in my own <code class="language-plaintext highlighter-rouge">AssetManager</code> class. Here is what it looks like (certain lines omited or changed for brevity and completeness).</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// package ...</span>
<span class="k">import</span> <span class="nn">com.badlogic.gdx.assets.AssetDescriptor</span>
<span class="k">import</span> <span class="nn">ktx.freetype.registerFreeTypeFontLoaders</span>
<span class="k">import</span> <span class="nn">org.reflections.Reflections</span>
<span class="k">import</span> <span class="nn">com.badlogic.gdx.assets.AssetManager</span> <span class="k">as</span> <span class="nc">GdxAssetManager</span>

<span class="kd">class</span> <span class="nc">AssetManager</span> <span class="p">{</span>

    <span class="nf">init</span> <span class="p">{</span>
        <span class="n">assetManager</span><span class="p">.</span><span class="nf">registerFreeTypeFontLoaders</span><span class="p">()</span>
        <span class="nf">loadAllAssets</span><span class="p">()</span>
    <span class="p">}</span>

    <span class="k">fun</span> <span class="nf">install</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">assetManager</span><span class="p">.</span><span class="nf">registerFreeTypeFontLoaders</span><span class="p">()</span>
        <span class="nf">loadAllAssets</span><span class="p">()</span>
    <span class="p">}</span>

    <span class="k">fun</span> <span class="nf">update</span><span class="p">():</span> <span class="nc">Boolean</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">assetManager</span><span class="p">.</span><span class="nf">update</span><span class="p">()</span>
    <span class="p">}</span>

    <span class="k">fun</span> <span class="nf">progress</span><span class="p">():</span> <span class="nc">Float</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">assetManager</span><span class="p">.</span><span class="n">progress</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">fun</span> <span class="nf">loadAllAssets</span><span class="p">()</span> <span class="p">{</span>
        <span class="kd">val</span> <span class="py">reflection</span> <span class="p">=</span> <span class="nc">Reflections</span><span class="p">(</span><span class="s">"com.xanadu.section"</span><span class="p">,</span> <span class="nc">FieldAnnotationsScanner</span><span class="p">(),</span> <span class="nc">TypeAnnotationsScanner</span><span class="p">(),</span> <span class="nc">SubTypesScanner</span><span class="p">())</span>
        <span class="kd">val</span> <span class="py">assets</span> <span class="p">=</span> <span class="n">reflection</span>
                <span class="p">.</span><span class="nf">getFieldsAnnotatedWith</span><span class="p">(</span><span class="nc">Asset</span><span class="o">::</span><span class="k">class</span><span class="p">.</span><span class="n">java</span><span class="p">)</span>
                <span class="p">.</span><span class="nf">mapNotNull</span> <span class="p">{</span>
                    <span class="n">it</span><span class="p">.</span><span class="n">isAccessible</span> <span class="p">=</span> <span class="k">true</span>
                    <span class="n">it</span><span class="p">.</span><span class="k">get</span><span class="p">(</span><span class="k">null</span><span class="p">)</span> <span class="k">as</span><span class="p">?</span> <span class="nc">AssetDescriptor</span><span class="p">&lt;</span><span class="err">*</span><span class="p">&gt;</span>
                <span class="p">}</span>
        <span class="n">assets</span><span class="p">.</span><span class="nf">forEach</span> <span class="p">{</span>
            <span class="n">assetManager</span><span class="p">.</span><span class="nf">load</span><span class="p">(</span><span class="n">it</span><span class="p">)</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">companion</span> <span class="k">object</span> <span class="p">{</span>
        <span class="k">private</span> <span class="kd">val</span> <span class="py">assetManager</span><span class="p">:</span> <span class="nc">GdxAssetManager</span> <span class="p">=</span> <span class="nc">GdxAssetManager</span><span class="p">()</span>
        
        <span class="k">fun</span> <span class="p">&lt;</span><span class="nc">T</span><span class="p">&gt;</span> <span class="nf">AssetDescriptor</span><span class="p">&lt;</span><span class="nc">T</span><span class="p">&gt;.</span><span class="k">get</span><span class="p">():</span> <span class="nc">T</span> <span class="p">{</span>
            <span class="k">return</span> <span class="n">assetManager</span><span class="p">.</span><span class="k">get</span><span class="p">(</span><span class="k">this</span><span class="p">)</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="nd">@Target</span><span class="p">(</span><span class="nc">AnnotationTarget</span><span class="p">.</span><span class="nc">FIELD</span><span class="p">)</span>
<span class="k">annotation</span> <span class="kd">class</span> <span class="nc">Asset</span><span class="p">()</span>
</code></pre></div></div>

<h1 id="improvements-for-the-future">Improvements for the Future</h1>

<ul>
  <li>Right now we’re using reflection at runtime to obtain all the assets. Ideally we should be generating this code with something like <strong>Kotlin Poet</strong> at compile time, as bigger projects will take some time finding all of our annotated fields.</li>
  <li>Our <code class="language-plaintext highlighter-rouge">@Asset</code> annotation is very simple, we could enrich it with some helpful functionalities. For example, we could add a <code class="language-plaintext highlighter-rouge">Level</code> enum to denote which levels of our game uses this asset, so instead of loading all assets at the beginning, we could load necessary assets at the beginning of each level, to avoid a large load time at startup.</li>
</ul>]]></content><author><name>Gregory Fournier</name><email>gregory.fournier@protonmail.com</email></author><category term="LibGDX" /><category term="LibKTX" /><summary type="html"><![CDATA[The AssetManager handles loading and unloading various assets such as Textures and Sounds. Rather than loading them on use, you can use the Asset Manager to load all necessary assets at game launch, or at the beginning of a level. It also serves as a central point for all assets, making it easier to avoid reimporting the same asset multiple times.]]></summary></entry></feed>