GLADEL'S STUFF
  • Home
    • Sorelle
    • BLEED RUNNER
    • Tear the Planks Down
  • About
  • Resume
  • Publications
  • Bonus...
    • Artwork >
      • Illustrations & Renders
      • Sketches & Lines
      • Comics
      • Pixels & Mouse
      • Collabs
    • Writing
    • 2021 - 2024 Legacy Projects
    • 2017 - 2019 Legacy Projects

GLADEL'S THING

Publications about my various interests.

Making the Art of My 2.5D Pixel DMFD Fangame "A Fire Made of Snowflakes"

3/5/2025

0 Comments

 
Picture
Over the past 5 months, I have been working on developing the art style of my in-development Dragon Marked For Death fangame, A Fire Made of Snowflakes. In it, I am trying to make an "advanced" form of the art style I developed for BLEED RUNNER​ back in 2022. 2.5D pixel art styles are some of my favorites to work with since, for me at least, creating 2D sprites is faster than making 3D models and making 3D environments is faster than making 2D environments. So, in this post, I go over the techniques, thought processes, and scripts that I use to present the art style of AFMOS so far.

Table of Contents

1. Logistics
​2. 2.5D Sprites
2.1 Drawing Sprites
2.2 Sprites Normal Maps
2.3 Object Hierarchy, Billboarding, and Casting Shadows
2.4 Directional Sprites
3. Terrain and Environments
3.1 Drawing Terrain Textures
3.2 Terrain Normal Maps
3.3 Painting Terrain
3.4 Grass
3.5 Trees
3.6 Fog and Skyboxes
4. Post-processing
​4.1 General settings
4.2 Color Palette
5. Particle Effects
5.1 Spawning Particles with Utility Scripts
5.2 Blood FX
5.3 Sparks FX
​6. DOTween Effects
6.1 "Play Effect on Start" Script
6.2 Character Take Damage FX
7. Dialogue
7.1 Resizable Dialogue Boxes
​7.2 Using TMPEffects
8. Conclusion

Logistics

  • Engine: Unity 6
  • Render Pipeline: Built-in Render Pipeline (BRP)​
  • Tools: DOTween, Post-processing Package, Cinemachine Package, TMPEffects, Paint.NET, Piskel, Figma, Laigter, UnitySpriteShaders

2.5D Sprites

Drawing Sprites

I draw sprites for characters, props, and attack wooshes using Paint.NET and mouse. I draw most sprites in a grid consisting of 32x32px frames. I have a template for this grid where I use the colors green and pink (or blue and orange depending on what helps me see the actual sprite better) interchangeably to measure the sprites and separate one animation frame from another. 32x32px frames are also just easy for me to draw in and a good mixture between something that would be too simplistic and something that would be too complex for me to draw a lot of frames for.
Picture
For coloring characters and objects, I use the PICO-8 color palette to make it easier to pick colors without going overboard (besides, the colors will be changed via post-processing in engine anyway).

I preview and edit individual animations using the web version of Piskel. If I make any changes in Piskel, I export a new version of the given animation and paste the revised frames into my Paint.NET file.

To make it easier to import sprites (and eventually their normal maps) into Unity, I import the entire spritesheet from the Paint.NET file rather than individual animations. I’ll explain why in the next section.

Sprites Normal Maps

After completing a spritesheet, I use Laigter to generate its normal maps using these settings:
  • CHARACTERS:
    • Height = 200
    • Soft = 3
  • PROPS:
    • ​Height = 250
    • Soft = 3
    • Abrupt = Depends on the prop (ex. glass objects should be set to "true")
  • ​ATTACK WOOSHES:
    • Height = 250
    • Soft = 0​​
Picture
Picture
Picture
Before importing into Unity, make sure your spritesheet and normal map images use the same canvas size and that the tiles line up, or else the final normal map display will be offset!​​​

I import both the spritesheet and the normal map sheet into Unity using these settings:
  • ​BOTH:
    • Filter Mode = Point (no filter)
    • Compression = None
  • SPRITESHEET:
    • Texture Type = Sprite (2D and UI)
    • Sprite Mode = Multiple - slice by 32x32px (depending on the spritesheet)
    • Pixels Per Unit = 16 (this means that 16 pixels equals 1 in-editor unit)
  • NORMAL MAP SHEET:
    • Texture Type = Normal Map

​In Unity, I create a new Material using the UnitySpriteShaders by traggett. Then I plug in the Normal Map sheet into the Normal Map section of the Material. Then, in the editor, I put that Material into a Sprite Renderer that displays one of the sprites that I want. The normal map should map exactly onto the sprite. If you change the sprite to another one on that same spritesheet, the normal map will automatically switch to the matching image.

Remember that if you use a sprite from a different sheet with a different canvas size and tiles that don't line up with the normal map, the normal map will look wrong!

Object Hierarchy, Billboarding, and Casting Shadows

For all of this to work, the hierarchy of the object that will have the 2.5D sprite is that there should be a parent object that hosts the character's main logic, and then a child object under it that hosts the character's "display and audio":
Picture
You should also attach the following SpriteBillboard and CastShadowsOnSprites scripts to your "Display and Audio" object:
I couldn’t figure out how to edit the sprite shader to also be a billboard shader, so I ended up creating a script to achieve a similar effect using this tutorial by Paper Mouse Games:
SpriteBillboard Script
Code Editor

    
To allow 2.5D sprites to cast shadows, I use a "hack" via a script:
CastShadowsOnSprites Script
Code Editor

    

Directional Sprites

I just followed this tutorial by Paper Mouse Games.

Terrain and Environments

Drawing Terrain Textures

For terrain tiles, I use pretty much the same methods as drawing character and object sprites, except I give myself more freedom with the color palette (since a lot of the tiles are snow textures, and I can only be a little subtle with the coloring for them).

Terrain Normal Maps

Same with the character sprites, I use Laigter to generate the normal maps for terrain tiles, but with slightly different settings:
  • Height = 200
  • Soft = 0
  • Bump = Abrupt

I import the images into Unity with Point (no filter) and no compression. Normal Maps are imported the same way as those for character spites, but the tile images themselves should be uploaded as Texture Type "Default" instead of "Sprite (2D and UI)". Also, instead of putting all the tiles into a spritesheet, I upload them all as separate squares (both the actual tiles and their normal maps). This makes it easier for me to turn them into Terrain Layers. Here is an example of one of the terrain layers in AFMOS:
Picture

Painting Terrain

I just make a Layer Palette in the Terrain editor:
Picture

Grass

You can download the grass textures I use here. My grass textures (at least currently) are simple 32x32px pixel sprites (although I draw them with a "fuzzier" brush than my other sprites because I like the blended look for the grass specifically). Sometimes the default settings for grass color and size are fine, except I change the Align To Ground (%) setting to 100 so it blends with the terrain better (I'm not sure if this affects performance though). If I want denser patches of grass, I lower the min width and raise the max height. Here are the grass settings for 3 of the visdev shots I made these past few months:
Picture
Picture
Picture
Picture
Picture
Picture
Picture
Picture

Trees

I couldn't figure out how to make the trees not super small when painting them onto the terrain, so I manually place trees instead. It's a lot of work but manageable. My current go-to pack for trees is this low-poly pine forest pack by Brandon Gillespie since it perfectly fits the foliage of Pagnas (AFMOS's snowy setting) and also has some nice-looking retro pixel textures on the models.

Fog and Skyboxes

I use BOXOPHOBIC's Skybox Extended Shader so I can have fog affect the skybox (because the default Unity skybox shader doesn't take fog into account for some reason). Fog is super intense even at small numbers, so just pick what works for your scene. For example, I use these settings for a blizzard-like environment:
Picture

Post-processing

Picture

General Settings

I have a base post-processing profile (with the post-processing volume set to Global) that I use in every scene to add effects I want the entire game to have, such as ambient occlusion. Here are the settings:
Picture
Picture
Picture
Picture
Picture

Color Palette

In general, AFMOS's post-processing color palette is blue, pink, cyan, and red to match with the colors of the protagonists, Alouette (red) and Milan (cyan).

My Bloom​ settings almost always use a light pink color so that heat sources (which are meant to be tinted pink in my color palette key) stand out more.

For Color Grading, Gamma and Gain settings mainly affect shadow colors. If I change those settings, shadows get a slight color tint instead of staying pitch-black, which gives a subtle vibrant effect.

​Since post-processing profiles can stack, I can use another post-processing profile on top of the base one for extra tweaks. These additional profiles really depend on the scene. Also, sometimes I don't use the base profile if the scene looks better that way or if it's not a gameplay scene. Here's one example:
Picture
Picture
Picture
Picture
Picture
Picture

Particle Effects

Spawning Particles with Utility Scripts

Instead of putting particle effect components on characters, I put them on dedicated objects in prefabs so that I can instantiate them wherever I want. In those prefabs, I can put additional particle effects under the parent and also single light sources. Here is an example:
Picture
I have several utility scripts for handling cleanup and sound effects when particles spawn. I might add more later as development continues. Here are some scripts:
ParticleHelper Script - Prefab and Light Cleanup
Code Editor

    
AudioPlayerOnStart Script - Plays SFX when a particle spawns
Code Editor

    

Blood FX

The blood FX uses a single particle emitter and 6 blood sprites imported as a spritesheet. Then I dragged the spritesheet into the Albedo section of the UnitySpriteShader.
Picture
The particle emitter uses bursts to spawn particles:
Picture
The amount of blood that actually spawns is very small. The reason why it looks like there is way more blood than in actuality is because I use trails set to an unlit blood material:
Picture
Picture
For the blood to quickly fall onto and stay on the floor, I use collision and a gravity modifier set to 10:
Picture
When a character takes damage, I instantiate the blood FX prefab in my HealthHandler component script. I also dynamically change how far the blood spray goes based on the power of the source attack:
HealthHandler Script - SpawnBloodSprayFX() Function
Code Editor

    

Sparks FX

The metal sparks FX is similar to the blood FX except that it also has a light. I use my custom cleanup script to play the light effect and tween down the light color over a duration that I set.

Over its lifetime, I set the sparks color from bright yellow to dark orange and then clear:
Picture
I do a similar effect with the trails while setting their lifetimes to be short:
Picture
Then for the collision settings, I add a little Bounce (0.1):
Picture

DOTween Effects

"Play Effect on Start" Script

DOTween can tween just about anything. Because of this, I'm able to make play-on-start scripts to play various effects on objects when they are instantiated. I can simply attach these scripts to the object I want the effect to play on. Example:
BounceOnStart Script
Code Editor

    

Character Take Damage FX

Whenever a character with a HealthHandler component takes damage, their sprite flashes red for the duration of their invincibility frames, and their "DisplayAndAudio" object shakes. These effects both use DOTween:
HealthHandler Script - Excerpt from TakeDamage() Function
Code Editor

    

Dialogue

Resizable Dialogue Boxes

I just followed this tutorial by PitilT.

Using TMPEffects

To get dialogue text moving, I use the TMPEffects package by Luca3317. It comes with a typewriter effect and tags to make text wavy, play at different speeds and delays, etc.. It also has support for callbacks so I can make my dialogue script play the next dialogue a couple seconds after the typewriter effect ends and also play dialogue pip SFX.

Conclusion

I'm working towards making a demo of A Fire Made of Snowflakes hopefully later this year, so all of my methods are subject to change. Still, I hope this post will be useful to people (and myself in the future).

Song of This Post

The song of this post is Corazón caracol by Pánico!
0 Comments



Leave a Reply.

    GLADEL'S THING

    Publications about my various interests.

    Author

    I'm Gladel (G.R). They/them or any.
    I'm using this blog for miscellaneous thoughts and write-ups on how I do certain things in my work. Thank you for visiting!

      Newsletter

      Hello
    Get Notified for New Blog Posts

    Archives

    May 2025
    December 2023
    July 2023
    April 2023

    Categories

    All
    Analysis Essays
    Art
    Brain Lists
    Dragon Marked For Death
    Random
    Tech Art

    RSS Feed

Last updated on 11 May 2025, 1:38 AM

Norm the of out break to chance every embraces who artist lil' a I'm.

Email

[email protected]

LinkedIn

www.linkedin.com/in/gladeline-rufo
  • Home
    • Sorelle
    • BLEED RUNNER
    • Tear the Planks Down
  • About
  • Resume
  • Publications
  • Bonus...
    • Artwork >
      • Illustrations & Renders
      • Sketches & Lines
      • Comics
      • Pixels & Mouse
      • Collabs
    • Writing
    • 2021 - 2024 Legacy Projects
    • 2017 - 2019 Legacy Projects