Blades of the Lotus - Platformer

Moderator: Moderators

User avatar
Goose2k
Posts: 320
Joined: Wed May 13, 2020 8:31 am
Contact:

Blades of the Lotus - Platformer

Post by Goose2k »

Image

Welcome to the devlog of our game "Blades of the Lotus", a side-scrolling ninja platformer!

lotus_jump_and_collide.gif
lotus_jump_and_collide.gif (2.68 MiB) Viewed 3343 times

I'm working with Abdel Oliveira (https://twitter.com/abdeloliveira80) to help bring his abandoned PC project to where it really belongs... on the NES!

Check out the original PC demo here: https://www.youtube.com/watch?v=J0u1uAOjwC0

Obviously the game will need to evolve for both the system, the controller, and just my own design sensibilities, but you can see there is a really great core in that PC demo to work from!

Development Details:
  • Targets Mapper 28 (Action 53) directly, rather than one of the supported discrete mappers.
  • 64KB PRG-ROM + CHR-RAM (CHR bank swapping for background animation).
  • Written in C (CC65) using NESLib and NESDoug libraries, with support from Norill for Action53 C APIs.
  • Famitone5 sound engine (also by nesdoug)
Dev Log Updates:

I'll be doing more regular updates on this itch thread, and on twitter. I'll update this thread periodically to summarize the current state of the game (every week or so).



Thanks for checking out the game!
Attachments
logo_wip.png
User avatar
Goose2k
Posts: 320
Joined: Wed May 13, 2020 8:31 am
Contact:

Re: Blades of the Lotus - Platformer

Post by Goose2k »

Status Update: May 5th, 2022

It's been a little under a week since I started the project, and things are progressing great!

I started by porting over my animation system from Witch n' Wiz as well as some basic title drawing routines.

Image

One part that I was a little nervous about with this project is scrolling across multiple nametables. I've never done it in any of my shipped projects, and only briefly experimented with it on a prototype last year, and not very successfully. So I wanted to tackle that early and make sure it was working before I started layering on more parts. Luckily it went very smooth, and I had it up and running quite quickly.

lotus_scrolling2.gif
lotus_scrolling2.gif (2.07 MiB) Viewed 3335 times
lotus_scrolling5.gif
lotus_scrolling5.gif (2.6 MiB) Viewed 3335 times

Part of what tripped me up with scrolling when I was experimenting with it last year, was collision detection. I think I was way over complicating it last time. This time, I took a very simple approach of doing all calculations in "world space", and only the rendering code worries about nametables and camera offsets. This went great, and I had collisions working in no time!

lotus_jump_and_collide.gif
lotus_jump_and_collide.gif (2.68 MiB) Viewed 3335 times

A big piece of any action game is the ability to die! So I added death when falling in pits, as well as "kill" tiles like these spikes. With this, I also implemented a title screen, game over screen, and the ability to transition between them all.

Image

You may have noticed in the previous gifs that my character sprites were looping around when the player presses against the edge of the screen. For my final task this week I cleaned up that behavior, as well as ensuring that the player never collides with "random data" outside the play area.

To avoid wrapping sprites on the top and bottom, I simply detect if the meta-sprite is 16 pixels or more above the top of the screen. Since the resolution is 240 high, that gives me 16 pixels of buffer to go into before the sprite wraps around. That is enough in my case.

For the left and right side of the screen I used the PPU feature to disable the left most column of 8 pixels, and then make sure the player can go into that area, which prevents them from reaching a point where the sprites will wrap.

lotus_noclip.gif
lotus_noclip.gif (3.93 MiB) Viewed 3335 times

As I write this I am realizing I don't need to disable the background layer (only the sprite layer) which should look even better!
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Re: Blades of the Lotus - Platformer

Post by DRW »

Some suggestions:

You might consider using an integer for the x coordinate. This way, you don't need to disable the left column.

Also, you might need to store your active level data as more than 32 or 33 tiles at a time, so that opponents can appear from outside the screen in a realistic manner. (Not like in "Ninja Gaiden" where the enemy spawns again if he's out of the screen by even a pixel.) And in this case, you would need an integer for the x coordinate anyway since the opponent can be a bunch of pixels outside the screen on the left and on the right side.

But if you keep your old system, I would still suggest to disable the left background and sprite column. Otherwise, the sprite disappears into nothingness, even though the background in his place is still visible. If you also disable the background, then that's simply where the visible playfield ends.

Another thing: The PC version had a status bar. You might need that too, or do you want to do all the status values as sprites?
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
User avatar
Goose2k
Posts: 320
Joined: Wed May 13, 2020 8:31 am
Contact:

Re: Blades of the Lotus - Platformer

Post by Goose2k »

Thanks for checking out the game, and all the thoughtful feedback.

> You might consider using an integer for the x coordinate. This way, you don't need to disable the left column.

I actually use 32 bit numbers for position (16 bit whole value + 16 bit floating point value). The issue is that my meta sprite routine doesn't hide off screen sprites on the right and on the Ieft I think there is no way to cleanly hide them without masking left column.

> Also, you might need to store your active level data as more than 32 or 33 tiles at a time, so that opponents can appear from outside the screen in a realistic manner.

Currently the whole level is just in ROM, so it's all there. My thought right now is to move the "next" 2 screens worth of level data to RAM, which should be enough to avoid stuff popping in at the last second I think.

> But if you keep your old system, I would still suggest to disable the left background and sprite column.

That is what it's doing, unless I'm misunderstanding what you mean. See final GIF.

> The PC version had a status bar. You might need that too, or do you want to do all the status values as sprites?

I'm not sure how closely I will follow the original pc demo tbh. I'm hoping to drop the status bar completely so I can do some screen split effects woth sprite 0 hit.


Thanks again!
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Blades of the Lotus - Platformer

Post by tokumaru »

Goose2k wrote: Fri May 06, 2022 7:52 amI actually use 32 bit numbers for position (16 bit whole value + 16 bit floating point value).
Talk about overkill! Is that simpler in C than 16.8?
The issue is that my meta sprite routine doesn't hide off screen sprites on the right and on the Ieft I think there is no way to cleanly hide them without masking left column.
You might want to consider clipping the sprites, because even though you can hack your way with the player sprite, enemies and other objects will need to be partly visible, otherwise the pop-in will be unbearable...

Clipping sprites is not particularly hard or slow, you just need to calculate the sprite coordinates as if they were 16 bits, instead of doing only the lower byte, and if the high byte is not 0, you skip that sprite. This will take care of anything < 0 or > 255.
Currently the whole level is just in ROM, so it's all there. My thought right now is to move the "next" 2 screens worth of level data to RAM, which should be enough to avoid stuff popping in at the last second I think.
The amount of level data you need to have available at any given time depends on the specific mechanics of your game, but for a normal platformer, 2 screens in either direction sounds like more than enough.
User avatar
Goose2k
Posts: 320
Joined: Wed May 13, 2020 8:31 am
Contact:

Re: Blades of the Lotus - Platformer

Post by Goose2k »

tokumaru wrote: Fri May 06, 2022 9:57 am
Goose2k wrote: Fri May 06, 2022 7:52 amI actually use 32 bit numbers for position (16 bit whole value + 16 bit floating point value).
Talk about overkill! Is that simpler in C than 16.8?
I'm not sure what 16.8 is, but yah it's as simple as:

Code: Select all

char _8bitNumber;
int _16bitNumber;
long _32bitNumber;
16 bits is certainly overkill for the low floating point fractional part, but I want 16 bits for the high part of the position, so the simplest approach is to just have both parts be 16 bits. There's just no "24 bit type" (as far as I know) in C.
tokumaru wrote: Fri May 06, 2022 9:57 am
The issue is that my meta sprite routine doesn't hide off screen sprites on the right and on the Ieft I think there is no way to cleanly hide them without masking left column.
You might want to consider clipping the sprites, because even though you can hack your way with the player sprite, enemies and other objects will need to be partly visible, otherwise the pop-in will be unbearable...

Clipping sprites is not particularly hard or slow, you just need to calculate the sprite coordinates as if they were 16 bits, instead of doing only the lower byte, and if the high byte is not 0, you skip that sprite. This will take care of anything < 0 or > 255.
Yah, I think I likely will need to. The challenging part for me personally is that the metasprite code is written in assembly which I struggle with. I'm sure I can figure it out when the time comes, but it's not going to be very simple for me.
tokumaru wrote: Fri May 06, 2022 9:57 am
Currently the whole level is just in ROM, so it's all there. My thought right now is to move the "next" 2 screens worth of level data to RAM, which should be enough to avoid stuff popping in at the last second I think.
The amount of level data you need to have available at any given time depends on the specific mechanics of your game, but for a normal platformer, 2 screens in either direction sounds like more than enough.
I only have 1 way scrolling (atm anyway), so that keeps things simple.

Now I'm struggling with how to fit a decent amount of level data into the 64kb ROM restrictions. I am expecting levels similar to Ninja Gaiden, Shadow of the Ninja, Contra, etc. So somewhat detailed, but with 1 way scrolling (not sure if I'll tackle vertical yet), with a decent amount of verticality to the horizontal levels. I'm using 16x16 background tiles atm, but may create 32x32 if it helps.

Back of the napkin math seems to indicate that simple RLE compression will not yield good results due to lack of repeating tiles. I'm also concern that the amount of time it will take to decompress level data on the fly is going to hurt the game. I'm kind of tempted to just allot a vast majority of the RAM to level data, and just keep them fairly short so I can decompress once at the start of each section.
Last edited by Goose2k on Fri May 06, 2022 1:45 pm, edited 2 times in total.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Blades of the Lotus - Platformer

Post by tokumaru »

Goose2k wrote: Fri May 06, 2022 1:01 pmI'm not sure what 16.8 is
It's 16 bits for the whole value + 8 bits for the fractional value.
floating point
I think you mean fixed-point, right?
The challenging part for me personally is that the metasprite code is written in assembly which I struggle with.
I see... Modifying other people's code can be tough.
Now I'm struggling with how to fit a decent amount of level data into the 64kb ROM restrictions.
Fitting a lot of levels in 64KB will indeed be a challenge.
Back of the napkin math seems to indicate that simple RLE compression will not yield good results due to lack of repeating tiles.
There are other options...
I'm also concern that the amount of time it will take to decompress level data on the fly is going to hurt the game.
Since the scroll speed is limited, you don't need to decompress entire screens at once... If you only scroll horizontally, you can break each screen into narrower columns to minimize the amount of data that needs to be decompressed each frame.
User avatar
Goose2k
Posts: 320
Joined: Wed May 13, 2020 8:31 am
Contact:

Re: Blades of the Lotus - Platformer

Post by Goose2k »

I wanted to expand a bit on my thoughts about level compression, and open it up to any feedback people have. This is my first time building a NES game of this nature, so assume I know nothing!

Game details:
  • 1 direction scrolling atm.
  • Somewhat detailed levels.
  • Lots of verticality within the horizontal levels.
  • Currently only supports horizontal levels, but may add vertical levels (but not 2 or 4-way scrolling - always one direction like Contra, Mario 2, etc)
I only have 64KB total for the the ROM, so my starting point is to allocate 16KB of that to level data. I think that's probably the max I can afford to give to level data.

I think really I probably just need to try some stuff, but I wanted to throw it out there in case anyone has ideas on a good way to store/load level data of this nature.

My thoughts so far are:
  • I want to aim for about 15-20 mins of gameplay for a new player, which at the current move speed would require 400 screens of level data (for a perfect run) or ~200 screens for an average run (kind of guessing that the player overall will move at half the max speed??)
  • I'm already using 16x16 meta tiles, but 32x32 might be a good fit for this type of game.
  • 200 screens * 16x15 meta tiles = ~47kb of data uncompressed (plus meta tile defs)
  • 200 screens * 8x8 mega-meta tiles = ~12kb (plus mega and meta tile defs)
  • I am writing this in C, so performance of decompression on the fly is a concern.
  • I have 2KB of RAM, so at most I can probably decompress 2-4 screens worth of data at a given time in RAM.
My gut tells me that 32x32 "mega tiles" (2x2 collections of 2x2 meta tiles) might be a good approach, as the decompression is pretty simple, and it seems to put me on target for 16KB of level data.

Super interested to hear what your thoughts are or if you've done something similar.
Last edited by Goose2k on Fri May 06, 2022 1:49 pm, edited 1 time in total.
User avatar
Goose2k
Posts: 320
Joined: Wed May 13, 2020 8:31 am
Contact:

Re: Blades of the Lotus - Platformer

Post by Goose2k »

tokumaru wrote: Fri May 06, 2022 1:25 pm I think you mean fixed-point, right?
Clarified in the original post; I meant "fractional part". But yah, I'm using Fixed-Point math. :D
calima
Posts: 1745
Joined: Tue Oct 06, 2015 10:16 am

Re: Blades of the Lotus - Platformer

Post by calima »

oam_meta_spr_clip exists in neslib. Are you using some other metasprite setup?
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Blades of the Lotus - Platformer

Post by tokumaru »

It still baffles me that neslib doesn't support sprite flipping! Having to double (or quadruple, if you also use vertical flipping!) all your sprite definitions sounds like a massive waste of space...
calima
Posts: 1745
Joined: Tue Oct 06, 2015 10:16 am

Re: Blades of the Lotus - Platformer

Post by calima »

What do you use as the origin? Can't be dynamic, that would be too inefficient. And forcing any one convention will make the other conventions' users angry. Plus if there are intentional overlaps, flipping could (would) get them wrong.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Blades of the Lotus - Platformer

Post by tokumaru »

calima wrote: Sat May 07, 2022 8:33 amWhat do you use as the origin?
The origin can be wherever you want, since the sprite coordinates are signed.
Plus if there are intentional overlaps, flipping could (would) get them wrong.
I don't see how, if individual sprites are still be processed in the same order.

In my very first meta-sprite subroutine, I would first adjust the origin to compensate for any flipping, and also initialize a pair of flipping masks (either $00 or $ff). Then, when processing the individual sprites, I would apply those masks to each sprite's coordinates before adding them to the origin.

Now I do something slightly simpler, in order to save a little CPU time: I precalculate the flipped X and Y values for each sprite and store them along with the original coordinates, meaning that each sprite entry occupies 6 bytes instead of 4. It's a 50% increase, but still much better than doubling or quadrupling the sprite data.
User avatar
Goose2k
Posts: 320
Joined: Wed May 13, 2020 8:31 am
Contact:

Re: Blades of the Lotus - Platformer

Post by Goose2k »

calima wrote: Fri May 06, 2022 11:39 pm oam_meta_spr_clip exists in neslib. Are you using some other metasprite setup?
Oh wow that's great! It's weird though, I don't see it in my version of neslib. I see it here though:

https://github.com/clbr/neslib/blob/master/display.sinc

So hopefully it's simple to integrate! Thank for pointing that out. I had no idea it existed.
User avatar
dougeff
Posts: 3079
Joined: Fri May 08, 2015 7:17 pm

Re: Blades of the Lotus - Platformer

Post by dougeff »

If you exactly centered a sprite (like in NES screen tool) so that position 0,0 is in the exact center of the sprite, you could flip a tile by 0-tile position...

Further thinking about it...

the metasprite code will add x to x offset, y to y offset. If you wanted to flip that sprite horizontally, the metasprite code could subtract instead of add.

old
sprite x = meta x + tile x offset
new, flipped x
sprite x = meta x - tile x offset

so, you would need to make 4 versions of the metasprite code. regular, x flipped, y flipped, x and y flipped. That would add a bit to the code size, but it should run roughly as fast.

What do you think of this solution, for flipping?



edit. not exactly centered. pixels extend to the right, so you need 4 pixels off from the visual center of the image.

for example, if the metasprite was 2 tiles wide, the right tile would be at 4, and the left one at -4 ($fc). if the metasprite was 3 wide, the right one would be at 8, middle at 0, left at -8 ($f8)
nesdoug.com -- blog/tutorial on programming for the NES
Post Reply