It is currently Sun Nov 19, 2017 9:12 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 131 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6 ... 9  Next
Author Message
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Mon Jul 10, 2017 8:25 pm 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 98
I will definitely look at that engine. Looks great at first glance.

As for graphics, doing yet another pass. Was able to gain 6 pixels in both X and Y directions by pushing the lines in the line tiles toward the edge.

So I am pushing things back, and shuffling around tiles...

I really don't want to push sprites to 16x16...

I for damned sure won't change the text to 8x8, because it will lose all its character.

I hope to get this stable enough to where I can compress all the tiles (get rid of duplicates etc) so I can gain some much needed tile space, especially on the sprite side.

-Thom


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Tue Jul 11, 2017 1:03 pm 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 98
Further refinement, turns out, I needed to completely push the Worriors off the screen to get a 10x6 matrix (which can be encoded as a symmetrical 5x3 array)...

Image

But this leaves no room for the Worriors, at all, and with the gate timer, this makes any sort of lives counter be awkward as hell..so...

I may back away to a 8x6 matrix (4x3 symmetry)... OR

I squeeze the sprites to 2x2 instead of 2x3... *deep-breath* will try... I also need to add additional walk cycles and their 90 degree counterparts, I will run out of chr space if I'm not careful...

I have to get all this squared away before I can start writing the meat of the game as all the mazes are drawn programmatically.

-Thom


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Tue Jul 11, 2017 1:38 pm 
Offline
User avatar

Joined: Sun May 27, 2012 8:43 pm
Posts: 1311
I think you can do well just cramming the lives count to the sides of the radar text, either with small icons or a number. Better to not compromise the playfield.


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Tue Jul 11, 2017 7:59 pm 
Offline
User avatar

Joined: Sat Jul 12, 2014 3:04 pm
Posts: 950
well, 10x6 isn't going to be the same as 11x6…


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Tue Jul 11, 2017 8:51 pm 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 98
Myask wrote:
well, 10x6 isn't going to be the same as 11x6…


I see no way to get 11x6 without squishing the sprites. Which.. given my background in research... I'll do... I won't promise I won't be griping all the way through it, but hey... :)

-Thom


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Tue Jul 11, 2017 11:38 pm 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 98
Currently giving myself a crash course in vram_set_update() and the different update vram functions in neslib..goal is to re-draw the dungeon in code, and work out a reasonably quick and compact data structure for the dungeon...now that I have a reasonably good idea of how the tiles in the nametable are to be laid out.

-Thom


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Wed Jul 12, 2017 12:19 am 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 98
Well gosh, that was easy.

Code:
  vram_adr(NAMETABLE_A);
  vram_unrle(wow_dungeon);
  pal_bg(palette);
  pal_spr(palette);
  vram_adr(NTADR_A(0,0));

  for (i=0;i<6;++i)
    {
      for (j=0;j<10;++j)
        {
          vram_adr(NTADR_A((j*3)+1,(i*3)+1));
          vram_put(0x74);
          vram_put(0x63);
          vram_put(0x75);
          vram_adr(NTADR_A((j*3)+1,(i*3)+2));
          vram_put(0x65);
          vram_put(0x00);
          vram_put(0x66);
          vram_adr(NTADR_A((j*3)+1,(i*3)+3));
          vram_put(0x76);
          vram_put(0x64);
          vram_put(0x77);
        }
    }

  ppu_on_all();
  ppu_wait_frame();


Which produces:

Image

Will make this more efficient, shortly..but it's nice to know that I understand the vram well enough.

Pushing code up to github now, calling it a night. it's 2am.

-Thom


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Thu Jul 13, 2017 12:54 am 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 98
Took a first crack at the dungeon rendering code, which renders from an array of data in the following format

Code:
ULDR TSWX
-------------
0000 0000


Where ULDR is Up, Down Left, Right which sides of the box are to be open, T indicates a teleport wall, S is an enemy spawn point, and W is a Wizard spawn point. Worluk is special as he always appears at one door, and traverses toward the other.

The first pass of the code is inefficient, and I will refine it as I think it through further, but the meat of it is:

Code:
  // ULDR
  // 1111

  dungeon=(char*)dungeon1;
 
  b=0;  // dungeon array index

  for (i=0;i<6;++i)
    {
      for (j=0;j<10;++j)
     {
     /* Tile 1 */
       vram_adr(NTADR_A((j*3)+1,(i*3)+1));
     if (( (dungeon[b] & 1<<7) ) && ( (dungeon[b] & 1<<6) ))            /* UP AND LEFT */
       {
         if ( (dungeon[b] & 1<<3) )                          /* LEFT WITH TELEPORT */
      {
        vram_put(0x73);                                   
      }
         else
      {
        vram_put(0x74);                               
      }
       }
     else if ( (dungeon[b] & 1<<7) )                           /* UP */
       {
         vram_put(0x63);
       }
     else if ( (dungeon[b] & 1<<6) )                           /* LEFT */
       {
         if ( (dungeon[b] & 1<<3) )                          /* LEFT WITH TELEPORT */
      {
        vram_put(0x73);                                   
      }
         else
      {
        vram_put(0x65);                               
      }
       }
     else
       {
         vram_put(0x00);
       }

     // Tile 2
     if (dungeon[b] & (1<<7))            /* UP */
       {
         vram_put(0x63);
       }
     else
       {
         vram_put(0x00);
       }
    
     // Tile 3
     if (( (dungeon[b] & 1<<7) ) && ( (dungeon[b] & 1<<4) ))            /* UP AND RIGHT */
       {
         if ( (dungeon[b] & 1<<3) )                          /* RIGHT WITH TELEPORT */
      {
        vram_put(0x98);
      }
         else
      {
        vram_put(0x75);
      }
       }
     else if ( (dungeon[b] & 1<<7) )                           /* UP */
       {
         vram_put(0x63);
       }
     else if ( (dungeon[b] & 1<<4) )                           /* RIGHT */
       {
         if ( (dungeon[b] & 1<<3) )                          /* RIGHT WITH TELEPORT */
      {
        vram_put(0x98);
      }
         else
      {
        vram_put(0x66);
      }
       }
     else
       {
         vram_put(0x00);
       }

       vram_adr(NTADR_A((j*3)+1,(i*3)+2));
     // Tile 4
     if (dungeon[b] & (1<<6))            /* LEFT */
       {
         if (dungeon[b] & (1<<3))      /* LEFT WITH TELEPORT */
      {
        vram_put(0x73);
      }
         else
      {
        vram_put(0x65);
      }
       }
     else
       {
         vram_put(0x00);
       }

     // Tile 5 is always empty.
     vram_put(0x00);

     // Tile 6
     if (dungeon[b] & (1<<4))            /* RIGHT */
       {
         if (dungeon[b] & (1<<3))      /* RIGHT WITH TELEPORT */
      {
        vram_put(0x98);
      }
         else
      {
        vram_put(0x66);
      }
       }
     else
       {
         vram_put(0x00);
       }
    

     vram_adr(NTADR_A((j*3)+1,(i*3)+3));
     // Tile 7
     if (( (dungeon[b] & 1<<6) ) && ( (dungeon[b] & 1<<5) ))            /* LEFT AND DOWN */
       {
         if ( (dungeon[b] & 1<<3) )                          /* LEFT WITH TELEPORT */
      {
        vram_put(0x73);
      }
         else
      {
        vram_put(0x76);
      }
       }
     else if ( (dungeon[b] & 1<<6) )                           /* LEFT */
       {
         if ( (dungeon[b] & 1<<3) )                          /* LEFT WITH TELEPORT */
      {
        vram_put(0x73);
      }
         else
      {
        vram_put(0x65);
      }
       }
     else if ( (dungeon[b] & 1<<5) )                           /* DOWN */
       {
         vram_put(0x64);
       }
     else
       {
         vram_put(0x00);
       }

     // Tile 8
     if (dungeon[b] & (1<<5))            /* DOWN */
       {
         vram_put(0x64);
       }
     else
       {
         vram_put(0x00);
       }

     // Tile 9
     if (( (dungeon[b] & 1<<4) ) && ( (dungeon[b] & 1<<5) ))            /* DOWN AND RIGHT */
       {
         if ( (dungeon[b] & 1<<3) )                          /* RIGHT WITH TELEPORT */
      {
        vram_put(0x98);
      }
         else
      {
        vram_put(0x77);
      }
       }
     else if ( (dungeon[b] & 1<<5) )                           /* DOWN */
       {
         vram_put(0x64);
       }
     else if ( (dungeon[b] & 1<<4) )                           /* RIGHT */
       {
         if ( (dungeon[b] & 1<<3) )                          /* RIGHT WITH TELEPORT */
      {
        vram_put(0x98);
      }
         else
      {
        vram_put(0x66);
      }
       }
     else
       {
         vram_put(0x00);
       }
     ++b;         
     }
    }


And this is the base dungeon template, 60 bytes for now, 30 if I mirror one axis, 15 if I mirror both axes.

Code:

const unsigned char dungeon1[60]={0xC0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x90,
                                  0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,
                                  0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,
                                  0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,
                                  0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,
                                  0x60,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x30};


Which produces the following output:

Image

I'll draw the first real dungeon tomorrow (actually, this is the layout for "The Pit" which is the hardest dungeon, hehe.)

-Thom


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Thu Jul 13, 2017 2:51 am 
Offline

Joined: Mon May 27, 2013 9:40 am
Posts: 356
Looking great.

I'd get rid of the *3's. Using "*" includes extra runtime code plus is slow. You can do the X*3 as (X+(X<<1)) for example. You can also precalculate the offsets. offsX, offsY are unsigned char. addr is unsigned int.

Code:
    offsY = 1;
    for (i=0;i<6;++i) {
        offsX = 1;
        for (j=0;j<10;++j) {
            addr = NTADR_A (offsX, offsY);

            vram_adr( addr );
            // Here: 'vram_put's for the first row.

            // Down a row in the nametable
            addr+=32;
            vram_adr (addr);
            // Here: 'vram_put's for the second row.

            // Down a row in the nametable
            addr+=32;
            vram_adr (addr);
            // Here: 'vram_put's for the third row.

            // Next tile:
            offsX += 3;
        }
        // Next row of tiles
        offsY += 3;
    }


That way you calculate the base address, in the most simple way (just a shift and an addition, which is what NTADR_A does), just once per tile, simplifying your code, thus saving both bytes and cycles.

_________________
http://www.mojontwins.com


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Thu Jul 13, 2017 6:41 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19232
Location: NE Indiana, USA (NTSC)
na_th_an wrote:
I'd get rid of the *3's. Using "*" includes extra runtime code plus is slow. You can do the X*3 as (X+(X<<1)) for example.

The compiler should be doing this shift conversion for you. If you can prove that it isn't, then either A. something in your code is of the wrong type or B. you need to file an issue.

Quote:
You can also precalculate the offsets. offsX, offsY are unsigned char. addr is unsigned int.

Code:
// ...
            // Next tile:
            offsX += 3;


This appears to be related to strength reduction, where you can update addresses with a simpler operation based on the recursion that xtimes3[x + 1] = xtimes3[x] + 3. So instead of multiplying by 3 for each cell, add 3 to the destination VRAM address after drawing each cell.


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Thu Jul 13, 2017 9:22 am 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 98
All valid points, indeed. I will go through and refine the algorithm as I can.

A note, I am not familiar with CC65 internals. To be blunt, the common wisdom BITD was that the 6502 COULDN'T do a decent C without EMULATING ANOTHER PROCESSOR (p-system, and most 6502 C's that I used literally modelled an 8080, so CC65 to me seems like something of a minor miracle.), so I am not sure WHAT compiler optimizations are actually taking place yet (I need to sit down and look at the outputted source code.

-Thom


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Thu Jul 13, 2017 9:59 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5822
Location: Canada
I don't think CC65 has a generic capability to generate shift/add combinations instead of multiplication, but it does seem to have special case library functions for multiplying by a literal in the range 2-10? Here's the one for multiplying by 3:
https://github.com/cc65/cc65/blob/master/libsrc/runtime/mulax3.s

So... doing (x<<1)+x is slightly faster, I think, but there's a lot of encumbering inefficiencies anyway (stack temporaries, promotion to integer), so the difference is kind of pointless unless you want to write the multiply directly in assembly.

I think you're actually better off with x*3 just because it will produce smaller code (and code size tends to be a serious problem with CC65).


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Thu Jul 13, 2017 2:45 pm 
Offline

Joined: Mon May 27, 2013 9:40 am
Posts: 356
I've been working for years with a fairly old version of z88dk, so I have the (bad?) habit of not trusting the compiler at all. I also have the bad habit of not checking, which I should start doing, as I was avoiding structs in cc65 'cause I mistakenly thought that they generated worse code when accessing the members than using plain variables. My bad.

In this case, the *3 would indeed be better 'cause this is not a time critical task, so saving bytes is a priority.

I stand, thus, corrected :)

tepples wrote:
This appears to be related to strength reduction, where you can update addresses with a simpler operation based on the recursion that xtimes3[x + 1] = xtimes3[x] + 3. So instead of multiplying by 3 for each cell, add 3 to the destination VRAM address after drawing each cell.


I do this all the time, when appliable. It saves me tons of headaches, at least for my own mindset.

_________________
http://www.mojontwins.com


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Thu Jul 13, 2017 4:09 pm 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 98
Okay, several hours of laying out a dungeon, and I'm ready to write a clicky editor.

Anyone got a suggestion on what to use to whip one up for Windows? ;)

-Thom


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Thu Jul 13, 2017 4:54 pm 
Offline

Joined: Mon May 27, 2013 9:40 am
Posts: 356
I use the good ol' Mappy (mapwin). It can be tuned up to output the current map layer as a plain, headerless set of bytes, one per tile, which you can then process in a batch script to fit your needs.

http://www.mojontwins.com/warehouse/Mappy-mojono.rar

_________________
http://www.mojontwins.com


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

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 2 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