You are browsing as a guest. Sign up (or log in) to start making projects!

nautrw

@nautrw

Joined June 1st, 2026

  • 46Devlogs
  • 7Projects
  • 5Ships
  • 78Votes
Open comments for this post

6h 53m 6s logged

Quite a bit of progress!

  • Pixel art revamp: The pixel art has generally improved massively. I actually took the time to get some inspiration from Google and worked on the tileset. It now includes a lake and also generally just looks better, with borders around the paths. It did take a lot of time, though. I also implemented animations for this, for the slime, and perhaps for the crossbow too. I also made a little card container for the top 2 stats.
  • Waves: I added waves! It’s now technically a fully playable tower defense game, I guess. As of right now it’s going to crash as soon as it gets farther than Wave 3 because I don’t have anything to do after it, but soon I will add another scene for that.
1
0
163
Open comments for this post

7h 16m 19s logged

Lots of progress again! This one was slightly more in the background, as I started a little bit of housekeeping:

  • Transition from Rects to FRects: FRects are the same thing as normal Rects, except that they allow for floats. This didn’t really have an impact on the game other than making it easier to work with vectors for positioning, as they also use floats.
  • UI Changes: I changed the positioning aspect of the UI. I recreated the Rect placement system of pygame, where you can select a point (eg. top left, center, midbottom, etc.) to use to position the rect. This is very flexible, and I copied it. Now, I can do things like place text with much more ease. I also changed the colors of the UI to make it darker and overall nicer. I made it so that the user had to select a turret and then go to a menu to see the cost and other attributes of it, which will be better for the future.
  • Coins: I added coins, which will be the temporary currency when inside the game. This will be used to buy towers and such. Outside the main game, I am planning to create another one that is used to buy skills and stuff, just to make it more realistic.
0
0
17
Open comments for this post

7h 4m 38s logged

It took a while, but there have been some pretty big improvements.

  • Transition to 1440x960px: I eventually found that being limited to 360x240 was going to be very limiting, specially with text because at low resolutions it looked like a jumbled mess. Thus I embarked on a pretty hard journey (not hard in retrospect) to figure out how to change the resolution but also keep the pixelated style without having to draw sprites at 4 times the resolution. The solution I ended up finding was to store a scale factor of 4 (360x4=1440, 240x4=960), and then scaling a separate surface to that resolution. Now, a surface is created with the same dimensions as the map, and everything is drawn to that surface instead of the map (I used to draw enemies, turrets, bullets, etc. onto the map because they moved together), and then that surface gets scaled. This allows me to keep the pixelated graphics on the actual game, and have crisp text on the GUI. For the offsets, I just moved the function that translated the screen coordinates to map ones from the map to the scene, and then adjusted it to take in the scale factor. Everything else works pretty much the same, as its only the image and mouse clicks getting scaled instead of rectangles. I scaled the button sprites to 32x32 to make them easier to draw, and then I have it in the config to scale them to 64x64. I decided to do that mostly for ease, because most of the other sprites are around that resolution anyway.
  • Turret placement: I added more buttons to the GUI and added turret placement. The GUI itself is always going to be kind of janky. I moved it into its own class so as to sort of clean up the code in the main scene, but now the GUI manager does weird things like self.scene.game.screen.width which isn’t very pretty. It’ll do, though. I track a variable storing the turret to be placed (None if it’s not in that state) and a variable that stores whether it can be placed. I check for collisions between the path tiles (I knew it would be useful!) and the sprite to check if it can be placed. I also modified the draw function of the turret to make it red or green depending on it.
    GUI: Generally, for the GUI, I keep a state from an Enum (basically a fancy way of storing a string for a state), and then change the UI according to that state. I designed it in a way where it only rebuilds it on command, so it won’t rebuild the whole thing every frame, in hopes to save some sort of performance.

Overall, some very good progress, even if it’s not 100% visible!

0
0
18
Open comments for this post

6h 47m 51s logged

I decided to just write the GUI from scratch. This is kind of uncharted territory for me. I tried using pygame_gui but it felt really restrictive and the use of a json file for customization is absurd to me. I made a basic element abstract class so that all elements must have an update and draw method. I then made a button class and a container class. All elements have an ID, and when a button is clicked it sends out a pygame event, which is a feature I did like from pygame_gui. I think I will end up eventually making an UI manager class, as handling the state within the scene is getting clunky and weird.

0
0
17
Ship

PLEASE TRY BOTH THE CLI APP (https://pypi.org/project/bishopviz/) AND THE WEBSITE (https://bishopviz.streamlit.app/)

I made bishopviz, an implementation of the Drunken Bishop Algorithm to generate randomart (like in ssh-keygen!) from (md5 hashes of) text, videos, images, etc. This project can be used as both a CLI app and as a web app. The web app has many cool data visualizations.

  • 4 devlogs
  • 8h
  • 9.03x multiplier
  • 70 Stardust
Try project → See source code →
Open comments for this post

1h 37m 48s logged

I COULDNT EDIT THE SHIP POST BUT THERE IS NO WEBSITE ANYMORE JUST RUN bishopviz -d TO OPEN THE WEBAPP

I’ve recorded a demo, published it on BOTH Streamlit and Pypi, fixed any bugs, and added a file input option. I think I’m ready to ship.

0
0
15
Open comments for this post

1h 56m 11s logged

I think I’m done with the data part. Lowk, it looked better in my head, but this was more of a practice in Streamlit and plotly than actual data analysis. I wanted to make it so that there was just an option in the CLI and then users could put it to start the server and visualize the data they just put the option. Unfortunately, due to the way Streamlit works, I just made it a separate app. This way users can launch the command from the cli and it can also be deployed as a standalone app.

0
0
9
Open comments for this post

2h 45m logged

I’ve got a lot of the cosmetic stuff done.

I moved the algorithm into its own class, which overall made it easier to track certain variables like its position. For the animate option (next paragraph) I had to make a move function that ran 1 generation of the algorithm, so that I could print between frames.

I made an animate option that takes in an amount of seconds and then displays an animation as the bishop moves. The only complicated part about this is that it uses an escape code to move the cursor back up, so as to give the illusion that the same printed text is moving.

I made a character set option and then got ChatGPT to generate some character sets. These follow the convention set by the actual algorithm, in which it’s just 17 characters, with 0 being empty, 15 being the start, and 16 being the ending position. I also added a bishop key so that during the animation it would show where the bishop was. To accomodate the Katakana and emoji options (I didn’t show Katakana but the emojis do show it), I had to modify the draw function to double the width of the graph. It’s still 17, just getting printed as 34 or so.

I got colors too. I just made the same dictionary as a character set but with the color names (I’m using click for the CLI, and it has an API for coloring text) as the values. I then modified the draw function to use the value of the dictionary at the key corresponding to the tile as the foreground if the colorize option was enabled.

Overall, the project has turned out pretty nice, and I will be working on the data visualization part next!

0
0
8
Open comments for this post

1h 23m 47s logged

I got the algorithm working, so that’s pretty much half the project done. I wrote the draw function with a character set argument, so that it is possible in the future to change what characters it uses.

0
0
35
Open comments for this post

6h 17m 37s logged

I’ve probably progressed more in these ~6.25 hours than the rest of the project combined.

  • Fixed the map dragging boundary checks. This was just a matter of separating the if statement into one for each axis. Now, even if the map won’t move on the y-axis, it can move on the x-axis, for example.
  • I added an enemy. This was also pretty simple. They take in a path instead of a position, and their initial position is just the first index of the path (the path is a list of coordinates that they walk to). Vector math made this much easier, as I could just subtract the current position of the enemy from the target, and multiply it with movement speed to move it. The enemy is actually a parent class, and the specific slime in the video is a very simple subclass of it that just has some stats. Default enemy behavior is handled in that parent class.
    • I made a customizable health bar class. The cool part about it is that it uses linear interpolation to change its color as the health changes relative to the maximum.
  • I made a ballistic projectile parent class and an arrow subclass. It takes a position and a target, as well as other stats, and uses vector math to move to the target. When it hits an enemy it takes health from the enemy and then ceases to exist.
  • There is a turret class and a crossbow. The turret takes a projectile class (the crossbow takes the arrow, for example). It will make a new instance of the projectile when shooting. It has a circle for a range of effect, and it will point to and shoot at enemies within the circle.
    • The r key will toggle between drawing the areas and not.

Quite a lot of progress!

0
0
70
Open comments for this post

7h 13m 26s logged

I decided to give up on the isometry because I wasn’t really getting anything done. I have gone back to using a 2d map instead.|

  • The map is made with the Tiled Map Editor (https://thorbjorn.itch.io/tiled) and saved as a JSON file.
    • Tiled is good for visually building maps but a pain to work with. I’d much rather write a map editor from scratch, genuinely. I might do it at some point, honestly.
    • The map is actually split up into 3 layers: the ground, where turrets can be placed; the path tiles, where enemies will walk; and the path polygon, which is a line that the enemies will follow. This allows me to have separate path and ground groups which will simplify turret-path collisions later. In theory, I will be able to make the enemies follow the polygon, too.
    • I had to write a whole function just to parse the map JSON files. It organizes the layers into a dictionary of keys and 2-dimensional Numpy arrays. For the path polygon, it converts it from a list of dicts to tuples. It also removes any other inconsistencies with the original file and only keeps the important stuff.
  • I made the map bigger than the screen itself so that it is draggable. The checks for boundaries are kind of buggy but it’ll do for now. This was just a matter of keeping a variable to track if the map is being dragged, keeping an offset, checking for boundaries, and checking for mouse movements.

I know this was kind of a setback, but real progress can be made now!

0
0
100
Open comments for this post

5h 22m 44s logged

Turns out, rendering isometric grids is pretty hard! I followed a tutorial by DaFluffyPotato on isometric rendering which let me understand the drawing part, but there are going to be some issues with the grid system in the future. I had an issue in which the grid wouldn’t draw half of itself, and it was because it was drawing everything to the right of the top tile outside it. I got it to work by multiplying the grid width by 2 and then adding an offset, but it’s kind of a band-aid and I want to research more into how to actually solve it. I did actually draw the sprites myself, though, and I have a grass block that looks really nice but that’ll be for later.

2
0
105
Open comments for this post

6h 50m 44s logged

I’ve been working for a while, mostly on backwards-facing stuff about the general project structure:

  • A basic game class is used for the actual game instance, letting me manage variables and such and then pass them around.
  • A scene manager class manages different screens in the game.
    • Abstract methods are used to make sure scenes will always handle events, update, and render by making sure the methods are always implemented.
    • Each scene is a class object with several methods.
  • A config manager takes in a bunch of dataclasses and allows accessing the config like globals.
  • Tests check to make sure that an error is raised if a wrong key is accessed, and other stuff.
  • Player ships all inherit from one overall base ship class, and so do turret from their base turret class.
    • Turrets have an attachment point and player ships have points to attach to.
    • Both sprites are joined at the points so as to create a mounting system in which the same ship can use different turret configurations.

The next thing to work on is to allow the turret to rotate as if it was on top of the ship, and to handle ship movement, having it rotate to face where it is moving.

The following image is actually 2 different sprites: the turret (green) and the ship (below). It draws them by blitting the turret on top of the ship sprite.

I have decided to change the theme of the project. The vast majority of the time in this devlog was the background, and luckily I didn’t have much progress on the actual game part. It will now be a tower defense game.

0
0
88
Ship

I made Fluttering Bird, a flappy bird knockoff in Pygame-Ce. It is Linux-only unless you are willing to build it on Windows (check the Readme), as I didn’t have a Windows machine available to me to compile it.

  • 4 devlogs
  • 8h
  • 2.79x multiplier
  • 23 Stardust
Try project → See source code →
Open comments for this post

57m 13s logged

I have made some final touches to the project. First, I changed the font to something more legible, and also used sys.exit() instead of exit() to close the game, as the latter threw an error when the app was compiled. I wasn’t able to make a Windows build because I don’t have a Windows machine available. I’m kind of giving up on this project but I guess it’s ready to ship.

0
0
8
Open comments for this post

3h 28m 5s logged

It took A LOT of work, but I finally got everything working!

  • I added a title and game over page. It took white a while to figure out, but I ended up being able to do it with many changes. First I made a scene manager, which lets me have multiple different scenes as classes, allow scenes to change to other scenes, and generally have much cleaner code. I made a scene manager class that stores a current scene. It has a method go_to which changes that scene variable and runs certain scene methods (more on that later). I then made a Scene class with several methods: handle_events, update, render, on_enter, and on_exit. The on_enter method runs after the scene is switched in go_to, and the on_exit method before. I run the update, handle_events, and render methods in the main game loop from on the current scene of the manager:
self.manager.scene.handle_events(pg.event.get())
self.manager.scene.update(self.dt)
self.manager.scene.render()
  • This ultimately leads to me being able to have the title page (class TitleScene) and the game over screen (GameOverScene).
  • I also started using a GUI library. When I made the TitleScene, I realized that I wanted it to have a button to play the game. At first I wanted to implement my own button but then I gave up because it would’ve been WAY too much work for a project that would use one or two. Thus, I found pygame_gui library. It made UI creation relatively easier. The hardest part was figuring out the theming specifications, as it uses this custom JSON file format. At the end I was able to figure it out, but it was kind of weird and the documentation wasn’t much help. I was able to get a score display working by making a label and then updating the label when it changed.
  • Other changes: I made the background of the main game cornfowerblue to test the score display; pipes are drawn underneath the floor to make it look like they are coming out; I am using a public domain font from Open Game Art but I might change it.

The hard work is paying off!

0
0
7
Open comments for this post

1h 8m 4s logged

I added the pipes! This was kind of hard to figure out, but I finally got it working!

  • For the pipes, I made a new Pipe class as a subclass of pygame.sprite.Sprite. But this is not like an ordinary sprite class, as it’s actually 2 pipes LARPing as 1. I made a basic pipe sprite, and then I duplicate it in the Pipe.__init__() method. This allows me to have a top pipe that is flipped and then the bottom pipe is just the sprite. The actual image attribute is a surface that has both the top and bottom pipes blitted on to it. It took me quite a bit of time to figure out the transparency, though. This is because at first it was just showing up as a fully black column, even though the middle gap was supposed to be transparent. I fixed this by making sure the blitting was actually being done where it was supposed to, and then adding the SRCALPHA flag to the part where I make the image Surface.
  • For collisions, I used a feature called masking, which allows for pixel-perfect collisions based on the actual image of the sprite and not the rectangle. I made both the player and the full pipe image (both top and bottom) have a mask, and then as of right now I am running exit() if they collide. This allows for the player to pass through the middle but then exit the game if it touches the pipes.
  • I am not keeping score just yet, but I managed to get that done by giving the Pipe class a passed boolean attribute, and in the main event loop I am simply looping over the pipes in the pipes Group and checking if their x-coordinate value is behind the player, which means that the player must’ve gotten through the pipe, and later triggering the score to increase.

It’s coming along really well, and I’ve been learning a lot from this project!

0
0
10
Open comments for this post

2h 45m 50s logged

First devlog! It’s quite simple but it took kind of a while due to having to polish it alot.

  • I first made a simple bird sprite that will be getting remade later.
  • I made the Bird class, which is a subclass of pygame.sprite.Sprite. It has a flap_y_delta, which is how much the bird moves upwards when it flaps, and tracks a velocity variable that is either negative or positive and it is added to the y-coordinate of the sprite. In the update method I add the gravity, which is 1200 pixels per second, to the velocity. It also has a flap() method which sets the velocity to the flap_y_delta. The flap_y_delta is negative (-400) because Pygame’s y-axis goes downwards as it increases. Instead of handling user input for the bird in its update() method, I do it in the main event loop and just run bird.flap() because I need to only allow one press of space per keypress. This stops the user from holding the space bar to repeatedly go upwards, but it’s still spammable.
    • The bird also has rotation. This was quite simple. First, in the __init__() method, I have an original image, and then the image attribute is just a copy of the original. Then, in the draw() method, I rotate the original image and set it to the image variable, which is what gets drawn to the screen. The angle is calculated by min(90, self.velocity * 0.1), because the velocity will be very high when it is falling so it will default to 90 degrees when falling, and it is a negative value when the bird is going upwards.
  • I made a floor sprite. Later on I put a red line on it to make sure it is repeating correctly. It will be remade later on.
  • The floor was quite easy to make. Basically I make a Floor class as if it was a normal sprite, and the update method does 2 things: first, it’s going to move it leftwards by a set speed (200 px/s); and then it’s going to check if it has moved fully to the left of the view (self.rect.right <= 0), in which case it’s going to set its x-value to its width times 2 (self.rect.x += self.rect.width * 2), making it wrap to the right outside of the screen. In the main game class I make a sprite group of 2 floors, the second being offset by its own width to make it start to the right. This makes the floor scroll smoothly and infinitely.

It’s coming along really well!

0
0
8
Ship

I made Asteroid Shooter, a space invaders-like game where you shoot asteroids. I made it with Pygame (community edition), pixel art made manually in Aseprite by me, public domain sounds, and a lot of trial and error. It tracks the player’s score, and it gets harder slowly over time. Overall, I learned more about Pygame (sounds, graphics, user input, OOP, etc.), pixel art, and game design.

  • 7 devlogs
  • 14h
  • 7.96x multiplier
  • 114 Stardust
Try project → See source code →
Open comments for this post

5h 6m 15s logged

I have done a lot and decided to just bundle it into one last big devlog, but the work was well worth it!

  • First, I finally redrew all of the sprites! This took the longest out of anything else, but it was very much worth the effort. I learned a lot more about pixel art using Aseprite, and I think the sprites came out very well. First, using references from Google, I remade the rocket. Then, I made 3 different sprites for asteroids and 3 for explosions. For the explosions, I learned about using several different colors/tones to create depth, and they look very good inside the game. Both explosions and asteroids will have their sprites chosen randomly when initalized. Then, I remade the bullet sprite. At first I thought I wanted it to be a missile, but it looked weird, so I just made it a fireball and it turned out very well. I used the same principles from the explosions for it. Finally, I drew a background. I made some preset stars and then pasted them throughout the whole thing.
  • I made some balancing adjustments. First, I made it so that the player can only shoot twice per second, as before it was 4 and quite overpowered. Then, I made it so that the minimum interval at which asteroids could spawn decreased over time as the score increased. I did this by subtracting the score multiplied by 0.005. This makes it so that asteroids spawn 50% faster by the time the player gets to score 100.
  • I then added sounds! I was able to get free public domain (CC0 licensed) sounds from this website called Open Game Art, and then used Audacity to make a loop and edit them to fit the game. I got one for the background music and made it loop infinitely and more-or-less perfectly. Then, I got one for shooting. Alongside the sounds I also added a system for keeping track of the sound’s volumes. This was kind of hard to figure out, but eventually I was able to make a dictionary and then a function that would toggle the volumes between 0 and 1. I had to do this because Pygame doesn’t have a feature to “group” audios or mute globally, and the background music plays constantly but the shooting sound plays ocasionally.
  • I reworked some of the “UIs”. They are still kind of lackluster, but I added a main menu that the player has to press the space key to enter the game, and shows the controls. Then, I made a game over screen and show the player’s final score. I also made the window have a caption and icon. The icon is just the first explosion sprite.
  • I compiled the games into executable files. PyInstaller requires using a special resources function to get paths. This was quite easy to change to, since I have my functions to load assets in one file. I had some troubles with the paths, still, and I ended up moving everything outside of the ./src directory last-minute. The hard part about this was that I switched to Linux a few days before making this project, so I didn’t have another machine to compile the Windows version of the release. At first I found a guide that I could do it through Wine, and then I had to install a Docker image of Ubuntu that had it all set up, but it ended up not working. I ended up just setting up a Windows 11 virtual machine using Gnome Boxes (much easier than having to set up QEMU). It took me a while but it should work. It runs as expected on the VM (Windows Defender notification will pop up but that’s a problem with PyInstaller).

I’m probably missing some stuff, as this was quite a while, but yeah. The game is finished.

0
0
12
Loading more…

Followers

Loading…