It is currently Sun Aug 19, 2018 6:28 pm

 All times are UTC - 7 hours

 Page 7 of 12 [ 166 posts ] Go to page Previous  1 ... 4, 5, 6, 7, 8, 9, 10 ... 12  Next
 Print view Previous topic | Next topic
Author Message
 Post subject: Re: WIP: Wizard of WorPosted: Fri Aug 11, 2017 12:34 pm

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

 Post subject: Re: WIP: Wizard of WorPosted: Fri Aug 11, 2017 1:23 pm

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 123
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

 Post subject: Re: WIP: Wizard of WorPosted: Fri Aug 11, 2017 2:47 pm

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

Top

 Post subject: Re: WIP: Wizard of WorPosted: Fri Aug 11, 2017 9:42 pm

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 123
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 51 times

-Thom

Top

 Post subject: Re: WIP: Wizard of WorPosted: Fri Aug 11, 2017 11:31 pm

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 123
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 72 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

 Post subject: Re: WIP: Wizard of WorPosted: Sat Aug 12, 2017 12:09 am

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

Top

 Post subject: Re: WIP: Wizard of WorPosted: Sat Aug 12, 2017 12:13 am

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 123
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

 Post subject: Re: WIP: Wizard of WorPosted: Sat Aug 26, 2017 1:12 pm

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 123
It's been quiet here, as I've been sidetracked on doing some Raspberry Pi work, but I'm continuing back on this, as soon as I hit a stopping point with the work I'm doing on the Pi.

-Thom

Top

 Post subject: Re: WIP: Wizard of WorPosted: Mon Sep 04, 2017 7:19 pm

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 123
and I'm back. Motion solved with the following code (to be optimized):

Code:
/**
* 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) && stamps[STAMP_LAST_STATE(i)] != STATE_PLAYER_RIGHT && !BOX_WALL_RIGHT(d))
stamps[STAMP_STATE(i)]=stamps[STAMP_LAST_STATE(i)]=STATE_PLAYER_RIGHT;
else if (PLAYER_PAD_LEFT(i) && stamps[STAMP_LAST_STATE(i)] != STATE_PLAYER_LEFT && !BOX_WALL_LEFT(d))
stamps[STAMP_STATE(i)]=stamps[STAMP_LAST_STATE(i)]=STATE_PLAYER_LEFT;
else if (PLAYER_PAD_UP(i) && stamps[STAMP_LAST_STATE(i)] != STATE_PLAYER_UP && !BOX_WALL_UP(d))
stamps[STAMP_STATE(i)]=stamps[STAMP_LAST_STATE(d)]=STATE_PLAYER_UP;
else if (PLAYER_PAD_DOWN(i) && stamps[STAMP_LAST_STATE(i)] != STATE_PLAYER_DOWN && !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();

if (stamps[STAMP_LAST_STATE(i)]==STATE_PLAYER_RIGHT && BOX_WALL_RIGHT(d))
stamps[STAMP_STATE(i)]=STATE_PLAYER_RIGHT_IDLE;
else if (stamps[STAMP_LAST_STATE(i)]==STATE_PLAYER_LEFT && BOX_WALL_LEFT(d))
stamps[STAMP_STATE(i)]=STATE_PLAYER_LEFT_IDLE;
else if (stamps[STAMP_LAST_STATE(i)]==STATE_PLAYER_UP && BOX_WALL_UP(d))
stamps[STAMP_STATE(i)]=STATE_PLAYER_UP_IDLE;
else if (stamps[STAMP_LAST_STATE(i)]==STATE_PLAYER_DOWN && BOX_WALL_DOWN(d))
stamps[STAMP_STATE(i)]=STATE_PLAYER_DOWN_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)]+=2;
else if (stamps[STAMP_STATE(i)]==STATE_PLAYER_LEFT)
stamps[STAMP_X(i)]-=2;
else if (stamps[STAMP_STATE(i)]==STATE_PLAYER_UP)
stamps[STAMP_Y(i)]-=2;
else if (stamps[STAMP_STATE(i)]==STATE_PLAYER_DOWN)
stamps[STAMP_Y(i)]+=2;

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

Also merged in a new cfg file and Makefile courtesy of polluks, which will work on newer CC65 compilers after 2.15.

Latest ROM here:
Attachment:
wow-working-player-collision.nes [40.02 KiB]
Downloaded 59 times

More to come shortly,
-Thom

Top

 Post subject: Re: WIP: Wizard of WorPosted: Mon Sep 04, 2017 9:55 pm

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 123
is control okay for everybody? You should be able to move and round corners with ease. Let me know.

-Thom

Top

 Post subject: Re: WIP: Wizard of WorPosted: Mon Sep 04, 2017 10:05 pm

Joined: Sun Apr 13, 2008 11:12 am
Posts: 7397
Location: Seattle
Feels good to me. The bit where trying to walk into a wall makes you continue walking in the previous direction until you can turn strikes me as "surprising, but useful".

Top

 Post subject: Re: WIP: Wizard of WorPosted: Mon Sep 04, 2017 10:19 pm

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6600
Location: Canada
It's good. I like that you can hold diagonal and it will alternate. That's exactly how I'd want/expect it to work.

The only thing that's maybe weird to me is if I press up just a little bit then stop, now pressing either left or right will move me upwards until the next grid, which feels a little weird, but maybe not something that needs to be addressed at all. (It's easy to learn this quirk, and it resolves itself pretty quickly anyway.)

Like I think I'd probably make it so that you can't stop moving between grid points, only reverse direction, so there's never a situation where you could have stopped just a little bit out of grid and have left/right forced to move up/down. I don't know if you'd want to do that, though, I presume the original game did not. That's just what I'd do, because it seems like walking a little bit out of the grid is already a commitment to move in that direction, might as well complete it?

Right now the sprite overlaps right-hand walls by one pixel.

Also kinda wish that my feet didn't always point right when going up/down but that also seems to be that way in the original? (I suppose it would make just as much sense to be able to walk upside-down as well, but that one doesn't feel "missing".)

Ejection from the starting point seems weird (immediate pop out, and then one frame of changed direction), but I'll assume that's something you haven't worked on yet.

Last edited by rainwarrior on Mon Sep 04, 2017 10:21 pm, edited 2 times in total.

Top

 Post subject: Re: WIP: Wizard of WorPosted: Mon Sep 04, 2017 10:19 pm

Joined: Wed Apr 02, 2008 2:09 pm
Posts: 1179
The rounding corners is quite fine.

But you've got some kind of serious glitch for the two players.

When player 2 changes to facing up or down, occasionally it affects player one. Let me know if you need an fm2 or something for debugging.

Edit: Oh, I appear to have missed the previous post saying there were problems with going through walls. Maybe the gif is useful for reproducing it, though.

_________________
https://kasumi.itch.io/indivisible

Top

 Post subject: Re: WIP: Wizard of WorPosted: Tue Sep 05, 2017 7:58 am

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 123
WOW, that's a neat bug. I'll try to squash that today. Thanks for finding it!

-Thom

Top

 Post subject: Re: WIP: Wizard of WorPosted: Tue Sep 05, 2017 8:25 am

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 123
Ok, it has to be here, is there something stupid that I'm doing with regards to reading the player pads?

Code:
/**
* 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();
}
}
}

Top

 Display posts from previous: All posts1 day7 days2 weeks1 month3 months6 months1 year Sort by AuthorPost timeSubject AscendingDescending
 Page 7 of 12 [ 166 posts ] Go to page Previous  1 ... 4, 5, 6, 7, 8, 9, 10 ... 12  Next

 All times are UTC - 7 hours

#### Who is online

Users browsing this forum: Rahsennor and 3 guests

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

Search for:
 Jump to:  Select a forum ------------------ NES / Famicom    NESdev    NESemdev    NES Graphics    NES Music    Homebrew Projects       2018 NESdev Competition       2017 NESdev Competition       2016 NESdev Competition       2014 NESdev Competition       2011 NESdev Competition    Newbie Help Center    NES Hardware and Flash Equipment       Reproduction    NESdev International       FCdev       NESdev China       NESdev Middle East Other    General Stuff    Membler Industries    Other Retro Dev       SNESdev       GBDev    Test Forum Site Issues    phpBB Issues    Web Issues    nesdevWiki
Powered by phpBB® Forum Software © phpBB Group