Programming tutorial: Part 9–Advanced sprites

Atari Lynx programming tutorial series:

This 9th part in the tutorial series on Atari Lynx programming continues where we left off with sprites after part 7 and 8. In those parts we covered the basics followed by color, pens, sizing and stretching. We will now take a look at reference points, tilting and the mechanics of drawing.

Reference points

A sprite has a reference point that is used to indicate where the sprite should go when you specify an (x,y) coordinate. The default for this point is the upper-left corner of the sprite.

clip_image001

You can change where this reference point is to anywhere within the sprite. The sprpck.exe tool will handle setting the reference point for you. It has a parameter called -a that will set the action point (or reference point) at the specified pixel in the xxxyyy format. If it is not specified, the default is the upper left corner of the sprite. Take our robot sprite of 8 by 8 pixels. The way we used it had a reference point of 0, 0 or upper left corner. By giving it an -a parameter of -a004003 like this:

$(SPRPCK) -t6 -p2 -a004003 robot.bmp

the sprite will get its reference point somewhere in the middle of the sprite.

clip_image002

As you can see the position of the sprite seems to change if you used the same (x,y) coordinate for hpos and vpos in the SCB. You need to take the reference point into account when positioning sprites.

The reference point is relevant for a couple of things:

  • The exact positioning of your sprite based on x and y coordinates
  • For the axis when flipping a sprite
  • When stretching and tilting it is the origin from which stretching and tilting occurs

Quadrants

In reality the reference point is not specified directly. Instead it is implicit from the way the sprite is drawn. The reference point is always at that particular point where the first pixel of the sprite is drawn. So far we have only seen a single quadrant in a sprite.

clip_image003

Regular sprite data only uses a single quadrant. With default drawing settings the drawing of the quadrant starts at the top left corner and draws a single screen line (also called scan line) to the right, continuing from the next line until all sprite pixels have been drawn. Consider this quadrant the South-East corner of the sprite.

A sprite can have up to four quadrants. The South-West quadrant (2) is drawn from the reference point with lines going right to left and top to bottom. The North-West quadrant (3) is drawn right to left and bottom to top. Finally the North-East quadrant (4) goes left to right and bottom to top.

clip_image004

The quadrants are drawn in counter-clockwise order, starting with the South-East quadrant unless you deliberately change this.

image

You cannot change the direction in which quadrants are processed, but you can change the starting quadrant. This is done by two separate flags in the sprite control byte 1 of the sprite’s SCB: DRAWUP and DRAWLEFT. By setting these bits in the SPRCTL1 register of the SCB, you change the default down/right setting.

SCB_REHVST_PAL robot2 =  {
  BPP_4 | TYPE_NORMAL,  
REHVST | DRAWUP,  0x01, 0, &robotcentered, 80, 50,  0x0500, 0x0500, 0x0000, 0x0000, { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } };

Or in code:

robot_sprite.sprctl1 = REHVST | DRAWUP;

The code example will make the drawing start in the North-West quadrant.

clip_image006

Initially you might not recognize the robot, but take a longer look and imagine that the bottom right corner (short leg) is still drawn first, but now in the corner that draws up and to the right (we only changed the DRAWUP flag). This will cause to the leg to be drawn upside down. The next quadrant (top left) is the right side of the head drawn to the left, effectively flipping it. The bottom left is the left side of the head drawn upside down and finally the left leg at the right side. In this example the reference point is at bottom left corner of the top right quadrant (2). As a matter of fact, it is always located at the center of the sprite where the quadrants come together and lies in the quadrant where drawing starts.

Combining things

Adding a couple of things together you might wonder what will happen if you use stretching combined with a multi-quadrant sprite. Well, the stretching continues across quadrants and in the order in which quadrants are drawn. Take a look at a robot sprite with a reference point near the center and a stretch of 1 pixel per line.

clip_image007

You can see the sprite getting bigger from the bottom right quadrant to the top right, top left and bottom left. So, use it wisely as it can provide intended benefits, but can also give you other behavior than you expected.

It is up to you what the sprite reference point is by choosing what goes in what quadrant. Just remember that all sprite pixels need to be specified in the pixel data. So, it is uncommon to have a reference point outside of the actual pixels of the sprite.

Flips and flops

It is relatively easy to flip sprites. Every sprite can be flipped in horizontal and/or vertical direction. This is controlled by the SPRCTL0 and two bit flags called HFLIP and VFLIP.

robot.sprctl0 = BPP_4 | TYPE_NORMAL | HFLIP;

This will make the robot sprite be flipped horizontally around the vertical axis defined by the reference point’s x position. The robot sprite will not show much when flipped, because the image is near symmetrical. The more obvious difference is that the perceived location suddenly seems to change when the reference point is still in the top left corner. For another sprite (tree leaves from Pitfall!) the flipping of the bottom right sprite vertically and horizontally produces the following (while also changing the palette for fun):

image

As you can clearly see, the sprites are flipped around the axes of the quadrants and seem to change the position of the sprite, even though they are drawn at the same position.

Tilting like a pinball machine

Tilting is somewhat similar to stretching. The process of tilting means that you change the starting position for every scanline in the sprite. Let’s assume you have a default single quadrant sprite. Every scanline that is rendered for the sprite will have a 16-bit value for tilt added to the horizontal offset of the sprite. This will happen for every scanline even for non-visible parts of the sprite. The 16-bit value consists of an upper byte for full pixels and a lower byte for fractions. A value of 0x0100 will increase the horizontal offset by 1 pixel every scanline. 0x0040 will do that every 4th scanline, when the fraction of 1/4th adds to a full pixel.

image

A great example of how to use tilting can be seen in Electrocop. The tiles at the floor have a parallax effect that is achieved by stretching and tilting.

image

Look at the tiles that start at where Electrocop is standing. You can see that these tiles have a straight side and a side that has a stretched side. You can easily build these from a single pixel sprite, that has a vertical size of about 4x magnification, a horizontal size of about 20x magnification. The horizontal size increases about 1 screen pixel every scan line on the left or right side. The ones that have a skewed side at the left start drawing at quadrant 4. The others with a skewed right side start in quadrant 1. Now for tilting inspect the dark grey tile that touches the blue energy bar at the left. It still has the characteristics that the light grey one on the left has, plus it has a tilt that pushes the starting point of every scanline to the left by 1 screen pixel.

Another example. Take a single pixel that we will change into a triangle like this:

clip_image001[6]

At the top is starts with a width of 30 pixels, and at the bottom it has a width of 1 pixel, with an offset of 10 from the left side. This can be accomplished with a stretch of –30/20, meaning a 30 pixel decrease over 20 lines and a tilt of 10/20 for a half pixel tilt every scanline.

In a SCB definition this looks like:

SCB_REHVST_PAL triangle =  {    BPP_4 | TYPE_NORMAL,    REHVST,    0x01,    0,    &singlepixel_data,    20, 20,    0x1e00, 0x1400,    0xfe80, 0x0080,    { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }
};

Notice the hsize and vsize of 0x1e00 and 0x1400 (30.00 and 20.00), the stretch of 0xfe80 (-1.5) and tilt of 0x0080 (0.5). The result of rendering a single pixel sprite with these characteristics is this:

image

Just imagine what you can do with the sprite engine if it can do this with single pixel sprites, without using any code.

Next time

We covered a lot of features of sprites. There are a couple of topics left that you should know about to fully understand and utilize the power of the engine. These include the sprite data structure, the sprite world and collision. Till next time.

This entry was posted in Tutorial. Bookmark the permalink.

5 Responses to Programming tutorial: Part 9–Advanced sprites

  1. Gadget says:

    -a006006

    Its a pity sprpck doesnt have a switch to automatically centre the anchor point… I might try and add support if I can. Do you know of any other way to adjust the anchor point in code or is it just done in the raw image data itself?

    These tutorials have been awesome btw, keep up the fantastic work!! I am well on the way to creating my first Lynx game thanks to you and the people on AtariAge.

  2. Pingback: Programming tutorial: Part 10–Collisions | Diary of an Atari Lynx developer

  3. Pingback: Programming tutorial: Part 11–Pens and more collisions | Diary of an Atari Lynx developer

  4. aehrath says:

    Nice work! I loved coding with the Atari Lynx. I worked on Double Dragon and Raiden for the Lynx. I started a YouTube blog where next episode will be about my time working on Double Dragon. Tune in if you are interested: https://www.youtube.com/channel/UCssoHKKNh0VIzQ9e8c4YQTg

Leave a comment