Problem with put/update char on background [c+Shiru neslib]

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Problem with put/update char on background [c+Shiru neslib]
by on (#155173)
Hi all (At the begining sorry for ma fatal English but foreign languages are not my strong side.)

I finishing engine core for my first game and have one problem with update screen (background) - to put one char without flicking. I use cc65 with Shiru neslib. In example Shiru - game Chase this element is very confusing and I don't understand how calculate adress of memory. I tried to adjust many examples from internet but without success.

Can you help me to write universal function? In my example backgroud was change under hero sprite (similarly as DigDug):

Code:
//position of sprite hero on screen
static unsigned char hero_x = 160;
static unsigned char hero_y = 136;

//calc for position of char of background
unsigned char x = hero_x>>3;
unsigned char y = hero_y>>3;

//number of destination tile
unsigned char c = 0x10;

update_char(x,y,c); // here I need change background char to 'c' on position (x,y)


I try this, but I know that something was wrong (change of character = background creazy flicking):

Code:
void update_char(unsigned char x, unsigned char y, unsigned char c)
{
   static unsigned char update_list[3];
   const unsigned char list_init[3]={0x00,0x00,0x00};
   unsigned int adr = 0x2000;    //This is probably
   adr = adr +  0x20 * y + x;    // totally f**ked up
   update_list[0]=MSB(adr);
   update_list[1]=LSB(adr);
   update_list[2]=c;
   memcpy(update_list,list_init,sizeof(list_init));
   set_vram_update(update_list);
}


EFFECT:
Image

PS: please don't send me to hell because I have trivial issue for You :)
Re: Problem with put/update char on background [c+Shiru nesl
by on (#155176)
(Flickering)
Probably a timing issue. You can only update the PPU during V-blank, otherwise it will mess up the screen.
Re: Problem with put/update char on background [c+Shiru nesl
by on (#155177)
dougeff wrote:
(Flickering)
Probably a timing issue. You can only update the PPU during V-blank, otherwise it will mess up the screen.

Well, I have this function and when I use him then screen flicking:
Code:
void put_str(unsigned int adr,const char *str)
{
   vram_adr(adr);
   while(1)
   {
      if(!*str) break;
      vram_put((*str++)-0x20);//-0x20 because ASCII code 0x20 is placed in tile 0 of the CHR
   }
}

I thought that this is a bad solution, but YES - flicking can be result of timing issue.
Re: Problem with put/update char on background [c+Shiru nesl
by on (#155207)
You will want to treat the high and low bytes of PPU addresses seperately, since they are pushed seperately to 2006 register...marked here as updateLow and updateHigh.

Code:
//to convert Sprite x,y to PPU address
void GetPPUAddress (void) {
   B = x >> 3;
   A = y & 0x38;
   updateLow = (A << 2) + B;
   updateHigh = ((y & 0xc0) >> 6) + 0x20;
   updateFlag = 1;
}

void UpdatePPU (void) {
   A = *((unsigned char*)0x2002);
   *((unsigned char*)0x2006) = updateHigh;
   *((unsigned char*)0x2006) = updateLow;
   *((unsigned char*)0x2007) = updateData;
   updateFlag = 0;
}

void main (void) {
//blah
   while(1){ //infinite loop
      WaitNMI();
      if (updateFlag != 0) {
         UpdatePPU();
      };
      AllOn (); //sets 2000, 2001, resets 2005,2006 registers
      GameLogic();
   };
//somewhere in the game logic, you set which tile to place, the x and y, then call GetPPUAddress()


I think this is right, I had to edit my code alot to simplify it.
Re: Problem with put/update char on background [c+Shiru nesl
by on (#155210)
Also, this example assumes you're only updating 1 tile, and to nametable 0. In reality, you will certainly be doing multiple writes to the PPU per frame. You will likely have to buffer the updates between frames, and have a variable to control how many writes you will be doing.
Re: Problem with put/update char on background [c+Shiru nesl
by on (#155211)
Axi0maT wrote:
Code:
   static unsigned char update_list[3];
   const unsigned char list_init[3]={0x00,0x00,0x00};
   unsigned int adr = 0x2000;    //This is probably
   adr = adr +  0x20 * y + x;    // totally f**ked up
   update_list[0]=MSB(adr);
   update_list[1]=LSB(adr);
   update_list[2]=c;
   memcpy(update_list,list_init,sizeof(list_init));
   set_vram_update(update_list);

This code is very suspect; first you set up the update in update_list, then you copy list_init over those values. Also, initializing an array like that with memcpy is wasteful, you could use memset.
Re: Problem with put/update char on background [c+Shiru nesl
by on (#155284)
Ok, now work great. Suggestion of dougeff was correct - I try init all arrays on every time and push values to memory in at the wrong time.
This must by set once only on start:

Code:
memcpy(list,list_init,sizeof(list_init));
set_vram_update(list);


then later only list_update must be changed

Code:
list[0]=MSB(NTADR_A(hero_x>>3,hero_y>>3));
list[1]=LSB(NTADR_A(hero_x>>3,hero_y>>3));
list[2]=0x38;


all the rest was automatically change when PPU is update.

Easy but I could not see this relationship for a long time. Thanks very much dougeff - you are great :) :) :)

thefox wrote:
Also, initializing an array like that with memcpy is wasteful, you could use memset.

it is possible that you have the right to use the memset but I follow on the Shiru code and works with memcpy. Unfortunately I do not have too much time to experiment so I decided to leave memset.
Re: Problem with put/update char on background [c+Shiru nesl
by on (#155314)
Happy to see it's working. Maybe you could post a screen shot when your game is more complete.
Re: Problem with put/update char on background [c+Shiru nesl
by on (#155331)
dougeff wrote:
Happy to see it's working. Maybe you could post a screen shot when your game is more complete.

Yeah, of course. The game is being developing for the contest at RetroKomp 2015 (Gdansk, Poland 16-18.10.2015), and after that game will be available for free. At this moment I have powerfull engine (for my requirements), and begin creating levels. I don't have any music, but I think that this is not a big problem - maybe someone help me with this element (eventually I use public domain music).