BRANDON FANNIN
  • Home
  • About
  • Résumé
  • Blog
  • Contact

Adventures in Game Development

Week 11 - Drops

1/24/2025

 
Couldn't think of a stupid joke for the title this week.  Anyway, I started off things by reviewing my list of goals for this project and I ended up cutting a number of things from the queue. My primary goal here isn't to recreate the entirety of Super Metroid, but to use existing designs in order to get used to using Godot. to that end, I removed things from my todo list that I have already figured out how to do in the engine, which will reduce the amount of time I need to spend on this training arc before I can start building something for real.

As for the actual implementation work for the week, I didn't run into any real surprises. First up, I finally added death effects for my enemies, though I did have to use the morphball bomb explosion effect as a placeholder, at least until I can find and slice up the real enemy death explosions.
Picture
The real explosions in the game do a better job of hiding the sprite pop, but functionality wise this one is done. Next was getting enemies to drop items when they die. Again, this was pretty simple in itself; I defined all the different types of drops, made them increment the player's stats when collided with, and set up data resources so that enemies can define their own drop rates for each type of item. Thing is, Metroid actually has a bit of a system when it comes to item drops: items don't drop if the player is full on that particular resource, and the drop rates of other items that the player is missing are boosted. I did not replicate the behavior exactly as it appears in the games, but I made a close approximation. When an enemy wants to drop an item, the Drop Manager looks at the player's current status. It only takes into account drop weights of resources that the player is currently not full on, skipping over those that are already topped off, and thus making sure that only things that the player needs will spawn.
Picture
While I don't truly have logic for missiles, super missiles, and power bombs up and running yet, I did still create the full suite of ammo drops as well.  

And.... that's about it for this week. Next up, I'm planning on shifting my attention to Godot systems that I'm less familiar with, specifically camera control and scene transitions. Once I get the ability to swap rooms working, hopefully I can start to figure out how save data works in this engine.

​See you next time.

Week 9 - Ouch

1/10/2025

 
Back to work after the new year.  There's not a whole lot of visual progress this week in comparison to earlier updates, but I still got a decent amount of work done. Under the hood I made it so that weapons actually apply damage to enemies instead of just instantly killing them, made them die properly when their health hit zero, and added in functions that allow entities to modify incoming damage values.  I also setup damage property flags to represent different types of incoming damage and made it so that enemies can be set to be immune to specific damage types. That will come into play relatively soon when I start adding in bombs, missiles, and different beam types.

With that set up, I also added a little bit of polish to the damage sequence so that we now get that classic sprite flash when something gets hit by an attack:
Picture
The system I made for this should be pretty versatile, able to take in lists of colors, frame counts, and duration to create looping effects. In theory, it should work perfectly for when I get i-frame visuals up and running. Speaking of player damage, I also made it so that enemies can damage players and even apply knockback to them.
Picture
I had to at least stub in invincibility frame logic to prevent them from applying damage continuously, but I will be adding visuals to let the player know when they're active in the near future. 

That's about it for progress this time, because I actually spent a good portion of the week getting sidetracked by research.  While trying to figure out the best way to handle collision detection for enemies, I stumbled across a post talking about physics optimization and kinda fell down a rabbit hole for a bit.  Evidentially Godot has systems called "servers" that handle all of the engine's rendering, physics, and computations under the hood.  While the Node system is very user friendly, it's not the most efficient in terms of processing, and so it can start to hold you back when you have a large number of nodes active at the same time. You can apparently get around this issue by polling the servers themselves instead of just using Nodes. 

This video does a pretty great job of showing the differences in the two approaches:
It's not quite as simple as they make it sound, especially if you want bullets with non-linear/non-standard movement, but the potential performance gains are pretty obvious. Now, this isn't exactly important for my work on this project because the number of live physics objects in any given scene will always be low, but it's pretty vital information for some of my future plans. 

We'll talk more about that when I start getting closer to checking everything off my todo list for Metroid though. For now, my next goals are to finish sprucing up my enemy damage effects (VFX for hit and death), adding visuals to the player's i-frames, and then starting set up the HUD so that we can actually see how much health the player has.

See you next time.

Weeks 7/8 - Adversary

12/20/2024

 
Ended up missing my update last week because I lost a significant amount of dev time to a nasty stomach bug, and holiday obligations ended up interrupting me on more than one occasion, so these two weeks effectively combine into a single week's worth of work. 

So what did we get done? I fixed a few bugs that cropped up with my tile destruction system, as well as implemented basic architecture for enemies and created our first enemy. I wanted to stick with something simple enough for my initial foray into enemy implementation, so I decided to go with one of the first enemies you encounter in Metroid; the Geemer.
Picture
Or at least that was the plan, but because of my struggles with Super Metroid Sprites, I ended up using the Metroid Fusion equivalent of the same enemy design. It's called an "Owtch", which really is a top-tier name.
Picture
Now, it's not that I couldn't find sprites for the Geemer this time around, just that they were cut up in a way that was a bit nonsensical and putting them together would have been a small nightmare. Besides, the Owtch does exist in Super Metroid so it still counts.

As far as enemies go, these guys just move along flat surfaces, following the geometry of the terrain as they encounter walls or ledges. Very simple to the player, relatively painless in terms of coding. For something like this you just need move forward and have one raycast downward and one facing forward to check for walls or cliffs.  If it finds one, play an animation to smooth the transition and update which directions the enemy thinks is "forward" and "down" so that the new surface becomes its "ground". 

Godot seems to have some interesting quirks with raycasts, such as them not being able to properly detect surfaces on the first frame the enemies exist, or needing to create a "query" object in order to actually use them, but besides that they behaved mostly as expected. 
Picture
Picture
Most of my issues involved two main factors: getting the sprites to properly reorient themselves to the surface they are attached to, and getting the enemy to properly re-attached to a surface after it encounters a cliff (the movement shown in the gif on the right). The former issue is born from the fact that I only actually have sprites for when the Owtch is upright or attached to a left wall. For ceilings and right walls, I need to carefully time a sprite flip when the transition animation finishes. You can probably see a little bit of popping in the gifs above when the enemy finishes rounding the top-right corner. I have since fixed that particular issue but didn't have time to grab new screenshots before making my post.

The second issue involves the fact that when the enemy encounters a cliff, there is a frame or two when it's in the middle of it's transition animation where it's not technically touching the ground at all, and early on in my tinkering it thought it was just constantly encountering cliffs when this happened, leading the enemy to spin in place in the air. The solution to this one was to shift the source of my ground-detection raycasts based on what part of the transition it is in. when it knows its firmly attached it searches from the back edge of it's hitbox, but while its in the process of transitioning around a corner it looks from the front edge instead.

Luckily, it seems the way I set up the movement logic on these guys plays nice with the destroyable terrain. I'm going to need to add in some safety checks to make sure the destructible blocks can't reform on top of an enemy, but I was honestly going to have to deal with that for the player anyway.
Picture
With all that working, I added actual health tracking to enemies, made it so that projectiles can actually hit them, and made it so that they can die properly.
Picture
Still need to add death VFX of course, as well as making it so that enemies can hurt the player as well.  Those will probably be in my next list of goals.  That being said, this should be my last update for the year. The holidays are basically upon us and I'm not going to be able to spend much time at a desk. 

Happy Holidays to anyone reading, and see you next time.

    Archives

    April 2025
    March 2025
    February 2025
    January 2025
    December 2024
    November 2024
    October 2024

    Categories

    All
    AI
    Animation
    Attack Logic
    Camera
    Clean Up
    Enemies
    Game Development
    Godot
    Level Design
    Music
    Optimization
    Player Mechanics
    Projectiles
    Project Start
    Research
    Sound
    State Machines
    Super Metroid
    Tile Maps
    UI
    VFX

    RSS Feed

Proudly powered by Weebly
  • Home
  • About
  • Résumé
  • Blog
  • Contact