Sunday, July 7, 2019

Big and Tall

One of the things that can use up a lot of your CPU time on the NES is metasprite rendering.  Each hardware sprite is 8x8 pixels (or optionally 8x16). Complicated characters are then made up of a bunch of different sprites together, which is often referred to as a metasprite

Rendering a metasprite isn't complicated -- you push X, Y, tile, and color values into the right spot for the first sprite, then read the next sprite, adjust X and Y appropriately, and repeat.  The problem is twofold. First, it's just a lot of instructions on the 6502 to read, add, and write the sprites, when there's a lot going on onscreen.  Second, you have to deal with clipping.

Sprites can be positioned from pixel 0 to 256 horizontally, which is represented in a single byte. If you wrap around from 256 to 0, the sprite will appear on the left side. So for a large metasprite that's near the edge of the screen, you have two options.  First is to hide the object entirely if any of the sprites go off the edge. This is faster, but looks bad -- the character pops onto or off of the screen. A lot of old nes games do that, and you get used to it as a player, but it looks cheesy.  The second is do check each single sprite as you're computing its position. If a sprite's X value wraps around from 256 to 0 (or vice versa), you omit drawing that sprite. That gives a much better appearance of smoothly scrolling off the edge of the screen.  Unfortunately, it's that much more math you're doing for each sprite in the game.  Since enemies are often made of at least 4 sprites, and often 8 or more, that can become cumbersome very quickly.

In Halcyon, I wasn't happy with the popping-off-the-edge solution, so I opted for taking the time to check each sprite. To try to keep it easier on the CPU time, I have a number of ugly optimizations that make the wrapping/clipping checks a bit faster.  Unfortunately, one side effect of those optimizations is that my metasprites can only be 32 pixels wide or tall.

That was fine until this week, when I wanted to make a tall barrier that opens when you defeat a boss.  It needed to be more than 32 pixels tall.

That ugly thing in the middle is an "enemy" wall that can raise/lower depending on what other enemies are alive. The graphics are just placeholders.


That was tonight's challenge -- how to work around my optimizations and allow larger enemies?

The answer ended up being fairly simple: I still limit each metasprite to 32x32 pixels, but I allow a metasprite to specify a new base position and start a new metasprite from there.  So really, a metasprite can be more of a meta-metasprite, being made of a few different metasprites at different offsets.

Ugly?  You bet.  But it works.

Friday, June 21, 2019

Stairs and a hoppy guy

One thing that Frankengraphics (the artist I'm working with) suggested was adding 8-pixel tall blocks that the character could run/drive up without jumping. Sort of like ramps, only without the continuous nature. I've been putting it off, because ramps are weird.

I finally decided to tackle it in the last few days. And it turned out that the discrete nature of the steps, combined with how I've handled collisions so far, made them really easy.  As in 30 minutes of work, and they just worked.


Next I decided I needed some hoppy bouncy enemies. Because erratically bouncing enemies are always a giant pain to fight, which is a good thing. My hoppy enemy took a bit longer than I thought to get it working right (a couple of hours for this guy, way longer than my stairs!), but I finally have it working mostly right.  Except that it needs art.  I'm using a random placeholder for now, so it mostly looks like a bouncing cheeseburger.


Saturday, June 15, 2019

Level Design in Earnest


Well, with moving platforms done, I decided I'm fair enough along that it's time to start doing "real" level design. I've got a bunch of maps that I've designed for demo purposes, so you can play through a bit of how the world will play, and I can test out how transitions work.  But they were never intended to be the real map.

So I've wiped out all that, and started now on the "real game."  And after a couple years of fiddling about with the engine, it's really refreshing churning out a few maps. 

Spoiler alert!


I've realized a few things:
  1. I'm bad at making interesting maps.  I have these big rooms, and it's hard to fill them with things that will actually be fun. I'm trying though.
  2. I don't have to go very far before I run into features that I need to add into the engine.  I hit the first save room quickly, a few days ago, and remembered that I hadn't implemented game saves. I got that added, then immediately started on a room with some 8-px steps (which the main character is supposed to be able to run up without jumping). Of course, I haven't actually implemented the running up stairs yet.  Time to do that I guess.
  3. Nothing reveals bugs like real content.  Just tonight, I plopped an enemy (the eyeball creepy crawly guy that I've used all over the place in the demo rooms) into my map, and he's broken.  WHY, computer, WHY!?
Exhibit A, in which I decide that I hate computers.

Friday, June 7, 2019

Moving platforms working

Ok, another lunch hour devoted to the platforms, and they're working!  My idea of how to make them ended up working perfectly.

I ended up wasting about 45 minutes though due to a stupid optimization. Instead of checking collisions against the full world coordinates of the player and platform (which are 2 bytes instead of 1, thus requiring quite a bit more instructions for the collision check), I was just caching and comparing their on-screen rendered coordinates (which is just 1 byte).  That works well EXCEPT for the fact that the player's render coordinates are calculated AFTER the collision check, meaning they're one frame behind.  For a lot of things, that one frame might not matter, but here it caused the player to keep getting stuck in the platforms.

Once I removed my silly optimization, things worked great!  Although I need to make some minor changes to the camera code. Right now the camera only scrolls horizontally when the player moves naturally, but not when the platform pushes the player.  Meaning currently a platform can drag you offscreen. That needs to change.


The nice thing about this addition is all the ways it can be used in gameplay: moving platforms, moving walls that get in your way, enemies that can be frozen and climbed, barriers that can get moved by a switch or trigger, etc.

Tuesday, June 4, 2019

Catching up, and Halcyon moving platforms.

Hmm. I haven't posted here in almost a year. I got thinking about my progress on Halcyon, and decided it was time to actually get back to writing about what I'm doing here.

I realized I didn't say a thing here about Super Homebrew War, my 4-player nes brawl, using characters from other well-known NES homebrew games, which scored 2nd place in this year's NESdev competition. 



Nor did I mention that I got inspired to try my hand at Dreamcast development. Like last year's port of Robo-Ninja Climb to the 2600, I decided to once again take my NES code, and try porting it directly to the Dreamcast. As usual, it took slightly longer than I hoped, but I now have a Dreamcast version of Robo-Ninja Climb finished.
The nice thing about Dreamcast homebrew is that you can test on hardware for the low price of a CD-ROM!

Now I'm back on to working on my metroidvania, Halcyon.  Tonight's challenge is obstacles/platforms that aren't part of the background, and thus can move around.  Like ramps, moving platforms are always slightly trickier than you'd think they should be.

After a few false starts, my current theory of how they'll work is like this:

  • Moving platforms are actually just an enemy instance, with a modified collision routine.  
  • During the enemy platform's update routine, I'll do a collision check: If the player collides with the platform, I'll move the player by the same amount that the platform moved. (which lets the platform push the player around)
  • During the player's movement, it will look for any enemies flagged as platforms, and handle collision results against them just like collisions against background tiles.
  • During the enemy's movement/collision checks, the collision box of the platform will be adjusted to be a tiny bit larger than during the player's collision checks, so that the platform will "grab" the player and move it if the player is riding on top
Believe it or not, but that moving thing above the tank is a platform.

I spent the evening writing the first half of this (the enemy update phase, which can move the player around).  Hopefully tomorrow or soon I'll get to the 2nd half (the player's adjusted collision routine), and we'll see if my theory works out.

Friday, July 6, 2018

Robo-Ninja Climb 2600

So I had this crazy idea.

The game logic of Robo-Ninja Climb is really simple. And so is the display. So in theory, with the NES and the Atari 2600 both having the same 6502 processor, I could take the NES source code for the game, rip out the rendering bits (and sound and controls), leaving just the core game logic, move it directly to the Atari, then rewrite all the rendering stuff.

In theory, this is made even easier by the fact that the Atari has built-in collision detection. On the NES, about half the work was tracking where you had scrolled, so you could do the math to compute collisions against spikes. On the Atari, I don't have to do that -- as long as I can draw them, it will do collisions for me. Which saves a ton of processing time.

So I got to work. First thing was stripping down everything I didn't need, replacing the controller code, and bringing over the main character physics. That went smoothly, and compiled for the Atari quite quickly. Of course, then I had to find a way to see if it worked.

It's certainly not as pretty as the NES version


Which meant writing an Atari kernel. I think it's somewhat like what women say after having a baby -- after a few years, you forget the pain and only remember the happy parts. Back to counting cycles, trying to squeeze everything into the 76 clock cycles per scanline. Ugh.

But it turns out it wasn't as bad for this game, as there's not nearly as much on the screen  (Anguna had a multi-color player, a  variable-length player missile (sword), changing playfield, a single color enemy, and en enemy missile. This has a single-color player, changing playfield, and single-color enemy. So not as bad.)

Anyway, after all that, I've got most of an Atari port of Robo-Ninja Climb working. Over the last few weeks, I've been slowly working through the more tedious or difficult parts: rendering items, adding title and level transition screens, etc. With a few more hours of work, I might have a Robo-Ninja Climb port for the Atari! (and I wonder if it's the first Atari port to ever directly use source code from the NES game that came first?)

Yes, I'm still working on the BlasterMasterMetroidVania game. And the 4-player adapter. I promise.

Wednesday, March 21, 2018

I blame Twitter

Huh. I haven't posted here since last December.  Not because I'm not doing things. But mostly because of all the NES dev folks that hang out on twitter and discord, so I've been posting short status updates there along with my usual twitter nonsense.

But because in 4 years when I come back here to this blog to try to remember what I was doing in early 2018, here you go future me. Turns out I have WAY too many projects going on at once! Begin wall-of-text mode!

  • I've got cool destroyable blocks going in my metroidvania game, and the basics of some enemies. I've added music thanks to the awesome sound engine that Derek of Gradual Games made. And unfortunately, I've realized that the current version of the game won't actually boot and run on hardware. UGH.  I think on EVERY PROJECT I've ever done, I say "oops, I wish I would have tested on hardware sooner."  Time to pare things down and figure out where it's going wrong. Hopefully in time for Midwest Gaming Classic, where I hope to show it off a little.
I also added a map screen to help you figure out where you've been. 


  • The Atari 4-player adapter hit a slight roadblock when I realized that there's something causing a weird static/flicker on the screen whenever player 4 moves their controller. It's hardware-related, not game-related, so I've been needing to do some hardware debugging, which is HARD. Thanks to some advice from Paul at InfiniteNESLives, I've added some capacitors in the last week or so, and they seemed to have helped. But now (based on some suggestions from another awesome Atari homebrewer, John Champeau), I've decided to test another design, based on 2 separate 1-to-2 joystick adapters, which gives some more options for a game to work with other peripherals at the same time (ie 2 joysticks plus an AtariVox speech synthesizer). We'll see how that goes -- I have the parts and the design should be pretty quick to slap together, but after that, I'm stuck in the same "how do I turn this from prototype to production" situation.
Yeah, I'm pretty sure that's NOT the recommended way to attach the capacitors to my board


  • Speaking of hardware, I've also started helping Kevin from KHAN games (he pronounces that K-Han, not KHAAAAAN, which is crazy) on a project that involves connecting a NES to the internet.  So I've rigged up my raspberry pi to my NES via the controller port, and I've been trying to get them to talk. So far it's been mixed results, but this week I managed to get the PI to tell the NES to print the alphabet. Until halfway through the screen, when things got horribly out of sync.  I'm going to have to read up on serial protocols and error checking, I think.  
Things were looking good until suddenly they weren't.
  • The results came in from the NESDev competition. Robo-Ninja-Climb got middle-of-the-pack results, which is what it deserved. The entries were really high-quality this year, so I'm pretty satisfied with where I ended up. If you want to hear me attempt to talk about it on the Assembly Line Podcast, now's your chance.

  • Speaking of the competition, I decided to make a multi-cart of my competition entries (and in theory, will update it each year with any new small games that I make for the NES). So I spent the last couple weeks modifying my competition entries to work on a different board/mapper.  That took a bit of work, as the new mapper (GTROM) uses ram instead of rom for tile graphic data (chr-ram), and four screens-worth of tile map data (nametables) that I have to account for. But now I have a slick demo cart to show off my games. If I can't get the Blastervania game ready by MGC, I'll at least have something to demo!





NES Anguna

Well, I had a little bit of time still, while Frankengraphics is finishing up her game Project Blue, to have a little downtime on Halcyon, s...