It is currently Sun Aug 20, 2017 11:33 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 36 posts ]  Go to page Previous  1, 2, 3  Next
Author Message
 Post subject: Re: Ludum Dare
PostPosted: Sat Dec 10, 2016 7:24 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5544
Location: Canada
Nice duck.

(o)< QUACK


Top
 Profile  
 
 Post subject: Re: Ludum Dare
PostPosted: Sun Dec 11, 2016 2:12 am 
Offline

Joined: Sat Oct 15, 2016 8:52 am
Posts: 73
That's actually a poorly drawn fireball - I had originally seen them as moving down-left, hence the angle!

For surrealism, have you seen the games by my former selves (link to one of their old kickstarters)? I believe I backed one or two on kickstarter. They're RPGmaker so the interactivity is rather limited, but the aesthetics are quite wonderful - they're like moving Hieronymus Bosch paintings.


Top
 Profile  
 
 Post subject: Re: Ludum Dare
PostPosted: Sun Dec 11, 2016 5:30 am 
Offline

Joined: Sat Oct 15, 2016 8:52 am
Posts: 73
Getting closer:

Attachment:
shenzenminiclassic.gif
shenzenminiclassic.gif [ 286.68 KiB | Viewed 1810 times ]


Top
 Profile  
 
 Post subject: Re: Ludum Dare
PostPosted: Tue Dec 13, 2016 5:19 pm 
Offline

Joined: Sat Oct 15, 2016 8:52 am
Posts: 73
This is now released:

https://team-disposable.itch.io/you-are-insignificant

Thanks everyone, comments and criticism appreciated. Thanks also for the comments while making the thing, nesdoug's tutorials, and all the help on the newbie forum in general. It's an excellent community, and much appreciated.


Top
 Profile  
 
 Post subject: Re: Ludum Dare
PostPosted: Fri Dec 16, 2016 7:59 am 
Offline
User avatar

Joined: Sun Mar 09, 2014 12:18 am
Posts: 36
Good job! It isn't easy getting a game playable by the end of Ludum Dare.
I enjoyed your game and made it to the end, although the delay when trying to move really threw me off while attempting many of the jumps.

How was your experience with making an NES game for Ludum Dare?


Top
 Profile  
 
 Post subject: Re: Ludum Dare
PostPosted: Mon Dec 19, 2016 4:53 pm 
Offline
User avatar

Joined: Sat Jun 29, 2013 4:36 am
Posts: 25
Really impressive to get a nes game out for the LD!

I can haz source? :mrgreen:

Here is my feeble attempt: http://ludumdare.com/compo/ludum-dare-3 ... &uid=65233

I took it as an excuse to try and download/test out the latest xamarin/mono android support.


Top
 Profile  
 
 Post subject: Re: Ludum Dare
PostPosted: Tue Dec 20, 2016 3:33 pm 
Offline

Joined: Sat Oct 15, 2016 8:52 am
Posts: 73
Your game looks good, I'll definitely try it out.

I'm not releasing the full source right now as it's a bit of a pig's ear, having been put together in three days. I'll probably release it if/when I clean it up a bit, but right now I'm a bit busy working on my compo entry.

Is there anything in it you where interested in? I'd be happy to pull out bits and explain them. Nothing is handled in a particularly elegant way, however!

All of the levels are raw byte by byte maps produced in the NES Screen tool - I did this as I also use them for collision detection, which is how the spikes, the lava, the gold and the player physics work.

The enemies are a set of arrays, the main one being "enemy_active", which the central routine runs a for loop against, like this:

Code:
for(index = 0; index < sizeof(enemy_active);++index)
{
     if(enemy_active[index] == 0x01)
     {
             //do enemy routine
     }

}


There are then a bunch of other arrays - enemy_x, enemy_y, enemy_directionfacing, etc - all of which correspond to the same index as enemy_active.

Those two and the player physics are pretty much the bulk of the game. The player physics are pretty basic - I haven't noticed the lag in movement myself, but it is likely because I am using an 8.8 movement system - so there are eight positions for each pixel.

Jumping is something I would definitely improve on if I did this again. Currently, the longer you press the jump button, the more is added to the magnificently named variable player_remainingjumpstrengthtoapply. Chunks of this are then whacked on to the players Y value each frame until it is zero, or the player hits their head. Gravity is actually running the whole time on them, so it just kind of naturally takes over, much like in real life. Hence the awkward jumping. I would go for velocity based system if I were doing it again.

The big thing that I've found programming in c on the NES is that you really, really need to appreciate it is just converting everything to 3 registers in the backend. So there lots of occasions where I'd like to be comparing two arrays together, like this:

Code:
if(enemy_destination_x[index] > enemy_x[index])
{
//do something
}


Only the result of the above will default to true, no matter what the values in enemy_destination_x and enemy_x.

Storing one of the values to a var, and then doing the comparison, makes it work properly however. So this works:

Code:
index2 = enemy_x[index];
if(enemy_destination_x[index] > index2)
{
//do something
}


Apart from the obvious stuff, like yes, even I can technically put a NES game together, this is the most important thing I learned - if a routine isn't working, it's probably too complex for the machine, and you need to shift some of the values off the registers and in to RAM. At least, I think that is what is happening. Regardless, it works, as the above is a literal example that had me stumped for a good hour or two before I figured out the answer.


Top
 Profile  
 
 Post subject: Re: Ludum Dare
PostPosted: Wed Dec 21, 2016 4:43 am 
Offline

Joined: Tue Oct 06, 2015 10:16 am
Posts: 493
Are you using an old version of cc65? I don't believe I've ever hit a bug like that where a two-array comparison would produce wrong results. It's slow yes, but correct.


Top
 Profile  
 
 Post subject: Re: Ludum Dare
PostPosted: Wed Dec 21, 2016 10:55 am 
Offline

Joined: Sat Oct 15, 2016 8:52 am
Posts: 73
cc65 V2.15 pre-compiled windows binary, which appears to be the same version in the current downloadable windows snapshot.

I can post an example later, if you like. I haven't checked what it's doing in the ASM though - it's just a presumption based on the fact an assignment of the right value to a var in C fixes it. Similar things have happened in both the ludum dare project and my latest project.


Top
 Profile  
 
 Post subject: Re: Ludum Dare
PostPosted: Wed Dec 21, 2016 11:03 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5544
Location: Canada
team_disposable wrote:
I can post an example later, if you like.

Please do. If the compiler is generating incorrect code that is a serious bug (and surprising).


Top
 Profile  
 
 Post subject: Re: Ludum Dare
PostPosted: Wed Dec 21, 2016 11:15 am 
Offline

Joined: Tue Oct 06, 2015 10:16 am
Posts: 493
Yep, cc65 is actively maintained, so any bugs should be reported with test cases.


Top
 Profile  
 
 Post subject: Re: Ludum Dare
PostPosted: Wed Dec 21, 2016 11:36 am 
Offline

Joined: Sat Oct 15, 2016 8:52 am
Posts: 73
Here's a rom that demonstrates both cases. Apologies, I just figured this was a regular thing - I'm sure it must be something I am doing, if not someone else would have noticed, no?

Pressing select switches between the two.

Please ignore the garish palettes and sparse rooms - I'm redecorating and haven't chosen a tone yet.

Here is the code difference (warning - big ol' chunk of code):

If no one spots anything stupid in the below, I'll go and report it to the CC65 people. And yes, index and index2 have a value in them. Do you want to see the ASM as well?

Code:
         if(debug_flip == 0x00)
         {
         
            index2 = enemy_x[index];
         
            if(enemy_destination_x[index] > index2)
            {
            
            ++enemy_x[index] ;
            enemy_directionfacing[index] = Going_Right;
            
            }
            else
            {
         
               if(enemy_destination_x[index] < index2)
               {
                  
                  --enemy_x[index] ;
                  enemy_directionfacing[index] = Going_Left;
               }
               else
               {
                  index2 = enemy_y[index];
         
                  if(enemy_destination_y[index] > index2){
                     
                     ++enemy_y[index] ;
                     enemy_directionfacing[index] = Going_Down;
                  }
                  
                  else
                  {
                     if(enemy_destination_y[index] < index2)
                     {
                     
                     --enemy_y[index] ;
                     enemy_directionfacing[index] = Going_Up;
                     }
                              
                  }
                              
               }
                  
            }
            

         }//end of debug flip is 0
         if(debug_flip == 0x01)
         {
            //index2 =
         
            if(enemy_destination_x[index] > enemy_x[index])
            {
            
            ++enemy_x[index] ;
            enemy_directionfacing[index] = Going_Right;
            
            }
            else
            {
         
               if(enemy_destination_x[index] < enemy_x[index])
               {
                  
                  --enemy_x[index] ;
                  enemy_directionfacing[index] = Going_Left;
               }
               else
               {
                  //index2 = enemy_y[index];
         
                  if(enemy_destination_y[index] > enemy_y[index]){
                     
                     ++enemy_y[index] ;
                     enemy_directionfacing[index] = Going_Down;
                  }
                  
                  else
                  {
                     if(enemy_destination_y[index] < enemy_y[index])
                     {
                     
                     --enemy_y[index] ;
                     enemy_directionfacing[index] = Going_Up;
                     }
                     
               
               
                  }
                  
                  
                  
               }
               
               
               
            }
   
         }//end of debug flip is 1


Attachments:
compo2.nes [24.02 KiB]
Downloaded 28 times
Top
 Profile  
 
 Post subject: Re: Ludum Dare
PostPosted: Wed Dec 21, 2016 12:27 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5544
Location: Canada
team_disposable wrote:
If no one spots anything stupid in the below

I don't see anything wrong with it offhand, though we're lacking the definition of index2 and other values, which could be important.

team_disposable wrote:
Do you want to see the ASM as well?

That would be helpful. It wouldn't be very easy to find the generated code in the ROM based on the C code.


Top
 Profile  
 
 Post subject: Re: Ludum Dare
PostPosted: Wed Dec 21, 2016 12:42 pm 
Offline

Joined: Sat Oct 15, 2016 8:52 am
Posts: 73
Going_Left, Going_Right etc are an enum.
enemy_destination_x, enemy_x, and its y counterparts are variable arrays populated from set of const arrays when the player enters a room.

It would seem the bug would probably be in the first comparison, and replicated in the others, so I've posted the first loops first. I'm not too fussed as I have a solution, so let me know if digging through ASM isn't your thing and I'll just go bugtrack it over at CC65.

here is the buggy first loop:

Code:
;
; if(enemy_destination_x[index] > enemy_x[index])
;
   ldy     _index
   lda     _enemy_destination_x,y
   jsr     pusha0
   ldy     _index
   lda     _enemy_x,y
   jsr     tosicmp0
   bcc     L2671
   beq     L2671
;
; ++enemy_x[index] ;
;
   lda     #<(_enemy_x)
   ldx     #>(_enemy_x)
   clc
   adc     _index
   bcc     L2679
   inx
L2679:   sta     ptr1
   stx     ptr1+1
   ldy     #$00
   lda     #$01
   clc
   adc     (ptr1),y
   sta     (ptr1),y
;
; enemy_directionfacing[index] = Going_Right;
;
   ldy     _index
   lda     #$00


the non-buggy first loop:

Code:

;
; index2 = enemy_x[index];
;
   ldy     _index
   lda     _enemy_x,y
   sta     _index2
;
; if(enemy_destination_x[index] > index2)
;
   ldy     _index
   lda     _enemy_destination_x,y
   sec
   sbc     _index2
   bcc     L263C
   beq     L263C
;
; ++enemy_x[index] ;
;
   lda     #<(_enemy_x)
   ldx     #>(_enemy_x)
   clc
   adc     _index
   bcc     L2642
   inx
L2642:   sta     ptr1
   stx     ptr1+1
   ldy     #$00
   lda     #$01
   clc
   adc     (ptr1),y
   sta     (ptr1),y
;
; enemy_directionfacing[index] = Going_Right;
;
   ldy     _index
   lda     #$00



Here's the full ASM of the buggy if loop:

Code:
 
;
; if(debug_flip == 0x01)
;
L2832:   lda     _debug_flip
   cmp     #$01
   jne     L266F
;
; if(enemy_destination_x[index] > enemy_x[index])
;
   ldy     _index
   lda     _enemy_destination_x,y
   jsr     pusha0
   ldy     _index
   lda     _enemy_x,y
   jsr     tosicmp0
   bcc     L2671
   beq     L2671
;
; ++enemy_x[index] ;
;
   lda     #<(_enemy_x)
   ldx     #>(_enemy_x)
   clc
   adc     _index
   bcc     L2679
   inx
L2679:   sta     ptr1
   stx     ptr1+1
   ldy     #$00
   lda     #$01
   clc
   adc     (ptr1),y
   sta     (ptr1),y
;
; enemy_directionfacing[index] = Going_Right;
;
   ldy     _index
   lda     #$00
;
; else
;
   jmp     L2830
;
; if(enemy_destination_x[index] < enemy_x[index])
;
L2671:   ldy     _index
   lda     _enemy_destination_x,y
   jsr     pusha0
   ldy     _index
   lda     _enemy_x,y
   jsr     tosicmp0
   bcs     L267F
;
; --enemy_x[index] ;
;
   lda     #<(_enemy_x)
   ldx     #>(_enemy_x)
   clc
   adc     _index
   bcc     L2687
   inx
L2687:   sta     ptr1
   stx     ptr1+1
   ldy     #$00
   lda     (ptr1),y
   sec
   sbc     #$01
   sta     (ptr1),y
;
; enemy_directionfacing[index] = Going_Left;
;
   ldy     _index
   lda     #$01
;
; else
;
   jmp     L2830
;
; if(enemy_destination_y[index] > enemy_y[index]){
;
L267F:   ldy     _index
   lda     _enemy_destination_y,y
   jsr     pusha0
   ldy     _index
   lda     _enemy_y,y
   jsr     tosicmp0
   bcc     L268D
   beq     L268D
;
; ++enemy_y[index] ;
;
   lda     #<(_enemy_y)
   ldx     #>(_enemy_y)
   clc
   adc     _index
   bcc     L2695
   inx
L2695:   sta     ptr1
   stx     ptr1+1
   ldy     #$00
   lda     #$01
   clc
   adc     (ptr1),y
   sta     (ptr1),y
;
; enemy_directionfacing[index] = Going_Down;
;
   ldy     _index
   lda     #$03
;
; else
;
   jmp     L2830
;
; if(enemy_destination_y[index] < enemy_y[index])
;
L268D:   ldy     _index
   lda     _enemy_destination_y,y
   jsr     pusha0
   ldy     _index
   lda     _enemy_y,y
   jsr     tosicmp0
   bcs     L266F
;
; --enemy_y[index] ;
;
   lda     #<(_enemy_y)
   ldx     #>(_enemy_y)
   clc
   adc     _index
   bcc     L26A3
   inx
L26A3:   sta     ptr1
   stx     ptr1+1
   ldy     #$00
   lda     (ptr1),y
   sec
   sbc     #$01
   sta     (ptr1),y
;
; enemy_directionfacing[index] = Going_Up;
;
   ldy     _index
   lda     #$02
L2830:   sta     _enemy_directionfacing,y


Top
 Profile  
 
 Post subject: Re: Ludum Dare
PostPosted: Wed Dec 21, 2016 9:55 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5544
Location: Canada
I don't actually see errors in the disassembly. I think the code its producing is actually correct.

By tracing that function in your running ROM I think the error is with your "sp" variable, which is supposed to point to the C stack area, but looks like you have it initialized to 0 instead. (Follow the value of $8A in the trace, uses of the C stack are trying to push variables to ROM at ~$FFFE as a result.)

The reason your workaround "fixes" it is that it doesn't happen to use the C stack, but I'm tremendously surprised you haven't seen huge errors elsewhere yet.

Here's an example trace:
Code:
A:01 X:00 Y:00 S:FB P:nvUbdIZC     $C5D9: A4 0E     LDY $000E = #$00
A:01 X:00 Y:00 S:FB P:nvUbdIZC     $C5DB: B9 58 00  LDA $0058,Y @ $0058 = #$60
A:60 X:00 Y:00 S:FB P:nvUbdIzC     $C5DE: 20 A4 CD  JSR $CDA4
A:60 X:00 Y:00 S:F9 P:nvUbdIzC       $CDA4: A2 00     LDX #$00
A:60 X:00 Y:00 S:F9 P:nvUbdIZC       $CDA6: 48        PHA
A:60 X:00 Y:00 S:F8 P:nvUbdIZC        $CDA7: A5 8A     LDA $008A = #$00
A:00 X:00 Y:00 S:F8 P:nvUbdIZC        $CDA9: 38        SEC
A:00 X:00 Y:00 S:F8 P:nvUbdIZC        $CDAA: E9 02     SBC #$02
A:FE X:00 Y:00 S:F8 P:NvUbdIzc        $CDAC: 85 8A     STA $008A = #$00
A:FE X:00 Y:00 S:F8 P:NvUbdIzc        $CDAE: B0 02     BCS $CDB2
A:FE X:00 Y:00 S:F8 P:NvUbdIzc        $CDB0: C6 8B     DEC $008B = #$00
A:FE X:00 Y:00 S:F8 P:NvUbdIzc        $CDB2: A0 01     LDY #$01
A:FE X:00 Y:01 S:F8 P:nvUbdIzc        $CDB4: 8A        TXA
A:00 X:00 Y:01 S:F8 P:nvUbdIZc        $CDB5: 91 8A     STA ($8A),Y @ $FFFF = #$C0
A:00 X:00 Y:01 S:F8 P:nvUbdIZc        $CDB7: 68        PLA
A:60 X:00 Y:01 S:F9 P:nvUbdIzc       $CDB8: 88        DEY
A:60 X:00 Y:00 S:F9 P:nvUbdIZc       $CDB9: 91 8A     STA ($8A),Y @ $FFFE = #$AA
A:60 X:00 Y:00 S:F9 P:nvUbdIZc       $CDBB: 60        RTS (from $CDA4) ---------------------------
A:60 X:00 Y:00 S:FB P:nvUbdIZc     $C5E1: A4 0E     LDY $000E = #$00
A:60 X:00 Y:00 S:FB P:nvUbdIZc     $C5E3: B9 30 00  LDA $0030,Y @ $0030 = #$67
A:67 X:00 Y:00 S:FB P:nvUbdIzc     $C5E6: 20 2F CD  JSR $CD2F
A:67 X:00 Y:00 S:F9 P:nvUbdIzc       $CD2F: A2 00     LDX #$00
A:67 X:00 Y:00 S:F9 P:nvUbdIZc       $CD31: 85 8C     STA $008C = #$3F
A:67 X:00 Y:00 S:F9 P:nvUbdIZc       $CD33: 86 8D     STX $008D = #$02
A:67 X:00 Y:00 S:F9 P:nvUbdIZc       $CD35: A0 00     LDY #$00
A:67 X:00 Y:00 S:F9 P:nvUbdIZc       $CD37: B1 8A     LDA ($8A),Y @ $FFFE = #$AA
A:AA X:00 Y:00 S:F9 P:NvUbdIzc       $CD39: AA        TAX
A:AA X:AA Y:00 S:F9 P:NvUbdIzc       $CD3A: E6 8A     INC $008A = #$FE
A:AA X:AA Y:00 S:F9 P:NvUbdIzc       $CD3C: D0 02     BNE $CD40
A:AA X:AA Y:00 S:F9 P:NvUbdIzc       $CD40: B1 8A     LDA ($8A),Y @ $FFFF = #$C0
A:C0 X:AA Y:00 S:F9 P:NvUbdIzc       $CD42: E6 8A     INC $008A = #$FF
A:C0 X:AA Y:00 S:F9 P:nvUbdIZc       $CD44: D0 02     BNE $CD48
A:C0 X:AA Y:00 S:F9 P:nvUbdIZc       $CD46: E6 8B     INC $008B = #$FF
A:C0 X:AA Y:00 S:F9 P:nvUbdIZc       $CD48: 38        SEC
A:C0 X:AA Y:00 S:F9 P:nvUbdIZC       $CD49: E5 8D     SBC $008D = #$00
A:C0 X:AA Y:00 S:F9 P:NvUbdIzC       $CD4B: D0 09     BNE $CD56
A:C0 X:AA Y:00 S:F9 P:NvUbdIzC       $CD56: 50 FD     BVC $CD55
A:C0 X:AA Y:00 S:F9 P:NvUbdIzC       $CD55: 60        RTS (from $CD2F) ---------------------------


So, the fix is not with CC65. The problem is that you have not initialized sp, which must be done by your CRT startup before entering main. I don't know whose CRT startup you are using, so I can't tell you where to fix it.

See line 100 here (in CC65's included NES CRT), and make sure the same gets done in your startup: https://github.com/cc65/cc65/blob/master/libsrc/nes/crt0.s


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 36 posts ]  Go to page Previous  1, 2, 3  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group