1. Star Child
  2. News

Star Child News

Star Child Dev Log #11

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!

Star Child Dev Log #10

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.

Star Child Dev Log #9

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.



Star Child Dev Log #8

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.

Star Child Dev Log #7

[p]Jay Ingle - lead developer, designer, and artist:[/p][p]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. [/p][p]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. [/p][p][/p][p]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. [/p][p][/p][p]Remember kids, anything under a ParallaxBackground node needs to also be under a ParallaxLayer node, in order to function properly.[/p][p][/p][p]Janne - the other guy:[/p][p]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.[/p][p]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.[/p][p]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.[/p]