It is currently Mon Aug 21, 2017 6:44 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 97 posts ]  Go to page Previous  1 ... 3, 4, 5, 6, 7
Author Message
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Fri Aug 11, 2017 12:34 pm 
Offline
User avatar

Joined: Tue Jun 10, 2014 8:15 pm
Posts: 35
Location: Canada
tschak909 wrote:
The modulo is the problem here, given an integer divide by 24 such as:

Code:
;; void __fastcall__ div24(unsigned char d);
_div24: lsr
        lsr
        lsr
        sta   TEMP
        lsr
        lsr
        adc   TEMP
        ror
        lsr
        adc   TEMP
        ror
        lsr
        rts


How can I determine a modulo? Is it sitting here in temp at some point?

-Thom


Modulo is easy, there are a few ways to do it. You'll have to figure out how to integerate it into C though. Here's a few ways:

Long slow division does not take too long in this case as 24 is a big divisor.
Code:
;24-94 cycles
_div24_mod24:
        ldy   #$FF
        sec
_div24:
        iny
        sbc   #24
        bcs   _div24
        adc   #24
        rts   ; Y = integer division result, A = modulo result


Using the unsigned integer division routine for div24, modulo24 can be found afterward with the help of a small look up table:
Code:
;54 cycles 
_div24_mod24:
        pha   ; save original value

        lsr
        lsr
        lsr
        sta   TEMP
        lsr
        lsr
        adc   TEMP
        ror
        lsr
        adc   TEMP
        ror
        lsr
       
        tay   ; integer division result
        pla   ; get original value
        sec
        sbc   _multiply24,Y
        rts   ; Y = integer division result, A = modulo result

_multiply24:
        .db 0,24,48,72,96,120
        .db 144,168,192,216,240


If you don't want to trash Y, you could just multiply by 24 instead of using a look up table.
Code:
_div24_mod24:
        pha   ; save original value

        lsr
        lsr
        lsr
        sta   TEMP
        lsr
        lsr
        adc   TEMP
        ror
        lsr
        adc   TEMP
        ror
        lsr
                        ; C 76543210
        sta   intDiv24  ; x 0000xxxx    integer division result (0-10 possible)
       
        asl             ; 0 000xxxx0    x2
        asl             ; 0 00xxxx00    x4
        asl             ; 0 0xxxx000    x8
        sta   TEMP
        asl             ; 0 xxxx0000    x16 (carry is always clear at this point)
        adc   TEMP      ;               x24
        sta   TEMP
        pla   ; get original value
        sec
        sbc   TEMP      ; A = modulo result, intDiv24 = integer division result
        rts



Hope that helps!


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Fri Aug 11, 2017 1:23 pm 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 74
Omegamatrix wrote:
tschak909 wrote:
The modulo is the problem here, given an integer divide by 24 such as:

Code:
;; void __fastcall__ div24(unsigned char d);
_div24: lsr
        lsr
        lsr
        sta   TEMP
        lsr
        lsr
        adc   TEMP
        ror
        lsr
        adc   TEMP
        ror
        lsr
        rts


How can I determine a modulo? Is it sitting here in temp at some point?

-Thom


Modulo is easy, there are a few ways to do it. You'll have to figure out how to integerate it into C though. Here's a few ways:

Long slow division does not take too long in this case as 24 is a big divisor.
Code:
;24-94 cycles
_div24_mod24:
        ldy   #$FF
        sec
_div24:
        iny
        sbc   #24
        bcs   _div24
        adc   #24
        rts   ; Y = integer division result, A = modulo result


Using the unsigned integer division routine for div24, modulo24 can be found afterward with the help of a small look up table:
Code:
;54 cycles 
_div24_mod24:
        pha   ; save original value

        lsr
        lsr
        lsr
        sta   TEMP
        lsr
        lsr
        adc   TEMP
        ror
        lsr
        adc   TEMP
        ror
        lsr
       
        tay   ; integer division result
        pla   ; get original value
        sec
        sbc   _multiply24,Y
        rts   ; Y = integer division result, A = modulo result

_multiply24:
        .db 0,24,48,72,96,120
        .db 144,168,192,216,240


If you don't want to trash Y, you could just multiply by 24 instead of using a look up table.
Code:
_div24_mod24:
        pha   ; save original value

        lsr
        lsr
        lsr
        sta   TEMP
        lsr
        lsr
        adc   TEMP
        ror
        lsr
        adc   TEMP
        ror
        lsr
                        ; C 76543210
        sta   intDiv24  ; x 0000xxxx    integer division result (0-10 possible)
       
        asl             ; 0 000xxxx0    x2
        asl             ; 0 00xxxx00    x4
        asl             ; 0 0xxxx000    x8
        sta   TEMP
        asl             ; 0 xxxx0000    x16 (carry is always clear at this point)
        adc   TEMP      ;               x24
        sta   TEMP
        pla   ; get original value
        sec
        sbc   TEMP      ; A = modulo result, intDiv24 = integer division result
        rts



Hope that helps!


OMEGAMATRIX! How are you, man? Good to see you over here from AtariAge. I just signed up here for my first NES project.

also, thanks for the fast divide routines. They're great.

-Thom


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Fri Aug 11, 2017 2:47 pm 
Offline
User avatar

Joined: Tue Jun 10, 2014 8:15 pm
Posts: 35
Location: Canada
I'm well. Looking for to see this homebrew develop. :)


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Fri Aug 11, 2017 9:42 pm 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 74
I'm getting closer, I've attached a ROM of the current behavior. It mostly works except in certain cases I can still go through walls, and am trying to figure out why this is:

code snippets:

Code:
/**
 * handle_pad_idle()
 */
void handle_pad_idle(void)
{
  // Change to idle state if pad is idle.
  switch(stamps[STAMP_LAST_STATE(i)])
    {
    case STATE_PLAYER_RIGHT:
      stamps[STAMP_STATE(i)]=STATE_PLAYER_RIGHT_IDLE;
      break;
    case STATE_PLAYER_LEFT:
      stamps[STAMP_STATE(i)]=STATE_PLAYER_LEFT_IDLE;
      break;
    case STATE_PLAYER_UP:
      stamps[STAMP_STATE(i)]=STATE_PLAYER_UP_IDLE;
      break;
    case STATE_PLAYER_DOWN:
      stamps[STAMP_STATE(i)]=STATE_PLAYER_DOWN_IDLE;
      break;
    }
}

/**
 * handle_player_in_field()
 * Handle when player is on the playfield
 */
void handle_player_in_field(void)
{
  if ((stamps[STAMP_X(i)]==PIXEL_BOX_X(a)) && (stamps[STAMP_Y(i)]==PIXEL_BOX_Y(b)))
    {
      // We are aligned.
      if (PLAYER_PAD_RIGHT(i) && !BOX_WALL_RIGHT(d))
        stamps[STAMP_STATE(i)]=stamps[STAMP_LAST_STATE(i)]=STATE_PLAYER_RIGHT;
      else if (PLAYER_PAD_LEFT(i) && !BOX_WALL_LEFT(d))
        stamps[STAMP_STATE(i)]=stamps[STAMP_LAST_STATE(i)]=STATE_PLAYER_LEFT;
      else if (PLAYER_PAD_UP(i) && !BOX_WALL_UP(d))
        stamps[STAMP_STATE(i)]=stamps[STAMP_LAST_STATE(d)]=STATE_PLAYER_UP;
      else if (PLAYER_PAD_DOWN(i) && !BOX_WALL_DOWN(d))
        stamps[STAMP_STATE(i)]=stamps[STAMP_LAST_STATE(d)]=STATE_PLAYER_DOWN;
      else if (PLAYER_PAD_IDLE(i))
          handle_pad_idle();
    }
  else
    {
      // We are not aligned.
      if (PLAYER_PAD_IDLE(i))
        handle_pad_idle();
      else if (PLAYER_PAD_RIGHT(i) && stamps[STAMP_LAST_STATE(i)]==STATE_PLAYER_LEFT)
        stamps[STAMP_STATE(i)]=STATE_PLAYER_RIGHT;
      else if (PLAYER_PAD_LEFT(i) && stamps[STAMP_LAST_STATE(i)]==STATE_PLAYER_RIGHT)
        stamps[STAMP_STATE(i)]=STATE_PLAYER_LEFT;
      else if (PLAYER_PAD_UP(i) && stamps[STAMP_LAST_STATE(i)]==STATE_PLAYER_DOWN)
        stamps[STAMP_STATE(i)]=STATE_PLAYER_UP;
      else if (PLAYER_PAD_DOWN(i) && stamps[STAMP_LAST_STATE(i)]==STATE_PLAYER_UP)
        stamps[STAMP_STATE(i)]=STATE_PLAYER_DOWN;
      else
        stamps[STAMP_STATE(i)]=stamps[STAMP_LAST_STATE(i)];
    }

  // Handle state movement
  if (stamps[STAMP_STATE(i)]==STATE_PLAYER_RIGHT)
    stamps[STAMP_X(i)]++;
  else if (stamps[STAMP_STATE(i)]==STATE_PLAYER_LEFT)
    stamps[STAMP_X(i)]--;
  else if (stamps[STAMP_STATE(i)]==STATE_PLAYER_UP)
    stamps[STAMP_Y(i)]--;
  else if (stamps[STAMP_STATE(i)]==STATE_PLAYER_DOWN)
    stamps[STAMP_Y(i)]++;

  // And set last state, if we aren't idle.
  if (!PLAYER_PAD_IDLE(i))
    stamps[STAMP_LAST_STATE(i)]=stamps[STAMP_STATE(i)];
}

/**
 * handle_player_in_box()
 * Handle when player is in box.
 */
void handle_player_in_box(void)
{
  if (stamps[STAMP_XTRA_A(i)]>0)
    {
      if (stamps[STAMP_XTRA_B(i)] != 0)
        {
          stamps[STAMP_XTRA_A(i)]=0;
        }
      else
        {
          stamps[STAMP_Y(i)]=PIXEL_BOX_Y(6)-1; // 6 is the Y for the box.
          if (sec==0) // 0 means approximately 1 second elapsed.
            stamps[STAMP_XTRA_A(i)]--;         // Decrement timer
        }
    }
  else
    {
      stamps[STAMP_Y(i)]=PIXEL_BOX_Y(5); // Pop out of box.
      if (i==0)
        {
          yellow_door_state=CLOSED;
        }
      else
        {
          blue_door_state=CLOSED;
        }
    }
}

/**
 * move_players()
 */
void move_players(void)
{
  for (i=0;i<2;++i)
    {
      get_current_box();
      stamps[STAMP_XTRA_B(i)]=pad_poll(i);

      if (stamps[STAMP_Y(i)]==PIXEL_BOX_Y(6)-1)
        {
          handle_player_in_box();
        }
      else
        {
          handle_player_in_field();
        }
    }
}


Some vars:

a=the x coordinate for box cell (0-9)
b=the y coordinate for box cell (0-5)
c=the entry in the dungeon table to get the walls for that cell
d=the value pointed to by c

PIXEL_BOX_X converts a to a screen pixel coordinate using a multiply by 24 and adding a center bias, effectively aligning sprite in the center of box.

PIXEL_BOX_Y is the same for the Y coordinate in b.

BOX_WALL_* are macros that check for a given bit set in D for a wall present in cell d

I'm so freaking close, it's %(#@@#(%@# grrrrr... heeeeeelp! :)

Of course, the code is in github, but I'm attaching a binary rom here in case somebody can derive the errant behavior:
Attachment:
wow-better-player-collision.nes [40.02 KiB]
Downloaded 8 times


-Thom


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Fri Aug 11, 2017 11:31 pm 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 74
Adding this block in the aligned condition improves the collision detection to the point where I am no longer going through any walls, BUT, The player tries to change direction one box before the actual corner, which causes the player to not go through the wall, but hit the preceeding wall early and stop trying to round the corner. urgh...

Code:
      if (PLAYER_PAD_RIGHT(i) && BOX_WALL_RIGHT(d))
        stamps[STAMP_STATE(i)]=STATE_PLAYER_RIGHT_IDLE;
      else if (PLAYER_PAD_LEFT(i) && BOX_WALL_LEFT(d))
        stamps[STAMP_STATE(i)]=STATE_PLAYER_LEFT_IDLE;
      else if (PLAYER_PAD_UP(i) && BOX_WALL_UP(d))
        stamps[STAMP_STATE(i)]=STATE_PLAYER_UP_IDLE;
      else if (PLAYER_PAD_DOWN(i) && BOX_WALL_DOWN(d))
        stamps[STAMP_STATE(i)]=STATE_PLAYER_DOWN_IDLE;


Attachment:
wow-better-player-coll-2.nes [40.02 KiB]
Downloaded 16 times


Setting it to last state on each if, replicates the through wall behavior, so it looks like I need to dig into last state setting.

-Thom


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Sat Aug 12, 2017 12:09 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5555
Location: Canada
The lion-head enemies have a nice bounce to them.


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Sat Aug 12, 2017 12:13 am 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 74
rainwarrior wrote:
The lion-head enemies have a nice bounce to them.


Thanks, I am doing occasional tests on a front loader attached to a cheapo AV upscaler which is just butchering the field output, and would love to see a pic of this running on a real CRT. The NTSC emulation in various emulators just doesn't feel right at all.

I will say that it is on my list that the monsters will all eventually have have random frame starts, so they aren't all skipping in unison, but right now, I am trying to get player to wall collision happening correctly. It's almost there. grrrrr...

-Thom


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 97 posts ]  Go to page Previous  1 ... 3, 4, 5, 6, 7

All times are UTC - 7 hours


Who is online

Users browsing this forum: Google Adsense [Bot] and 6 guests


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