Sean Esopenko

Ludum Dare 51

So close to the day, prepping the base code!

gameplay-gif-with-control-settings.gif

We have no art assets in the game yet, so that we're not excluded from the sound & art voting categories. Being a full time software developer with a lot of experience, I've been spending this week hammering through base code and infrastructure, in preparation for tomorrow's theme drop:

  • HTML5 and Windows builds pushed to itch.io automatically when a git tag is created, within minutes. No manual exporting required, the automated pipeline does it for us.
  • Empty placeholder game title screen, ready for title screen artwork
  • Control re-mapping menu system, allowing players to remap their controls for accessibility needs
  • Graphics settings system, toggling full screen, borderless window, etc
  • Sound settings system, controlling master, sound effects, and music volume
  • Credits page, with the team members listed for the game jam
  • Movement and jumping of a placeholder graphic protagonist, play tested in a sidescrolling environment built with black square tiles
  • Moving through doorways, represented by placeholder squares at the moment
  • Damage system where the player respawns from the last door exited when they take enough hits, currently just a numeric representation in the top left
  • playtastygames.com website for our game making collective.
  • public discord invite link

We released Clique Hell High 112 times and this is how we did it...

IMAGE ALT TEXT HERE Let's Play recording by 100th_coin of Clique Hell High, which was released 112 times

Shipping software is stressful and getting your game delivered and playable during the zero hour of Ludum Dare is even more stressful. There are so many places where the delivery process can go wrong and doing it by hand makes that process fragile. With only 48-72 hours to make a game, every time 5-20 minutes is spent packaging up a game and deploying to itch.io is taking precious time away from development of a game. However, the feedback is critical throughout the development process, so what is one to do? Well, we shipped Clique Hell High 112 times since Friday afternoon, and none of us had to step away from any of our tasks at hand. How did we do it? We used Github Actions to build an automated continuous delivery pipeline: every time we tagged a release, automated tooling exported our game, packaged it up, and uploaded it to itch.io. Here are the details on how we did it.

Tools used:

godot.png

The first step in the pipeline was our actual IDE/Engine. Looking over the landscape of game engines, Godot was the best featured with all the tooling required to set it up in a CICD pipeline. If you haven't used Godot, give it a look, because while scenes inside scenes is the killer app of Godot, overall it's a great game engine/editor for small projects like game jam. It's the perfect engine for small game projects.

Godot lets you place scenes inside scenes as nodes, and if your team agrees to only one team member editing a scene at a time, you still have a lot of opportunities to synergize and work on the same systems together. One person works on arranging the level in one scene, and is the only person who's allowed to make changes in Git for it. How do the rest of the team members contribute to the level simultaneously? With scenes as instances. Towards the end of the project we would have one team member working on the mechanics for the exit door in its own scene, while another arranged the enemies in the main map. Nobody had merge conflicts thanks to scenes within scenes in godot.

gitemtags/emscreenshot.png 112 git versions, each one published automatically to itch.io

During the first hour, we had a rough level that the player could wander in and the rest of our team who weren't developers were able to play it on itch.io, with each iteration released hourly. Practically with every change of our code base, our pipeline shipped a new version to itch.io.

GitHub-logo.png

The next component was our version control system and merging our work together, integrating it, as frequently as possible, multiple times per hour. To do this, we used git, backed by github. Every team member actively working with the Godot editor had a copy of Github Desktop, and a github account with access to the private project repository. Every hour, each contributor committed their work to github and merged it together. This meant everybody who was dependant on everyone else got to see if their work stepped on the toes of others right away. Our play testers on the team could spot problems with integrated systems quickly.

github_desktop.png Github Desktop makes it possible to snapshot your work and integrate with other contributors on the team

Compared to a network drive, a version control system like git lets our team snapshot their local changes (undo on steroids) while integrating together upstream and test their integrated changes together.

Delivery pipelines have been around for a while but they used to be the domain of large corporations: clunky jenkins servers packaging up code bases maintained by hundreds of developers, with the automated systems being babied like precious, cantankerous animals. Over the past decade, these automated systems have become easier to set up with bot Bitbucket and Github offering completely free, easy to use solutions.

export_stage.png export stage of our pipeline

Now that we have our code integrated, how did we package it up? The solution was Github Actions, particularly the firebelly/godot-export github action. With a .github/workflows/main.yml file using the documented YAML code from the export action, every time we tagged a release, the github action packaged the godot export up into zip files. Instead of requiring a team member to manually export the project to their local computer, the pipeline did this for us. You don't even have to use github, because other providers offer similar solutions, all of them with free tiers:

Add an action for exporting the game in your pipeline. Here's a snippet of the yaml we used to export our Godot project automatically:

yaml - name: export game id: export # Use latest version (see releases for all versions) uses: firebelley/godot-export@v4.1.1 with: # Defining all the required inputs godot_executable_download_url: https://github.com/godotengine/godot/releases/download/3.4.4-stable/Godot_v3.4.4-stable_linux_headless.64.zip godot_export_templates_download_url: https://github.com/godotengine/godot/releases/download/3.4.4-stable/Godot_v3.4.4-stable_export_templates.tpz relative_project_path: ./ archive_output: true

*YAML code snippet of the export stage of our github action *

And here's the log output of the files being zipped up:

```

⚒️ Zipping binaries /usr/bin/7z a /home/runner/.local/share/godot/archives/webgl.zip /home/runner/.local/share/godot/builds/webgl/* /usr/bin/7z a /home/runner/.local/share/godot/archives/win.zip /home/runner/.local/share/godot/builds/win/*

7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21 p7zip Version 16.02 (locale=C.UTF-8,Utf16=on,HugeFiles=on,64 bits,2 CPUs Intel(R) Xeon(R) Platinum 8171M CPU @ 2.60GHz (50654),ASM,AES-NI)

Scanning the drive: 2 files, 191255312 bytes (183 MiB)

Creating archive: /home/runner/.local/share/godot/archives/win.zip

Items to compress: 2

Files read from disk: 2 Archive size: 37712907 bytes (36 MiB) Everything is Ok

7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21 p7zip Version 16.02 (locale=C.UTF-8,Utf16=on,HugeFiles=on,64 bits,2 CPUs Intel(R) Xeon(R) Platinum 8171M CPU @ 2.60GHz (50654),ASM,AES-NI)

Scanning the drive: 9 files, 174647145 bytes (167 MiB)

Creating archive: /home/runner/.local/share/godot/archives/webgl.zip

Items to compress: 9

Files read from disk: 9 Archive size: 28699214 bytes (28 MiB) Everything is Ok ```

Output of the zipping sub-stage of our export stage

So what happens here? Well, to be honest, without any other work the zip files would fall into the ether, into a black hole, without any means of using them. The resulting files are saved as artifacts in the pipeline, available for download in github by any team members with access to the github repository. This got us part of the way there.

artifacts.png *web HTML5 and windows exe artifacts automatically produced by our pipeline *

These artifacts are saved in the github repository, one batch of artifacts for each version for archival purposes, using the following snippet:

yaml - name: upload windows artifact id: upload_win_artifact uses: actions/upload-artifact@v3 with: name: ${{ steps.tag_version.outputs.TAG_VERSION }}-win path: ${{ steps.export.outputs.archive_directory }}/win.zip - name: upload webgl artifact id: upload_webgl_artifact uses: actions/upload-artifact@v3 with: name: ${{ steps.tag_version.outputs.TAG_VERSION }}-webgl path: ${{ steps.export.outputs.archive_directory }}/webgl.zip

*artifact uploading YAML snippet *

The next step in our pipeline is the juicy bit: uploading the zip files automatically to itch.io. This took a few steps to set up, with the first one being getting an authentication token for itch.io's upload program, Butler. I had to download butler for my windows PC, then use butler to log into the system. Detailed instructions for logging into butler for your pipeline are here.

butler-login.png *butler login prompt *

If you think it's a good idea to put this API key right in your repository, think again. If your repository were compromised somebody would be able to make api calls to itch.io as though they are you, and could do nefarious things in your name, such as try to DDOS itch.io during the game jam. Github has a Secrets system to store secrets securely with one-way entering: once you enter it a human can't get it back out. After logging in, the secret api key is set up using Github Action Secrets.

github secrets.png *The secrets we had set up for our pipeline. not even I can read them now. *

Now that our secrets were set up, we used the following snippet to upload our artifacts to itch.io automatically:

yaml - name: download-artifact-win id: artifact_win_download uses: actions/download-artifact@v2.0.8 with: name: ${{ steps.tag_version.outputs.TAG_VERSION }}-win path: build/win - name: list artifact id: list_artifact run: ls -lha ./build/win - name: push windows to itch id: itch_win_push uses: KikimoraGames/itch-publish@v0.0.3 with: butlerApiKey: ${{secrets.BUTLER_API_KEY}} gameData: ./build/win/win.zip itchUsername: ${{secrets.ITCH_USERNAME}} itchGameId: ${{ secrets.ITCH_GAME_ID }} buildChannel: windows buildNumber: ${{ steps.tag_version.outputs.TAG_VERSION }} - name: download-artifact-webgl id: artifact_webgl_download uses: actions/download-artifact@v2.0.8 with: name: ${{ steps.tag_version.outputs.TAG_VERSION }}-webgl path: build/webgl - name: push webgl to itch id: itch_webgl_push uses: KikimoraGames/itch-publish@v0.0.3 with: butlerApiKey: ${{secrets.BUTLER_API_KEY}} gameData: ./build/webgl/webgl.zip itchUsername: ${{secrets.ITCH_USERNAME}} itchGameId: ${{ secrets.ITCH_GAME_ID }} buildChannel: webgl buildNumber: ${{ steps.tag_version.outputs.TAG_VERSION }} push to itch stages of our pipeline

For the windows and html5 exports each, it downloads the packaged artifact then used KikimoraGames/itch-publish to automatically publish the zip files to itch.io. We're almost there.

As-is, the uploads aren't ready for consumption and the itch.io page needed some configuration for the file downloads. The html5 download had to be configured as an HTML5 download in order for it to appear in a player on the page. With this step done, every time we tagged a commit and pushed the tags, our itch.io page was updated minutes later We could ask our friends and play testers to test our game in progress and they could provide feedback.

itchemupload/emdialog.png *our file configuratons for our automatically uploaded artifacts *

In the end, we tagged our repository 112 times since friday afternoon, which resulted in 112 releases. We were confident that we could ship the game 20 minutes before the cut-off because we had done it 112 times already, and knew exactly how long the pipeline would take. We even snuck in an extra release with some minor tweaks for good measure with 44 seconds to go and hit our publish button on the submission.

pipeline-runs.png * multiple releases per hour means feedback multiple times per hour *

Nobody on our team had made a game before with this many people and having this tooling to continually integrate our work, and continually test it, then continually package it up, let us work together with confidence. It's free to use, with thousands of free pipeline minutes included with github and 500mb of free storage.

Next game jam, get immediate feedback by setting up your own pipeline and leave the stress of packaging behind. Focus on your deliverables and not your delivery. I hope this is helpful for others at the next jam and if you have questions feel free to leave them on the post.

Godot's features we loved using when making Clique Hell High

logoemlarge/emcolor_light.png

None of us on our team made a game before, let alone participated in a game jam, so we were quite nervous participating in Ludum Dare 51. Godot, an open source and free game engine, was the tool that we decided on using and we wouldn't have completed Clique Hell High if we a different engine.

mapemprototype/emin_godot.png The final gauntlet of our game built in Godot 3.5.1 with custom tooling created during the weekend jam

We were able to animate cut scenes for Clique Hell High right in Godot

animatinemplayer/emexample_short.gif Animations were composited right in Godot for the opening and cut scenes, speeding up our workflow

As the jam progressed we started to get the hang of the essential functions of Godot's animation system. Godot lets you animate "everything," meaning any property of any node could be animated such as:

  • Visibility of a node
  • Position
  • Opacity

Keyframes could be dropped in, animation frames of an animated sprint chosen, then the resulting animated scene dropped in the game. It was quick enough to work with to rule out using secondary software for compositing our animations.

It's free (but not that kind of free)

Let's be honest, free is good, and by free, I don't mean monetary free. I mean zero control over how we use the software. With 6 of us sharing the wifi, our internet was a little spotty at times, and if we had to deal with license/registration servers glitching out right in the middle of our jam, we'd have failed entirely. Godot has no licensing servers so you don't have to worry about a poor internet connection preventing your use of the tool. Oh and it doesn't cost money.

Killer App: Scenes Inside Scenes

finalemroom/emin_editor.png The final room as a scene, which ended up being instanced in the main level as a node itself

Git version control let multiple team members work on the project at the same time and Godot takes advantage of this with scenes being useable as regular nodes. One team member could be declared as the current owner of a scene (such as the ending area of our game) and hands off for other team members. Then another team member could drop an instance of said scene in the master level scene, and both team members could thus contribute to the level without merge conflicts. Game engines which don't let the designers instance scenes inside scenes reduce the ability to team up and work simultaneously on problems, because merge conflicts can arise when working on the same scene. This let us work faster, as a result.

GDScript is easy to learn

gdscript_snippet.png GDScript has been easy to pick up and sophisticated enough to solve problems

It's python-like meaning that the syntax is quick to pick up on if one's used python, and quick to pick up on if one hasn't. No curly braces to miss which means newer devs on the team don't have to troubleshoot syntax errors due to missing closing braces. The textual not and keywords are easy to read. Not only is it syntactic sugar, but the editor itself is quite powerful, adequate for small projects without having to reach for other tools. No need to install 3gb of dot.net SDKs, no worry about C++ linkers misbehaving on different systems. Download it and program right away.

It has an HTML5 export

html5-topper.png

There are just too many games to go through during the jam to download and install games and being able to export to HTML5 was key to letting people play our game with ease. We didn't run into any major problems that wouldn't have happened in Unity any ways. Loading of content was done in loading scenes before playing said content, to ensure that stuttering didn't occur during gameplay or cut scenes. We used the GDNative mode for the HTML5 exporter and the game played well enough in browsers to not hear any complaints from players so far.

We built tools for our designers with tool

In a gdscript file, if the keyword tool is placed at the top, then it exposes whether the node is rendered in the editor or in the game with a simple if Engine.editor_hint: conditional. This was used for a few key game components which allowed our level designers to tweak the level components and see the results right in the enditor.

The most useful one was the editor hint to determine if a cat or dog should be rendered right in the game engine editor, letting our designers see visually which enemies were toggled as dogs and which as cats.

``` func process(delta): if not Engine.editorhint: _handlefacing()

if Engine.editor_hint:
    _set_visual()
    var should_show_aim_line:bool = not aim_at_player
    if not show_aim_line and should_show_aim_line:
        show_aim_line = true
        $LineFireDirection.show()
    if not should_show_aim_line and show_aim_line:
        show_aim_line = false
        $LineFireDirection.hide()
    if show_aim_line:
        calc_line_dir()

``` Checking whether it's the editor that's rendering and if so, rendering visual aids for the level designers

The custom script variables accessible for the enemies were picked up on by the editor, and visuals were rendered accordingly.

enemy_variables.png

Some of the enemies aim directly at the player, while others fire in a fixed direction. This was done with an aim_at_player variable, which was then picked up on in the editor to render a visual guide.

editingemenemy/emwith_tool.gif

Then with a simple function, if aim_at_player is false, it determines the direction based off the angle configured.

func _get_line_fire_dir()->Vector2: var r := deg2rad(aim_direction) var p := (Vector2(cos(r), sin(r)).normalized() * aim_guide_length) as Vector2 return p

The command line interface is build pipeline friendly

We set up an automated build pipeline using github actions (which you can read about in my previous article, We released Clique Hell High 112 times and this is how we did it.... Godot has a sophisticated command line interface that lets you do most everything related to exporting directly from the command line without special tooling. The selection of ready-to-use github actions was large enough for us to find one that worked well within an hour.

Summary

Overall, Godot exceeded our expectations. Most folks on the team who used godot over the jam had never used it before, but were able to contribute to the game effectively. It's easy enough to learn "on the job" and Godot never really got in our way as we worked on the game. For anybody who hasn't tried it out, give it a whirl, because it was more than adequate for us and key to being able to deliver Clique Hell High and all of the content in it within the 72 hour time constraint.

Live Stream Today: Side Scroller Mechanics in Godot

twitchemstream/emprogramming.png

Time: 4:15pm MST to 6:15pm MST

Stream: https://www.twitch.tv/kwirky88

Greetings! I'm Sean Esopenko, aka kwirky88, and I've been programming software professionally for 18 years. The game jam's done and while we're waiting for feedback on our game Clique High Hell I need to keep getting my gamedev itch scratched. I'm streaming as I work on a proof of concept for a new game, fleshing out side scroller game mechanics in the open source, free game engine Godot.

People of all backgrounds and experience are welcome! My streams are typically educational in nature, for myself, and the viewers.

How are you judging "Mood", if at all?

The Mood category is quite difficult to judge so typically I've been leaving it unrated. Who else is having difficulty judging this category and why?

Ludum Dare 52

Looking for Beta Testers of Calorie Crunch!

Hey folks! We're looking for beta testers of our in-progress game, Calorie Crunch! We're itching to hear what we can improve before the jam due date so if you have time to try it out in your browser, please have a look.

After trying our game, if your own game works in the browser please leave a link to your game on this post for us to try out, too!

calorieemcrunch/emplay_thumbnail.png

Here are some of my Godot settings for Web/HTML5 player exports of my games

For those who've made their games with Godot (Version 3.5.1), it's fairly straight forward to get a web player working with some tweaking. I find the Godot engine lends itself well to HTML5 exports and most everyone should be able to increase engagement with web players when using the engine.

If you find this post helpful, click the like button. If you have any advice to share for others not covered here, please leave a comment to help everyone out.

Increase your engagement

HTML5 versions of games are great because 10-100x more players will play your game. Our own game, Calorie Crunch had 150 web plays yesterday on itch.io and only a single download, demonstrating the preference of web players over downloads. Web play is an easy way to get WAY more engagement because it's so convenient for players. We're all trying to play as many games as possible so making it easy helps.

People like myself are afraid of downloading games because of the possibility of viruses so I hope you can get the web view working soon, your game looks interesting. I can't download games at all on my work laptop because of configurations the IT people have made to prevent viruses, so web players make it easier for me to check out games during breaks.

How I do it with Godot 3.5.1:

Don't use the Ludum Dare web player, it's buggy! Use itch.io's web player! Sorry Ludum Dare, I like the effort you're putting into the new feature but players should be aware that Ludum Dare's web player is kinda in an Alpha stage and if you want dependable playback of your games, leverage itch.io for now. Do a lot of testing of your game in Ludum Dare's built in player before depending on it, it's different from game to game.

Here's what I do to get my Godot games working on HTML5 on itch.io

Export Config Settings:
  • Export Type: GDNative (this is important, my web builds don't work without it, don't know why it's not default)
  • Canvas Resize Policy: Adaptive
  • Focus Canvas on Start: On
  • Export filename: index.html (this is important for itch.io and others, they expect your root file to be index.html)
Project Settings:
  • Display: Window: High DPI Support enabled (not enabling this results in ugly pixel resizing, this setting makes it smooth as butter and even nicer on high res 4k screens, ipads, etc)
  • display: Window: Mode: 2D
  • Display: Window: Aspect: Keep
Itch.io Settings:
  • Shared Array Buffer Support. Seems to work well with my godot projects
  • Run on page load. It says it doesn't work for unity games but I haven't run into issues for godot games with the above settings
    • If your game opens up to a splash screen it can look real slick on your itch.io page. Couple it with a big, beautiful "Play" button and it naturally invites your players to click and start playing your game.
  • Add full screen button setting in itch.io. I like this, it adds a full screen button to the game. Sometimes the game has to go full screen to work properly and a good number of people participating in the jams know this when rating games.

I created GATT: "Godot Autotile Texture Templater" to make Godot tile art easier

Farming on a grid-like system has been a common gameplay mechanic for this jam and our own game, Calorie Crunch, used a grid system itself, but due to time limitations we couldn't get a working tilemap in time for the jam and had to resort to something else. To speed up the process next time, and for others, I've created some tooling to make it easier.

The autotile templates provided with the official Godot documentation on Autotiles aren't easy to use because the guide lines have been baked into each tile, requiring lots of editing using a graphics program (such as gimp). They're usually not at the dimensions required, either. Godot Autotile Texture Templater (GATT) solves this problem by generating templates for use in Autotiles.

screenshot.png

Set your block size and desired base colours and 2 files will be generated for use in Photoshop or Gimp as a base for your own tile art. Or use it right away in a prototype right in Godot.

useemin/emgodot.png

Download and try the tool from itch.io. The open source code repository is linked from the itch.io page as well.

Live Coding Stream @ 3:15pm MST: Building Tile Map Tool for 3/4 down views!

Yesterday I shared GATT - Godot Autotile Texture Templater, a tool for generating templates for autotile tile maps in Godot. Today I'm continuing work on it, implementing 3/4 view tile sets in the tool, and will be demonstrating how to use Godot to paint a tile map with 3/4 top down views.

You can watch the stream starting at 3:15pm MST today (very soon! I'm streaming until I'm tired and can't code any more :D. I'll post a link to the stream recording when done so that if anybody misses it they can still watch it.

https://www.twitch.tv/kwirky88