Jump to content
IGNORED

Nyan Cat Game - Work in Progress


JeremiahK

Recommended Posts

So about a week ago, I was wondering what I wanted my first 2600 game to be. I had seen the Nyantari demo, and I liked how it was implemented. However, it isn't a game, only a demo, and as far as I know nobody has made a Nyan Cat homebrew game yet. I looked up some Flash games and found Nyan Cat FLY! It's not the greatest game, but I like the concept, especially because the gameplay should be entirely possible on the 2600. I have been brainstorming for the past week now, and I started writing code for the game over the weekend.

I wanted to start with the easy part (if you want to call it that, nothing on the 2600 is easy), so as of now I only have the score/level display. This was my first time making a 6-digit score, or even a 48-pixel sprite, for that matter. The kernel for the 6-digit score is well commented, but the rest is very messy. I will probably spend a couple days making it neater before I move on to the next step, but I just wanted to put this out here for now.

 

For the latest source code and .bin, here is the Github repository: https://github.com/JeremiahK96/vcs-nyancat

nyancat.bin

nyancat1.3.asm

Edited by JeremiahK
  • Like 4
Link to comment
Share on other sites

That's a cool project idea. It does look it should fit the 2600 well.

 

I reviewed your source and have a few comments that may help you.

 

1. If you aren't already doing so, use source control. I recommend git. You can use a service like github to back up and share in the cloud. This also makes it easier for others to contribute to your project in the future.

2. You could trade some CPU cycles for RAM by using a single pointer for looking up the digit graphics. This would make the code more complex, so I'd only go this route once necessary. Still, it could potentially get you 10 more bytes of RAM.

3. There is a STA.W instruction which allows a 4 cycle write to zeropage addresses. You can do that instead of "hex 8D 04 00"

  • Like 2
Link to comment
Share on other sites

1. If you aren't already doing so, use source control. I recommend git. You can use a service like github to back up and share in the cloud. This also makes it easier for others to contribute to your project in the future.

 

I have been planning to start using github, but never really had a reason to before now.

 

 

2. You could trade some CPU cycles for RAM by using a single pointer for looking up the digit graphics. This would make the code more complex, so I'd only go this route once necessary. Still, it could potentially get you 10 more bytes of RAM.

 

Excellent suggestion. I had originally needed the 6 pointers because I was loading the graphics from ROM on-the-fly during the kernel. I switched to using the stack so I could save enough cycles to add the level counter. I was planning on changing the pointers to simpler 1-byte offsets, since all the graphics are in the same page anyway. Cutting it all down to a single offset variable would save 13 bytes of RAM.

Another idea I had to save some RAM involved the stack. The score/level kernel loop doesn't use a loop counter because there aren't enough cycles. Instead it checks the last outputted graphics to see if it was zero, and all the digit graphics are 7 pixels high with a zeroed byte at the end. The downside is that this causes the last 7 bytes of RAM to always be $00, but I could probably rearrange the order of the instructions in the kernel loop so that only 1 zeroed byte is neccesary. Or I could even set up the stack so that it wraps back to $00, which is VSYNC, assuming that pulling from VSYNC gives you a zero and no bad side-effects happen. I'll have to see what happens. Of course, you would then have to reset the stack pointer to $FF.

 

 

3. There is a STA.W instruction which allows a 4 cycle write to zeropage addresses. You can do that instead of "hex 8D 04 00"

 

Thanks for the tip. I wasn't sure if there was a better way, so I forced it in there. Actually last night I realized that I could simply use ROR and ROL instead of the shifts/transfers, which saves 2 cycles, so I can use the zeropage mode after all.

Link to comment
Share on other sites

 

Or I could even set up the stack so that it wraps back to $00, which is VSYNC, assuming that pulling from VSYNC gives you a zero and no bad side-effects happen. I'll have to see what happens.

VSYNC is write-only. Reading from address 0 will actually give the state of the collision flags in CXM0P.

  • Like 1
Link to comment
Share on other sites

Okay, thanks. If that's the case, I have an idea on how to actually use that as an advantage.

Since I am using the playfield to cover up the extra copies of the missiles used in the level counter, both bits 6 and 7 in CXM0P should be set during the display routine. The graphics data for the digits are already set up so that bit 7 is always cleared, so it should be as simple as changing the loop branch from a BNE to a BPL. This would free up all 7 bytes of the wasted RAM in the kernel. Fingers crossed...

Link to comment
Share on other sites

 

I have been planning to start using github, but never really had a reason to before now.

 

 

Alternatively, if you want to use source control, but don't want to have it be open-source, other services such as Bitbucket and Gitlab offer free private repositories.

  • Like 1
Link to comment
Share on other sites

 

Alternatively, if you want to use source control, but don't want to have it be open-source, other services such as Bitbucket and Gitlab offer free private repositories.

 

Thanks. I'm okay with open-source for this project, but it's good to have options future projects.

 

I am too tired right now to post my updated code, but I have cleaned it up a lot. My idea with reading from the collision registers actually works. I had to wait until the stack pulled from $02, which is the collision register for P0 and PF. I added an invisible part to the beginning of the kernel to make sure the right collision register bit works. :D

Link to comment
Share on other sites

Here is the updated code. If you run the .bin you won't see much difference, but I managed to get rid of all 7 pointers as well as the 7 wasted bytes of zeroed RAM in the stack. This frees up 21 bytes of RAM. It also uses less ROM space, and uses fewer game logic cycles. :D

I added a link to the repository on Github into the original post, as well.

nyancat.bin

vcs-nyancat.zip

  • Like 3
Link to comment
Share on other sites

Here is the updated code. If you run the .bin you won't see much difference, but I managed to get rid of all 7 pointers as well as the 7 wasted bytes of zeroed RAM in the stack. This frees up 21 bytes of RAM. It also uses less ROM space, and uses fewer game logic cycles. :D

I added a link to the repository on Github into the original post, as well.

 

Right on, good looking counter/UI so far. :)

 

Looking forward to your Nyancat game. ^^

  • Like 3
Link to comment
Share on other sites

  • 3 weeks later...

I have ideas for the cat graphics, but unfortunately I can already tell there aren't enough cycles to pull it off without flicker. I'm thinking of using leftmost 3 bits of PF0 to draw the rainbow, with animations for moving up or down. Then some well-timed color changes to draw the pop-tart as a single-color rectangle with one of the players to draw the cat's face, using the ball behind the face to color the eyes and mouth. I could use a missile to draw the tail. The plan was to leave the other player for drawing the food items, but you simply can't draw the cat graphics and 3 other sprites with unique graphics and colors on the same line.

 

I thought of only having flicker in the row that has the cat in it, while all the other rows have no flicker, but I think constant, consistent flicker would look better. Then I could do it Asteroids-style, alternating between drawing the player and the other objects on each frame. This would allow me to use both player objects for both kernels, which I could use to make a better rainbow or cat, and maybe even up to 6 food items in a row.

 

I have taken a bit of a break from this project, as I have been busy with other things, including training for a marathon that is coming up, but I hope to get back at it soon. I have done work on the level progress bar. It's not quite done, but is very close.

Edited by JeremiahK
Link to comment
Share on other sites

I think you should reconsider. It would be much more playable without a giant flickering main character. Maybe something along the lines of this would work?

 

Rainbow, body, background, eyes, and mouth are all drawn with PF/BK. Colors are set multiple times each scanline, but the PF graphics can be set ahead of time and remain static.

 

Timing not to scale:

					  [-Face-]
[----HSYNC--][--------------Rainbow][---Body--]
COLUPF COLUBK COLUP1 GRP1     COLUBK     COLUBK     GRP0 
Link to comment
Share on other sites

That was more or less the original plan, but how can you also draw more than 1 copy of the second player (food items) with unique graphics and color, and also make them horizontally movable? The only way I could think to do it would be to make a different kernel for each horizontal position of the food items, which might actually be doable. If it's not, unfortunately the choice is between flicker or simpler cat graphics (probably no rainbow).

Link to comment
Share on other sites

I was meaning duplicate copies of the second player object. If it is possible to properly show 2 copies medium spaced, then it should be possible to flicker ONLY the food items, but still be able to have up to 4 food items in a single row. As of now, though, it's all just ideas, because I want to finish the kernel for the health/progress bar before moving on to the main gameplay kernel.

Link to comment
Share on other sites

  • 4 weeks later...

It's been a while since I have worked on this project. I have a few days to work on it right now, between running the Indianapolis Marathon on Saturday and flying out to Florida later this weekend to help my grandmother move to Indiana.

I had previously written code for a progress bar that had colors for both "full" and "empty", as well as the background color and the grey cat health face (5 colors on the same line). Unfortunately, there wasn't quite enough time to set all the colors in the proper time, so I have re-written it so that the progress bar's "empty" color is the same grey as the cat health face. As of now, there is no code for animating the progress bar, but I had written it before, so it's just a matter of copying it over

nyancat.bin

Edited by JeremiahK
Link to comment
Share on other sites

Thank you. My 6-digit score kernel is based off of the one found in the book "Making Games for the Atari 2600", which I highly recommend. There is a lot of information about many of the more complex techniques in it. I must say that for some reason some of the cycle timing in the printed examples are wrong, but there is a website with all of the projects' code available for free at 8bitworkshop.com, including the 6-digit score technique.

Link to comment
Share on other sites

  • 2 weeks later...

I have spent a lot of time thinking about how I want to do the main game kernel (usually late at night in bed), and I think I have figured out how I want to do it. I have added a huge line of comments in my code describing how I want to do each section (no actual code yet), which I include here.

; The rainbow will be drawn using both the playfield (PF0) and the background.

; The pop-tart will be a single-color rectangle drawn with the background.

; The cat's head and front paws will be drawn with player 0. If it is possible,
; the rear paws will be drawn with missile 0.

; All the food items will be drawn with player 1. It's NUSIZ will be set to
; 2 copies wide, and it will use flicker to draw up to 4 food items per row,
; 2 for each frame.

; The cat's face color will be drawn with the ball, behind the head.

; The PF0 register will be written to twice per scanline, the playfield
; color will be set twice per scanline, and the background color 3 times
; per scanline. If this is not possible, I can draw the rainbow with only the
; playfield, saving 2 register writes at the expense of graphics.

; Player 0's graphics will be written to once per scanline, while player 1's
; will be written to twice. Player 0's color will never change, while player 1's
; will need also 2 writes per scanline.

; The ball will also need to be enabled or disabled each scanline. I am planning
; on using the graphics table for PF0 to control the ball and missile as well,
; since PF0 only uses the 4 high bits, saving cycles by only having to read once
; for three writes (a shift will be neccesary).

; I may have to push some of the cat graphics onto the stack to save cycles
; in the kernel. I can reuse the RAM that was needed to draw the score graphics.



; Output 4 blank scanlines, while setting up the graphics objects.
PreKernel:
    
    ; Align player 0 and the ball for drawing the cat's face, set up both
    ; missiles to draw the rear paws, and align player 1 to draw
    ; the current frame's food items for the top row.

    ; Depending on how tight the cycles will be, it may also be neccesary to push
    ; some of the graphics into RAM here so they can be loaded more quickly
    ; in the kernel.
    
    ; If any part of the cat needs to be drawn in the top row,
    ; skip straight to CatRows.



; Draw all the rows above the cat's two rows.
HiRows:

    ; First, output a single-color line to draw the bottom of a "throb" line.
    ; This will probably be a good time to prepare the pointers for the
    ; food items' graphics, as well as loading the colors for the food items.
    
    ; After that, output 14 lines to draw a single row with food items,
    ; but without drawing the cat. The food graphics will be updated every line,
    ; but there will probably not be enough time to also update the food colors
    ; every line throughout the kernel.
    
    ; Lastly, output four single-color lines to draw most of a "throb" line,
    ; while setting the position of player 1 to draw the next set of food items.
    
    ; If this is not the last row before drawing the cat's rows,
    ; loop back to HiRows to draw the next row.



; Draw the two rows that contain the cat.
CatRows:

    ; Output a line to finish the bottom of a "throb" line, like in HiRows.
    ; If the cat is at the very top of the row, draw the top of the pop-tart.
    
    ; Then output the 14 lines to draw a single row. This will include drawing
    ; the rainbow, the pop-tart, the head and face or paws, and the food items.
    ; All graphics will be updated every line.
    
    ; Then output the 5 lines to draw a "throb" line, but also draw the entire
    ; cat with the rainbow. In order to align player 1 for the next row's
    ; food items, it will be neccesary to have three versions of this kernel,
    ; one for each of the three 60-color-clock spaced positions to reset.
    ; HMOVE will be written to on the first four scanlines. With a maximum
    ; movement of 15 color-clocks per scanline, this will allow a movement of
    ; up to 60 color clocks. With three versions of the kernel, it should be
    ; possible to put player 1 anywhere on the screen.
    
    ; Then output 14 lines to draw the next row, exactly the same way as the
    ; previous one. It will be neccesary to have multiple versions of this, as well,
    ; since GRP1 needs to be updated at the correct time depending on the position
    ; of player 1.
    
    ; Lastly, output only one line (not four) to draw the top of a "throb" line.
    ; Use this time to prepare the next row's food item pointers (unless this is
    ; the last row). If this is the last row, skip over LoRows.
    
    ; If the cat is at the very bottom of the screen, don't disable the
    ; missile/player graphics until after they are drawn, so they don't get
    ; clipped at the bottom of the screen. An easy way to do this would be to
    ; simply disable them after they would have been drawn, whether they are
    ; already disabled or not.



; Draw all the rows below the cat's two rows.
LoRows:

    ; Output 4 lines, drawing the rest of the "throb" line, while preparing
    ; player 1 for the next row's food items.
    
    ; Output 14 lines to draw a row, exactly the same as in HiRows.
    ; It may be possible to code this as a subroutine to save ROM space.
    
    ; Lastly, output the a single line for the next "throb" line.
    ; Use this time to prepare the next row's food item pointers (unless this is
    ; the last row). If this is not the last row, loop to LoRows for the next row.

I forgot to mention that the kernel will have the ability to draw the cat at any vertical point, including halfway between rows. This way you can have a nice smooth motion as the cat changes rows, rather than the chunky motion we have all come to put up with in 2600 games.

 

Hopefully this will work. According to my preliminary calculations, there aren't quite enough cycles to do this, but I might be able to figure out some tricky ways to make it work. As of now, I will only be adding code to draw the cat and rainbow (no food items yet).

 

Here is a mockup of how it will hopefully look (without the food items, of course):

 

 

lKquvfz.png

Edited by JeremiahK
  • Like 4
Link to comment
Share on other sites

I like it. It's feasible but still is going to push the system to it's limits.

 

Instead of writing PF0 twice each scanline, just set it once in prekernel and write to COLUPF one more time. As a bonus you're going to have the COLUBK value in register anyway, so just write it again to COLUPF and you save a load there too. Since PF and BK are the same color once you're right of the cat the mirrored PF0 will be invisible. Now this ruins you're multiplexing of the enable bits for ball and M0, but you can use the LSB of some color values instead since those are ignored. Finally, you could easily increase the rainbow size now since the PF is static and mirrored. Simply set PF1 in prekernel too and move the cat right. This might be useful for giving some extra time to set up for the first copy of P1.

  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...