It is currently Mon Jul 24, 2017 11:39 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 69 posts ]  Go to page Previous  1, 2, 3, 4, 5
Author Message
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Sun Jul 16, 2017 11:43 pm 
Online

Joined: Sun Apr 13, 2008 11:12 am
Posts: 5920
Location: Seattle
You have about 2200 cycles per vblank (113⅔ · 20) for everything that needs to be sent to the PPU. Updating sprites (OAM DMA) takes roughly 1/4 of that. CC65 is probably adding some overhead, too.

Almost every game I've looked at has some kind of scheduler for PPU updates. Sometimes they're really minimal (e.g. some flip-screen games just change between "PPU is off, uploading new data" and "game is running")


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Mon Jul 17, 2017 12:07 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5423
Location: Canada
tschak909 wrote:
Yup, looks like that's the problem. The question I have is, is it safe to call set_vram_update(); when the PPU is on?

I need to literally update different areas of the screen, depending on different events, score change, worrior doors opening, teleport happening, etc. If I can't call set_vram_update() while ppu is active, will I need to roll my own little queuing and scheduler code for this?

I think you can call set_vram_update whenever you want, that's just setting a pointer and the actual PPU update is done by neslib's NMI handler (which will run at the next vblank). The problem is just that the NMI handler has no way of safeguarding against or helping to diagnose the "too much data takes too long" case.

I believe all the neslib functions you can't call while rendering is on are labelled as such in the header.

If you need all of those updates to happen in one frame, you could write a custom assembly NMI handler that can get that much data through in a single vblank, but the library's generic one is not efficient enough to do it.

Otherwise you can break up your updates so you only have to do some of it each frame.


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Mon Jul 17, 2017 2:50 am 
Offline

Joined: Mon May 27, 2013 9:40 am
Posts: 326
The solution is making your vram_update array dynamic, fill it with what you need to change for that frame, and let the NMI handler do its magic. I'm sure you don't need to update everythign every frame, so this just works.

Reserve a big enough update buffer in BSS, such as:

Code:
unsigned char update_buffer [UPDATE_LIST_SIZE*3+1];
unsigned char *ul;


Here, UPDATE_LIST_SIZE = 32 works for me (more than enough!). ul is a pointer we'll use to update the buffer.

Then your main loop would do something in the lines of:

Code:
set_vram_update (update_buffer);
while (game_on) {
    ul = update_buffer; // Point to the beginning of the buffer
    ... do your game logic, write to ul, increment ul.
    *ul = NT_UPD_EOF;
    ppu_wait_frame ();
}
set_vram_update (0);
...


In your game logic, whenever you need to update something, just write everything to the update buffer through *ul, for example:

Code:
*ul ++ = MSB(NTADR_A(1,19))|NT_UPD_HORZ,LSB(NTADR_A(1,19));
*ul ++ = 3;
*ul ++ = 0x74;
*ul ++ = 0x63;
*ul ++ = 0x75;


I'm sure just a number of things will fill the buffer each frame, so this will work and you won't run out of VBlank time.

_________________
http://www.mojontwins.com


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Mon Jul 17, 2017 7:43 am 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 48
Ok. I'm already basically doing this, I'll just not try to do it in one big buffer. (I was doing 256 bytes in BSS and just creating update records for every single thing to update, and simply just changing the data...) :)

-Thom


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Mon Jul 17, 2017 9:49 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 18667
Location: NE Indiana, USA (NTSC)
tschak909 wrote:
I'm just curious as to how the result frames on a tube.

It depends on how the tube is calibrated. It's often joked that NTSC stands for Never The Same Color, but it can also mean Never The Same Crop. There's a diagram at "Overscan" on the wiki. For convenience and in case something happens to the wiki:

  • Danger Zone (outside Action Safe Area)
  • Action Safe Area, 256x224, (0, 8)-(255, 231)
  • PocketNES Safe Area, 240x212, (8, 16)-(247, 227)
  • Title Safe Area, 224x192, (16, 24)-(223, 215)

An LCD will probably show the Action Safe Area almost exactly. The average CRT will show somewhere between the PocketNES Safe Area and the Action Safe Area, but older CRTs or CRTs in poor shape might not show much out of the Title Safe Area or might show some of the Danger Zone.


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Mon Jul 17, 2017 10:15 am 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 48
oh I know the joke, all too well. :) It's especially poignant on the VCS, because you're literally generating half of the video signal yourself! :) (I have literally made black and white pixels artifact into color on the VCS on accident.) ;)

I just wanted to see how tight my tolerances are, since I do not have a toaster or a tube anymore. :)

(and yes, I have the overscan chart for the NES, I'm really bunching up against it. I just want to see how close to the cliff I actually am.)

-Thom


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Mon Jul 17, 2017 10:18 pm 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 48
Code that currently opens/closes the worrior doors

Code:
/**
 * set_door(player, openclose)
 * player = Player 0 (blue) or Player 1 (yellow) door.
 * openclose = 0 for open, 1 for close.
 */
void set_door(unsigned char player, unsigned char openclose)
{
  // Clear the update buffer
  clear_update_buffer();

  // Set the addresses for the two rows of tiles that make up the door
  update_buffer[0]=(player==0?MSB(NTADR_A(1,18))|NT_UPD_HORZ:MSB(NTADR_A(28,18))|NT_UPD_HORZ);
  update_buffer[1]=(player==0?LSB(NTADR_A(1,18)):LSB(NTADR_A(28,18)));
  update_buffer[2]=3;

  update_buffer[6]=(player==0?MSB(NTADR_A(1,19))|NT_UPD_HORZ:MSB(NTADR_A(28,19))|NT_UPD_HORZ);
  update_buffer[7]=(player==0?LSB(NTADR_A(1,19)):LSB(NTADR_A(28,19)));
  update_buffer[8]=3;

  // And then set the tiles for each update depending on desired door state.
  if (openclose==0 && player==0)
    {
      update_buffer[3]=0x65;
      update_buffer[4]=0x00;
      update_buffer[5]=0x00;
      update_buffer[9]=0x65;
      update_buffer[10]=0x00;
      update_buffer[11]=0x00;
    }
  else if (openclose==1 && player==0)
    {
      update_buffer[3]=0x76;
      update_buffer[4]=0x64;
      update_buffer[5]=0x64;
      update_buffer[9]=0x74;
      update_buffer[10]=0x63;
      update_buffer[11]=0x63;
    }
  else if (openclose==0 && player==1)
    {
      update_buffer[3]=0x00;
      update_buffer[4]=0x00;
      update_buffer[5]=0x66;
      update_buffer[9]=0x00;
      update_buffer[10]=0x00;
      update_buffer[11]=0x66;
    }
  else if (openclose==1 && player==1)
    {
      update_buffer[3]=0x64;
      update_buffer[4]=0x64;
      update_buffer[5]=0x77;
      update_buffer[9]=0x63;
      update_buffer[10]=0x63;
      update_buffer[11]=0x75;
    }

}


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Tue Jul 18, 2017 4:08 pm 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 48
Doors and teleports working, next, scores... but I need to make a little queuing mechanism and make the functions use it... still thinking... in the mean time, a bit of silliness:

Image


Top
 Profile  
 
 Post subject: Re: WIP: Wizard of Wor
PostPosted: Sun Jul 23, 2017 10:28 am 
Offline

Joined: Mon Jul 03, 2017 4:37 pm
Posts: 48
Scoring now implemented. I had a bit of a trip trying to be a bit too clever with the algorithm,

https://www.youtube.com/watch?v=tsEfDJwiPNY

but it's there, and now I'm implementing the sprite structure, a simple array of 8 entries with 5 elements each (40 bytes) containing:

Code:
/**
 * 8 objects on screen, two players and 6 enemies.
 *
 * [0] - Sprite X position
 * [1] - Sprite Y position
 * [2] - Sprite Type - (worrior, burwor, thurwor, gorwor... Bit 7 means empty.)
 * [3] - Dungeon X coordinate
 * [4] - Dungeon Y coordinate
 */


So, onward and upward. (and yes, this structure will change, i'm slowly adding what I need and then rewriting it if I need to tighten it up)

-Thom


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

All times are UTC - 7 hours


Who is online

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