Jump to content
IGNORED

Nyan Cat Game - Work in Progress


JeremiahK

Recommended Posts

Another thing that'll free up cycles, at the expense of ROM, is to eliminate the branch by unrolling the loop. Instead of this (assuming the digits are 8 scanlines in height):

  ldy #7
ScoreKernel:
 ... 48 pixel logic
 dey
 bpl ScoreKernel

you'd do this:

  ldy #7
 ... 48 pixel logic
   dey
 ... 48 pixel logic
   dey
 ... 48 pixel logic
   dey
 ... 48 pixel logic
   dey
 ... 48 pixel logic
   dey
 ... 48 pixel logic
   dey
 ... 48 pixel logic
   dey
 ... 48 pixel logic

Easier way to do that is via a macro:

  MAC SCOREKERNEL
.line SET {1}
 if .line = 7
   ldy #7
 endif
  ... 48 pixel logic
 if .line > 0
   dey
 endif
  ENDM

then use the macro like this to draw the 8 scanlines:

 SCOREKERNEL 7
 SCOREKERNEL 6
 SCOREKERNEL 5
 SCOREKERNEL 4
 SCOREKERNEL 3
 SCOREKERNEL 2
 SCOREKERNEL 1
 SCOREKERNEL 0
Link to comment
Share on other sites

Unrolling the loop would also free up some cycles during the loads because you'd no longer need an indexed load. Just hardcode the ZP address for each load. Honestly, I don't see how this would work without unrolling. Even if you don't use Y for loop maintenance don't you still need it for the indexed loads and that means extra overhead to deal with Y being used for two different things each scan line.

 

Of course, there's always bus stuffing. PM me if you ever want to switch over to the dark side.

  • Like 3
Link to comment
Share on other sites

Thanks, I am trying to avoid an unrolled kernel if possible. As for using Y for indexing, I have some ideas, such as loading Y with INTIM and using TIM64T to load the timer. This would restore Y and handle the loop in 6 cycles, and if I preload Y initially, I should be able to draw a maximum of 7 scanlines. Another option is to simply pull the graphics from the stack, which doesn't need an index. However, this would make it very hard to use the stack pointer for an extra register.

Edited by JeremiahK
Link to comment
Share on other sites

What I'm really try to point out is that you have to use Y as the index to load the value for Y into a non indexed location before loading it into Y.

 

In other words you can't do ldy DigitY,y. The tay instruction is no good either, because then you've lost your value for A and you can't load it after you stomp on the index value in Y. Using the stack is even worse because now you've got to deal with the values for X and SP.

 

Instead you must do this which costs 6 more cycles.

; TODO Restore Y with index
lda DigitY,y
sta DigitYTemp
; TODO Pre load A, X, SP, GRP0, GRP1 etc.
ldy Digit0Temp

Maybe someone has a clever solution for this, but I haven't thought of a good one yet.

 

8 grp updates using ld? zp,y and sta zp is (4+3)*8= 56 cycles

2 nusiz1 updates using lda # sta zp is (2+3)*2 = 10cycles

restoring Y index is at least ldy ZP = 3 cycles

branch taken for loop = 3 cycles

Providing the above calculations are correct 72 cycles are already used leaving just 4 more to deal with the ldy zp,y problem.

  • Like 1
Link to comment
Share on other sites

So after a lot of playing around with code, this is the best I have come up with that allows 7-bit-wide number digits. I am 99% sure this will work, but I have another method that only allows 6-bit-wide digits just in case (using VDEL on only P0). Fingers crossed!

Edit: Scratch that, I miscalculated the timing on some of the instructions, marked with ***. :( Looks like you are correct, ZackAttack, I only have 4 cycles to work with for the loop handling here.

    ; set TIM64T so it will decrement properly from 5-0 during kernel
    
    ldy #6	; 2 66	inital state of Y
Board
    lda #3	; 2 68
    sta NUSIZ1	; 3 71	set NUSIZ1 for score
    
    ldx Lvl,y	; 4 75
    txs		; 2 01	LevelDigit->S
    
    lda Scr1,y	; 4 05
    sta GRP0	; 3 08	ScoreDigit1->[GRP0]
    lda Scr2,y	; 4 12
    sta GRP1	; 2 14	ScoreDigit2->[GRP1] / ScoreDigit1->GRP0 ***
    lda Scr3,y	; 4 18
    sta GRP0	; 2 20	ScoreDigit3->[GRP0] / ScoreDigit2->GRP1 ***
    
    ldx Scr4,y	; 4 24	ScoreDigit4->X
    lda Scr5,y	; 4 28
    sta Temp	; 3 31	ScoreDigit5->Temp
    lda Scr6,y	; 4 35	ScoreDigit6->A
    ldy Temp	; 3 38	ScoreDigit5->Y
    
    stx GRP1	; 3 41	ScoreDigit4->[GRP1] / ScoreDigit3->GRP0
    sty GRP0	; 3 44	ScoreDigit5->[GRP0] / ScoreDigit4->GRP1
    sta GRP1	; 3 47	ScoreDigit6->[GRP1] / ScoreDigit5->GRP0
    tsx		; 2 49
    stx GRP1	; 3 52  LevelDigit->[GRP1] / ScoreDigit6->GRP1
    stx GRP1	; 3 55	LevelDigit->GRP1
    lda #4	; 2 57
    sta NUSIZ1	; 3 60	set NUSIZ1 for level digit
    
    ldy INTIM	; 3 63  !!! prepares Y index for the next line !!!
    bne Board	; 3 66
Edited by JeremiahK
Link to comment
Share on other sites

What you already have working is already impressive. One other idea could be to use non numeric glyphs for the level indicator. Then it doesn't have to look the same as the score and they could be customized to work well with what's available. Perhaps it would add a little more charm to the game?

 

Otherwise, unroll the loop, use a more powerful bank scheme such as 3E, use harmony hardware with ARM co processing, or just leave well enough alone.

Link to comment
Share on other sites

What I'm really try to point out is that you have to use Y as the index to load the value for Y into a non indexed location before loading it into Y.

 

In other words you can't do ldy DigitY,y. The tay instruction is no good either, because then you've lost your value for A and you can't load it after you stomp on the index value in Y. Using the stack is even worse because now you've got to deal with the values for X and SP.

 

Exactly. Although if I used X as the index instead of Y, I could interact with the stack more easily. I'll have to look into that, maybe there's something there...

Ah, never mind. Then I would run into the problem of loading X, since I couldn't do ldx Digit,x

 

What you already have working is already impressive. One other idea could be to use non numeric glyphs for the level indicator. Then it doesn't have to look the same as the score and they could be customized to work well with what's available. Perhaps it would add a little more charm to the game?

 

Otherwise, unroll the loop, use a more powerful bank scheme such as 3E, use harmony hardware with ARM co processing, or just leave well enough alone.

 

I'm OK with sticking with the kernel I have, or doing other graphics than numbers to indicate the level. I just want to see if I can push the hardware to the edge. ;)

Edited by JeremiahK
Link to comment
Share on other sites

 

So after a lot of playing around with code, this is the best I have come up with that allows 7-bit-wide number digits. I am 99% sure this will work, but I have another method that only allows 6-bit-wide digits just in case (using VDEL on only P0). Fingers crossed!

Edit: Scratch that, I miscalculated the timing on some of the instructions, marked with ***. :( Looks like you are correct, ZackAttack, I only have 4 cycles to work with for the loop handling here.

    ; set TIM64T so it will decrement properly from 5-0 during kernel
    
    ldy #6	; 2 66	inital state of Y
Board
    lda #3	; 2 68
    sta NUSIZ1	; 3 71	set NUSIZ1 for score
    
    ldx Lvl,y	; 4 75
    txs		; 2 01	LevelDigit->S
    
    lda Scr1,y	; 4 05
    sta GRP0	; 3 08	ScoreDigit1->[GRP0]
    lda Scr2,y	; 4 12
    sta GRP1	; 2 14	ScoreDigit2->[GRP1] / ScoreDigit1->GRP0 ***
    lda Scr3,y	; 4 18
    sta GRP0	; 2 20	ScoreDigit3->[GRP0] / ScoreDigit2->GRP1 ***
    
    ldx Scr4,y	; 4 24	ScoreDigit4->X
    lda Scr5,y	; 4 28
    sta Temp	; 3 31	ScoreDigit5->Temp
    lda Scr6,y	; 4 35	ScoreDigit6->A
    ldy Temp	; 3 38	ScoreDigit5->Y
    
    stx GRP1	; 3 41	ScoreDigit4->[GRP1] / ScoreDigit3->GRP0
    sty GRP0	; 3 44	ScoreDigit5->[GRP0] / ScoreDigit4->GRP1
    sta GRP1	; 3 47	ScoreDigit6->[GRP1] / ScoreDigit5->GRP0
    tsx		; 2 49
    stx GRP1	; 3 52  LevelDigit->[GRP1] / ScoreDigit6->GRP1
    stx GRP1	; 3 55	LevelDigit->GRP1
    lda #4	; 2 57
    sta NUSIZ1	; 3 60	set NUSIZ1 for level digit
    
    ldy INTIM	; 3 63  !!! prepares Y index for the next line !!!
    bne Board	; 3 66

I haven't read the whole thread, so I'm kinda jumping in the middle here.

 

Years ago I did a 7 full size digit display (with a little trickery). You can see it here.

 

I'm glad to see you're using INTIM for your loop counter. I have used TIM8T before, but TIM64T also works well.

 

If you are doing a six digit score with another digit (or two) for the lives/level then consider putting the score on the far right and use then extend the spacing with NUSIZx to wrap it around. wrapping around the screen that way gives a very wide spacing. Here are some examples:

 

post-7074-0-76796200-1515130949_thumb.png

 

post-7074-0-11221500-1515130967_thumb.png

  • Like 2
Link to comment
Share on other sites

Thank you! Now it's on to the game mechanics, that might take a while... ;)

Yes that's the other half of the battle. ^^ You've a lot of fun things going on so I don't think you'll have a lot of trouble, you're awesome. :D

 

Carrot Kingdom I'm having most trouble with the design. The kernel, technical things were cake, but I'm not a super great designer.

  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...

I have been busy of late trying to apply for my 2nd job so I can get a steady income (I am 21, in case you don't have time to read everybody's profiles) I am glad to say that after almost 11 months since my last job, I now have a new job. I start on the 5th, the day after my Eagles get to play in the Superbowl. :D

Anyways, I decided to put in some more time on this game, and I made a commit for the first time in a couple weeks. It was a small change, just an optimization, but I hope to tackle some bigger issues this week, hopefully working on the controls and food generation.

I am planning on supporting both joystick and paddle control. Since the paddles should only need to be read 7 times, I should be able to do that without sacrificing too much game logic space.

I have decided to skip the idea of using flicker to have up to 4 food items per row, because the 64-pixel NUSIZ spacing of the objects combined with the 160-pixel display will make it pretty much impossible to make that work well in reality. Instead, there will normally be 2 items per row, with no flicker, except for when the 3rd item needs to spawn. In that case, the center item will not flicker, but the others will for a short time.

 

Oh, and here's the screenshot you asked for over a week ago. I tried to post it before, but I guess it didn't work.

post-59805-0-29194600-1517345813_thumb.png

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

  • 2 months later...

Glad to know that kids will love the game! Unfortunately, I have not done much, if anything, in the past 2 months. Before, I was unemployed, so I had all the time in the world. Now I thankfully have a job, and since today is my first time having two days off in a row, I am trying to get back into the swing of things. It has given me some time to think about how I want to address different issues, and fix a couple of minor inconsistency flaws in the kernel.

I have the important code for the controls done, I just need to connect it to the joystick (and paddle later). Next up is working on the object generation, which will take some time, since I want it to be simple yet flexible to make it easier to implement levels later.

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

All right, did a quick-and-simple joystick update. Currently, holding the joystick up or down will make the cat move quickly until it hits the top or bottom row, making it a little hard to just flick through one row at a time. I intend on making it so you need to move one row at a time, returning the joystick to center after each move, unless you hold the fire button, which would function as it is now. Not sure how this is best implemented, but I'll figure it out.

nyancat.bin

  • 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...