Final post / Post-mortem:
Short version: This was my third MFGJ, and it continues to be a good time! My main goals for this jam were to prototype an idea that I've had bouncing around for a while, and to actually interact with the community through writing devlogs and checking the Discord actively. In those three goals, I feel it was a pretty successful two weeks! Something always comes up, of course, but I think I did a pretty good job paring down my scope and expectations. I would've liked to write more devlogs.
Long version, a.k.a. things I wanted to devlog:
Outline:
- Backbuffercopy + shaders
- Fixing the screen UI
- Animations!
- Tilemap funkiness
- YSorts
1. Backbuffercopy + shaders
This was my first big breakthrough. The first thing I figured out when making my hot-cold overlay is that it's super easy to draw a circle and a rectangle in Godot from code, and not nearly as easy to draw a rectangle with a circle cut out of it! The structure of my UI, finally, is
UI -> A canvaslayer node, so that it isn't affected by the viewport moving TemperatureOverlay -> a Control node, with a script to feed info to the overlay elements Heat -> A Node2D BackBufferCopy -> a backbuffercopy node Cold -> A Node2D Not Cold -> A Node2D "Not Cold" has a ShaderMaterial, with the Shader code shader_type canvas_item; void fragment(){COLOR = texture(SCREEN_TEXTURE, SCREEN_UV)}
The funny thing about all this is that I'm not positive that each element is necessary for it to work. The BackBufferCopy node, by virtue of existing in the tree, saves a buffered image of the screen when it would be drawn, so it captures all the player action going on under the UI and the red circle that shows Heat. Cold draws a blue rectangle that's a bit bigger than the screen and covers everything. Then, "Not Cold" draws a circle that gets smaller than the screen as the player's body temperature drops below neutral. It's a plain, white circle, which has the buffer from the backbuffercopy reflected onto every pixel by the shader. I think! Shaders are super weird, and I'm still learning a lot.
2. Fixing the screen UI
I spend a lot of time screwing around with that UI above to get it to follow the player correctly. In the final iteration, these three things seem to be essential:
- The root node of the UI is offset to the center of the screen
- The TemperatureOverlay node has its anchor and margin values set following the "Center" instructions from https://docs.godotengine.org/en/3.2/tutorials/gui/size_and_anchors.html
- The BackBufferCopy, and this took me forever to notice!, is set so that Copy Mode is "Viewport", and the Rect is 0,0 to 480,320, the size of the game
3. Animations!
This is just a fun little note. If you play and use the fire swirl, you may notice that it appears to pass behind the player, in super fancy faux-3D fashion! What I did to accomplish this, and I'm proud of just how ridiculous it is, is that the player has two sprites, one on either side of the flame in the node tree. The first Sprite is fully animated by the AnimationPlayer and is active all the time. The second one becomes visible only during the fire swirl, and is just the top of the player animation that plays during the swirl attack but in a position to be drawn above the fire. So silly, but it works!
4. Tilemap funkiness
There are four TileMap nodes in the game. There's one that has all the ground, one that has all the snow, and is checked against when the player uses FireSwirl (And tiles are set to -1 to disappear), One to draw all the border trees, and one to draw just the tops of the trees, so that the player passes in front of the trunks and behind the tops. All my tilemaps come from sprite atlases, and I cannot for the life of me understand how the whole process works. Future goals are to know a single, solitary thing about how TileMaps really work.
5. YSorts
This was a real treat to figure out at the end! Between the TreeTrunks TileMap and the Treetops TileMap, there is what's called a YSort node. Nested in the YSort are another YSort that creates and holds all the bats, the Player, a YSort holding all the trees you can walk around, and a YSort containing all the signs and shrines. While that's all a lot to take in in a single sentence, what it means in the node tree is that Z-Sorting (Figuring out what to draw in front of what) happens automatically for every child of a YSort or child of a nested YSort. This is super cool, to me, and I'm happy it's baked in to Godot 3+
If you've read this far, leave me a message if anything didn't make sense, and I hope you found something here useful! I may come back later and add images, which would probably be a lot more useful than descriptions.