#Star Child, a pixel art sci-fi metroidvania

160 messages · Page 1 of 1 (latest)

wary radish
#

We've been working on Star Child for a good while, setting up a lot of the basics and figuring out exactly what it is that we want to build. Now we're in a pretty good state and decided it's a good time to start writing updates on our progress as well.

#

Since this is the first time writing, you'll likely want to hear a bit about the studio behind the game, Pale Blue Studios. It's a small indie game studio from the U.S., and is headed by Jay Ingle. Jay does most development, game design, and pixel art by himself, and gets assistance for other things like music, promo art, marketing, and so on. Jay is mainly assisted by Janne Enberg, who has a long history in development and startups. He takes care of a lot of the practical work required like video editing, web development, project planning, version control, builds, store page management, and so on. Janne also assists with some design questions, as well as tougher development challenges as necessary. The music and sfx for Star Child are made by TantrumTech.

And also briefly about Star Child, the game we're working on. The really short version is it's a pixel-art sci-fi metroidvania. The slightly longer version is that we're trying to honor the classics of the genre, while adding our own creativity to the sauce. We want the game to feel fast and fluid, and have just the right level of challenge.

#

Latest update from Jay Ingle - lead developer, designer, and artist:

We want Star Child to be a fun action game. When I look at other fun action games, one of the main things that stands out for me is projectile patterns. These projectile patterns need to be interesting, varied, and they need to provide the player with an opportunity to learn, react, and adapt to different situations. My skill at coding natural projectile pathing is minimal, but with that in mind, I set up a Projectile class, to provide base functionality for all projectiles.

We have one class for projectiles that I can control directly with code, such as projectiles that go straight and do not need to react to the physics of the world. In Godot, these projectiles are easily created with Area2D nodes. For more complex projectile movement, I use the RigidBody2D node, allowing Godot's built-in physics engine to do it's job, handling physics calculations for me.

I created a simple ceiling turret enemy to test my Projectile class, and after a bit of struggle, all is working just fine.

I also created a couple animated fireball projectiles (using the excellent PyxelEdit application), which are combined with other effects such as a glow, a fiery particle tail, and an explosion on contact, in Godot.

I now look forward to pretending like I am creating a bullet hell game, and making cool patterns of fireballs for you, the player, to avoid and overcome!

#

Latest update from Janne - the other guy:

Pale Blue Studios didn't have a lot of the basics in place for communicating with the world, so I've been trying to set up all the basics for that. First needed to set up the domain, then build a basic website for it, a press kit for the game, set up email hosting for the domain, and started collecting a list of industry contacts to send keys to when we are close to launching the game.

Jay already owned the domain, but it had nothing set up on it. I first migrated it to a domain registrar I was happy to work with, and set up name servers for it with Cloudflare due to their excellent service. I then built a simple website using SvelteKit and Pico CSS, and published it on GitHub Pages. Also set up automation so any updates we make to the content get automatically published as well. After configuring the DNS on Cloudflare to point to the GitHub Pages -hosted site, we now had palebluestudios.net up and running.

With the domain generally set up and working, I looked at the current landscape of email hosting services. Wanting a high quality service for a reasonable price that wouldn't make us waste time on manual processes with downloading invoices all the time etc., I ended up picking Zoho, signed up for it, and set us up the accounts and groups we need to operate, and started to update our listed email addresses.

I also took the chance to set up a custom domain handle on our Bluesky account to make it a bit easier to verify it's us, and with these set up I went though the process to ask the Bluesky "Games Industry Labeller" service to label us as a game studio. I also went ahead and found a bunch of relevant Bluesky starter kits for us to follow.

#

Lastly I started to set up some new marketing tools for us, a new account on imgur, as well as a list of game industry contacts. Spent several hours digging through lists of relevant people I already know and follow, wikipedia's list of video game magazines, various searches on Youtube and Bluesky to find the business contacts Youtubers, streamers, game journalists, podcasts, etc. have posted online. We'll want to send these people free keys to try out the game close to the release with the hope that they'll talk about it, make videos, blog posts, reviews, or articles about it and so far we're up to 67 contacts. I expect we'll want to get to somewhere around 1000+ before the launch due to the low success ratio of sending keys out en masse, I read somewhere that 2-3% is a pretty common result.

The domain registration costs us about $10/yr, each email account 0.90€/user/month. The other services set up here, Cloudflare, GitHub Pages, Bluesky, Imgur, and Google Sheets where we store the contact information are all free.

#

We'd be thrilled to hear any feedback you guys have, and we'll continue posting updates here as we get more things done.

wary radish
#

one of my favorite gifs of the game so far

#

oof, the encoding was super bad on that, need to retry with a better encoder

#

ok yeah much better

wary radish
#

Here's the latest updates in the development of Star Child

Jay Ingle - lead developer, designer, and artist:

Lately I've been playing with fireballs again, prototyping the mini challenges I'm trying to build into the game.

For this I used the projectile classes and scenes I set up previously, wrote some projectile spawning logic, and coded some signals so the nodes can tell the turret when they die.

Still working on getting the projectiles pointing the right way, Godot's look_at() doesn't seem to work quite as I expected for this and I might need to write my own logic instead.

Looking forward to creating some cool graphics for this little encounter. Would appreciate any suggestions you might have on visual design. I'm planning on reusing a smaller and simpler version in other parts of the levels.

Janne - the other guy:

I've been working mostly on the little background things, continued setting up accounts, preparing materials, collecting lists of contacts, and planning how we'll find a significant number of relevant contacts before the launch.

Most of my weeks are fairly light on the different types of work, so the updates for my part are going to be typically shorter than on the first one 🙂

wary radish
#

Jay Ingle - lead developer, designer, and artist:

This week I set out to make a bunch of mini-challenges, using my existing enemies and environmental hazards. These little challenges will mostly be hidden in the numerous secret areas throughout the game. I made 10 of these this week, here are a couple of them!

Creating this spikey room made me want to create more levels for my first game (Toleo). Toleo has lots of spikes, and precise platforming. But for Star Child, we are making a less difficult game, so the challenge here is much lower than Toleo. Spikes, as the only challenge in a room, will be very minimal, but keep your eyes open for just a little Toleo-style spikey-hell in Star Child!

I made some rooms with only one enemy type, and some rooms with every combination of enemy and hazard I currently have. I think these crawlers are cute.

wary radish
#

Jay Ingle - lead developer, designer, and artist:

This week I made teleporters. Two of them, working as a pair. I got them working pretty quick. They are fully functional, but limited in a few ways: there has to be exactly two of them, and they each have to be designated as the initial starting or destination teleporter. Since they share a script, and signals, more code would be needed if I wanted them to behave in any other way.

Then I added the visual effects, a red/green particle effect on the teleporter itself: green indicating which teleporter is active, and red your destination. And I think the player shrinking/growing when teleporting works well to sell the effect.

Creating levels with these teleporters is fun, and when mixing together all of the other mechanics and gimmicks I have already, there is no end to the flow of ideas.

Janne - the other guy:

Unfortunately the system we'd been using previously for keeping track of the progress is being shut down, and I've been investigating what options are best for us. I found that Mattermost supports boards, and they seem to be ok - not great, but good enough for what we need. Since I already have a Mattermost server running, I thought it would be a fine thing to start using and I've been migrating our content over.

Also I did some play testing and fixed a bunch of small issues I found with our controls, loading settings, file structure, sound buses, and gathered a list of issues I found overall with the gameplay.

wary radish
#

Jay Ingle - lead developer, designer, and artist:

Allowing the player to rebind controls, using the Godot engine, is complicated and difficult. The basics aren't too bad, but when you get into the details, things get very complex, very quickly. Input events and actions are data structures in Godot, and they are difficult to understand, work with, and debug.

I spent most of this week staring at my controls rebinding code, pondering, considering, what EXACTLY do I want to do with this current code? It almost works perfectly, but it is abysmal to debug. I could take some time to restructure it into a less-confusing mess. I have some good ideas.

In between sessions of looking at dumb UI code, I updated the graphics and effects on some of my environmental mechanics. The new tech style is different from our alien planet organic style, which can make these important objects stand out from the alien environment.

Janne - the other guy:

Jay took a bit of time to finally show me how to use our level template scenes to create new test levels, so I had a bit of fun playing around with them, experimenting with how it all works, and doing some testing. Found a few more things we might want to fix due to this testing.

wary radish
#

Jay Ingle - lead developer, designer, and artist:

This week I made a shootable switch. This switch, once activated, contacts the Global Signal Bus, emitting a signal that opens a nearby door. With a tiny bit of additional code, this switch can be used to signal the activation or opening of anything we wish.

Then I made the door, and connected the signal that the switch sends, to a local function in the door script, which actually opens the door, changes the sprite, and removes the hitbox collision. Just as with the switch, this door is ready to be updated for more functionality, and is able to be opened by any source we want via the Global Signal Bus. Improved door graphics and animation coming soon!

This week I also made some new item pickup graphics. Each area in Star Child will contain a number of secret keys that can be used to access secret bosses, secret upgrades, and all the other cool things you definitely want to find!

wary radish
#

Jay Ingle - lead developer, designer, and artist:

This is my third or fourth iteration of screen shake code for this project. The first couple of attempts worked ok, but were limited, and I didn't have enough options to get exactly the effect that I wanted. The next failed attempt used a shader, and shader code. But the shader code was reliant on zooming the camera in a few pixels, which destroyed the alignment of tiles along the edge of the screen.

Finally, I found some simple code thanks to Queble on Youtube. This code makes sense to my brain, there is no mystery. That means that I can adjust it as much as I want, and I still understand what is happening. The amount of screen shake in this example seems pretty close to what I want.

When I first setup this screen shake, it was shaking the foreground, but not my parallax background. This was happening because I did not have my ParallaxLayers set up under the ParallaxBackground node.

Remember kids, anything under a ParallaxBackground node needs to also be under a ParallaxLayer node, in order to function properly.

#

Janne - the other guy:

I tried to help Jay solve some of the complexity with our input mapping logic, figure out a way to structure the code so it's less fragile and easier to implement and maintain. It seems like we now have a pretty reasonable idea of how to disconnect the InputMap internals from our settings and ensure consistency.

Also one of the last features that hadn't been implemented was our automap, so I started structuring code around making it possible, set up the bindings to show and hide the automap component as a part of our HUD, and then the structures for how to track which levels the player has been to. Added the data to our savegames, and then replaced our level loading logic that was uniquely implemented in a few places with a single function call that can then notify the automap as well of new levels being loaded.

I'm probably going to use patterns in the filenames to determine the shape of the world grid and parse the coordinates in the grid for the level based on the filenames. That'll need some refactoring of our existing test levels to start putting them in a maintainable structure, and once we have the scaffolding in place we'll need to work on the visual implementation with Jay as well.

wary radish
#

oh, good to know! need to look into that 😄

thanks!

wary radish
#

Jay Ingle - lead developer, designer, and artist:

This week I buried myself in code. I have worked with GDScript for about 3 years now, and I finally feel like I have a handle on the basics. The very basics. I am a novice programmer. I can make things work, eventually. This week gave me a bit more confidence though. Even though there are still things that intimidate me, confuse me, or frustrate me, I can see the progress.

I worked through piles of scripts. I reworked badly designed sections, using more enumerators and dictionaries.

I changed every get_node() i found into using a signal or a global value instead. get_node() is dependent on scene tree structure, and should rarely be used. If there is a value that you need in another script, you can make it a global value in an autoload instead. If you need to trigger something, or send some information, signals are perfect. A Global Signal Bus is a great way to store all of your signals in one place, call them easily, and keep them organized.

This was also a time for commenting. If you don't properly comment your code, which I hadn't been doing, shame on you (me). Anyway, welcome to the new era of me commenting my code.

Also I need to put types into all the arguments of my functions. Yep, back to work.

#

Janne - the other guy:

Unlike Jay, I've been programming since I was a young child and also have decades of professional experience in coding and leading software projects. With Star Child I've been trying to slowly introduce better coding practices in a way that doesn't make it too difficult for Jay to work with.

One of the recent opportunities for this was the automap, one of the last completely missing features we had. I had a vision on how to build it based on flexible structures that will allow us to forget the internals of the automap as long as we follow a few basic patterns when building the game.

As an initial target, I wanted the automap to build its own data structures based on the levels we actually have in the game, and the easiest most easy-to-comprehend way to make this kind of "auto-discovery" was based on filenames. Our levels normally go somewhere under res://Levels, and I decided that adding a prefix to the filenames could be used as a grid coordinate system, A-Z for rows, followed by a number for columns. It gets a bit more complicated than that since Star Child has rooms spanning multiple rows and columns in the grid, but not significantly more complicated.

With this target, I decided on the following patterns:

  • B4 = Row B, Column 4
  • A-B3 = Rows A-B, Column 3
  • C4-5 = Row C, Columns 4-5
  • D-E5-6 = Rows D-E, Columns 5-6
#

To keep things easier, I wrote 4 separate Regular Expressions to match each of those cases separately as well as splitting out the rows and columns from it, and then functions to find all scenes recursively under res://Levels, and identify which of them look like a level - having this coordinate at the start followed by an underscore. Once identified, I build a grid of all the coordinates used, and find the min and max ranges for rows and columns, and fill in the blanks. Now we have our basic map as a grid. This script is autoloaded as a global script, and additionally processes the grid into maps of which coordinate maps to which scene, and extracts various properties from the filenames for easy access later e.g. the full path to the scene file and the ranges for the columns and rows.

Next up we needed a data structure for what the player actually knows of the map, so I created a dictionary with the list of current coordinates for the player (as a single level can span multiple), and all known coordinates and added it to our save + load logic. All the logic above is in an automap_data script. To get data into it, I replaced all previous "switch to level" -logic with a single central function, that also calls enter_level with the scene path. This can then be used to again determine the coordinates from the filename, and simply update current coordinates, and add any missing ones to known coordinates. In the end we also send a map updated -signal.

Rendering of this is currently functional but not quite ready. Added a new automap scene with a script attached to our HUD. The scene has a few basic visual elements attached, background image, a CenterContainer, and then a Control with a unique name "MapGrid" for easy access in code. Every time the automap is rendered, it first fetches data from the automap_data, and processes a few lists to make rendering easier:

#
  • List of all non-blank coordinates
  • Available size for each grid cell inside the container, with margins removed, rounded to nearest full pixel, and approximately centered with offsets
  • A map of coordinate to their visual element in the grid

For the visual elements I tried multiple approaches that didn't end up working right, and in the end ColorRect inside a Control seemed to be a reasonable way to accomplish what I had in mind. Each of them needed a custom_minimum_size and then position, and to be added to the MapGrid, but that was pretty easy.

Then after the automap has been initialized, and every time we get a signal that map has updated, we'll refresh the automap. Refreshing simply means taking the current coordinates, known coordinates, and non-blank coordinates, and looping through every coordinate and updating their colors. We default to black color, but if it's in the current coordinates we set it as green, if it's known then light gray, and if it's just a non-blank coordinate we make it dark gray.

This renders the full map and tells you which areas you've visited, and where you are rather effectively. Now of course we'll want to refine the list of which areas we'll highlight that you've not visited, but the structures are now in place.

One last thing that I wanted to update based on this, was our level changing logic. We have a Scene Changer node we can add to areas where we want you to transition to the next screen from, and previously each of them needed the full resource path of the target level. Since we now have coordinates for the levels, I decided that we could just give the Scene Changers clear names like "ToB2" and have it automatically find the scene based on that name, and transition there - so that's what I made it do.

#

Now all Jay has to do is create a new level res://Levels/tests/Z99_some_test_room.tscn and the automap will automatically know where it is and update accordingly, and then add a Scene Changer with the name "ToZ99" and it will work. The one remaining thing we'll want to try out is automatically identifying where the player should be spawned in based on a corresponding Scene Changer name, so if you're going from B2 to B3 with Scene Changer names "ToB3", you'll probably want to spawn in by the Scene Changer pointing to the level you just came from, "ToB2".

To make writing all of this easier initially I wrote logic to just print the map grid and automap state to the console, so just building a string where every empty cell is a space, and then assigning characters for "current", "visited", and "not visited", appending to the string before printing. This made it a lot faster to know when I had logic that was fully functional for the internals without having to worry about the visual glitches on the rendering, of which there were many on the initial attempts.

The background is fully a placeholder and generally tweaking the visuals further we'll post-pone until the full size of the map grid starts taking shape, so we know the final size of the cells, how and if we want to highlight connections between rooms and all that.

wary radish
#

Jay Ingle - lead developer, designer, and artist:

I made my first video game, Toleo, in one year. That is, one year from the moment I decided that it was time I made a video game, until the moment that it was 100% completed. I worked on Toleo for 6 months while working a regular job. At that point, I quit the regular job, focused on Toleo for the next 6 months, and shoved it out the door.

When I started Toleo, my background in programming was very minimal. I learned BASIC when I was a child. I read a book on C when I was a teenager. I took a Visual Basic class, and a programming microcomputers class (in Assembly language) in college.

I knew what a variable was, but I had never actually written a program before. Not to completion, anyway. I also had zero prior knowledge or experience with the Godot game engine that I used for creating the game.

The code in Toleo is bad. But you wouldn't know that unless I told you. It doesn't matter to the player, as long as the game works.

I want to be a better programmer because it gives me more options when working with other people. It also makes game creation faster, and less confusing.

Here is your devlog lesson for today: if you want to make a video game, do not be intimidated by programming. You can make a perfectly good video game with bad programming. You can make a good game with extremely limited programming knowledge. Just do your best to make the code in your next game a little better than last time.

#

Janne - the other guy:

I want to continue a bit on the same theme as Jay, though from the perspective of a very experienced developer. I see constantly people getting demotivated to do any programming because they're not great programmers, and from my point of view all they really have to do is choose things that are reasonably feasible to actually accomplish with your skill level.

If you don't understand how to build dynamic code, you probably shouldn't expect to build a very dynamic game. Start small, use the skills you do have, and build things in a way you know works. It's ok if it's not perfect, if the code is ugly, whatever. Once you get sick and tired of copy & pasting you'll learn how to avoid that, and also why you want to do things a better way at the same time. You'll be motivated to learn, not just forced to learn by some prick who insists you must learn to program this way without an actual purpose to it.

If you don't know what is feasible, ask for help to figure that out, but you can also get some idea based on existing games. If you're thinking of building something similar to a game where the list of credits is very long it's probably not feasible for you if you have to ask.

Start small, and if you want to stay motivated find a way to build on successes, instead of failures. Learning to finish projects and ship them is a difficult thing as well, and it's best to learn on small projects.

Now on what I've been working on - last time I shared a bit about the internals of the automapping, next I worked on our release system. I like build and release automation systems, so I knew I wanted one for Star Child a long time ago. Initially I set up one that can download Godot, the export templates, and then run Windows + Linux builds and upload them to cloud storage for when we want to share them manually. Now I think we're getting close enough to wanting real feedback from a few players so I also wanted to have Steam releases working.

#

Took quite a bit of setting up with Steam's partner interface being a very clunky mess, but now we've got things working rather well. When Jay or I push to our Git server, automation starts the build. After the build completes, it checks if the changes were pushed to the "beta" branch or something else - if on "beta" branch we use steamcmd to release it to the beta branch on Steam, and if anything else we release to "latest" branch on steam. This way we can always get the latest changes easily tested for anyone, we can easily release a controlled state to beta, and we still need manual confirmation to publish anything to the default branch that people will install when buying the game.

The "SteamPipe SDK" which you need is a pretty awful creation and is distributed in a rather stupid manner, but distributed it are "ContentBuilder scripts", which are the various .vdf files you need to set up for steamcmd to upload your game correctly to Steam. Check the examples, they are largely nice, however debugging issues with it is incredibly annoying as the errors you just get are short non-descriptive errors like "Failed" instead of explaining what is wrong.

We set up 2 depots for the game, one for the Windows build, one for Linux+SteamOS, and before running the upload script I ensured we had a separate folder with the ready build in each available. I pointed the ContentRoot, and FileMapping paths to the correct places, and set up the AppID and DepotIDs correctly and after some trial and error I ended up getting it to work.

#

One of the annoying things is that the upload happens with a logged in Steam account on steamcmd, so you have to have this Steam account login information somewhere, and ensure your build server can log into it. In practice for me this meant manually logging into Steam on each of the build agent machines, because Steam insists on sending some login verification code over email to it. Also you'll want a separate unique Steam account with only the necessary permissions for it, which Steam explains in their uploading documentation (at the moment "Edit App Metadata" and "Publish App Changes to Steam").

If you're comfortable with DevOps work this scripting wasn't significantly more difficult than most release pipelines, but the dependency on these poorly documented tools with some weird configuration file formats, poor error messages, etc. definitely made it unnecessarily complicated. If you're not comfortable with DevOps work I can see this being rather annoying to do reliably, you'd probably end up doing it on your own computer, manually, when you feel like releasing something.

I've been pondering if at some point I should release some of the scripts I built for building and releasing Star Child, but a lot of it depends on tools I install on my own build agents, and many of the scripts are very opinionated, so it's probably not going to be directly usable by anyone else anyway. Also I'm not particularly interested in trying to maintain some repository of Godot release tooling for others to use, as I can expect it to spiral out of control with people wanting it to support everything imaginable under the sun.

Either way, right now I'm pretty happy with what we have. It gives us easy stress-free releases, and sufficient control over what is released to whom and when.

#

One last thing to add - Jay worked a bit on the new structure for the "start game" menu, and I helped with some of the logic for it. Here's a sneak peek of how it looks like - very much placeholder visuals, but way more usable.

wary radish
#

Jay Ingle - lead developer, designer, and artist:

If you were designing a video game, and you wanted to create a world with a lot of secrets to find, what would you put inside those secrets? What incentive do you give the player for spending time searching for secrets? If you have a lot of different systems like currency, items, health, ammo, and weapon upgrades, this is not a difficult question to answer.

Star Child is not a game that has a lot of systems. I prefer focused experiences in games I play, and games I create. We strip away all of the extra junk and find the core fun experience. Developers often create content by adding collectibles, or bits of lore inside their secrets. Collectibles and lore do not sound like a core fun experience to me.

As you traverse the world of Star Child, you will come across doors that require certain keys. If you have the correct keys, the door opens.

And if you do not have each of the specific keys to place on these altars, you shall not pass.

There are a variety of things hidden in the numerous secret places in Star Child, but the most common are secret keys that open secret doors. I can't tell you what is behind the secret doors. It is a secret.

wary radish
#

Jay Ingle - lead developer, designer, and artist:

Last week I talked about creating a Door that will open if the player has collected the appropriate keys. We have the Door object, and also the Key Altars, which activate themselves, and display their key, if it has been collected. If the Door then acknowledges that all Key Altars have been activated, the Door opens.

When I try to think about how I would have handled coding this situation in the past, it hurts my head to even work through it. Thankfully, I have improved a little.

Initial setup needed: Add Door to a scene. Add all Key Altars into a parent node, and set that parent node as the Key Altar Container in the Door's corresponding exported property. Also set which key each key altar needs, in their properties.

No further setup needed. Can setup be simplified even further? Maybe a tiny bit. But I definitely need to set which key corresponds to which altar. And I feel that dragging the Key Altar Container node into the exported property on the Door isn't too much trouble.

At run time, each Key Altar checks the player's current inventory, looking for its match. If it does, it shows the key, and sets Activated to True.

The Door then uses the Key Altar Container to set up an array which contains all of its children nodes, then checks each one to find out if Activated is True. If all Activated in the array are True, the door opens!

I don't feel that this code is perfect. I don't feel like it is the BEST way to approach the situation. But I am happy with it. Feels like I am using the tools available in a decent manner. Feels like progress.

My apologies if some of this language was too Godot-specific for the casually interested observer!

wary radish
#

Jay Ingle - lead developer, designer, and artist:

I have done a lot of research into 2d platformer game structure lately. I found 3 primary types of game structure in sidescrollers.

  1. Level Select. These are mostly old school, or very retro-inspired games, where you choose your level either from an overworld (Super Mario World), or from a simple level select screen (Mega Man, Super Meatboy). These are mostly linear, but you are often given some choices in your path.

  2. Pure Worlds. Every modern Metroidvania plays it straight. You are put into the world, and ALL mechanics are inside the world itself. A level select screen is from a VIDEO GAME. This is not a video game, this is a REAL WORLD. No video gameyness here.

An alternate version of the Pure World is where you have a hub area that you move around in, like a more interactive overworld level select screen, that your character can freely more around in. Hard to think of examples right now but uh, Quake 1? This is the same as a level select overworld, but presented as part of the actual game world itself.

  1. Roguelikes. Randomized dungeon runs. Often with an in-world hub area where you shop and prepare for the next dive (Dead Cells).

The plan for Star Child from the beginning was for a Pure World. Your standard Metroidvania world. Somewhere between Metroid and Super Metroid in terms of complexity. This is a crowded genre. How can 1 indie dev compete with the giants of indie platformers? If I try to do the same, Star Child will only end up being a less-good version of bigger games.

When I recently started serious level design for Star Child, ironing out the flow of the experience, the game really started letting me know what kinda game it wants to be. Star Child wants to be a fast, fluid, action platformer. But Star Child does not want to be a pale imitation of giants. Star Child wants to subvert, surprise, and delight.

wary radish
#

Jay Ingle - lead developer, designer, and artist:

This week, we got a Star Child first playtesting build ready to be played by people other than myself and Janne! Does that mean the game is nearly complete?! No! But here are some screenshots to keep your appetite thoroughly wet.

This week, I created a mini-episode, including most of the enemies and mechanics that we have so far. There is still some placeholder art, but everything functions! (And you really want that key).

The episode can be started from the main menu. You can save the game. You can load the game. And you can finish the game!

So we have a functional video game. Now we just need to make more of it, and make it more fun!

wary radish
#

Jay Ingle - lead developer, designer, and artist:

Last week I worked a bit of overtime to get our first playtest build to a state of functional and fun. I got to slow down some this week, and make some cool new stuff; including mechanics and graphical adjustments for a new, spicy, environment.

Welcome to Fire Mountain. Have some breakaway blocks, and rising pillars.

And I also updated the rocket graphics. Now with spinning action!

Stay tuned for more cool new stuff.

wary radish
#

Jay Ingle - lead developer, designer, and artist:

First, there was Purple Alien. This is the environment we have shown in most of our screenshots and videos to this point. Our task was to fully create ONE of several environments in the game, and besides a bit of art still to do, everything is functional and not a huge step away from release-quality.

The Purple Alien environment includes a purple tileset for walls and floors, several types of plants, mushrooms, and rocks, native enemies, and a few environmental hazards/mechanics. The Purple Alien environment also has its own background, and music track.

This week my task was to create the next environment, which I have dubbed Fire Mountain. A simple palette swap works for the base tiles, since this is also a rocky-type environment. Hue-shifting my starry sky background to a nice yellow seems to work well.

As for the local flora, a palette-swap of the Purple Alien plants does not seem appropriate for this hot place. So, I created plants that hopefully appear to fit into this area.

Some good news is that I don't have to rewrite code when it comes to having these plants animate whenever they are brushed against in the game. I could have one single plant object that changes to a different type based on environment, but since this is a different plant, which will be used in a different place, I choose to make it a separate object.

For environmental mechanics, so far we have pillars that rise when you shoot the appropriate switch, and blocks that crack and then break and fall away when you step on them. I showed these in the previous devlog. I will also add lava tiles, you have to have lava in a Fire Mountain after all.

And enemies. I have ideas, I have sketches, and it's time to get back to work. Come back next week to see what fiery bitey things will be chasing you all over FIRE MOUNTAIN!

#

Janne - the other guy:

Lately I've been doing a lot of things outside the game itself, e.g. setting up our official community Discord server with clear rules, roles, channels and all that, as well as preparing all the things needed for playtesting to start. Requested our playtesting keys from Steam and set up tracking for which ones we've used already, wrote guides for how to get the testing done and what kind of feedback we're looking for, and coordinated with Jay to ensure that we have a nice amount of content for people to test. It's still early stages though so the content is just a small fraction of what there will be.

I also got to experience the joy of previous good habits paying dividends when I fixed a bug with some character state not being saved correctly being fixed essentially with 3 lines of code in the same file with the state. The really nice thing here was that it was really easy to find the relevant code after not having touched it for months. Another potential complaint was that we might not be fully resetting character state when starting a new game, and a likely solution took only 2 lines.

wary radish
#

Jay Ingle - lead developer, designer, and artist:

Sometimes I wonder what this devlog should be about. Is this a bullet-point list of what I have spent my work hours doing this week? Do I really want to tell you everything? There needs to be surprises!

Sometimes I feel like talking about broader issues in independent game development. How do you learn to code? What tools do you use?

Sometimes I want to talk about more personal things. Motivation, inspiration, work ethic.

I did a lot of things this week. I spent time working on automatically adjusting particle effect colors for new environments. I created some lava for you to fall into. I created an enemy that rises up out of the lava and spits at you. I also added the ability to switch the music to the next song by hitting a hotkey, for me and the playtesters as well. I also installed a Godot plugin, called G.U.I.D.E., which handles input. Remapping keybinds in Godot can be a massive pain, and G.U.I.D.E. does a great job at providing a much simpler framework. It also has full documentation, as well as several video tutorials on Youtube, created by the developer. Highly recommended.

This week, I studied a lot. If you are looking for the best overall pixel art course that I have found online, check out Pixel Art Master Course on Udemy. It's very thorough and helpful. I spent time reading a game design book called Level Up! by Scott Rogers. It is very good at breaking down all of the details of game design. I read Beginning Game Development with Godot (2021). I did not learn much. I am not THAT much of a beginner. I also read some of a French comic book called "The Obscure Cities" and the mysteries in the stories are very much inspiring my subversive creativity.

#

Here are some tools I use for game development. The Godot game engine. Very nice, open-source, constantly being updated, and learning resources are abundant. Pyxel Edit. This is the best tool for creating tilesets, period. It is not as fully-featured as Aseprite, lacking powerful features such as custom brushes, but for simple pixel art, tilesets, and animation, it is extremely useful.

Now how is my personal game development journey going, for me? Well, I am motivated. This is my dream job, since I was a little kid, and I have a huge drive to create worlds, craft stories, and provide unique experiences to players. I want to create games that are infused with my own personal creativity.

Once upon a time, I watched Twin Peaks season 3. I thought it was the single most uniquely creative visual project I have ever seen. Everything single moment of the show was pulled from the depths of David Lynch's creative mind. And I was ashamed. Why am I not putting ALL of my creativity into everything that I am doing with my life? I remember this moment, and I continue to work to release the unique vision that I have inside.

wary radish
#

Jay Ingle - lead developer, designer, and artist:

Let's say you want to make a video game in the Metroidvania style. You have a large amount of reference material, but how do you make your game unique? One way is to use The But Technique. Here's how it works.

In the original Metroid, there is a seahorse-lookin thing that rises up out of lava, and shoots at you. Like this:

So far, all we have done is copy what Metroid did. Now let's apply The But Technique. We have a seahorse-lookin thing that rises up out of the lava and shoots at you.. BUT... but what? But whatever you want! How about... a seahorse-lookin thing that rises up out of the lava and shoots at you, BUT the projectile is massive.

Now we have something much more interesting, and even unexpected. This was just the first thing I thought of. But ideas are easy when you just let them roll out of your brain:

A seahorse-lookin thing that rises up out of the lava and shoots at you..

BUT... the projectile is massive.
BUT... the seahorse rises all the way out of the lava then shoots in all directions, then explodes.
BUT... the projectile is an enemy that hits the ground and starts hunting for the player.
BUT... the projectile is a planet.

Apply The But Technique by brainstorming a list of a bunch of random alterations to the original idea, unfiltered and straight out of your own personal unique creativity. Then pick the best ones and try them out!

Now I don't remeber the first time I heard about this technique, or even what it was called then, but shoutout to Dev Worm on Youtube for reminding me of it (Dev Worm has good tutorials for Godot beginners).

wary radish
#

Jay Ingle - lead developer, designer, and artist:

Godot has a neat AnimationPlayer node. It can do just about anything you can imagine. It can even call functions located in other places, so the power is nearly unlimited.

When I first began using Godot, and I needed something to happen at a certain time, I would use a Timer node. Then I would set up an AnimatedSprite2D node for the animations. Let's say I want a hitbox to be enabled at a certain time during an animation. Well we can start the Timer and the animation at the same time, and then when the Timer finishes, we enable the hitbox. Then when the animation finishes, we can start a different timer that will restart the animation.. and restart the other Timer... and hopefully you can see how this quickly becomes complicated, even for something simple. The other problem is that the animation is not exactly tied to when the hitbox is enabled. It SHOULD be synchronized, and if I have set my Timers correctly, and animations are a certain length, then things will be synchronized, but will very easily break. Any change to any component will destroy the timing. AnimationPlayer nodes remove all the guesswork, and tie things together real nice.

In the first image with the flames we have added sprite frames from a Sprite2D node, and we call functions enable_hitbox() and disable_hitbox() at specific times. We have a nice visual where we can see which frame is shown at the time of those function calls. We could easily set this to loop, but at the end of that timeline I am calling start_timer(), which is how long until we restart this animation again, because I want a little more control of how long the flame is inactive.

In the second image with horizontal particles we can see that you can even keyframe aspects of a particle system. We can change colors, increase or decrease amount of particles, and many other things.

#

If you are new to Godot, and you are using AnimatedSprite nodes, I would advise switching everything to Sprite node plus AnimationPlayer instead. Especially if you are not too familiar with animations and keyframes in general. AnimatedSprite nodes are very simple, very basic, and do their job well, but AnimationPlayer nodes are much more powerful, and will save you a lot of time and effort. Let them do the heavy lifting!

wary radish
#

Jay Ingle - lead developer, designer, and artist:

This week, we are going to take a look at how I create an enemy for Star Child, from start to finish. Minus the graphics; I prefer to prototype and get it working first, then refine the visuals. This week I will talk about the nodes that I need, and how each are set up. Next week, I will talk about the code.

Here is our finished product, with placeholder graphics:

#

Here is what we can see in the editor. Note our node structure on the left side.

#

You may also notice that not all of my nodes are named very well, but that is not a big issue, since we will be using well-named variables that reference each node, in our code, as you can see here:

#

Our root node is an Area2D, which I like to use for enemies whenever they do not need to engage with the physics engine. Area2Ds can be moved around directly with code, or using an AnimationPlayer. We will be doing both.

We are using a Sprite2D node for the graphics:

#

A simple spritesheet contains each frame. You can see under the Animation heading on the right that this spritesheet contains 8 horizontal columns, and 1 vertical row. These frames will be accessed and animated by the AnimationPlayer.

I have created a Marker2D node, which marks the spot where our lava bombs will be spawning from:

#

Here is a look at our AnimationPlayer node:

#

We have two animations: 1 for Walking, and 1 for Firing. Our Walk animation autostarts when the scene is loaded, and our Fire animation starts whenever our cooldown timer finishes. This is what happens during the Fire animation:

First, you don't see it here, and I will talk about it more next week, but the enemy stops moving. I stop the enemy, then the animation is played, which means the enemy sits there for 1 second before beginning the actual firing animation. This telegraphs the attack and lets the player get out of the way.

Second, the attack animation begins, and halfway thru the attack frames, fire() is called. This spawns the lava bomb, and the details of how we spawn that bomb will be discussed next week.

Finally, at the end of the animation track, we call start_walking() again.

A few other nodes of note:

I am using four raycasts to detect walls and floors, and tell the enemy when it is time to turn around. For previous enemies I created, I just used two, and had them switch sides when the enemy turned around. I thought using four would be simpler, but to be honest, this way introduced another possible bug that I did not like. I resolved it, but I think in the future I will be doing it the previous way.

FireCooldown timer controls how long before the enemy fires again.

TurnAroundTimer fixes a possible bug where the enemy gets stuck turning around over and over. This might be solving a problem with the two-rays system that I'm not using here, but it has become somewhat of a standard thing I do for this type of enemy.

TimerDeath starts whenever the enemy is destroyed by the player. It waits a couple seconds then removes the enemy from the world. We cannot immediately remove the enemy, because then you wouldn't see the graphical effects that occur immediately upon/after death. More on that next week.

We also have a CollisionShape2D node, a ParticlesExplosion node, and a few Audio players.

#

And that is our basic node structure for this enemy, tune in next week and we will dig into the code and see exactly how everything works!

Janne - the other guy:

One of the things I had to change was a bit of the internals of the automap system. Previously I built it with the plan that we'd be building one large connected map, with individual levels identified by coordinates with A-Z for columns and 1-99 for rows. The plan changed and instead we wanted to support multiple zones with their own coordinate system.

What I decided on was that I didn't want the automap rendering part to know about any of this, so the data structures I had in place already for rendering shouldn't change and I would just change the values as necessary.

The initialization logic became a bit more complicated as I needed to initialize the structures for each zone, and determine the coordinate and zone from the file path, but in the end it didn't take very long to change. I already called a function in the automap data manager when switching levels, and now that function also checks if the zone is changed and switches the data structures given to the rendering layer to the correct zone.

Save structure also changed to support saving known coordinates for all different zones, but that was relatively simple as well since we're clearly in a pre-release state and I didn't have to care about supporting the data in the old save files, so instead I'm just throwing away the automap state in the old format.

wary radish
#

Jay Ingle - lead developer, designer, and artist:

Last week we took a look at creating a new enemy, setting up our nodes. This week we look at the code itself. If you want to understand more about creating this enemy, make sure you have read last week's devlog. Here is our finished product, with placeholder graphics:

#

We setup some variables here:

#

We need to preload the projectile that the enemy fires, so we can instance it later. We have walk speed, a control variable for when the enemy is walking, and one for when dead. I also setup an enum for left and right, since i prefer DirectionType.LEFT rather than the magic "-1", even though i know that -1 means left in Godot coordinates, this is more readable and less error-prone. Dir.LEFT would probably be an improvement, but I have not standardized what DIR means to me yet, it could mean a few things. So when it doubt, spell it out.

Our ready function, which is called whenever the enemy is first loaded into the scene, sets our first fire_cooldown wait_time to our exported first_delay variable (which we will see later), and starts the cooldown.

Main process and switching direction:

#

The process function is a built-in function that is called by the engine every frame. Since this Area2D root node enemy will only be moving left and right, we can use Godot's built-in global_transform for walking back and forth.

Make sure control variable walking is true, make sure dead is false, and away we go. We make absolutely sure to multiple by delta, because if we don't, a higher frame-rate would mean that the enemy would move faster!

Next we check the raycasts that are checking for the absence of floor.. ceiling actually.. cause it's upside down sorta..... There is no ceiling in Godot, floor is based on gravity direction.. but I digress. If there is no more ceiling to traverse in front of you, turn around. Then, if there is a wall in front of you, turn around.

We have a turn_around_timer that only lets us turn around once, until the delay is finished. Imagine the enemy reaching a wall, turning around, but it isn't far enough away from the wall on the next frame, so it detects the wall again, so it turns around again, and becomes stuck in a loop of turning around forever. The first time I encountered this issue, it wasn't happening for me, but it was for Janne. Reason? My monitor was 60Hz and his was 120Hz. The enemy had time to get away from the wall on my slow refresh rate, but was too quick on Janne's!

I also set the turn_around_timer to autostart, because the enemy was turning around on it's own at the very start of the scene. I finally figured out that the enemy was loading in before the ceiling. So it detected no ceiling next to it, so it turned around. Must be careful of raycasts that are set to detect something that might be loading in later than expected.

This devlog is longer than expected so... tune in next week and we will talk more about how this enemy works under the hood!

tiny sonnet
#

Good job, friend! It looks really retro, and I like that.

wary radish
#

Janne: Seems I forgot to post the updates from last week, sorry, I'll just update them here at the same time for a longer post!

Jay Ingle - lead developer, designer, and artist:

Let's continue on creating the Lava Bomber. Here is our enemy and its behavior, with placeholder graphics:

#

First, we can take a look at some exported variables:

#

@export just means that we can adjust these values directly in the editor, per enemy, rather than having to go into the code itself. Knockback strength and damage_dealt are self-explanatory, other than the fact that this damage_dealt is how much damage the player takes when running into the enemy, not the damage from the actual lava bomb the enemy is dropping. first_delay lets you set how long the bomber initially takes before firing, from the moment the scene is loaded, per enemy. If we did not have this value, every bomber would fire their first shot at the same time. This can look unnatural if there are several on the screen.

#

The above code is several signals that are built into Godot's nodes. the first _on_body_entered(body) performs its code whenever a body enters the hitbox of the enemy, such as the player, which is a CharacterBody2D. What can be detected by this hitbox is specified by collision layers. I have specified that nothing except the player, or the player's attacks, can interact with the enemy's hitbox. So we can check if the player is the body that has entered, and if so, damage the player. Otherwise, it must be an attack from the player, and thus run the appropriate code, i.e. setting dead to true and running explode_and_die(). Some of the player's attacks are actually bodies (such as RigidBody2D), and some are areas (Area2D), which is why we need the _on_area_entered(area) signal at the bottom as well. Godot also has convenient groups we can add things to, and check things against, and I have one called "attacks" that all player attacks are in.

The middle signal is called when the death timer times out. The death timer is called when the enemy is killed, which allows time for death effects and such to play out, before the node is completely removed from the scene. queue_free() = remove enemy completely right now.

#

Above we can see how we damage the player. First of all, this should be in an enemy class script. And it is! But here is the problem: Godot classes are tied to node types. They can only extend a specific node type. Let's say I have one enemy that has a root node of RigidBody2D, and another enemy, such as this one, that has a root node of Area2D. Well, these enemies cannot be part of the same class. I have tried making the root node the same for all enemies, but Godot doesn't like it when you try to do physics on a node that is a child of something that does not have physics interaction. As in, I tried to make every enemy root node Node2D, and have a child that is the RigidBody2D for physics. This does not work, as far as I know. So make every enemy a RigidBody2D? Then I would have to write specific code for every enemy that is a RigidBody2D that does not need to interact with physics, just to stop it from interacting with physics. Another idea is to have 2 enemy classes. One for one that uses physics, and one for enemies that don't. But then I would have 2 of the same exact script. And I would have to remember to update both anytime I wanted to update one of them. This is not good. So, for now, I have an enemy class script for enemies that interact with the physics engine, and enemies that are of the Area2D type, they have all of their own code. I do not like any of these answers, but this way is the one I'm least likely to mess up, over the course of the project.

And second of all, this should not even be in an enemy class, damage_player() should be in the player script. This caused problems that I cannot even remember. So here we are, let's not work on fixing something that works already. Do it better next time. Explaining the details of this function isn't important for talking about this enemy, so let's move on.

#

_on_fire_cooldown_timeout() is called when it is time to fire a bomb. As long as the enemy is not dead, wouldn't want a dead enemy to be firing at you. After that is a solution to a problem. Currently, if the enemy reaches the edge of the ceiling, he turns around. What if he reaches the edge, and it also just so happens to be the time to start firing a shot? Well he might be turning around the entire time he is firing a shot. And if so, where the merry-go-round stops is anyone's guess, he might just walk off into thin air. So he will only fire a shot if he is not too close to the edge. Now, the tradeoff for this fix is he can skip a cycle of firing, doubling the time between shots. This is rare, and the player will surely not even notice.

The last line: animations.play("fire") is important of course. It not only plays the visual animation, but it also calls the fire() function, and the start_walking() function.

#

Our fire() function is a standard method of instantiating a scene in Godot, which means I am adding a preloaded scene into this scene (lava_bomb variable holding this preloaded scene). I do this to add the lava bomb into the world, at the right time. I have also added a Marker2D node in the enemy scene, which gives us an easy way to say where exactly to spawn the bomb.

At the end of the "fire" animation track, it calls start_walking() and the cycle continues.

At the bottom we see the explode_and_die() function that was referenced previously. It starts the death timer, disables the hitbox collision, makes the enemy invisible, plays the death audio sound, and shows you some particle effects. If we just did a queue_free() to delete the enemy the moment it was hit by an attack, it would instantly be gone, and you would not hear the audio, or see the effects. So we gotta give it a couple seconds to finish its work, and then delete when death timer completes.

We are nearing the end of this story, but we have at least one more week to talk about this guy. Specifically, we need to talk about the lava_bomb that is being added to the scene when the enemy fires. This is a completely unique scene that we can take a look at. So tune in next week! (right below)

#

Jay Ingle - lead developer, designer, and artist:

Hello, this will be the final in our series examining the ingredients that make up our Lava Bomber enemy. See the past few weeks for all the rest.

This is our completed enemy, with placeholder graphics:

#

Today we will be taking a look at the lava bomb itself, that the bomber drops on your head. In the last devlog, we looked at how the lava bomb is its own scene, and how we instantiate it at the proper time, in the proper place. You can see that code here:

#

But for now, let us take a look at the node structure of our lava bomb scene:

#

We have our root node, which is a RigidBody2D (extended class: RigidProjectileClass, but we will talk about that later). We have an unused collision shape simply because Godot will complain if we don't have one directly related to our RigidBody2D. This has no layers selected, so it will not interact with anything else. We have our AnimatedSprite. We have an Area2D that we use for detecting the player's hitbox, as well as detecting when it hits a wall/floor. If we were to use the RigidBody2D to detect the player's hitbox, then the RigidBody2D would push the player, in Godot's physics engine. We only want the projectile to damage the player, not influence their position (beyond a bit of knockback). But we still want to use a RigidBody2D node, since this gives us access to the physics engine, for other reasons. A standard death timer, which we explained the functionality of last time. An VisibleOnScreenNotifier node, which will allow us to detect when the projectile has gone off-screen, so we can remove it from the game accordingly. And finally, a particle explosion when it hits something.

Unlike last time, when we talked about NOT having multiple classes for enemies based on their root node, we do have a class for each type of projectile. This is because each type of projectile essentially acts very similarly, and it is easier to keep these things in mind. Whereas, enemies can have all kinds of unusual behavior, and it is harder to keep track of classes in this case (entirely due to Godot's way of handling classes).

Here is our entire lava bomb script:

#

The power variable at the top controls how strongly the projectile is going to be pushed by the physics engine, upon spawning it. The _ready() function is automatically called when the lava bomb enters the scene. Because we are extended from the RigidBody2D node, Godot gives us an apply_impulse() function that we use to push the projectile in the direction we want, with the amount of power we want. So, lava bomb is spawned in by the lava bomber, then the impulse is applied, pushing the bomb downward, at which point the physics engine takes over, gravity is applied every frame, etc.

We talked about body_entered signals last time, this is much the same. We do not have to create the explode_and_die() or damage_player() functions because they are already in our RigidProjectileClass script.

Well that is about it for the Lava Bomber enemy, and the Lava Bomb it spawns. Perhaps next time I can show you the graphics that will actually be in the game.

If you have any tips, advice, or ideas about any of the last several devlogs, please do post them. I am well aware that I am not the most experienced programmer, and I often stumble around blindly, learning the quirks of the Godot engine. But even if my methods are not the best, I make em work! Nothing more important than that.

wary radish
#

Jay Ingle - lead developer, designer, and artist:

The last few devlogs were spent talking about the scene construction and coding of an enemy. This week, we can finally show the actual graphics, rather than just placeholder art.

Here is our lava_bomber, whose name does not seem to fit so well anymore, but alas:

#

So you see particles circling the prongs. This is actually a trick I thought up. I was originally going to make particles coming from the left, and then some coming from the right, giving the illusion of a sort of bar of electricity. I got the particles going one way, then I thought about making them appear to circle. There is no circling. I have one particle effect on top, the bigger particles, going one way. Then I added another particle generator a bit lower down, with smaller particles, going the other way, and voila, it looks like they are circling! It's not a magic trick; it's an illusion.

I also put some graphical work into our lava_spitter, as you can see here:

#

I am trying to make some of my enemies, or environmental hazards, into robotic creatures. This is for standard consistency, but also the grey colors can be used in any environment. I'm not completely happy with the trail of particles that follows the projectile, but I have some ideas on how to make it better. It should probably appear to be more attached to the projectile, rather than falling behind it, similar to what you see above with the bomb that the lava_bomber drops. The enemy itself could use a bit of animation as well, perhaps circling particles similar to the lava_bomber, or some movement of its prongs.

In other graphical news, I have put some effort into making our Laser weapon look cool:

#

The original idea was a weapon that felt similar to the laser shotgun from Helldivers. It has morphed into a sorta of lightning whip/energy dagger/Half-Life inspired beam weapon. It is a quick animation, so I only have room for a couple frames, but I think I got a decent progression there. It looks to my eyes like it is somewhat extending as it is being fired, and the particles really sell the energy effect. I liked how it kinda looked like a dagger, so I adjusted the weapon base itself to look more like a sword hilt. Almost an Arabian flair. We will couple this with a weighty buzzing zap sound effect, and I think it will feel great to destroy enemies with!

Thanks for reading, and come back next week for more!

wary radish
#

Jay Ingle - lead developer, designer, and artist:

Hello, this week I will show you a deer. This is a deer that will run back and forth, pausing occasionally. If it detects the player, it will rear up, form a ball of energy between its antlers, and then fire a laser beam at you. I want to make this a small deer, a bit unassuming, with quite a powerful attack. I want the animations to be good, but to not be too natural. Not aiming for organic perfection, or too much cartoonish gesturing. The vibe should be 8 or 16-bit low frame count, and a bit awkward, slightly unusual.

#

This is Pyxel Edit which I use for my basic pixel art, tilesets, and animations. I use Aseprite when I need to use more powerful features, but Pyxel Edit works great for most simple things.

Step 1 for creating deer animations is to look at a deer running. I found a 9-frame deer running animation sheet. I chose 4 keyframes out of these, the most important frames during the run, needed to fully express the motion. I drew the deer himself, I always start with two-tone as you see here. A medium base color, and a darker color to indicate the limbs that are further away from your view. After a good bit of fiddling with it, here is our result. I am content with the basic animation flow.

#

Our deer needs a sort of idle animation, this will occur whenever the deer stops running for a moment, and perhaps also as a cooldown after firing his laser. Gives him a little personality, a little variation, and gives the player some timing.

#

And finally, attacking. Deer rears up and fires a laser at you. Deers don't rear much, like this anyway. This is no ordinary deer.

#

Stay tuned, next time I will show the finished graphics, and soon after, the deer in-game, in-action, in-all its glory.

(editor's note, this whole thing was supposed to be posted a week ago, oops)

#

Jay Ingle - lead developer, designer, and artist:

Last week we took a look at how we created some basic animations for an enemy deer. This week, let us compare the basic animations with the more-polished ones. I guess I don't have a lot to say about this, let me know what you think about the art and the colors! And tune in next week to see this completed deer, running around in the actual game. I will discuss the design of the mechanics, and possibly talk about some of the coding involved.

Running:

#

Idle/Reset:

wary radish
#

Jay Ingle - lead developer, designer, and artist:

Today let us take a look at the mostly-finished deer enemy that we have been discussing in recent weeks.

When left on its own, the deer will run back and forth for a random amount of time between 3 and 5 seconds. When this timer ends, the deer will stop for a moment and play its Idle animation. Then it resumes running, again randomizing the running time.

#

As for the gameplay design of this deer, my idea was to have an enemy that, when it detects you, raises up and shoots you with a laser beam. The raising up action will be the telegraph to the player that the attack is coming.

#

Here we have the Attack animation that plays when the deer detects the player:

#

The first track plays the correct animation frames, at the proper speed and timing.

The second track calls functions that show the particles that appear around the laser (these do not show in the animation editor for technical reasons, but they do show in-game), and also at the end, calls the function that causes the deer to play its idle animation before resuming running around. However, if the deer still detects you after shooting at you, it will fire again.

The third track causes the actual laser sprite to fade in, and fade out.

And finally, the fourth track enables and disables the hitbox of the laser, allowing it to damage the player.
You can avoid the attack by either running away, or by crouching.

#

So if the deer does not detect the player after attacking, it will play its Idle animation and then resume running. However, if you are crouching in front of the deer, it will skip its Idle animation, and go straight into trying to run into you.

#

It is this decision that I believe completes the design, and makes this an overall interesting enemy.

Thanks for reading!

wary radish
#

Jay Ingle - lead developer, designer, and artist:

Today we can look at a new environment in Star Child, I call it Fire Mountain! I'm pretty happy with my weird alien plants, and their subtle animation when you touch them.

#

You can see below a decent example of the type of combination-ability platforming you will need to utilize to get those upgrades! We also have animated lava, some random lava particle spray, and some fireballs.

#

I can't show you every environment before release, but hopefully this will wet your appetite for more!

wary radish
#

Jay Ingle - lead developer, designer, and artist:

What happens when you die? I don't know, hasn't happened to me yet.

However, I have died in plenty of video games. What happens when you die in a video game? Dark Souls says "YOU DIED" and lets you press a button to continue immediately. Symphony of the Night makes you wait a long time, plays an unskippable cinematic, then takes you back to the memory card screen, and then lets you slowly load your saved game. My first game Toleo says "UNFULFILLED" and does nothing else, it just waits for you to press the respawn button. A lot of retro games just fade out back to the main menu.

So what do we want to happen in Star Child? So far, I've had nothing set up. Well that's not true, I put a 5 second countdown screen with the game over text from Friday the 13th NES, which then booted you to the main menu, and greatly annoyed my playtesters. That joke was dead very quickly, so then I set it to autoload the last save game, a few seconds after dying in the game. Now I've finally set up a proper Game Over/You Died screen overlay. Complete with placeholder font and button.

#

Let us look at the simple way we make this happen. First we set up the nodes we will need, adding them to our HUD scene.

#

We need a ColorRect, which is set to be a black square that covers the screen, starts invisible, and is faded in, to dim the screen. Very important: we have to go into the inspector for the ColorRect, then change Mouse mode to Ignore:

#

It defaults to Stop, which means that, even when invisible, this ColorRect will be in front of everything else, and you would not be able to click on anything behind it. This can be quite a tough bug to diagnose, but thankfully the Godot debugger has a very helpful Misc section which shows the last Control element that has been clicked on.

#

We also need an animation player, a label to display our You Died type message, and a button to continue the game. Let's take a look at our animation track.

#

The top track causes the screen to dim by fading-in the black square ColorRect. The next track fades-in the You Died message, a little delayed so the dimmed starts first. The next track keeps the button invisible, until it blinks into visibility near the end. And at the same time, the final track calls a method that enables the button and grabs focus.

So, when the player dies, it starts a death timer. When this death timer times-out, it sends a signal that calls the game_over() function. This function just starts the game_over animation, which handles everything else. Note: I added enabling the button, in the top function, after taking this screenshot. And finally, the bottom function is a signal connected to the Continue button, which loads your previous save game.

#

This is all pretty simple to implement thanks to the power of Godot's animation player. But there is still one question: Why "Failure"? Failure presumes that you are trying to accomplish something, and you have failed. What is Star Child trying to accomplish? You must play to find out!

wary radish
#

Jay Ingle - lead developer, designer, and artist:

Let's look at how I animated some lava. Here is my first attempt. Not very smooth, but it does show basically what I am aiming for.

#

To make the animation appear more smooth, I decided to start with moving a ball up and down, and to the side, and then drawing the lava over those areas.

#

Which results in a smoother animation:

#

However, now it appears to me that the up and down motion is inconsistent. So to clean that up, I decided to use a guide line. This helps me to make sure that when the lava moves up, it also moves down with the same number of pixels, following the guide line.

#

However, I did make the top of the lava a bit unbalanced, because I want the slight impression that it is reaching up and trying to grab you. We are certainly improving in smoothness and consistency. I also created a lava spray particle effect, with randomized timing and amount of particles.

#

The final idea I had was to layer the effect. So I took the animation, switched up the frames so it appears to be moving in the opposite direction, darkened it, and moved it up a couple pixels. It took some work to offset the animation so that it looks nice next to the regular lava.

#

And there we have it. Here is a full scene so you can see how it will appear in the actual game. I hope you like it!

wary radish
#

Jay Ingle - lead developer, designer, and artist:

Let us take a look at the process of animating some plants. In the world of Star Child, we don't always have a lot of scrolling/parallax going on, so we need to find ways to make things move, to provide pleasing visual interest.

We want all plants to move a little when you touch them, or when a rocket flies past them. This looks neat, but also makes you feel like you are IN this world, a part of this world, affecting things with your actions and movements.

We also want plants to sway in the correct direction. Some plants are small enough where we can just give them a little dip, and not have to animate and code them to work in two different directions. Such as these little bell plants:

#

Just a little animation for the little plants. Here is what is interesting: the closer the size of the plant to the player, the more animation is needed. Small plants only need small animations. BIG plants, since they are heavier, are less affected by our movement, and thus they don't move a whole lot when we touch them.

#

However, animation speed should be faster for the smaller plants, and slower for the big plants. When we combine several of these plants, the effect can be quite nice, and seem natural. Notice that the middle-sized plant has the most frames of animation, and moves the most when we touch it.

#

Here is the bit of code that runs whenever something touches a plant:

#

We check if the animation is already playing, because we don't want to skip back to the first frame to start the animation over, if it is already in the middle, that looks quite strange.

We then randomize the speed of the animation, from 0.8 (80% speed) to 1.2 (120% speed). This is per-plant, so each plant will animate at a slightly different rate, even if they are the same size.

Next we check the relative location of the "body" that has interacted with the plant. "body" is gdscript terminology, it generally refers to things that exist in the physics simulation, and move around in the world. A physics body. Could be the player, could be a rocket, could be an enemy, etc.

If the body's horizontal (x) position is greater than the plant's position (global_position.x in this case), that means the body is further to the right than the plant (and must be moving left into the plant's hitbox), and thus, we sway the plant to the left.

These plants that I have shown have been limited in their animation techniques. This is due to the small size, or their solid-ish nature. Tune in next week and we will go thru the entire process of creating some plant animations, for plants that bend and move a lot more.

wary radish
#

Jay Ingle - lead developer, designer, and artist:

Hello. This week I made some plants, and I animated them, and I created particle effects for them.

This is Pyxel Edit, which I use for most of the art in Star Child (and I used for all of the art in Toleo).

#

Let's take a closer look at one of these plants.

#

The most important aspect of this animation, and most animation, is how different things animate with different timings. Some things animation first, then other things follow. Even the pixel art tutorial books I read have trouble expressing this perfectly, so let's look at it directly.

#

We imagine the player walking into the plant, coming from the right side. The first thing that happens, on frame 01 is the furthest-right leaf moves to the left. Then on frame 02, the middle leaf moves left. On frame 03, the furthest-left leaf moves to the right, but also, the right leaf moves back to its original position. On frame 04, the middle leaf moves back to original position. And the next frame is the original frame 00, which also means the furthest-left leaf has returned to original position.

What I want is a wave-effect with the leaves. Here is how it looks in-game, with a little particle effect for some falling leaves.

#

I like it! I think it fits in our game.

Another thing I did this week was improve our rocket explosion particle effect. Here is what it used to look like:

#

Here is a new and improved version. Better color ramp, and a secondary explosive effect that lasts a little longer and shoots out a little further:

#

Better, I think.

That's all for now, see you next week!

wary radish
#

Jay Ingle - lead developer, designer, and artist:

Great news! You will be able to play Star Child, 2 months from now!

Steam Next Fest begins February 23rd, 2026, showcasing many new indie games. Star Child will have a playable demo for this event. We will also have an updated store page, and a new gameplay trailer.

What can you expect from the Star Child demo?

The Star Child demo will be a short, self-contained gameplay episode. A short story. A small journey.

We discussed a few possibilities for this demo. One idea was for the gameplay to be the actual start of the game, just less polished, and you would be able to resume your save, when the full game is released. But not for this demo. This will be a separate, self-contained mini-episode, where you will get to experience a few different pieces of the overall game, arranged into a bit of a side story. There will be no spoilers for the full game, so enjoy.

Now what do I need to do to design and complete this demo?

Plenty! This week I was working on implementing a plugin for control management. I have converted all player controls into using the plugin instead of Godot's built-in input system. Next week I will be setting up auto-switching between keyboard and controller, and control rebinding.

This leads into finishing the options menu, and the main menu. I also need to design the visuals for the automap.

I need another enemy or two, for the demo scenario. And level design. And a bit of story that is thematically similar to the full game. And a bit of polish to as many graphical effects as I can.

I need to work with our audio man Anthrocarbon to get the sound effects and music perfected.

Will there be a boss fight in this demo? I really want there to be! This is a time constraint. If this demo does not have a boss fight, I will work to get a boss fight demo out soon after.

I've got 2 months and I have started mapping out this journey. I can do it! Stay tuned.

wary radish
#

Jay Ingle - lead developer, designer, and artist:

I recently took some placeholder animations, and made em look nice.

Here is the original, placeholder animation:

#

And how it looked in-game:

#

So I created a replacement animation:

#

Certainly an improvement, but it still isn't quite right. This is because to make the flame disappear, we are just reversing the animation. This makes it look like the flame is being sucked back into the ground. It looks kind of odd, kind of alien, and sometimes that is what I am looking for. It looks more like a flame being, than actual real flame. But let us see what it looks like, with a more realistic approach:

#

I'm gonna have to say that this final animation looks the best. I just need to keep in mind that what looks the "best" doesn't always evoke the feeling that I am looking for. But in this case, natural feels better than alien jank.

wary radish
#

Kyle aka Anthrocarbon - music and sfx

MUSICAL CHAIRS!
(Silence is vital.)

Months after my previous log, the stars have aligned and some more music has reached Jay for review. I’ve had multiple long sessions keenly tweaking sliders and knobs, until the growing song turned into a distortion-dependent facsimile of any other nameless four-to-the-floor demo track, sitting in a paper sleeve on a dusty shelf, in whatever local CD store still stocks physical media and didn’t notice the ‘DJ’ leave it there. Despite those stepping stones, though, the song I recently sent to Jay had most of what we needed. It only took something like 6 months to break the drought. kappa emote

That success may be thanks to my chair. No this is not a sponsor spot for G-string C7, Battle Bucket, or Nipplechairs.

You see, I have this ongoing ‘bet’ with humankind, that it is not possible for any person ever, to design and manufacture a comfortable chair. I bought this current chair from a salvage shop, and because IT LIED TO ME, my apparent comfort morphed into aches after only 48 hours, and that resulted in me half leaning forward, which left me feeling urgent and attentive, thus, able to focus on getting at least one track done. (Sorry for the delay, Jay. At least we might be able to make an ‘all the failed cuts’ album as a standalone gag gift.)

#

I wish all my chairs were broken in just the right way to make something usable happen, but the truth is that although much of my time is spent on partial songs nobody ever gets to hear, mistakes are terribly important - especially in creative pursuits. The faster I fail, and the more skilful I become at learning something beneficial from the exercise, and the clearer my understanding of how to juice my brainfruits. A huge part of the process is good old experimentation. I’ve probably oozed praise for the “Arcade” plugin in FL Studio before, but in addition, I have a special place in my heart for the Distructor and LuxeVerb plugins. The way they expand the sound stage and mutate vanilla synth sounds is delightful, and they make the process of experimentation an aurally fulfilling little narrative.

However, on the topic of experimentation and process, I still wouldn’t be caught dead using AI generative tools. Slop-machines make ‘prototyping’ easy for some, but the easier the skill floor is, the more I need my creative process to make it hard! It’s dangerous to be lazy when authenticity is the only currency that matters. So whether it’s a pretty butterfly, a horse’s tail, or a reductive relationship with chairs that provides the seed for your internal randomiser, always lean into it. The brain is incredible at abstracting thought from irrational stimuli, and elevating our arts will always depend on us leaning into that mysterious and oft frustrating mechanism. Essentially, you do you. (This is why I’m not heard from most of the time.)

#

FOLEY MOLEY!
(I’ll rhyme better next time, I promise.)

We’ve managed to find a navigable hill to climb in our most recent approach in the SFX department, focusing on the organic sounds instead of my entertaining my fixation on lofi-ing the crap out of samples to make them more ‘retro’ and tastefully glitchy. Further in that direction, I resolved to reduce filtering and enhancements, and record more takes of the source samples. Although compression is great for compliance with game engine needs and file size control, short SFX samples at higher fidelity are not resource hogs like musical tracks. So, in the pursuit of creating more apt noises, I have reached for more interesting objects to smack, drop, and squish. Here are some of the latest helpers.

#

I’m not a hoarder, but I’m far from austere and tidy. There have been countless uses for random bits and pieces I’ve held on to over the decades, and although many have been shortlisted for use as Foley tools, the way sounds are created from them are far more influential than an object’s shape or material. Those physical properties govern what is possible to extract from the object, but the experimentation is by far the most critical part of the process. I’m obsessed with my metal Slinky because as once had something metallic to my ear that sounded like power lines snapping (sci fi pew pew sort of thing,) and I’ve chased that noise ever since. I recently started looking at cryoseisms which have similar aural profundity to cable jolts, but here in Australia, there’s virtually no chance of going out to record samples of them - lacking ice, glaciers and all that.

Where I’m going with this, is that I love the variety such a ‘hoard’ offers, but the imagination and creativity of the craft are best spent on discovering how to manipulate and combine these object. A skilled Foley artist can score a film with a fry pan, a cardboard box, and a cup of rice. I think maybe I’m just greedy. Or perhaps, the ‘fun’ aspect motivates the necessary experimentation, and my mind can be adequately juiced when it imagines an object looks like it should sound interesting. Maybe the abundant variety in shape and material is crucial after all.

  • Anthrocarbon
wary radish
#

Jay Ingle - lead developer, designer, and artist:

Recently I have been implementing the G.U.I.D.E. plugin for handling player input. Godot's input system is generally ok, but 3 things are very complicated to do: disable/enable all controls (like you would want to do when you have a cutscene), remapping controls, and switching between different control devices (such as keyboard, controller). The free G.U.I.D.E. plugin can help make these tasks a lot simpler. It also returns vectors for 2d and 3d inputs, which can be used in movement code, but we already have our movement set up, and won't be focusing on that functionality.

Star Child can be played with keyboard, or controller. If you are playing on keyboard, and you pick up a controller, and press a button on that controller, the game automatically switches to controller mode. If you then pressed a button on the keyboard, or moved the mouse (moved a certain distance, not just bumped your desk), the game switches to keyboard mode. This is handled very nicely by the G.U.I.D.E. plugin. This is not an advertisement for a free plugin, but hey, if you are making a game for Godot, you should be using it.

We also now have the ability to show button prompts on the screen. Which now changes based on what device you are using.

#

I will most likely only show you button prompts in a tutorial, because honestly this game does not have a complicated control scheme, so it should be intuitive for literally everyone, at least on controller. Which buttons players use on their keyboard is less standardized. G.U.I.D.E. also builds the button icons in real time, and thus can automatically produce an icon of any type of controller button, and even international keyboard symbols. Automatic icon localization, very nice.

The Star Child demo needs to be complete and ready to play on Steam in 6 weeks! So for now, control remapping is taking a backseat, and I need to finish the (new) main menu functionality, and work on some gameplay and art. See you soon.

Get the G.U.I.D.E - Godot Unified Input Detection Engine plugin here:

https://godotneers.github.io/G.U.I.D.E/

/G.U.I.D.E

G.U.I.D.E is an extension for the Godot Engine that allows you to easily use input from multiple sources.

wary radish
#

Jay Ingle - lead developer, designer, and artist:

This week I've been doing menu and UI work. This is my least favorite part of game development, however I have found some satisfaction from solving some coding problems.

Recently, I have improved my coding. I have been using dictionaries and For loops to set properties as needed. The catalyst for this was the realization that I can populate a dictionary with references to nodes, and iterate thru them as needed. It got even better when I learned that I can use scene-unique names (denoted by the %) in my menus, so that if I rearrange the containers, nothing is broken, and I don't have fix broken references.

@onready var menus = {
    "Options": %CenterMain,
    "Audio": %CenterAudio,
    "Video": %CenterVideo,
    "Keyboard": %CenterKeyboard,
    "Controller": %CenterController,
}

So if I wanted to hide all of these menu nodes, I could do:

func hide_menus():
    for menu in menus:
        menus[menu].visible = false

In the past, I would have set onready vars for every menu, which would have to be redone if I changed the node structure of the containers.

@onready var options_menu = $OptionsMenu
@onready var audio_menu = $AudioMenu
    # ...etc

Then I would have done this mess:

func hide_menus():
    options_menu.visible = false
    audio_menu.visible = false
    video_menu.visible = false
    keyboard_menu.visible = false
    controller_menu.visible = false
#

This is bad, obviously. It wastes so much time, and is highly prone to bugs/typos. It is quite a relief to understand how to write decent code using data structures.

And I must thank my teacher, ChatGPT. Oh no! Are we letting AI write code for Star Child? No. But in absence of an actual human teacher, AI has been extremely helpful to me, in learning how to write better code. Conclusion: AI is great for learning, if you approach it like you are actually trying to learn and be independent, rather than trying to let AI do your homework for you.

I, for one, will never accept our robot overlords. However, thank you, robot, for helping me be a better game developer.

One month and six days until the Star Child demo will be out, in time for Steam Next Fest! I better get back to work.

wary radish
#

Jay Ingle - lead developer, designer, and artist:

This week I was sick! But I worked a lot on our main menu design, and some enemies.

Here is the enemy i have named Homer. Doh.

#

This enemy homes in on your location. Could use a little refinement, like only turning a certain number degrees over time, rather than instantly snapping to the player's direction. But just for the direction, and the homing, and facing towards the player, the code is like this:

#

Nothing too fancy there. Now Homer doesn't just move toward you and then explode in your face, he also spawns Little Homers if you shoot him a couple times!

#

These Little Homers are smaller, faster, and could use some refinement code to help them not stack up together too much. A little randomness in direction and speed could help too.

There are only 3 weeks left until the Star Child demo will be released on Steam for Next Fest! This coming week is critical. There is art that needs to be done, including creating art for Homer that does not result in any cease or desist letters from anyone. Drop by next week to see what Homer ends up looking like!

Janne - the other guy:

I've been trying to help polish a few things for the demo. I worked on small things like setting the game fullscreen on startup, setting up some behavior for the menu, fixing a few things with saving and loading of settings.

I'll try to help out where I can with the more pure logic things and other things I'm reasonably familiar with, so we get the game in as good a state as we can for the demo.

wary radish
#

Jay Ingle - lead developer, designer, and artist:

This week I worked on a lot of enemy and environmental art. With our demo dropping officially in 16 days, I don't want to show all of it to you. You can see it for yourself very soon! How about I show you a few little things, and if you want to see more, head over to Steam and wishlist Star Child. Free demo ready for Steam Next Fest Feb. 23rd!

#

Janne - the other guy:

I've been trying to help out where I can and some of what I've accomplished recently have been:

  • Build system updates and export configurations to build both full release, and demo version with unnecessary assets removed
  • Registration, setup, and testing of the demo build on Steamworks
  • Fairly heavy reworking of our automap, including some tooling to pregenerate data from our level scenes via a tool script that can be run locally and automatically on our build server
  • Refactoring of our scene changer logic that made it a bit more reliable and easier to use the configuration directly for our automap
  • A fair bit of main menu, options menu, etc. work - made an updated Godot UI theme, fixed some controls for the options screens,
  • Implemented debug keys and other such things in a manner that's a bit cleaner for actual public release, fewer people should accidentally bump into them
  • Fixed some weird issues with builds, e.g. an UTF-8 ⬅️ was rendered incorrectly after build and I replaced it with an icon
  • Added placeholder controls overlay to the first level until we get control rebindings done
  • Updated credits
  • Lots and lots of testing, fixing things I could fix myself, and reporting various bugs to Jay
wary radish
#

Janne - the other guy:

We've been working a lot on polishing things for our demo to get it out for people to test a bit before Next Fest still and get some initial feedback that we can hopefully resolve before the showtime.

Some highlights:

  • Improved our level preprocessing tooling to detect which rooms have save points, which are secrets, and where the exits are located for automap
  • Redesign of automap + some bug fixes
  • Replaced placeholder art in demo content with proper ones
  • Completely new set of 25 levels for demo content, which we'll still expand on
  • Implemented new enemy type
  • Added music, updated sfx
  • Updated UI theme and fixed consistency issues
  • Tweaks based on initial gameplay testing feedback to difficulty of a few levels, knockback, crouch, fire rate, inertia, etc.

Overall lots of progress and we're already very happy with what we've accomplished so far.

Here's some of the challenges that you can expect to see in the demo content:

#

If you haven't yet wishlisted Star Child, what are you waiting for? Try the free demo too!

https://store.steampowered.com/app/2953070/Star_Child/

Thanks for all the support, see you on the Next Fest.

Star Child is an explosive new futuristic action-adventure game built by a small and passionate indie team.

Explore a mysterious alien world full of unique environments, populated by dangerous alien foes.…

Release Date

2026

wary radish
wary radish
wary radish
#

Janne - the other guy:

Last week we had just gotten our demo out, now we've had a bit of time to gather some feedback and start polishing things that weren't still quite ready.

Here's a bit of a preview of what you can expect from the demo:

#

In no particular order we've managed to do at least the following:

  • Rebalanced a few levels, and added significantly more of them
  • Crouch now takes priority over running
  • Reduced knockback and stun time
  • Increased fire rate
  • Added a bit of inertia to movement to make small movements more accurate
  • Time elapsed no longer resets to last saved time when you die
  • Elapsed time for saves is now shown a bit more nicely
  • Automap design slightly updated again
  • A bit more consistency for visual styles
  • Fixed a bunch of little UI bugs like being able to focus buttons that should be disabled or hidden
  • Clouds now behave nicer and don't pop into the visible areas of the screen, and they can handle rooms of any size now
  • Menu plays sounds when moving around and when adjusting volume
  • Added version and copyright information to main menu
#

We're also still going to update a couple of things before Next Fest still, e.g. our turret enemy still needs a death animation.

wary radish
#

Also got a gameplay preview video out https://www.youtube.com/watch?v=9gE1oEiRgJA

Star Child is an explosive new action-adventure set on a sinister alien planet. Fight numerous aliens and formidable bosses, wield powerful explosives and destructive laser weapons, find secrets and unlock new abilities as you progress. Can you survive your dangerous mission?

The free demo is out now and featured on Steam Next Fest! https://sto...

▶ Play video
wary radish
#

Jay Ingle - lead developer, designer, and artist:

Hello again. We last spoke a couple weeks ago, with Janne filling in on devlog duty. I have been working a lot on our demo, which was released in time for Steam Next Fest.

Since the release, I've been doing plenty of little fixes, little balances, and also watching a lot of people play the demo. But really, who has time for work when One Heart One Life mode exists?

#

One of the most encouraging things about this demo release: most people, once they finish the 30 minutes to 1 hour of play in the demo, play it again! I think that with the way the demo is designed, players get the feeling that they CAN beat this on a harder mode. That is good. A few people have finished the game on Hard ~ 1 Heart mode, which allows you to save and reload all you want, and you can even pick up heart containers (for percentage completion), but they will not increase your health points. Took me about 44 minutes, with a total of 45 deaths! Most of them only on one certain screen, which is pretty vicious on Hard mode.

#

However, the mode with the coolest name: One Heart One Life, has not been beaten. Yet. Will you be the first? Not if I beat it first. Join the official Pale Blue Studios discord and post a screenshot of your completed save file for all the brownie points in the world!

One more little note: the One Life modifier does not delete your save, it just puts you back at the very start if you die. And it does keep track of your deaths, so if you complete the demo with the One Life modifier, your save slot will show how many times you died in your attempts!

Janne - the other guy

I could just add by summarizing some of the important fixes and updates we've done in the last week:

  • Added a few new gameplay modes from player suggestions, the above mentioned "One Heart" and "One Life" -options.
  • Added a message showing automap controls
  • Removed the weapon from the character sprite until you pick one up
  • Added various effects when damaging the shield
  • Lots of new sfx added as well as a few animations that weren't quite yet complete earlier.
  • Some HUD elements are more visible now.
  • Fixed code warnings, and a small memory leak
  • Saves now track a few more things, and we show more relevant information in the load screen, e.g. we track completion % and deaths.
  • Fixed some practical usability issues such as being able to open the pause menu while dying
  • Some balancing of difficulty here and there
  • Tried to change the desktop icon, probably unsuccessfully? 😄
  • Automap styles updated multiple times, now they're pretty great.

Overall the number of changes is fairly large for 1 week, but most of them were pretty small, and the game feels significantly better due to them.

wary radish
#

Jay Ingle - lead developer, designer, and artist:

This week I've been busy setting up a proper text system. This system is used to display controls during the tutorial section of Star Child. However, even more importantly, this is the voice of the antagonist. Well, part of the voice of the antagonist. Our sound designer Kyle (Anthrocarbon) is currently working on the auditory portion of the antagonist's voice.

I originally set up a method to display text on screen, for our demo release. But this was rushed. I just set up a Label and an AnimationPlayer. Then copy/pasted onto the scenes that needed to show text, and changed text or animation based on the scene. This system was extremely limited and inefficient, and I knew I would replace it later, when I had time. This past week was the time.

Here we have our node tree setup:

#

The Label is there to show our basic text. InputPromptKeyboard and InputPromptController are RichTextLabel nodes, they are used to show tutorial messages about the controls, such as "Press A to fire." They use the G.U.I.D.E. plugin to display controls based on your current control scheme: keyboard or controller, and auto-switch if the player changes between them.

Our fancy new TextSystem scene now has the capabilities to display exported text in a couple different ways: Timer (text shows up on screen after a certain amount of time), and Signal (text shows up when a signal is received to do so).

In the Star Child demo, when you arrive on the screen where you first pick up your Rocket weapon, a message would appear on the screen like "Press A to fire." However, this message was displayed when you enter the screen, NOT after you pick up the weapon. This confused players a bit, they would hit A to fire, it wouldn't happen, then they would realize that they needed to pick up the weapon first. Now, the message shows AFTER picking up the weapon. The Item system can now send a signal to the TextSystem, which informs the TextSystem that it is time to show the text now!

#

The signal can also contain info such as what text to display, which animation to play, and font color. And we can easily add new animations and effects for the text.

In other news, I have made a few big changes in regards to player movement/mechanics. Until this week, when you got hit in Star Child, you would lose all of your jumps. But now, if you jump once, then get hit in midair, you will still retain your dobulejump, that you can use after getting hit. Now this may allow an occasional intentional damage-boost by players wanting to go faster, but I think that is ok. You still lose momentum when getting hit, so you cannot just run thru everything.

I have also lowered the maximum fall speed. Which possibly probably maybe makes drop-jumping timing a bit easier.

Also, the automap is now an item you pick up. And we have a new screen in the demo where you pick it up, and, circling back around to our TextSystem, it tells you what button to press to view it.

And finally, congratulations to SpaciousJimmy to be the first person to beat the Star Child demo, on One Heart One Life mode! (See last devlog for details).

wary radish
#

Jay Ingle - lead developer, designer, and artist:

Star Child will be released in 2026!

I have plenty of work left to do, but I am confident that I can get it done. I also believe that when it is finished, Star Child will be a fun, engaging, and memorable experience!

Recently, I finalized the story of Star Child. No spoilers here. But as for themes: cloning, life, death, family, pathos, betrayal, and cosmic devastation. I have also managed to figure out how to tie the gameplay and story together. I hope I can pull it off, but I am excited for you to experience the story.

Now we know how many levels I need to create. And how many bosses and tilesets. And how many songs we need from our music creator Kyle (Anthrocarbon).

We have a lot of music already, and it all perfectly fits the atmosphere that I am aiming for with each of the areas in the game. Kyle also creates all of the sound effects, and I am very happy with his work in sound design as well.

What is next for me? I need to finalize the graphics for a few tilesets, and then create some more decorations.

Here is an old screenshot of some sand blocks and wooden beams I was working on. (I am so glad I improved the rocket sprite).

#

I sure do love saturated colors eh? Maybe we should bring that down a little. But hey, what would you do to improve the graphics for the desert sand blocks? Let me know, thanks!