WIP: Wizard of Wor

A place where you can keep others updated about your NES-related projects through screenshots, videos or information in general.

Moderator: Moderators

Post Reply
tschak909
Posts: 139
Joined: Mon Jul 03, 2017 4:37 pm
Contact:

Re: WIP: Wizard of Wor

Post by tschak909 » Fri Aug 04, 2017 11:20 pm

Hello, everybody. A bit further, I have player movement working, except:

* of course, timer state needs to be extended a bit to have the pop-out action
* right now all box calculations are done with the top left x,y, which makes player movement with the sprite quite funny if you traverse an intersection and are not completely in the adjunct box.

I need to think through how best to solve the latter problem, if anyone has any ideas, feel free to reply. In the mean time, I've attached a ROM to show behavior.
wow-player-test.nes
(40.02 KiB) Downloaded 101 times
relevant code:

Code: Select all

/**
 * move_players()
 */
void move_players(void)
{
  for (i=0;i<2;++i)
    {
      // Get the player's box.
      a=div24(stamps[STAMP_X(i)]-8);
      b=div24(stamps[STAMP_Y(i)]-8);
      c=(b*10)+a; // C is now the box #
      d=dungeon[c];

      if (stamps[STAMP_XTRA_A(i)]==TRUE)
        {
          // Player inside box.
          if (sec==0)  // One second has elapsed.
            {
              stamps[STAMP_XTRA_B(i)]--;
              if (stamps[STAMP_XTRA_B(i)]==0x00)
                {
                  stamps[STAMP_XTRA_A(i)]=FALSE;
                }
            }
          else
            {
              // do nothing, for now.
            }
        }
      else
        {
          // Player outside box.
          if (stamps[STAMP_XTRA_B(i)]==0x00)
            {
              // Eject player
              stamps[STAMP_Y(i)]=PIXEL_BOX_Y(5); // Place inside playfield.
              stamps[STAMP_XTRA_B(i)]=0xff; // Indicate player has been ejected.
              if (i==0)
                {
                  yellow_door_state=CLOSED;
                }
              else
                {
                  blue_door_state=CLOSED;
                }
            }
          else
            {
              // Player is free to move, move about.
              if ((stamps[STAMP_STATE(i)] == STATE_PLAYER_RIGHT_IDLE) ||
                  (stamps[STAMP_STATE(i)] == STATE_PLAYER_LEFT_IDLE)  ||
                  (stamps[STAMP_STATE(i)] == STATE_PLAYER_UP_IDLE)    ||
                  (stamps[STAMP_STATE(i)] == STATE_PLAYER_DOWN_IDLE))
                {
                  // Player is idle, do nothing, else...
                }
              else
                {
                  // Player wants to move.
                  if (stamps[STAMP_STATE(i)]==STATE_PLAYER_RIGHT)
                    {
                      if (d&1<<4)
                        {
                          // Right wall nearby.
                          if (stamps[STAMP_X(i)]==PIXEL_BOX_X(a))
                            {
                              // don't do a damned thing.
                            }
                          else
                            {
                              stamps[STAMP_X(i)]++;
                            }
                        }
                      else
                        {
                          stamps[STAMP_X(i)]++;
                        }
                    }
                  else if (stamps[STAMP_STATE(i)]==STATE_PLAYER_LEFT)
                    {
                      if (d&1<<6)
                        {
                          // Left wall nearby
                          if (stamps[STAMP_X(i)]==PIXEL_BOX_X(a))
                            {
                              // Don't do anything
                            }
                          else
                            {
                              stamps[STAMP_X(i)]--;
                            }
                        }
                      else
                        {
                          stamps[STAMP_X(i)]--;
                        }
                    }
                  else if (stamps[STAMP_STATE(i)]==STATE_PLAYER_UP)
                    {
                      if (d&1<<7)
                        {
                          // Up wall nearby
                          if (stamps[STAMP_Y(i)]==PIXEL_BOX_Y(b))
                            {
                              // Don't do anything
                            }
                          else
                            {
                              stamps[STAMP_Y(i)]--;
                            }
                        }
                      else
                        {
                          stamps[STAMP_Y(i)]--;
                        }
                    }
                  else if (stamps[STAMP_STATE(i)]==STATE_PLAYER_DOWN)
                    {
                      if (d&1<<5)
                        {
                          // Down wall nearby
                          if (stamps[STAMP_Y(i)]==PIXEL_BOX_Y(b))
                            {
                              // Don't do anything.
                            }
                          else
                            {
                              stamps[STAMP_Y(i)]++;
                            }
                        }
                      else
                        {
                          stamps[STAMP_Y(i)]++;
                        }
                    }
                }
            }
        }
    }
}
-Thom

tschak909
Posts: 139
Joined: Mon Jul 03, 2017 4:37 pm
Contact:

Re: WIP: Wizard of Wor

Post by tschak909 » Sun Aug 06, 2017 11:38 pm

Day 3 of still trying to hammer through the controls, still stuck.

The intended behavior is to have the player traverse into an opening only if their feet are all the way at the extreme end of the box, if they aren't, then the player moves in the last successful direction until the feet touch the box extreme end.)

trying to do this without resorting to more pedestrian methods is making my head hurt.

-Thom

User avatar
Myask
Posts: 965
Joined: Sat Jul 12, 2014 3:04 pm

Re: WIP: Wizard of Wor

Post by Myask » Mon Aug 07, 2017 1:38 am

Oh, pac-man/Zelda1-style moves? That's fairly simple.

Code: Select all

//pseudocode
//once per frame...
if (any direction pressed)
	if (aligned with tile)
		move (pressed direction)
		lastmove = pressed
		alignedWithIntersection = false
	else if //not aligned
		if (pressed direction is at right angle to last moved direction)
			move (last moved)
		else
			move (pressed) //either toward or opposite last move
			lastmove = pressed
		//then check alignment with possible intersections
		//often accomplished with modulo
		//note that you only need check one coordinate
		//based on what direction lastmove is

tschak909
Posts: 139
Joined: Mon Jul 03, 2017 4:37 pm
Contact:

Re: WIP: Wizard of Wor

Post by tschak909 » Mon Aug 07, 2017 11:05 am

The modulo is the problem here, given an integer divide by 24 such as:

Code: Select all

;; 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

lidnariq
Posts: 9510
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: WIP: Wizard of Wor

Post by lidnariq » Mon Aug 07, 2017 11:14 am

No, the remainder is thrown away in the carry bits as it does the math.

That routine's actually calculating
TEMP = (arg/8)
TEMP += (arg/32)
TEMP += (arg/128)+!!(arg&64)

.... that's not ÷24, that's ÷6.

tschak909
Posts: 139
Joined: Mon Jul 03, 2017 4:37 pm
Contact:

Re: WIP: Wizard of Wor

Post by tschak909 » Mon Aug 07, 2017 11:20 am

That's what I figured. I'm trying to see how I can handle the collision detection sanely, without needing to resort to a modulo, as each box is 24 pixels by 24 pixels (a 3x3 set of tiles).

-Thom

tschak909
Posts: 139
Joined: Mon Jul 03, 2017 4:37 pm
Contact:

Re: WIP: Wizard of Wor

Post by tschak909 » Mon Aug 07, 2017 11:24 am

I am deathly afraid of how much code will be added if I use a modulo operator (%) here...

-Thom

lidnariq
Posts: 9510
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: WIP: Wizard of Wor

Post by lidnariq » Mon Aug 07, 2017 11:31 am

I have a trivial PIC asm get-remainder routine that just works by manually doing to the long division and throwing away the quotient, something akin to

Code: Select all

uint8 getremainder(uint8 dividend, uint8 divisor) {
  uint8 count=1;
  while (! divisor & 0x80) { divisor<<=1; count++; }
  for (; count; count--, divisor >>=1) {
    if (dividend > divisor) dividend -= divisor;
  }
  return dividend;
}
No idea if cc65's comparably efficient.

For ÷24 just unrolling that's probably not unreasonable.

tepples
Posts: 22019
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: WIP: Wizard of Wor

Post by tepples » Mon Aug 07, 2017 11:49 am

The other way to do it is to represent all character positions in world space using units of 1/256 cell. This makes collision detection easier, as you have a whole number of cells and fraction of cells, and you can easily multiply by 24 for display:

Code: Select all

; assume actor_x is in tiles and actor_xsub is in 1/256 tiles
lda actor_x,x
sta temp_hi
lda actor_xsub,x
asl a
rol temp_hi  ; temp_hi:A = X*2

adc actor_xsub,x
sta temp_lo
lda temp_hi
adc actor_x,x  ; A:temp_lo = X*3

.repeat 3
  asl temp_lo
  rol a  ; A:templo = X*6, X*12, X*24
.endrepeat

; by now, A is pixel position of sprite
As for walking into a wall edge-on, I'd recommend walking toward the center of the cell instead of walking in the same direction as before. This way, if you slighly overshoot the area between walls, you'll back up into the cell close to you instead of the next cell up. Should I draw a diagram of this suggestion to illustrate?

tschak909
Posts: 139
Joined: Mon Jul 03, 2017 4:37 pm
Contact:

Re: WIP: Wizard of Wor

Post by tschak909 » Mon Aug 07, 2017 12:28 pm

Sure.

-Thom

User avatar
Myask
Posts: 965
Joined: Sat Jul 12, 2014 3:04 pm

Re: WIP: Wizard of Wor

Post by Myask » Mon Aug 07, 2017 3:26 pm

Then just store the "distance to next cell", with 0 being aligned, decrement each time you move…and if you turn around halfway, set it to 23-last instead of decrementing it. No modulo necessary by keeping track of it (and it doubles as the "aligned" variable).

tepples
Posts: 22019
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: WIP: Wizard of Wor

Post by tepples » Mon Aug 07, 2017 3:28 pm

press_against_wall_options.gif
press_against_wall_options.gif (20.6 KiB) Viewed 2957 times
A: The character stops just past the center of the cell. Then the player presses toward a wall. But because movement is blocked by a wall, the character finishes entering the cell he was last entering before turning into the next hallway.

B: The character stops just past the center of the cell. Then the player presses toward a wall. But because movement is blocked by a wall, the character inches toward the center of the cell and then proceeds down the nearest hallway.

tschak909
Posts: 139
Joined: Mon Jul 03, 2017 4:37 pm
Contact:

Re: WIP: Wizard of Wor

Post by tschak909 » Mon Aug 07, 2017 3:33 pm

Myask wrote:Then just store the "distance to next cell", with 0 being aligned, decrement each time you move…and if you turn around halfway, set it to 23-last instead of decrementing it. No modulo necessary by keeping track of it (and it doubles as the "aligned" variable).
Makes sense, I see this in an older page of my notes, I just didn't haven't been able to think it all the way through.

Collision detection code has always been my steep hill, and I always have to fully understand the conditions to states, before I can hammer it out.

Everybody has provided excellent info. I am going to digest it, and keep working through the problem.

Thanks,
-Thom

User avatar
Myask
Posts: 965
Joined: Sat Jul 12, 2014 3:04 pm

Re: WIP: Wizard of Wor

Post by Myask » Mon Aug 07, 2017 4:00 pm

I should note that the (23-last) is assuming you're using 24-pixel cells [invert (24-last)and decrement combined], and the decrement in that and elsewhere assuming that you're moving the sprite at 1px/frame.

You'd have to add a compare vs 12 to go "should I turn around" on pressing a right-angle direction to get behavior B tepples diagrammed.
My suggestion was instead to "continue to next cell if a direction is held unless you explicitly turn around"…which I'm not sure is better. Pac-man, you rarely want to turn around because a ghost is behind you, and turning before the corner causing you to reverse course into a ghost would be bad. However, if you press it late and it doesn't turn you around, which my behavior C wouldn't, then that might also be bad.

tschak909
Posts: 139
Joined: Mon Jul 03, 2017 4:37 pm
Contact:

Re: WIP: Wizard of Wor

Post by tschak909 » Thu Aug 10, 2017 10:42 pm

Still working through it.. sigh.. I suck.

-Thom

Post Reply