Jump to content
  • entries
    652
  • comments
    2,629
  • views
    874,084

It's full of stars!

SpiceWare

1,196 views

Received a question via Messager that I'm going to reply to here as I'm sure others are wondering as well:

 

On 8/20/2014 at 8:28 AM, RHillFake said:

How exactly do you do the stars in the BG for Draconian? I am trying to learn to do more stuff for my future games.

 

I've seen posts by you in the batari Basic forum, so first thing to note is that none of my games were written using batari Basic1. Collect, Medieval Mayhem, and Stay Frosty (the original game which is in Stella's Stocking) are 100% 6507 assembly while all my other games utilize DPC+ Bankswitching2 with a mixture of 6507 assembly and C code. The C code runs on the ARM chip in the Harmony cart. If you don't have one, I highly recommend you get one for testing your games on a real Atari - you can order it here. The Melody Board also has the ARM chip, and is used for the production of stand alone cartridges.

 

Last weekend I gave a presentation for Classic Game Fest over in Austin that included this slide that I'll use for reference:

blogentry-3056-0-36794400-1408814177_thumb.png

 

 

DPC+ Bankswitching lets you use the ARM chip in two ways:

  • As a processor during Vertical Blank and Overscan to run the game logic. It's a 70 MHz 32 bit processor, so it can do significantly more calculations than the Atari's 1 MHz 8 bit processor
  • During the Kernel, only the 6507 can update TIA to draw the display, so the ARM chip is used as a co-processor which greatly increases the number of TIA updates that can be done

As one of the co-processor abilities, DPC+ adds datastreams to the Atari. You can think of a datastream as a list of values such as:

  • 10
  • 55
  • 20
  • 25

The datastream will auto-advance so that the first time you read it you'd get 10, the next time you'd get 55, then 20 and so on. Datastreams are very helpful during the kernel as you can update a player (sprite) in just 5 cycles:

   LDA #<DF0DATAW
   STA GRP0
 

 

which is much faster than a typical routine, which would have used 18:

   LDA #SPRITEHEIGHT
   DCP SpriteTemp
   BCS DoDraw
   LDA #0
   .BYTE $2C
DoDraw:
   LDA (GfxPtr),Y
   STA GRP0
 

 

Utilizing these datastreams, and their ability to reduce the time it takes to update TIA registers, I came up with this Slick Kernel which let me do the following:

  • any object (player0, player1, missile0, missile1 or ball) can be repositioned in a single scanline. In the time Frantic takes to reposition 1 player we can now reposition 4 objects.
  • players can be set for any size when they're repositioned. In theory they can also be set for duplicate and triplicate, but we don't use that feature because it conflicts with missile usage (ie: if a player is set for multiple copies, so is the corresponding missile).
  • players can be set for any color when they're repositioned. Single color sprites only, like seen in Space Rocks. It doesn't support line-by-line color changes like in Frantic.
  • players can be shifted right/left on any scanline, which creates the illusion that 2x and 4x sized sprites have more than 8 pixels of horizontal detail. See reply 16 in the Space Rocks homewbrew topic if you're not sure what this means.
  • missiles can be set to any size (sizes are 1x, 2x, 4x and 8x) when the missile is repositioned.
  • ball color can be changed whenever its repositioned.

The key things out of that list, as far as the background stars are concerned, are the ability to reposition any object in just 1 scanline, and the ability to change the color of the ball object whenever it's repositioned.

 

As you might suspect, the stars are all drawn using the ball object. I did that because of how the colors work on the Atari - missile0 takes on the color of player0, missile1 takes on the color of player1 and the ball takes on the color of the playfield. Since the playfield is not used3 each star can have a unique color, which was common on a lot of the old arcade games.

 

I'm going to reference the source code now. Each of my blog entries include the full source code and you can download the most recent version (as of August 23, 2014) here.

 

Since only 1 object can be repositioned each scanline, the Vertical Blank routines do the following:

void VerticalBlank()
{
    InitDatastreams();
    ...
    DisplaySprites();
    DisplayShots();
    ...
    DisplayStars();
    ...
}
 

 

The ... removes code that's not relevant to this discussion.

  • InitDatastreams() - blanks out all the datastreams. At this point nothing would be displayed if the Kernel was run.
  • DisplaySprites() - sprites are most important, so this routine will fill in the datastreams for player0 and player1 to draw as many sprites as possible. Any sprite not drawn will get a priority boost for the next frame, this is the flicker logic. If two sprites line up vertically the routines are smart enough to reposition one of the players a scanline earlier.
  • DisplayShots() - shots are next in importance, so this routine will fill in the datastreams for missile0 and missile1 to draw as many shots as possible. Like DisplaySprites(), this routine has flicker logic and can reposition an object on earlier scanlines (if possible)
  • DisplayStars() - this will do a quick scan through the reposition datastream and add a reposition to show any star that it can. Unlike the prior routines, it will not try to use an earlier scanline. This routine will also purposely skip stars to create the blinking star effect.

This early build of Draconian does not purposely skip stars, so any blinking effect is due to reposition conflicts:

draconian_20140320_2007.bin

 

 

At the start of each round, InitLevel() runs the following to create a random starfield:

    // create new random starfield
    gStarfieldXoffset = 0;
    gStarfieldYoffset = 0;
    gStarfieldTopStar = 0;
    for (i=0;i<MAX_STARS;i++)
    {
        STARFIELD_X[i] = (160 * (Random32() & 0xff)) >> 8;              // random 0-159
        STARFIELD_Y[i] = ((Random32() & 0x300) >> 8) + 2;               // random 2-5
        if (MM_TV_TYPE == 2)
            STARFIELD_COLOR[i] = ((14 * (Random32() & 0xff)) >> 8) + 2; // if SECAM use random color 2-15
        else
            STARFIELD_COLOR[i] = ((Random32() & 0xF700) >> 8) + 0x08;   // random color with luma 8-15
    }
 

 

The gStarfieldXoffset, gStarfieldYoffset and gStarfieldTopStar variables are used by DisplayStars() to pan the stars around in the background. Each star gets a random X location, a random Y location (really how many scanlines to skip before display the next star), and a random color.

 

 

1 batari Basic is really slick, but it's too restricted in its abilities for my needs.

 

2 there is a DPC+ Kernel for batari Basic that utilizes DPC+ Bankswitching to improve what you can do with batari Basic. Its concievable that somebody could write a new DPC+ kernel for batari Basic that uses my Slick Kernel to add support for background stars.

 

3 actually the playfield is used, just not when drawing gameplay area. On the game screen the playfield is used to draw the status line as well as the digits in the score and reserve lives.

  • Like 5


0 Comments


Recommended Comments

There are no comments to display.

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...