WIP: Wizard of Wor
Moderator: Moderators
Re: WIP: Wizard of Wor
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
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
Re: WIP: Wizard of Wor
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)...
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
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
- mikejmoffitt
- Posts: 1353
- Joined: Sun May 27, 2012 8:43 pm
Re: WIP: Wizard of Wor
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.
Re: WIP: Wizard of Wor
well, 10x6 isn't going to be the same as 11x6…
Re: WIP: Wizard of Wor
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...Myask wrote:well, 10x6 isn't going to be the same as 11x6…
-Thom
Re: WIP: Wizard of Wor
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
-Thom
Re: WIP: Wizard of Wor
Well gosh, that was easy.
Which produces:
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
Code: Select all
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();
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
Re: WIP: Wizard of Wor
Took a first crack at the dungeon rendering code, which renders from an array of data in the following format
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:
And this is the base dungeon template, 60 bytes for now, 30 if I mirror one axis, 15 if I mirror both axes.
Which produces the following output:
I'll draw the first real dungeon tomorrow (actually, this is the layout for "The Pit" which is the hardest dungeon, hehe.)
-Thom
Code: Select all
ULDR TSWX
-------------
0000 0000
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: Select all
// 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;
}
}
Code: Select all
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};
I'll draw the first real dungeon tomorrow (actually, this is the layout for "The Pit" which is the hardest dungeon, hehe.)
-Thom
Re: WIP: Wizard of Wor
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.
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.
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: Select all
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;
}
Re: WIP: Wizard of Wor
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.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.
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.You can also precalculate the offsets. offsX, offsY are unsigned char. addr is unsigned int.
Code: Select all
// ... // Next tile: offsX += 3;
Re: WIP: Wizard of Wor
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
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
- rainwarrior
- Posts: 8732
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: WIP: Wizard of Wor
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/maste ... e/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).
https://github.com/cc65/cc65/blob/maste ... e/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).
Re: WIP: Wizard of Wor
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
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
I do this all the time, when appliable. It saves me tons of headaches, at least for my own mindset.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.
Re: WIP: Wizard of Wor
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
Anyone got a suggestion on what to use to whip one up for Windows?
-Thom
Re: WIP: Wizard of Wor
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/warehouse/Mappy-mojono.rar