<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Cole Cecil</title>
    <description>I'm Cole. I develop software for a living, and I also do it for fun in my free time. I write here about my personal projects, as well as creating tutorials to share the things I've learned.
</description>
    <link>https://colececil.dev/</link>
    <atom:link href="https://colececil.dev/feed.xml" rel="self" type="application/rss+xml"/>
    <copyright>
        
        &#169; 2016-2025 Cole Cecil. All rights reserved.
    </copyright>
    <pubDate>Tue, 25 Mar 2025 16:47:16 -0500</pubDate>
    <lastBuildDate>Tue, 25 Mar 2025 16:47:16 -0500</lastBuildDate>
    <generator>Jekyll v3.8.7</generator>
    
      <item>
        <title>Inventing a New Cryptid: Long Mary</title>
        <description>
            &lt;p&gt;In this post, I want to share the story of a strange creature born from a bizarre alignment of white-knuckled fear, fatigue-fueled delirium, bullheaded creativity, a slightly-too-optimistic trust of technology, and yes - a camel-shaped snow drift. This is the story of Long Mary, a terrifying cryptid that captured my imagination (and my heart) last December.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;the-birth-of-a-new-cryptid&quot;&gt;The Birth of a New Cryptid&lt;/h2&gt;

&lt;p&gt;This all started when my wife and I were driving to upstate New York to visit her family for Christmas. We were on the last leg of our journey - it was getting dark, and we were starting to get impatient for the drive to be over with. In an unfortunate turn of events, we realized a little too late that Google Maps had taken us onto some slightly terrifying back roads in the mountains of northern Pennsylvania, in the interest of “a faster route”. (Note: It wasn’t. Not by a long shot.) I’m sure this route would have been enjoyable had it not been for night’s veil of darkness and the pavement’s occasional dusting of snow, but as it was, these conditions made the steep hills and narrow, winding paths much more treacherous than was ideal. I remember obediently making a GPS-mandated turn onto one particularly perilous-looking stretch of road and stating aloud, “Welp, we’re gonna die”. (This behavior may have been influenced by the fact that I’d recently listened to &lt;a href=&quot;https://youtu.be/7G8f-AMx9-w&quot;&gt;this harrowing story told by MrBallen&lt;/a&gt;. The story definitely crossed my mind in that moment.)&lt;/p&gt;

&lt;p&gt;Anyway, at one point while we were navigating these hazardous roads, I noticed an unusual shape just off the road ahead, out of the corner of my eye. My first impression was that it was a strange, camel-shaped creature. Upon closer inspection, it turned out to be a snow drift next to a mailbox. I laughed to myself and told my wife what I’d seen. Soon after, we drove past a sign that read “Long Mary Road”. Synapses fired, ideas formed, and the rest is cryptid history.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/inventing-a-new-cryptid/long-mary-final.png&quot; alt=&quot;Depiction of Long Mary&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;depicting-long-mary---the-artistic-process&quot;&gt;Depicting Long Mary - The Artistic Process&lt;/h2&gt;

&lt;p&gt;During the following week spent with family, I found I couldn’t get this creature out of my head. I became fixated on imagining what Long Mary might look like up close. I’d recently been playing around with &lt;a href=&quot;https://en.wikipedia.org/wiki/Stable_Diffusion&quot;&gt;Stable Diffusion&lt;/a&gt;, a machine learning model that can generate images from text prompts. I thought it would be fun to try using it as part of a creative process aimed at creating a depiction of Long Mary. The sections below describe this process in detail.&lt;/p&gt;

&lt;h3 id=&quot;step-1-brainstorming&quot;&gt;Step 1: Brainstorming&lt;/h3&gt;

&lt;p&gt;My first goal was just to see what kinds of ideas Stable Diffusion could come up with. It took some time and experimentation, but I eventually arrived at a prompt that seemed to give me decent results. The images it generated didn’t have the level of quality I was looking for in a final image, but that didn’t really matter at this stage. The main point was to get some ideas for creating Long Mary’s physical features.&lt;/p&gt;

&lt;p&gt;After generating many, many images, I selected a handful of my favorites, with the intention of incorporating elements of each of them into the final image. Here are the ones I selected:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/inventing-a-new-cryptid/long-mary-inspirations.png&quot; alt=&quot;Long Mary inspirations&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As I mentioned, I went through many iterations of the prompt, but here is one of the final versions I used in this step of the process:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Photo of a cryptid, extremely long neck, so many vertebrae, short stubby legs, ugly misshapen head, a single hump on its back, long crooked fangs, matted fur, its fur is covered in snow, sasquatch, chupacabra, mange, crouching, crawling, dark snowy forest, trees, horror, creepy, grotesque, little nightmares, slightly blurry photo, nature photography, dusk, ultra realistic&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Stable Diffusion also has a “negative prompt” feature, which lets you specify things to exclude from the image. Here’s the negative prompt I used with the prompt above:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;hand drawn, illustrated, out of frame, cartoon, unreal engine&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As you might notice, it doesn’t always do a great job of following instructions. I’ve definitely found Stable Diffusion (and &lt;a href=&quot;https://en.wikipedia.org/wiki/Generative_artificial_intelligence&quot;&gt;generative AI&lt;/a&gt; in general) to be quite finnicky, and it can be frustrating at times trying to get the results you want. The process tends to involve a lot of trial and error. (Of course, it could also be that I have more to learn about &lt;a href=&quot;https://en.wikipedia.org/wiki/Prompt_engineering&quot;&gt;prompt engineering&lt;/a&gt;!)&lt;/p&gt;

&lt;h3 id=&quot;step-2-concept-sketch&quot;&gt;Step 2: Concept Sketch&lt;/h3&gt;

&lt;p&gt;Next, I sketched out a rough concept of what I thought the final image should look like, based on my results from the previous step. Here’s what I came up with:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/inventing-a-new-cryptid/long-mary-sketch.png&quot; alt=&quot;Concept sketch of Long Mary&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;step-3-generation-of-the-final-image&quot;&gt;Step 3: Generation of the Final Image&lt;/h3&gt;

&lt;p&gt;The final step of the process involved using Stable Diffusion’s img2img feature, which tells it to use an input image along with the text prompt to generate the output image. I figured that by using my concept sketch to influence the output, I would have more control over what the final image looked like.&lt;/p&gt;

&lt;p&gt;This is where things got a bit convoluted. I wasn’t able to get the result I wanted from just my sketch and a text prompt. However, I was able to get a little bit closer to what I was looking for. So what I ended up doing was taking the output image and plugging it back in as the input image, along with the same text prompt. I performed several iterations of this until I was happy with the result. The final image was shown near the beginning of this post, but here it is again:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/inventing-a-new-cryptid/long-mary-final.png&quot; alt=&quot;Final image of Long Mary&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, I can’t seem to find the prompts I used for this step, but I believe they focused more on the environment and the art style, since Long Mary’s physical features were included in the sketch.&lt;/p&gt;

&lt;p&gt;As a bonus, though, here are some neat alternative versions that look like they belong in an illustrated bestiary. (These were also generated at some point during this final step of the process.)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/inventing-a-new-cryptid/long-mary-alternative-versions.png&quot; alt=&quot;Alternative versions of Long Mary&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;additional-lore&quot;&gt;Additional Lore&lt;/h2&gt;

&lt;p&gt;Upon sharing my creation with some friends, one of them wondered if ChatGPT could generate an &lt;a href=&quot;https://scp-wiki.wikidot.com/guide-for-newcomers&quot;&gt;SCP&lt;/a&gt; entry for Long Mary. I gave it a go, and the result exceeded my expectations:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Special Containment Procedures:&lt;/strong&gt; Long Mary is to be contained within a standard Class-3 anomalous mammal containment unit at Site-17. The unit is to be designed to replicate the mountainous forest habitat of northern Pennsylvania, including a artificial snow feature for the creature’s use. Access to the containment unit is restricted to Level 3 personnel and above, with Level 4 clearance required for any direct interaction with the specimen.&lt;/p&gt;

  &lt;p&gt;Long Mary is to be fed a diet of raw meat, supplemented with vitamins and minerals as necessary. Any attempts at domestication or training are strictly forbidden.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Long Mary is a cryptid mammal indigenous to the mountainous forests of northern Pennsylvania. It stands approximately 2 meters tall at the shoulder and 3 meters in length, with a weight of approximately 500 kg. It has a distinctive snow-covered hump on its back and a long neck, as well as a large head and sharp teeth. It is primarily white in color, with some grey and black markings on its face and legs.&lt;/p&gt;

  &lt;p&gt;When crouched down, Long Mary bears a strong resemblance to a snow drift, with only its head and neck visible. This camouflage allows it to blend in with its surroundings and ambush prey. It is an apex predator in its habitat, with its diet consisting primarily of large mammals such as deer and elk.&lt;/p&gt;

  &lt;p&gt;Long Mary has proven to be highly aggressive towards humans, with several reported attacks on hikers and hunters in the area. It is believed to be territorial and will attack any perceived threat to its territory.&lt;/p&gt;

  &lt;p&gt;Research into Long Mary’s anomalous properties is ongoing. It is currently unknown how the creature is able to maintain its snowy appearance year-round, as well as the potential use of its camouflage in other environments. Further study is required to fully understand the nature of this cryptid.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here’s the prompt I fed into ChatGPT to generate this SCP entry:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Imagine there is a cryptid that lives in the mountainous forests of northern Pennsylvania called Long Mary. It is a mammal that walks on four legs, and it has a snow-covered hump on its back. It has a long neck, along with a large head and a large mouth full of sharp teeth. When it crouches down, it looks like a snow drift with a post next to it. Please write an SCP entry about Long Mary. Feel free to embellish and make up new details about it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I was surprised at how many fascinating and relevant details it came up with, considering the small amount of information I gave it!&lt;/p&gt;

&lt;h2 id=&quot;parting-thoughts&quot;&gt;Parting Thoughts&lt;/h2&gt;

&lt;p&gt;This ended up being a really fun project, and I love how it turned out. I would definitely use Stable Diffusion for brainstorming again in future projects, as it can generate a greater variety of ideas than I’m able to come up with on my own. As for whether it’s a good idea to use it to generate final images for a project, I’d say it depends on the project. If you’re looking for something really specific or need to maintain consistency with other images, it could be really difficult and time-consuming to get Stable Diffusion to produce what you want. On the other hand, if you’re more open to variation, it could work well.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed the story of Long Mary and learning about its creation. Though if you ever find yourself in the area around its territory, I’d recommend exercising extreme caution.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/inventing-a-new-cryptid/long-mary-location.png&quot; alt=&quot;Map of Long Mary's approximate territory&quot; /&gt;&lt;/p&gt;

            &lt;p&gt;&amp;#169; 
            2023
             &lt;a href=&quot;https://colececil.dev&quot;&gt;Cole Cecil&lt;/a&gt;. All rights reserved.&lt;/p&gt;
        </description>
        <pubDate>Mon, 18 Sep 2023 00:51:00 -0500</pubDate>
        <link>https://colececil.dev/blog/2023/inventing-a-new-cryptid/</link>
        <guid isPermaLink="true">https://colececil.dev/blog/2023/inventing-a-new-cryptid/</guid>
        
        
      </item>
    
      <item>
        <title>Choosing a Game Engine</title>
        <description>
            &lt;p&gt;When making a video game, deciding which game engine you are going to use is one of the first big choices you have to make, and it has a huge effect on the outcome of your project. Choosing an engine that’s a bad fit for your project can lead to things like dead ends, delays, extra expenses, and having to cut features.&lt;/p&gt;

&lt;p&gt;Because of the importance of this decision, you should have a good set of criteria to use when choosing an engine, and you should have some familiarity with the available options. In this article, I’m going to cover both of those points.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;what-is-a-game-engine&quot;&gt;What is a game engine?&lt;/h2&gt;

&lt;p&gt;First of all, let me introduce what a game engine is, in case you are not familiar. A game engine is essentially a cohesive set of tools used for making a game. Making use of a preexisting game engine prevents you from having to spend your time solving problems that are not specific to your game. Most games have quite a number of things in common when it comes to implementation, so it makes sense to have tools to prevent us from wasting our time solving problems that already have solutions.&lt;/p&gt;

&lt;p&gt;Here are some examples of typical things a game engine provides:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;An editor&lt;/li&gt;
  &lt;li&gt;A rendering engine&lt;/li&gt;
  &lt;li&gt;A physics engine&lt;/li&gt;
  &lt;li&gt;Animation tools&lt;/li&gt;
  &lt;li&gt;Audio tools&lt;/li&gt;
  &lt;li&gt;An input system&lt;/li&gt;
  &lt;li&gt;Scene management&lt;/li&gt;
  &lt;li&gt;Scripting&lt;/li&gt;
  &lt;li&gt;Multi-platform support&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;criteria-for-choosing-a-game-engine&quot;&gt;Criteria for choosing a game engine&lt;/h2&gt;

&lt;p&gt;As with making any big decision, it’s helpful to have criteria to evaluate how well each choice will work out for you. Here are some good criteria to consider when choosing a game engine:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Aspirations for your game:&lt;/strong&gt; What are you planning to do with your game? If you are planning to eventually sell your game, you are going to want to make sure you can create a polished product, along with being able to continue to support it in the long term. This means you should choose an engine that is well maintained and supported, and also that is going to be around for a while. If you are creating more of a hobbyist game that you don’t plan on maintaining for a long time, you don’t have to worry about these things as much.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Type of game:&lt;/strong&gt; What genre of game are you planning on making? Are you planning on making a 2D game or a 3D game? Different game engines have varying levels of support for these types of things, so you’ll want to keep this in mind while choosing one.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Platforms to support:&lt;/strong&gt; What platforms do you want to distribute your game on? Desktop? Consoles? VR? Make sure you pick a game engine that supports your desired platforms.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Cost:&lt;/strong&gt; Does the cost of the engine fit your budget?&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Support:&lt;/strong&gt; Does the engine have an active community and good documentation? Will it continue to be supported for as long as you need it to be?&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Current skills/experience:&lt;/strong&gt; What skills and experience do you currently have? For instance, if you haven’t done any coding before, it would probably be a good idea to choose a game engine that doesn’t expect you to write code. Or if you do have coding experience, it might be a good idea to choose an engine that supports a programming language that you already know or is similar to one you know.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Future considerations:&lt;/strong&gt; If you aspire to get a job in the game industry, it might be a good idea to find out what tools are being used in the kinds of places you’d like to work, and develop your skills in those tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;some-popular-options&quot;&gt;Some popular options&lt;/h2&gt;

&lt;p&gt;Below, I’ve listed and summarized some popular options for game engines. This is by no means an exhaustive list - there are tons of engines out there! However, I’ve tried to include some of the most popular options, and also to include options for a variety of needs.&lt;/p&gt;

&lt;p&gt;Below the description of each engine, I also show some examples of well-known, successful, or impressive games made with that engine.&lt;/p&gt;

&lt;h3 id=&quot;unity&quot;&gt;Unity&lt;/h3&gt;

&lt;p&gt;Unity is one of the most popular game engines out there, and it is especially popular for making indie games. It’s very versatile in its ability to make different types of games, though it does have a bit of a higher learning curve than some other engines. It also has an extensive asset store (with things like tools, scripts, and graphics you can buy), which can be helpful if you’re just starting out or if you want to go the route of using pre-made assets to cut down on development time.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Runs in:&lt;/strong&gt; Windows, Mac, experimental Linux support&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Target platforms:&lt;/strong&gt; Desktop, mobile, consoles, VR, web&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Scripting languages:&lt;/strong&gt; C#&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;2D/3D support:&lt;/strong&gt; Both&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Cost:&lt;/strong&gt; Free if revenue/funding less than $100K in the past year, monthly subscription otherwise&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href=&quot;https://unity.com&quot;&gt;https://unity.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/images/choosing-a-game-engine/unity-games.png&quot; alt=&quot;Some games made with Unity: Hollow Knight, Outer Wilds, Ori and the Blind Forest, Untitled Goose Game, and Firewatch&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;unreal-engine&quot;&gt;Unreal Engine&lt;/h3&gt;

&lt;p&gt;Unreal Engine is another one of the most popular engines out there, and it is known for being capable of advanced 3D graphics. It is more focused toward experienced developers, and a lot of AAA games are made with it. However, it does also have a visual scripting language designed for beginners. It also has an extensive marketplace similar to Unity’s asset store.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Runs in:&lt;/strong&gt; Windows, Mac, Linux&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Target platforms:&lt;/strong&gt; Desktop, mobile, consoles, VR, web&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Scripting languages:&lt;/strong&gt; C++, visual scripting&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;2D/3D support:&lt;/strong&gt; 3D, some 2D&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Cost:&lt;/strong&gt; Free if game revenue less than $3K per quarter, 5% royalties otherwise&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href=&quot;https://www.unrealengine.com&quot;&gt;https://www.unrealengine.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/images/choosing-a-game-engine/unreal-engine-games.png&quot; alt=&quot;Some games made with Unreal Engine: PlayerUnknown's Battlegrounds, What Remains of Edith Finch, Hellblade: Senua's Sacrifice, Abzu, and The Outer Worlds&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;game-maker-studio&quot;&gt;Game Maker Studio&lt;/h3&gt;

&lt;p&gt;GameMaker Studio is a popular game engine primarily for creating 2D games. It focuses on being easy to learn and use, and it has enabled the creation of several very successful games.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Runs in:&lt;/strong&gt; Windows, Mac&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Target platforms:&lt;/strong&gt; Desktop, mobile, consoles, web&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Scripting languages:&lt;/strong&gt; Game Maker Language, JavaScript, visual scripting&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;2D/3D support:&lt;/strong&gt; 2D, some 3D&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Cost:&lt;/strong&gt; Yearly or one-time fee, depending on the license (has 30 day free trial)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href=&quot;https://www.yoyogames.com/gamemaker&quot;&gt;https://www.yoyogames.com/gamemaker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/images/choosing-a-game-engine/game-maker-studio-games.png&quot; alt=&quot;Some games made with Game Maker Studio: Undertale, Hyper Light Drifter, Nidhogg 2, Hotline Miami, and Spelunky&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;godot&quot;&gt;Godot&lt;/h3&gt;

&lt;p&gt;Godot is a free and open source engine that has become very popular in recent years. It is said to be more lightweight than many other engines, and it has an active community. There aren’t really any well-known games that have been made with Godot yet, since it hasn’t been around for as long as some of the other engines, but it’s definitely worth a look.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Runs in:&lt;/strong&gt; Windows, Mac, Linux&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Target platforms:&lt;/strong&gt; Desktop, mobile, VR, web&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Scripting languages:&lt;/strong&gt; GDScript (similar to Python), C#, C++, visual scripting&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;2D/3D support:&lt;/strong&gt; Both&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Cost:&lt;/strong&gt; Free and open source&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href=&quot;https://godotengine.org&quot;&gt;https://godotengine.org&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/images/choosing-a-game-engine/godot-games.png&quot; alt=&quot;Some games made with Godot: 1000 Days to Escape, Resolutiion, Seek Etyliv, Endhall, and City Game Studio&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;construct&quot;&gt;Construct&lt;/h3&gt;

&lt;p&gt;Construct 3 is a browser-based game engine geared toward people who are new to programming and making games. It enables people to build prototypes and small games very quickly, but is less suited toward larger projects.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Runs in:&lt;/strong&gt; Web browser&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Target platforms:&lt;/strong&gt; Mobile, web&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Scripting languages:&lt;/strong&gt; JavaScript, visual scripting&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;2D/3D support:&lt;/strong&gt; 2D&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Cost:&lt;/strong&gt; Monthly fee (has limited feature free trial version)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href=&quot;https://www.construct.net&quot;&gt;https://www.construct.net&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/images/choosing-a-game-engine/construct-games.png&quot; alt=&quot;Some games made with Construct: Iconoclasts, Cyber Shadow, The Next Penelope, Insanity's Blade, and Airscape: The Fall of Gravity&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;genre-specific-engines&quot;&gt;Genre-specific engines&lt;/h3&gt;

&lt;p&gt;In addition to general-purpose game engines, like the ones listed above, there are also engines that are designed specifically for making games of a particular genre. Using a genre-specific engine can be a good choice if your game fits closely with what the engine has in mind - it can save you a lot of time and effort, since it’s specifically designed for that. However, keep in mind that if your game or aspects of your game don’t fit within the expectations of the engine, it could end up being harder (or even impossible) to make your game work the way you want it to.&lt;/p&gt;

&lt;p&gt;Here are some examples of genre-specific engines:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://twinery.org/&quot;&gt;Twine&lt;/a&gt; &lt;em&gt;(text-based interactive fiction)&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.visionaire-studio.net/&quot;&gt;Visionaire Studio&lt;/a&gt; &lt;em&gt;(adventure games)&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.puzzlescript.net/&quot;&gt;PuzzleScript&lt;/a&gt; &lt;em&gt;(puzzle games)&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.rpgmakerweb.com/&quot;&gt;RPG Maker&lt;/a&gt; &lt;em&gt;(RPGs)&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.renpy.org/&quot;&gt;RenPy&lt;/a&gt; &lt;em&gt;(visual novels)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/images/choosing-a-game-engine/genre-specific-engine-games.png&quot; alt=&quot;Some games made with genre-specific engines: Depression Quest, Deponia, Paradigm, To the Moon, and Doki Doki Literature Club&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;make-your-own-engine&quot;&gt;Make your own engine&lt;/h3&gt;

&lt;p&gt;Of course, there is always the option of creating your own game engine, rather than using an existing one. This gives you as much flexibility as you could ever wish for, but it obviously takes a lot more work and time.&lt;/p&gt;

&lt;p&gt;I would only recommend taking this approach if:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;You are experienced in making games.&lt;/li&gt;
  &lt;li&gt;You will enjoy the process of making your own game engine and don’t mind taking a lot more time to finish your game.&lt;/li&gt;
  &lt;li&gt;Available game engines don’t fit your needs for some reason (in my opinion, this is unlikely).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One situation where making your own engine could be a good investment is if you can make something that fits your needs and your process really well, and if you can use it for multiple projects. Again, keep in mind that pulling this off is unlikely to happen without the insight and skills learned from previous experience in making games.&lt;/p&gt;

            &lt;p&gt;&amp;#169; 
            2020
             &lt;a href=&quot;https://colececil.dev&quot;&gt;Cole Cecil&lt;/a&gt;. All rights reserved.&lt;/p&gt;
        </description>
        <pubDate>Thu, 16 Apr 2020 20:32:00 -0500</pubDate>
        <link>https://colececil.dev/blog/2020/choosing-a-game-engine/</link>
        <guid isPermaLink="true">https://colececil.dev/blog/2020/choosing-a-game-engine/</guid>
        
        
      </item>
    
      <item>
        <title>Bludgeon Update: Color Palette Refinement</title>
        <description>
            &lt;p&gt;One of my recent changes to &lt;a href=&quot;https://meticulousmonster.com/bludgeon/&quot;&gt;Bludgeon&lt;/a&gt; (the game I’m developing) has been to refine the color palette. Up until this point, I haven’t had a good process for choosing colors. I basically just haphazardly picked out colors I liked. I tried to reuse colors as much as possible to keep the color count down, having read multiple places that too many colors can make pixel art look sloppy. However, I didn’t really have a way to keep track of the colors in my palette, so I’m pretty sure I ended up with too many similar colors.&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;I’d been wanting to figure out a way to refine and keep track of my color palette, ideally before creating a whole lot of art for the game. So I did some research, and I came across &lt;a href=&quot;http://pixeljoint.com/forum/forum_posts.asp?TID=10695&quot;&gt;this thread on Pixel Joint&lt;/a&gt; that has a lot of interesting insights about choosing colors. I also found &lt;a href=&quot;https://www.reddit.com/r/PixelArt/comments/35v454/tutorial_creating_a_universal_color_ramp/&quot;&gt;this helpful tutorial on Reddit&lt;/a&gt;. Both of these sources introduced me to the concept of interconnected color ramps.&lt;/p&gt;

&lt;p&gt;If you’re not familiar, a color ramp is a set of colors that can be used together in an object to show light and shadow - basically, a set of related colors organized from darkest to lightest. I had previously been creating independent color ramps for each hue I used. This works, but it doesn’t do much to minimize the number of colors used. When the color ramps overlap each other and share colors, it helps reduce the number of colors and makes the whole palette more cohesive. Referring to the examples in the links above, I created this color palette for Bludgeon:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/color-palette-refinement/palette.png&quot; alt=&quot;Bludgeon color palette&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In this image, the different color ramps are illustrated by the lines connecting the colors. You can see that all of the color ramps merge together at the dark end and the light end. Also, some of them intersect - for example, the pinks and blues, the blues and greens, and the browns and oranges. I found that I really like this way of visualizing a color palette. It helps me see how all the colors are related, and it shows me color options that I’d overlook if I was just looking at a grid of colors.&lt;/p&gt;

&lt;p&gt;The process I used to create this palette went as follows:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;I chose several of my favorite colors from the Bludgeon artwork I’d created so far.&lt;/li&gt;
  &lt;li&gt;I tried to figure out ways in which these colors related to each other. I mostly did this by dragging color splotches around in my image editor until I got them organized in a way that looked right.&lt;/li&gt;
  &lt;li&gt;I filled in the gaps between the colors. I often did this by interpolating between the colors on either side, and I sometimes did it just by picking other colors I liked that seemed to fit.&lt;/li&gt;
  &lt;li&gt;I made a lot of small tweaks to the color palette, mostly based on whether I felt I had all the colors I needed. This part involved a lot of trial and error. I didn’t really have a specific color count in mind - I just tried to keep it to a minimum while still feeling like I had enough colors for everything.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once I was happy with the color palette I created, I applied it to my existing artwork. I think it turned out pretty good - it seems to have helped a lot with making the artwork look more cohesive and adding some needed contrast. Here are some comparisons between the old versions and the new versions:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/color-palette-refinement/title-screen.png&quot; alt=&quot;Old title screen compared with title screen&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/color-palette-refinement/dungeon.png&quot; alt=&quot;Old dungeon compared with new dungeon&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/color-palette-refinement/world-map.png&quot; alt=&quot;Old world map compared with new world map&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You might notice that the bottommost image (the world map) doesn’t have too many differences between the old version and the new version. This is because I was already pretty happy with most its colors, so I made sure to put a lot of them in the final color palette.&lt;/p&gt;

&lt;p&gt;I’m sure I still have a lot to learn when it comes to choosing colors, but I feel like this experiment went really well. I think I picked a good point in time to go through this refinement process. I had enough existing art to be able to figure out what sorts of colors I wanted, but I didn’t have so much art done that it would be a ton of work to update the colors using the new palette. If you have any thoughts, please leave a comment below. I hope this post is helpful to others who are still learning, but I’d also love to hear any insight from people who have more experience with this stuff.&lt;/p&gt;

            &lt;p&gt;&amp;#169; 
            2019
             &lt;a href=&quot;https://colececil.dev&quot;&gt;Cole Cecil&lt;/a&gt;. All rights reserved.&lt;/p&gt;
        </description>
        <pubDate>Sat, 09 Nov 2019 00:00:00 -0600</pubDate>
        <link>https://colececil.dev/blog/2019/color-palette-refinement/</link>
        <guid isPermaLink="true">https://colececil.dev/blog/2019/color-palette-refinement/</guid>
        
        
      </item>
    
      <item>
        <title>Introducing Meticulous Monster</title>
        <description>
            &lt;p&gt;I just wanted to post a quick update to introduce &lt;a href=&quot;https://meticulousmonster.com/&quot; target=&quot;_blank&quot;&gt;Meticulous Monster&lt;/a&gt; – this is a company I created for the purpose of releasing Bludgeon once it’s ready, along with any future games I decide to make. I actually created it early last year, but I’m announcing it now because I finally got &lt;a href=&quot;https://meticulousmonster.com/&quot; target=&quot;_blank&quot;&gt;a website&lt;/a&gt; up for it!&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;In other news, Bludgeon is still coming along nicely – and it has &lt;a href=&quot;https://meticulousmonster.com/bludgeon&quot; target=&quot;_blank&quot;&gt;its own web page&lt;/a&gt; now! I had the opportunity to demo it at &lt;a href=&quot;https://epx.org.uiowa.edu/events/epx-con-animation-and-gaming-conference/&quot; target=&quot;_blank&quot;&gt;EPX Con&lt;/a&gt;, an animation and gaming conference, yesterday. As always, I had a great time meeting people and seeing them enjoy the game.&lt;/p&gt;

            &lt;p&gt;&amp;#169; 
            2018
             &lt;a href=&quot;https://colececil.dev&quot;&gt;Cole Cecil&lt;/a&gt;. All rights reserved.&lt;/p&gt;
        </description>
        <pubDate>Sun, 15 Apr 2018 22:00:00 -0500</pubDate>
        <link>https://colececil.dev/blog/2018/meticulous-monster/</link>
        <guid isPermaLink="true">https://colececil.dev/blog/2018/meticulous-monster/</guid>
        
        
      </item>
    
      <item>
        <title>Learning to Write Music</title>
        <description>
            &lt;p&gt;I’ve been interested in the idea of composing music for quite a while, and being able to write music was the last thing I wasn’t sure I’d be able to do in order to make a video game on my own. Over the summer, I finally decided to give it a try and see how it worked out. I wasn’t sure if I could do it, but I figured it couldn’t hurt to try.&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;After my first attempt at writing music, I was happy to find out I was able to do it! It’s not as hard as I thought it might be, but it’s still pretty tough sometimes. In my first attempt at writing a song, I wasn’t really trying to write any particular type of song, and I wasn’t writing the song for any particular purpose other than just to see if I &lt;em&gt;could&lt;/em&gt; write a song. It turned out to have an ambient/sci-fi feel to it.&lt;/p&gt;

&lt;div class=&quot;song&quot;&gt;
    &lt;iframe width=&quot;100%&quot; height=&quot;166&quot; scrolling=&quot;no&quot; frameborder=&quot;no&quot; src=&quot;https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/323167321&amp;amp;color=%23ff5500&amp;amp;auto_play=false&amp;amp;hide_related=true&amp;amp;show_comments=false&amp;amp;show_user=true&amp;amp;show_reposts=false&amp;amp;show_teaser=false&amp;amp;show_playcount=false&quot;&gt;
    &lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;I didn’t learn much about music growing up, so my first step was to learn more about how music works. Several years ago, I read an introductory book on music theory. I believe it was &lt;a href=&quot;https://www.goodreads.com/book/show/6486885-music-theory-for-computer-musicians&quot;&gt;Music Theory for Computer Musicians&lt;/a&gt;, if I remember correctly. It helped me a lot in understanding how music works and the building blocks that it’s made of. I think this is around the time when I started thinking of trying to write music, but I didn’t actually get to trying it until recently. In the meantime, I just tried to think about music more as I listened to it, and I tried to figure out what makes good music good.&lt;/p&gt;

&lt;p&gt;Eventually, I came across &lt;a href=&quot;https://learningmusic.ableton.com&quot;&gt;a free music making tutorial by Ableton&lt;/a&gt;. I went through it and found it to be a really good interactive browser-based tutorial. It made composing music seem much more approachable to me, and it helped me to finally be motivated enough to try it. So far, I’ve been using a free DAW (digital audio workstation) called &lt;a href=&quot;https://lmms.io&quot;&gt;LMMS&lt;/a&gt; to compose music.&lt;/p&gt;

&lt;p&gt;After I successfully wrote my first song, I decided to try writing a main menu theme for Bludgeon, the game I’m making. I was aiming for a medieval-sounding song, and I also wanted it to feel rough and warlike (going for the kind of feel the Skyrim theme song has). I’m really happy with how it turned out.&lt;/p&gt;

&lt;div class=&quot;song&quot;&gt;
    &lt;iframe width=&quot;100%&quot; height=&quot;166&quot; scrolling=&quot;no&quot; frameborder=&quot;no&quot; src=&quot;https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/333500214&amp;amp;color=%23ff5500&amp;amp;auto_play=false&amp;amp;hide_related=true&amp;amp;show_comments=false&amp;amp;show_user=true&amp;amp;show_reposts=false&amp;amp;show_teaser=false&amp;amp;show_playcount=false&quot;&gt;
    &lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;For this song, I actually came up with part of the melody in my head while doing the dishes one day. For most of the songs I’ve written so far, I didn’t come up with a melody ahead of time, but kind of just came across one by putting random-ish notes in the DAW, and then adjusting them until I had something that sounded good.&lt;/p&gt;

&lt;p&gt;After this, I wanted to write a different song that plays during fights in Bludgeon. Being inspired by how all the songs in the Undertale soundtrack are tied together so well with a few musical themes, I wanted to figure out how to do the same thing in Bludgeon. So I tried copying part of the Bludgeon theme song over and switching some notes around, and I used that as a starting point for this song. I also wanted this song to have more energy since it will be playing during battles, so I started out with a more energetic-sounding drum beat. As I keep writing songs for Bludgeon, I’m interested in seeing if I’m able to keep them sounding different enough to be interesting but also similar enough to sound like they belong together.&lt;/p&gt;

&lt;div class=&quot;song&quot;&gt;
    &lt;iframe width=&quot;100%&quot; height=&quot;166&quot; scrolling=&quot;no&quot; frameborder=&quot;no&quot; src=&quot;https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/343905664&amp;amp;color=%23ff5500&amp;amp;auto_play=false&amp;amp;hide_related=true&amp;amp;show_comments=false&amp;amp;show_user=true&amp;amp;show_reposts=false&amp;amp;show_teaser=false&amp;amp;show_playcount=false&quot;&gt;
    &lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;This holiday season, I had the idea of trying to compose a seasonal/Christmas-type song. This was partly because I thought it would be a fun time of reflection/relaxation over the holidays, and partly because I was annoyed by all the inane Christmas songs I kept hearing over the radio and at stores (I wanted to see if I could write a Christmas song that sounded the way I wish more Christmas songs sounded). The way the sound of my song turned out and the timing worked out, it ended up being a song about the winter solstice. I used &lt;a href=&quot;https://www.youtube.com/watch?v=wqmhdg4PsNg&quot;&gt;Schala’s theme from Chrono Trigger&lt;/a&gt; as inspiration for this song, and I was probably also inspired by Carol of the Bells and Dance of the Sugar Plum Fairy, as those are some of my favorite holiday songs. I’m really happy with the way this turned out, and I think it’s cool that I have a new way of expressing myself now that I can write music.&lt;/p&gt;

&lt;div class=&quot;song&quot;&gt;
    &lt;iframe width=&quot;100%&quot; height=&quot;166&quot; scrolling=&quot;no&quot; frameborder=&quot;no&quot; src=&quot;https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/372724247&amp;amp;color=%23ff5500&amp;amp;auto_play=false&amp;amp;hide_related=true&amp;amp;show_comments=false&amp;amp;show_user=true&amp;amp;show_reposts=false&amp;amp;show_teaser=false&amp;amp;show_playcount=false&quot;&gt;
    &lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;To wrap up, here are some of the things I’ve learned so far while learning to write music:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Music sounds good when it repeats itself enough for the mind to latch onto, but not when it’s so repetitive that it’s boring or annoying.&lt;/li&gt;
  &lt;li&gt;Music sounds good when it has a lot of things going on at the same time that all go together. It seems to me that a good way of doing this is starting a song out simple and then gradually adding more and more elements to it - I have a hunch that hearing a song that works this way gives the mind a sense of discovery. It also seems good to accentuate different components of a song at different times to help the mind take everything in, since it can be hard to focus on listening to several parts at once.&lt;/li&gt;
  &lt;li&gt;When writing a song, just like creating anything else, you won’t have the end product all thought out at the start of the project. You start with a simple idea and keep adding to it and iterating on it until you’re happy with it. In fact, you don’t even necessarily have to have an idea to start with - you can just start throwing out random notes until something starts to sound good, and then keep going in that direction.&lt;/li&gt;
  &lt;li&gt;You never know if you’ll be able to do something until you try. I always kind of assumed I wouldn’t be able to write music, but I only found out I could after I tried it. I’m still starting out and don’t always know what I’m doing, but I know I have a decent start and can keep building on it.&lt;/li&gt;
&lt;/ul&gt;

            &lt;p&gt;&amp;#169; 
            2017
             &lt;a href=&quot;https://colececil.dev&quot;&gt;Cole Cecil&lt;/a&gt;. All rights reserved.&lt;/p&gt;
        </description>
        <pubDate>Sat, 30 Dec 2017 20:50:00 -0600</pubDate>
        <link>https://colececil.dev/blog/2017/learning-to-write-music/</link>
        <guid isPermaLink="true">https://colececil.dev/blog/2017/learning-to-write-music/</guid>
        
        
      </item>
    
      <item>
        <title>Bludgeon Update: Building a Dungeon</title>
        <description>
            &lt;p&gt;I’ve recently been working on updating the background art for Bludgeon. For quite a while, I’ve been using a very boring, plain, brick wall as the background during combat (you can see what it used to look like in &lt;a href=&quot;https://youtu.be/NweOQPDtkfE&quot;&gt;this video&lt;/a&gt;). This was fine for initial versions of the game, but I really wanted to make something nicer. I decided to start out by making a dungeon, though I’m planning to eventually make several different levels to fight in.&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;My first step was to brainstorm about ideas of what would be in a dungeon, specifically a dungeon in the world of Bludgeon. Since the gameplay of Bludgeon is heavily focused on birds, I thought of making the game world very bird-centric as well. Because of this, I tried to think of how birds or bird-like figures could be displayed in a dungeon background. The initial idea I came up with was to have stone pillars between cells that had bird-like feet at the bottom. I also wanted to put some bird statues in the dungeon. With that in mind, I spend some time drawing and came up with this concept art:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/building-a-dungeon/dungeon-concept-art.jpg&quot; alt=&quot;Dungeon concept art&quot; /&gt;&lt;/p&gt;

&lt;p&gt;While I was doing a Google image search to find sources of inspiration for bird statues, I came across &lt;a href=&quot;https://www.huffingtonpost.com/2013/10/03/calcified-animals_n_4032659.html&quot;&gt;these cool/creepy pictures&lt;/a&gt; of animals that had been calcified in a lake with high soda and salt content. I ended up basing my statue off of the picture of the dove. My concept art had turned out creepier-looking than I had anticipated, but I decided I liked it. While I was drawing pictures of a creepy dungeon, my wife, Kezia, was drawing beautiful pictures like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/building-a-dungeon/eastern-redbud.png&quot; alt=&quot;Eastern redbud&quot; /&gt;&lt;/p&gt;

&lt;p&gt;After coming up with some concept art that I liked, my next step was to draw a rough pixel art version of the background, to get the main structure and layout in place. In addition to the ideas from my concept art, I also added chains, beak-like torches, pictures of bird faces along the walls, stairways, and an iron railing. If I remember correctly, the beak-like torches were Kezia’s idea. I like them – they kind of remind me of the &lt;a href=&quot;https://www.mariowiki.com/Mask_Gate&quot;&gt;mask gates from Mario 2&lt;/a&gt;. Also, while drawing this rough draft, I had to find &lt;a href=&quot;https://www.studentartguide.com/articles/one-point-perspective-drawing&quot;&gt;an article to give me a refresher on how to draw in one-point perspective&lt;/a&gt; – it had been a while since I’d done that!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/building-a-dungeon/dungeon-draft.png&quot; alt=&quot;Dungeon rough draft&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now that I had the basic structure for my background, it was time to fill it in with details, colors, and shading (I’m still trying to get better at the shading part). I decided to add bricks only in some places to give the impression of texture on the wall while keeping it clean and simple. I also made the spikes more irregular to make them more visually interesting and to make them stand out more (some people previously had trouble noticing the spikes during playtesting). I also animated the flames on the torches, though you can’t tell that from this static image. I might tweak the background a bit later to clean some stuff up or to add more detail (perhaps adding irregularities to make the dungeon look more aged), but I’m pretty happy with how it turned out.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/building-a-dungeon/completed-dungeon.png&quot; alt=&quot;Dungeon final version&quot; /&gt;&lt;/p&gt;

            &lt;p&gt;&amp;#169; 
            2017
             &lt;a href=&quot;https://colececil.dev&quot;&gt;Cole Cecil&lt;/a&gt;. All rights reserved.&lt;/p&gt;
        </description>
        <pubDate>Tue, 21 Nov 2017 19:35:00 -0600</pubDate>
        <link>https://colececil.dev/blog/2017/building-a-dungeon/</link>
        <guid isPermaLink="true">https://colececil.dev/blog/2017/building-a-dungeon/</guid>
        
        
      </item>
    
      <item>
        <title>Scaling Pixel Art Without Destroying It</title>
        <description>
            &lt;p&gt;When I started using pixel art in game development, I assumed that it would easily work at any screen resolution, since modern screen resolutions are much higher than the native resolution of a pixel art game. However, I quickly came to realize that this is not the case – it’s actually quite tricky to get pixel art to look correct when scaling it up by an arbitrary amount. It works fine when it’s scaled by an integer multiple (2x, 3x, etc.), but there are issues when scaling by a non-integer multiple. This causes problems because the texture pixels (in other words, the pixels in the artwork, also known as &lt;em&gt;texels&lt;/em&gt;) get scaled to fractional pixels on the screen. Because screens can’t display fractional pixels, the rendering has to either round to the nearest whole pixel, or it has to blend different texels into the same screen pixel. Choosing one of the two standard texture scaling modes will end up either making some of the pixels in the pixel art bigger than others or making them all blurry. Neither of these options look great, as seen in the example below.&lt;/p&gt;

&lt;!--more--&gt;

&lt;figure class=&quot;nonresponsive-figure&quot; style=&quot;max-width: 422px;&quot;&gt;
    &lt;img src=&quot;/images/scaling-pixel-art-without-destroying-it/pixel-shader-example.gif&quot; alt=&quot;Example showing pixel art scaling issues&quot; /&gt;
    &lt;figcaption&gt;
        &lt;table width=&quot;422px&quot;&gt;
            &lt;tr&gt;
                &lt;td width=&quot;33%&quot; class=&quot;text-center&quot;&gt;Distorted&lt;/td&gt;
                &lt;td width=&quot;33%&quot; class=&quot;text-center&quot;&gt;Good&lt;/td&gt;
                &lt;td width=&quot;33%&quot; class=&quot;text-center&quot;&gt;Blurry&lt;/td&gt;
            &lt;/tr&gt;
        &lt;/table&gt;
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This led me to do a lot of googling to try to find a solution to the problem. Most resources I found claimed that you have to stick with scaling by integer multiples if you want it to look good, but I knew I’d played plenty of pixel art games that could scale to my screen size and look just fine. So I kept searching, and I finally came across a great solution using a shader (this is the “Good” version in the example image above), described at a blog called &lt;a href=&quot;https://csantosbh.wordpress.com/2014/01/25/manual-texture-filtering-for-pixelated-games-in-webgl/&quot;&gt;A Personal Wonderland&lt;/a&gt;. The author does a really nice job of explaining and illustrating the solution in a very mathematical way. It still took me a while to understand how it works, but I figured it out and was able to implement it in a Unity shader. Since it was so hard to find information about how to solve this problem, I decided to write this tutorial about scaling pixel art, explaining it in a way that makes more sense to my brain (and hopefully others’), and also giving an example of the solution in Unity.&lt;/p&gt;

&lt;h2 id=&quot;standard-scaling-approaches&quot;&gt;Standard Scaling Approaches&lt;/h2&gt;

&lt;p&gt;The pixel art scaling shader is sort of a mix between the two standard scaling approaches: nearest neighbor filtering and bilinear filtering. Since fully understanding how the shader works depends on understanding these two filtering approaches, I’m going to first spend some time explaining them.&lt;/p&gt;

&lt;h3 id=&quot;nearest-neighbor-filtering&quot;&gt;Nearest Neighbor Filtering&lt;/h3&gt;

&lt;p&gt;Nearest neighbor filtering is the simplest way to scale an image. With this method, you’re basically just taking the pixels from the texture and making them bigger to form the scaled image. This is done by giving a pixel in the scaled image the same color as the nearest texel.&lt;/p&gt;

&lt;p&gt;The algorithm for performing nearest neighbor filtering is illustrated in the diagram below. First, the texture is taken, represented by a point at the center of each of the texels. This is then stretched to the size of the final scaled image and overlaid onto it. Each pixel in the scaled image is also represented by a point in its center. Next, for each point in the scaled image, the nearest point in the texture is found. The pixel represented by the scaled image point takes the same color as the texel represented by the texture point.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/scaling-pixel-art-without-destroying-it/nearest-neighbor-1.png&quot; alt=&quot;Diagram showing nearest neighbor filtering&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the diagram above, the scaled image turns out perfectly, since it’s an integer multiple of the texture (in this case, 2x, since the texture is 3x3 and the scaled image is 6x6). However, if the scaled image is not an integer multiple of the texture, the final product won’t turn out quite right. See the diagram below for an example of this. Here, the texture is still 3x3, but the scaled image is 7x7. In the scaled image, you can see that some of the texels show up in different sizes and shapes, since it’s slightly larger than an integer multiple of the texture (2.333x).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/scaling-pixel-art-without-destroying-it/nearest-neighbor-2.png&quot; alt=&quot;Diagram showing nearest neighbor filtering&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;bilinear-filtering&quot;&gt;Bilinear Filtering&lt;/h3&gt;

&lt;p&gt;With bilinear filtering, instead of making the texels bigger to form the scaled image, you’re blending the colors of the texels in the space between them. The term &lt;em&gt;bilinear&lt;/em&gt; refers to the blending of colors in both the x and y directions.&lt;/p&gt;

&lt;p&gt;As with nearest neighbor filtering, the bilinear filtering algorithm starts out by taking the set of points representing the texels, stretching it to the size of the scaled image, and overlaying it onto the set of points representing the pixels in the scaled image. Then, for each point in the scaled image, the four surrounding texel points are found. The colors of both pairs of texel points are first interpolated in one direction (either the x or y direction), so that the two new points are collinear with the point of the pixel being looked at. Finally, the color of the pixel is determined by interpolating the colors of the two new points at the location of the pixel point. See the diagram below for an illustration of this.&lt;/p&gt;

&lt;p&gt;One other thing to note here is that some pixels around the edge might not be surrounded by four texels. The way this is generally dealt with is by creating imaginary texels past the edges of the texture with the same colors as edge texels.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/scaling-pixel-art-without-destroying-it/bilinear-1.png&quot; alt=&quot;Diagram showing bilinear filtering&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here, I scaled the same 3x3 texture to 6x6, as I did with nearest neighbor filtering. However, as you can see, bilinear filtering produces a very blurry-looking result. This is not great for pixel art, obviously. However, there is one advantage to bilinear filtering, as seen in the diagram below (scaling the 3x3 texture to 7x7, like I did with nearest neighbor filtering). Even though the texture isn’t scaled to an integer multiple, it still looks uniform, rather than having the texels show up in different sizes and shapes.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/scaling-pixel-art-without-destroying-it/bilinear-2.png&quot; alt=&quot;Diagram showing bilinear filtering&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;pixel-art-scaling-shader&quot;&gt;Pixel Art Scaling Shader&lt;/h2&gt;

&lt;p&gt;Now that we’ve gone through how nearest neighbor and bilinear filtering work, we can move on to the pixel art scaling shader. As I mentioned earlier, this shader works by combining both nearest neighbor and bilinear filtering. For the most part, the shader uses nearest neighbor filtering, as this is best suited to pixel art. However, at the borders between texels, bilinear filtering is used. This is because, if a screen pixel is situated at one of these borders, it would contain parts of more than one texel. Remember, if we were to use nearest neighbor, that pixel would have to choose the color of only one of the texels, making the pixel art look distorted. The use of bilinear filtering at the borders blends the colors of the texels that share the same pixel, making it look more natural. This will not cause a noticeable blur, like pure bilinear filtering does, since we only use it at these borders. An example is shown in the diagram below.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/scaling-pixel-art-without-destroying-it/pixel-art-shader.png&quot; alt=&quot;Diagram showing the pixel art scaling shader&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;shader-code&quot;&gt;Shader Code&lt;/h3&gt;

&lt;p&gt;Now that I’ve explained how the shader works conceptually, I’ll go through the code. Note that the code I’m showing is for Unity, but it should be relatively straightforward to translate it to something that works with another game engine or graphics library.&lt;/p&gt;

&lt;p&gt;I’ll try to explain the code pretty clearly, but if you don’t have any experience with shaders, it might be a good idea to read up on them. When I was learning how to write shaders (specifically in Unity), I found &lt;a href=&quot;https://en.wikibooks.org/wiki/Cg_Programming&quot;&gt;this Cg Programming Wikibook&lt;/a&gt; to be an extremely helpful resource. Unity also has &lt;a href=&quot;https://docs.unity3d.com/Manual/SL-VertexFragmentShaderExamples.html&quot;&gt;some helpful examples in their documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id=&quot;variables-and-structs&quot;&gt;Variables and Structs&lt;/h4&gt;

&lt;p&gt;To start, here are the variables and &lt;code class=&quot;highlighter-rouge&quot;&gt;structs&lt;/code&gt; defined for the shader:&lt;/p&gt;

&lt;div class=&quot;language-glsl highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kt&quot;&gt;sampler2D&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_MainTex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;float4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_MainTex_TexelSize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;texelsPerPixel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vertexInput&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;float4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vertex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;POSITION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fixed4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;COLOR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;float2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;textureCoords&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TEXCOORD0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vertexOutput&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;float4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vertex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SV_POSITION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fixed4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;COLOR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;float2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;textureCoords&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TEXCOORD0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;_MainTex&lt;/code&gt; is the texture to draw, which is passed into the shader through the &lt;code class=&quot;highlighter-rouge&quot;&gt;Properties&lt;/code&gt; block. &lt;code class=&quot;highlighter-rouge&quot;&gt;_MainTex_TexelSize&lt;/code&gt; represents the size in texels of the main texture. This is a predefined property set up by Unity, as described &lt;a href=&quot;https://docs.unity3d.com/Manual/SL-PropertiesInPrograms.html&quot;&gt;here&lt;/a&gt;. &lt;code class=&quot;highlighter-rouge&quot;&gt;texelsPerPixel&lt;/code&gt; is a value that we will set from a Unity script using &lt;a href=&quot;https://docs.unity3d.com/ScriptReference/Shader.SetGlobalFloat.html&quot;&gt;Shader.SetGlobalFloat&lt;/a&gt;. As you can probably tell from the name, this variable represents the number of texels per screen pixel. We can calculate this value by dividing the screen width/height by the width/height of the game’s native resolution. If the aspect ratio of both the screen and the game’s native resolution are the same, you can use either the width or the height, but if the aspect ratios are different, you need to choose the dimension that doesn’t get letterboxed or pillarboxed.&lt;/p&gt;

&lt;p&gt;The two &lt;code class=&quot;highlighter-rouge&quot;&gt;structs&lt;/code&gt; defined here represent the input and output of the vertex shader. &lt;code class=&quot;highlighter-rouge&quot;&gt;vertexInput&lt;/code&gt; contains the vertex position (in local space), the vertex color (which comes from the material color set in Unity), and the texture coordinates (which represent the x and y positions of the texture that match up with the vertex). &lt;code class=&quot;highlighter-rouge&quot;&gt;vertexOutput&lt;/code&gt; contains the vertex position (in clip space), the vertex color, and the texture coordinates.&lt;/p&gt;

&lt;h4 id=&quot;vertex-shader&quot;&gt;Vertex Shader&lt;/h4&gt;

&lt;p&gt;Moving on, let’s discuss the code for the vertex shader. The vertex shader is executed for each vertex of the object the shader is rendering. Here, we’re just getting the data in the format we’ll need it in for the fragment shader.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: The code for the vector shader and fragment shader is based on logic from &lt;a href=&quot;https://csantosbh.wordpress.com/2014/01/25/manual-texture-filtering-for-pixelated-games-in-webgl/&quot;&gt;A Personal Wonderland&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;language-glsl highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;vertexOutput&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;vertexShader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertexInput&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;vertexOutput&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UNITY_MATRIX_MVP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;textureCoords&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;textureCoords&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_MainTex_TexelSize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In line 4, we convert the vertex position from local space to clip space by multiplying it by the model view projection matrix. This is a pretty standard operation to perform in vertex shaders. In line 5, we convert the texture coordinates from the range [0, 1] to the range [0, texture size]. We do this because, in the fragment shader, we’ll need to know the texture coordinates in terms of texel position. Line 6 simply passes the input vertex color to the output.&lt;/p&gt;

&lt;h4 id=&quot;fragment-shader&quot;&gt;Fragment Shader&lt;/h4&gt;

&lt;p&gt;Now to the fragment shader, which is executed for each pixel in order to calculate its color. This is where the main logic of the shader resides.&lt;/p&gt;

&lt;div class=&quot;language-glsl highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;fixed4&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fragmentShader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertexOutput&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SV_Target&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;float2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;locationWithinTexel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frac&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;textureCoords&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;float2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;interpolationAmount&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;locationWithinTexel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;texelsPerPixel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;locationWithinTexel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;texelsPerPixel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;float2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;finalTextureCoords&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;textureCoords&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;interpolationAmount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_MainTex_TexelSize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tex2D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_MainTex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;finalTextureCoords&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here’s a simplified version of the logic we’re implementing in this function:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;For the current screen pixel, find its location in relation to the nearest texels (line 3).&lt;/li&gt;
  &lt;li&gt;Using this information, determine how much (if at all) we need to interpolate between the colors of the nearest texels (lines 4-5). This is where the algorithm decides whether to use nearest neighbor or bilinear filtering for the current pixel. No interpolation means it’s using nearest neighbor filtering; interpolation means it’s using bilinear filtering.&lt;/li&gt;
  &lt;li&gt;Given the interpolation amount, calculate and return the color of the pixel (lines 6-8).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Before we get into the details, I want to talk about how we go about interpolating the color values. We’ll actually set up the textures in Unity to use bilinear filtering. This will cause the graphics card to give bilinearly interpolated color values based on the texture coordinates given to it, and we’ll use our shader to pick the interpolated color values we want by changing the texture coordinates slightly. If we don’t want to interpolate colors for a pixel, we just choose the texture coordinates at the center of the texel. Otherwise, we choose the texture coordinates according to the amount of interpolation we want.&lt;/p&gt;

&lt;p&gt;Okay, now that I’ve outlined the general logic, let’s go into more detail. Line 3 gets the fractional part of the texture coordinates. Remember that in the vertex shader, we converted the range of the texture coordinates from [0, 1] to [0, texture size], so our texture coordinates here have texels as the unit. So in getting the fractional part of the texture coordinates, we’re getting the fractional texel value where the screen pixel is located. As an example, if the texture coordinates were (34.4, 98.7), we’d be assigning the value (.4, .7) to &lt;code class=&quot;highlighter-rouge&quot;&gt;locationWithinTexel&lt;/code&gt;. A value of (.5, .5) would mean that the center of the screen pixel lies directly on the center of the texel.&lt;/p&gt;

&lt;p&gt;In lines 4-5, we’re using the &lt;code class=&quot;highlighter-rouge&quot;&gt;locationWithinTexel&lt;/code&gt; value and the &lt;code class=&quot;highlighter-rouge&quot;&gt;texelsPerPixel&lt;/code&gt; value to determine how much interpolation to use for this pixel. In most cases, we’ll end up choosing an interpolation amount of (.5, .5), which represents no interpolation, since it’s at the center of the texel. However, if the screen pixel is at a location where it partly lies within different texels, we’ll want to do some interpolation. An interpolation amount of (0, 0), (0, 1), (1, 0), or (1, 1) would represent the maximum amount of interpolation, since those points lie at the corners between texels. The first &lt;code class=&quot;highlighter-rouge&quot;&gt;clamp&lt;/code&gt; function deals with pixels that lie on one side of the texel, and the second &lt;code class=&quot;highlighter-rouge&quot;&gt;clamp&lt;/code&gt; function deals with pixels that lie on the other side of the texel. As an example, assume the scale we have is 2 screen pixels for each texel, so the &lt;code class=&quot;highlighter-rouge&quot;&gt;texelsPerPixel&lt;/code&gt; value is .5. If the x-value of &lt;code class=&quot;highlighter-rouge&quot;&gt;locationWithinTexel&lt;/code&gt; is 0, we should have the maximum amount of interpolation on the x-axis, since exactly half of the pixel would be on one texel and half would be on the other. On the other hand, if the x-value of &lt;code class=&quot;highlighter-rouge&quot;&gt;locationWithinTexel&lt;/code&gt; is .25 (equal to half of &lt;code class=&quot;highlighter-rouge&quot;&gt;texelsPerPixel&lt;/code&gt;), the left edge of the pixel would be lined up with the left edge of the texel. This means that there should be no interpolation on the x-axis, since the pixel is fully contained in the texel horizontally. As you can see, the first &lt;code class=&quot;highlighter-rouge&quot;&gt;clamp&lt;/code&gt; function is designed to give a value of 0 when &lt;code class=&quot;highlighter-rouge&quot;&gt;locationWithinTexel&lt;/code&gt; is 0 and to give a value of .5 when &lt;code class=&quot;highlighter-rouge&quot;&gt;locationWithinTexel&lt;/code&gt; is at least half of &lt;code class=&quot;highlighter-rouge&quot;&gt;texelsPerPixel&lt;/code&gt;. Anything in between is interpolated between 0 and .5. The second &lt;code class=&quot;highlighter-rouge&quot;&gt;clamp&lt;/code&gt; function is designed similarly for the other side of the texel. If you want to see more details (and graphs) of this formula, please see &lt;a href=&quot;https://csantosbh.wordpress.com/2014/01/25/manual-texture-filtering-for-pixelated-games-in-webgl/&quot;&gt;the blog post at A Personal Wonderland&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In lines 6-7, we’re calculating the texture coordinates at which to retrieve the bilinearly filtered color from the graphics card (remember, this happens because we set the texture in Unity to use bilinear filtering). First, we take the non-fractional part of the input texture coordinates. If we were to sample the texture at this location, we would get a color with maximum interpolation between texels. Next, we add the value for &lt;code class=&quot;highlighter-rouge&quot;&gt;interpolationAmount&lt;/code&gt; that we calculated in lines 4-5. If &lt;code class=&quot;highlighter-rouge&quot;&gt;interpolationAmount&lt;/code&gt; is .5 on an axis, then the color will not be interpolated on that axis. If it’s 0 or 1, then it will have maximum interpolation, with 0 being on one side of the texel and 1 being on the other. Anything between those values will cause interpolation somewhere between the minimum and maximum. At this point, our texture coordinates are still in the range [0, texture size], but we need to get them back into the range [0, 1] before we can use them to grab the color. To do so, we simply divide by the texture width and height, or &lt;code class=&quot;highlighter-rouge&quot;&gt;_MainTex_TexelSize.zw&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, on line 8, we sample the texture at the calculated texture coordinates in order to get the color value we need. We also multiply this by the input color, which will have the effect of tinting the output with the material color set in Unity. If the material color is set to white, this will have no effect, since it will be multiplying by 1.&lt;/p&gt;

&lt;h4 id=&quot;complete-shader-code&quot;&gt;Complete Shader Code&lt;/h4&gt;

&lt;p&gt;Well, that wraps up the explanation of the pixel art scaling shader! That was a lot of information, but I hope you made it this far and understand how it all works. For reference, here is the complete shader code:&lt;/p&gt;

&lt;div class=&quot;language-glsl highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;rouge-gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;rouge-code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;n&quot;&gt;Shader&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Custom/PixelArtShader&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Properties&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;_MainTex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Texture&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;SubShader&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Tags&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s&quot;&gt;&quot;Queue&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Transparent&quot;&lt;/span&gt;
      &lt;span class=&quot;s&quot;&gt;&quot;IgnoreProjector&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;True&quot;&lt;/span&gt;
      &lt;span class=&quot;s&quot;&gt;&quot;RenderType&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Transparent&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;ZWrite&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Off&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Blend&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SrcAlpha&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OneMinusSrcAlpha&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;Pass&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;CGPROGRAM&lt;/span&gt;
      &lt;span class=&quot;cp&quot;&gt;#pragma vertex vertexShader
&lt;/span&gt;      &lt;span class=&quot;cp&quot;&gt;#pragma fragment fragmentShader
&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;sampler2D&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_MainTex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;float4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_MainTex_TexelSize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;texelsPerPixel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vertexInput&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;float4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vertex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;POSITION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;fixed4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;COLOR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;float2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;textureCoords&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TEXCOORD0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vertexOutput&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;float4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vertex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SV_POSITION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;fixed4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;COLOR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;float2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;textureCoords&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TEXCOORD0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

      &lt;span class=&quot;n&quot;&gt;vertexOutput&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vertexShader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertexInput&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;vertexOutput&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kr&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UNITY_MATRIX_MVP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;kr&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;textureCoords&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;textureCoords&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_MainTex_TexelSize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kr&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

      &lt;span class=&quot;n&quot;&gt;fixed4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fragmentShader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertexOutput&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SV_Target&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;float2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;locationWithinTexel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frac&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;textureCoords&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;float2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;interpolationAmount&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;locationWithinTexel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;texelsPerPixel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;locationWithinTexel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;texelsPerPixel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;float2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;finalTextureCoords&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;textureCoords&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;interpolationAmount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_MainTex_TexelSize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tex2D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_MainTex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;finalTextureCoords&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

      &lt;span class=&quot;n&quot;&gt;ENDCG&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

            &lt;p&gt;&amp;#169; 
            2017
             &lt;a href=&quot;https://colececil.dev&quot;&gt;Cole Cecil&lt;/a&gt;. All rights reserved.&lt;/p&gt;
        </description>
        <pubDate>Sun, 30 Apr 2017 17:38:00 -0500</pubDate>
        <link>https://colececil.dev/blog/2017/scaling-pixel-art-without-destroying-it/</link>
        <guid isPermaLink="true">https://colececil.dev/blog/2017/scaling-pixel-art-without-destroying-it/</guid>
        
        
      </item>
    
      <item>
        <title>Introducing Bludgeon</title>
        <description>
            &lt;p&gt;Earlier this year, the Iowa City Game Dev group that I’m a part of hosted a month-long game jam, with the theme being “sports which could never exist”. I participated in the game jam and made a game called Bludgeon. It’s a local multiplayer game featuring two knights riding birds while wielding flails. The goal is to knock the other player into the spikes on the edge of the screen. Survival is made more difficult by the fact that you can’t control the direction your player is moving while using your weapon. Here’s a video (of me vs. the AI player) from the game jam version of the game:&lt;/p&gt;

&lt;!--more--&gt;

&lt;div class=&quot;video&quot;&gt;
    &lt;div class=&quot;embed-responsive embed-responsive-16by9&quot;&gt;
        &lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/NweOQPDtkfE?rel=0&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;
        &lt;/iframe&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;I really liked the way the initial version of the game turned out (by the way, if you want to try the initial version, you can download it &lt;a href=&quot;https://ccecil.itch.io/bludgeon-game-jam&quot;&gt;here&lt;/a&gt;). I had previously been working on a metroidvania game, but after some consideration, I decided to pursue Bludgeon right now instead. The reason is because I haven’t commercially released a game yet, and I figured it would be better to have my first game be of a more manageable scope. That way, I can get more experience under my belt before taking on a larger project.&lt;/p&gt;

&lt;h2 id=&quot;my-experience-working-on-bludgeon-so-far&quot;&gt;My Experience Working on Bludgeon so Far&lt;/h2&gt;

&lt;p&gt;I want to take some time here to talk about my experience working on Bludgeon so far: what approaches I’ve taken, what I’ve learned, what’s been successful, etc.&lt;/p&gt;

&lt;h3 id=&quot;the-game-jam&quot;&gt;The Game Jam&lt;/h3&gt;

&lt;p&gt;Before the game jam started, there were a few different possibilities for the theme, and I started brainstorming to come up with ideas for them. For the “sports which could never exist” theme that ended up getting chosen, I was trying to think more along the lines of combat sports, since I’m not really into typical sports all that much. I then started thinking about &lt;a href=&quot;https://en.wikipedia.org/wiki/Joust_(video_game)&quot;&gt;Joust&lt;/a&gt;, a fun arcade game I’d played for the first time somewhat recently. I wanted to make a game that took some of the control elements that make playing Joust fun, but make it into a completely different game. I didn’t just want to make a rip-off of Joust, but more just something inspired by it. I hope I’ve succeeded in doing that; I think I have, as I believe the gameplay is totally different (though many people have immediately recognized it as being similar to Joust).&lt;/p&gt;

&lt;p&gt;After the game jam started, I opened up &lt;a href=&quot;https://unity3d.com/&quot;&gt;Unity&lt;/a&gt; (the game engine I’m using to make Bludgeon) and got to work. I’d had the idea to give the players flails as weapons, thinking that might make for some fun controls and combat situations. So my first task was to figure out how to get flail physics working. I won’t go into the details too much here, but it involved using Unity’s distance joints for each of the chain links and the ball at the end.&lt;/p&gt;

&lt;p&gt;Having the basic physics and controls working a couple weeks into the game jam, I decided I’d better start working on some artwork real soon (at this point the player was represented by a red square, and the flail was represented by yellow squares and a big yellow ball). This is where I learned one of my main lessons of the game jam: artwork takes quite a long time, especially if you’re not super experienced at it (though I can’t say I have the experience of being super experienced at it, so I wouldn’t know for sure whether that would make me faster at it). Fortunately, I’d been practicing pixel art via &lt;a href=&quot;https://twitter.com/Pixel_Dailies&quot;&gt;Pixel Dailies&lt;/a&gt;, so I’m at least better at it than I used to be (but I still have quite a ways to go… look at that background). I am pretty happy with the way the characters turned out, though. Anyway, I spent about half of the game jam working on the artwork.&lt;/p&gt;

&lt;p&gt;After I got some artwork out, I spent a decent amount of time tweaking stuff and trying to balance the gameplay. This was the other major lesson I learned: balancing gameplay is really hard! It turns out that when you tweak one thing, it ends up affecting lots of other things. So you have to tweak a whole bunch of things at once, and, with a lot of testing, hope that it works out well. One area where I think I was successful here was in taking a risk/reward approach in designing the gameplay. The bigger the reward you want to get, the bigger the risk you have to take. Here are some examples of this in the gameplay:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;While you are using your flail, you can no longer control which direction your character is moving, because the directional controls double as the controls for swinging the flail.&lt;/li&gt;
  &lt;li&gt;While you are holding your flail, you are weighed down, and you get less of a boost when your bird flaps its wings.&lt;/li&gt;
  &lt;li&gt;If you keep your flail out for long enough, it gets charged up and becomes more powerful (i.e., more knockback).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the end of the game jam, I was pretty happy with what I’d been able to create in a month (please note, I spent almost all of my free time during that month working on the game). I wasn’t 100% sure whether I wanted to continue working on Bludgeon, though; I thought it was kind of fun, but maybe not fun enough.&lt;/p&gt;

&lt;h3 id=&quot;post-game-jam&quot;&gt;Post Game Jam&lt;/h3&gt;

&lt;p&gt;After the game jam, I decided to take a break for a bit and play Dark Souls 2… and it turned into a very long break. And I still haven’t finished Dark Souls 2 (it’s so long!). But I did start working on Bludgeon again recently. I decided to try to change the way the controls work, because I thought the game jam version of the game didn’t feel tight enough. It seemed that players would spend most of their time flying past each other rather than engaging in meaningful combat, because it was just too hard to control.&lt;/p&gt;

&lt;p&gt;Previously, you had to use the controller’s d-pad to control the player’s movement and to swing the flail. Additionally, when swinging the flail, the direction you pressed would just apply force to the flail in that direction. I decided to work on improving the flail controls. The first thing I did was to switch from using the d-pad to using the analog stick. A friend had pointed out to me that this might work better, given that you are swinging something around in a circle. That did feel better, so I then moved on to making the flail controls more precise. Instead of just applying force in the direction of the input, I changed it so that the flail would reflect the position of the analog stick. For instance, if you hold up on the analog stick, the flail will stay above the player. If you then move the analog stick to the bottom-right, the ball will move to the bottom-right of the player and stay there as long as that’s where the analog stick is. This made the flail movement less realistic, but it made the game a lot more fun by providing better controls (my belief is that if you have to sacrifice realism for fun in games, it’s pretty much always worth it).&lt;/p&gt;

&lt;p&gt;The tighter controls ended up allowing players to spend more time engaging in meaningful combat. The extra precision also allows players to use their flails to block attacks, adding another interesting dimension to the gameplay.&lt;/p&gt;

&lt;h3 id=&quot;indie-game-showcase&quot;&gt;Indie Game Showcase&lt;/h3&gt;

&lt;p&gt;Last weekend, the Iowa City Game Dev group had a local video game exhibition for our community. I decided to show Bludgeon there, and I had a blast! My wife Kezia was also there helping me demo the game, because she is that awesome (I didn’t even have to ask her to help… she just did).&lt;/p&gt;

&lt;p&gt;We had a really good turnout, and I got to see lots of different people play my game. It was really exciting and rewarding to see people having fun playing a game that I made. One of my main goals in making games is to make stuff that is meaningful to people or that brings people together, so it was great to see so many people having fun together playing Bludgeon. They seemed to have more fun with it than I expected, so that was really encouraging. I also got a lot of great feedback and ideas from those who played.&lt;/p&gt;

&lt;p&gt;After watching a bunch of people play Bludgeon last weekend, I became more confident that I could make it into a game that’s fun enough to feel good about selling. Reflecting on what’s happened so far, I think another thing that ended up being successful for me was deciding to work on making the core gameplay more fun before adding more features. I think it’s important to start with a good foundation before adding a bunch of stuff onto it.&lt;/p&gt;

&lt;p&gt;Thanks to everyone who showed up to last weekend’s event and tried Bludgeon! And thanks to the Mill for hosting this event, as well as to &lt;a href=&quot;http://izzyneuha.us/&quot;&gt;Izzy Neuhaus&lt;/a&gt; for setting it up. By the way, here are links to some of the games demoed by other developers at the event (sorry if I missed anyone):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://store.steampowered.com/app/499580/&quot;&gt;Crystal Control 2&lt;/a&gt; by Virtually Competent&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.hamslabyrinth.com/&quot;&gt;Ham’s Labrynth&lt;/a&gt; by BaladiDog Games&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.t7g3.com/&quot;&gt;The 13th Doll&lt;/a&gt; by Attic Door Productions&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://store.steampowered.com/app/331440/&quot;&gt;bit Dungeon II&lt;/a&gt; by KintoGames&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.KintoGames.ThiefPrincess&amp;amp;hl=en&quot;&gt;Thief Princess&lt;/a&gt; by KintoGames&lt;/li&gt;
  &lt;li&gt;Super Bogus World 2 by &lt;a href=&quot;http://www.hubolhubolhubol.com/&quot;&gt;Hubol Gordon&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;next-steps&quot;&gt;Next Steps&lt;/h2&gt;

&lt;p&gt;Going forward, I plan to keep working on Bludgeon, adding features, and polishing it up. I hope to make it more and more fun and unique as time goes on. I don’t have any schedule I’m following for now, but here is some of the stuff I’m hoping/considering to add in the future:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Allow up to 4 players&lt;/li&gt;
  &lt;li&gt;Add different stages with different environmental hazards&lt;/li&gt;
  &lt;li&gt;Probably add a health bar as an additional way to win/lose&lt;/li&gt;
  &lt;li&gt;A variety of power-ups&lt;/li&gt;
  &lt;li&gt;Different costumes or characters&lt;/li&gt;
  &lt;li&gt;Fewer bugs :)&lt;/li&gt;
&lt;/ul&gt;

            &lt;p&gt;&amp;#169; 
            2016
             &lt;a href=&quot;https://colececil.dev&quot;&gt;Cole Cecil&lt;/a&gt;. All rights reserved.&lt;/p&gt;
        </description>
        <pubDate>Wed, 31 Aug 2016 01:28:00 -0500</pubDate>
        <link>https://colececil.dev/blog/2016/introducing-bludgeon/</link>
        <guid isPermaLink="true">https://colececil.dev/blog/2016/introducing-bludgeon/</guid>
        
        
      </item>
    
      <item>
        <title>Hello, World!</title>
        <description>
            &lt;p&gt;Hi, everyone! So I finally did it. I created a blog. I’ve never really aspired to become a blogger, but recently I’ve been considering it more and more. I finally decided to commit to it, give it a try, and see how it goes. Hopefully it works out well.&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;In case you don’t know me, I’m a software developer that does web development for a living. I’m also very interested in game development, which I’ve been messing around with in my free time for quite a while now. In fact, more than anything else, it’s the game dev stuff that really got me to consider starting this blog. I think I’ve built up my game dev skills to the point where I’m ready to try to create a finished game to sell. And since I’m aspiring to do that, I figured it would be a good idea to establish more of an online presence and hopefully get a bit of a following as I develop my game. So a lot of the stuff I post on here will probably be related to game development, but there might be other stuff as well. In short, here’s what I’m hoping to accomplish with my blog at this point:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Share information and updates about projects I’m working on (games or other).&lt;/li&gt;
  &lt;li&gt;Create tutorials to share knowledge and skills I’ve learned.&lt;/li&gt;
  &lt;li&gt;Get better at writing (and communication in general).&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;how-this-site-was-built&quot;&gt;How This Site Was Built&lt;/h2&gt;

&lt;p&gt;I had some fun creating this site, and I learned some new stuff in the process. Here’s what I did to create it:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Framework:&lt;/strong&gt; I used a static site generator called &lt;a href=&quot;http://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt; to create this site. It’s pretty cool, because once you use it to create the templates for all your different types of pages, you can add new content just by creating Markdown files. I’m a big fan of using plain text whenever possible, so I love using Markdown whenever I have to generate formatted text.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Hosting:&lt;/strong&gt; This site is being hosted with &lt;a href=&quot;https://pages.github.com/&quot;&gt;GitHub Pages&lt;/a&gt;, which has a couple of nice benefits. The first big one is that it’s free. It also integrates with Jekyll, so all I have to do to update my site is make a commit to the master branch of my Git repository, and the new version of my site is generated for me. Pretty convenient!&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Style:&lt;/strong&gt; I used &lt;a href=&quot;http://getbootstrap.com/&quot;&gt;Bootstrap&lt;/a&gt; as a starting point for all my CSS. I have a lot of experience with it, and I like to use it for responsive design stuff. I’m using the &lt;a href=&quot;http://sass-lang.com/&quot;&gt;Sass&lt;/a&gt; version of it and building my styles on top of it. For coming up with my color scheme, I used a really cool site called &lt;a href=&quot;https://coolors.co/&quot;&gt;Coolors&lt;/a&gt;. As far as design inspiration, there were a couple different sites that I took a bit of inspiration from. I really like the look and feel of &lt;a href=&quot;https://chocolatey.org/&quot;&gt;Chocolatey’s web site&lt;/a&gt;, and I ended up doing a similar style for my site. When I was looking for examples of how existing blogs were laid out, I liked how the &lt;a href=&quot;https://crew.co/backstage/blog&quot;&gt;blog by Crew&lt;/a&gt; was done, and I ended up making a somewhat similar layout to theirs (although they’ve updated it since then).&lt;/li&gt;
&lt;/ul&gt;

            &lt;p&gt;&amp;#169; 
            2016
             &lt;a href=&quot;https://colececil.dev&quot;&gt;Cole Cecil&lt;/a&gt;. All rights reserved.&lt;/p&gt;
        </description>
        <pubDate>Sun, 28 Aug 2016 17:53:00 -0500</pubDate>
        <link>https://colececil.dev/blog/2016/hello-world/</link>
        <guid isPermaLink="true">https://colececil.dev/blog/2016/hello-world/</guid>
        
        
      </item>
    
  </channel>
</rss>
