<< Sunflower Collection >> 2000 Gold Edition: Sevecol
RLE Sprite Guide Author: Jonathan Griffiths (jpg@wave.co.nz)
Introduction:
Sprite is the most commonly used element in the game, only recently being surpassed by 3D polygon engines. Smart Sprite system will bring great help to the game. This is a short article introduces a smart, and very RESPRITE system.
The SPRITE discussed herein refers to a rectangular subtraction, an arbitrary color in the subtitudinal map can be defined. When the Sprite is rendered to the screen, the pixel defined as transparent color is not painted. Out. Sprite produces the above effect on the scene.
RLE Sprite is a method for saving Sprite to a screen drawing. The discussion will show how to implement RLE Sprite-based engine. * All code is written with C. Some of them use JLIB ( A portable graphic library.) They can easily change to other graphics libraries. These documents are all I use jlib and I have written for RLL Sprite. You can check the code integrity. Clipart can compile * Jlib can be found below:
ftp://x2ftp.oulu.fi/pub/msdos/programing/djgpp2/jlib_x-x.zip;
You should use the inflexible font reading file, otherwise the ASCII chart will be confusing.
Simple Sprite:
Let's start with simple sprite. The simplest Sprite system is used in a 2-dimensional group to store the color of each point in sprite. The Sprite of a spaceship looks below:
XXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXX XXXXXXXXXXXXX XXXXXXXXXXX XXXXX 'X' = color value 0 (black in this embodiment) XXXX XXXX XXXX '' = other colors (Say Green) XXX XXXX XXXXXX XX XXXXXX XX XXXXXX XXXX XXXXXX XXXXX XX XXX XX XX XXXXXXXXXXXXXXXXX a 15x14 cheesy spaceboat sprite. *
If you use this space boat to make sprite, you should create an array of 15x14 and press the color to fill it on the image above, as follows:
#define ship_width 15 # define ship_height 14unsigned char ship_sprite [ship_width * ship_height] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 , 0, 0, 0, ...}
You can draw Sprite: int X, y; int xpos, ypos; ...
For (y = 0; y We painted each pixel in sprite. If the pixels are opaque, we will draw it. Check if it is 5 to be faster than other values, so we set transparent colors to 0. You can draw any sprite with a way, but also check if it is in the screen, but it is slow, not a good way. The first question is that you have to check each pixel, see if it is transparent, not to draw it. * Let's jump to the theory of the mainland for a while, think about the theoretical Picture of Sprite's speed limit. We choose a algorithm close to it. The fastest way to paint Sprite is to do not check any pixels, and can draw correctly on the screen, let's take a pixel that you need to draw, then stop. You have no waste of time in loop and comparison. There is a method As mentioned above, we call it the edited sprite. Edited Sprite is actually the program, as follows: Void Draw_SpaceShip (int x, int y) {/ * these commands Draw the sprites solid pixels * / Draw_point (x 20, y 20, 1); Draw_point (x 21, y 20, 2); Draw_Point (x 22, Y 20, 2); Draw_Point (x 23, y 20, 1); ...} * The second question is that this method is difficult and dangerous. And cannot be ported to all the computers. However, this method gives us how to draw a big revelation on the screen faster. We should find a way to rule out the pixels, just painting the opaque pixels. Enter RLE Sprite RLL is Run Length Encoding. It is a simple method for compressing duplicate data. It provides a good compression / decoding time ratio. RLL is replaced with a very short code. The above example: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, Use RLE compression to: (22 0's), (2 1's), (13 0's), (2 1's), (6 0's) There are a lot of repetitive data to get a good effect, if the source file is less or no repetition, the use of RLE compression may be larger than the source file. We choose RLL to save sprite, it can easily ignore transparent pixels, we don't check each pixel before we draw them. Let's see how to implement RLE Sprite First, we use the RLE code to save Sprite, then: Our RLE code does not save any data, only saving information. As follows: 0, 0, 0, 0, 0, 3, 3, 3, 5, 6, 0, 0, 0, 0, 0 We save: (Blank 6), (Solid 5), (Blank 5) When we explain our RLE code, we get the exact value of each pixel from the original data, we want to start a new RLE sequence to correspond to each line of Sprite. (This can help us with cropping, here will discuss) We can draw a row of sprite through the code below: While code did not end get the next value IF Value Is Blankskip Count Pixelselsedraw Count Pixelsendendend The code and RLE are different, the first code I used two bytes: is_solid, length. If is_solid is 0, it is continuous Lenet Blank, otherwise it is a continuous color. I still have a better code, It doesn't have to judge whether it is Blank. The new code uses one byte to save the color information and the number of times. Lower 4 digits. The 5th bit is non-transparent color is set, and the other 3 is useless (7, 6, 4), it can There are 16 repetitive pixels. If you have more bytes, you will be stored. This method is explained below. Original data: 0, 0, 0, 0, 0, 0, 3, 3, 3, 5, 6, 0, 0, 0, 0rle (Blank 6), (Solid 5), (Blank 5) RLE improvement Realization: 6, 5 | 32, 5 Last RLE Code: 6, 37, 5 In order to add the starting point of the RLE code when we exist with RLE, the last line code output is: The last RLE 3, 6, 37, 5 The first step of implementation is to establish RLE data from the Sprite data. Basic algorithm: for each line in the spritewrite a dummy value for the number of runs in this linewhile there is data leftif data is solidcount until not solid, or no data, or run len> 16elsecount until solid, or no data, or run len> 16endput code And CountendWrite The Real Value for the number of runs in this Linend You should set a point pointing to each line RLE data. This allows you to use cropping. Ptr Pointer To Rle Line Pointers for Each Line XXOXXX PTR --------------> (Num Codes, Code, ... XXOOXX PTR --------------> (Num Codes, CODE, ... Xoooxx Ptr --------------> (Num Codes, Code, ... Xooox Ptr --------------> (Num Codes, Code, ... Xoooxx Ptr --------------> (Num Codes, Code, ... Xoooxx PTR --------------> (NUM Codes, Code, ... XXXXXX PTR --------------> (Num Codes, Code, ... x by y Array Of Data Rle Codes for Each LineJlib's internal function generate_rle () You can do this. You build RLE data as above, draw it, you can use the following code: For (y = 0; y It looks fast than the previous version, yes. * Let us assume that we can use the pointer to draw points on the screen. Assume 256 color display * Our RLE code allows us to check if it is transparent color if we use the switch statement to press the macro: #define SPR_STENCIL_COPY (D, S, L) {/ Switch (L) {/ case 31: d [14] = s [14]; / case 30: d [13] = s [13]; /...case 17: D [0] = s [0]; /} /} Here "L" is the RLE code, if L is less than 16, do not do, otherwise you can draw multiple points on the screen (no loop), so you can save a lot of time. Our sprite implements: Setup a pointer "foo" to the x by y array of datafor (y Smart readers take note that we can save the last Blank of each line, they don't do anything, so there is a lot of people :-) In jlib, you can draw a sprite background, and we can't now. Ok, our Sprite has high efficiency. A problem is in front of us, how to crop? How to draw a part of the sprite on the screen? How should we draw some of the Sprite to see when Sprite comes out? Cropping can always be excluded. Take a look at the following code: IF ((Sprite_x Sprite_Width <0) / * Off lhs of screen * / | (sprite_x> screen_width) / * off rhs of screen * / | (Sprite_y Sprite_Height <0) / * Off top of screen * / | (sprite_y> screen_height) / * off bottom of screen * / return; / * don't draw it * / end From the above cycle to see the ratio X Simple in the direction. The consumption of cutting can draw Sprite. * How to determine whether the sprite is cropped:? #Define CLIPPED_X 0x1 # define CLIPPED_Y 0x2int clipped = 0; if (sprite_y> sprite_height> SCREEN_HEIGHT) / * Hits screen BOTTOM * / clipped = CLIPPED_Y;} if (sprite_y <0) / * Hits screen ? TOP * / clipped = CLIPPED_Y;?} if (sprite_x> sprite_width> SCREEN_WIDTH) / * Hits screen RIGHT * / clipped | = CLIPPED_X;?} if (sprite_x <0) / * Hits screen LEFT * / clipped | = CLIPPED_X } / * If not clipped, use a faster non-clipping function * / if (! Credited) {DRAW_SPRITE_WITHOUT_CLIPPING (...);} IF a Sprite Is Clipped Only in The Y Direction, We can Clip The Sprite Byaltering The Outer Y Loop: IF (! (!) {if (y <0) Top_Lines = -y; elsetop lines = 0; setup a pointer "foo" to the x by y Array Of Data Top_Lines * Data_Widthif (bottom neseds clipping) { max_y = SCREEN_HEIGHT; elsemax_y = height_of_spritefor (y = 0; y The cropping of Y direction is almost the same as the non-crop. It is only a few ways to process the cutting of the X direction. The simplest is to check each pixel in the X cropping algorithm. It is able to be improved. Another method Whether it is a cropping of the X direction or the Y direction, it is better than the above. As follows: If the left is cropped, we must calculate how many pixels in each line are on the left side of the screen, and you can skip these points, draw the pixels below this line. If the right is cropping, we calculate the first few rows on the side of the screen, you can draw other lines on the screen. This is more complicated than the croping algorithm in the original X direction. Width = width_of_spriteif (x <0) {left = -X; width = x; / * Decriment width * /} elseleft = 0; setup a pointer "foo" to the x by y Array Of Data Leftif (rhs Needs Clipping) width = SCREEN_WIDTH-rhs_xposfor (y = 0; y The cutting of the X and Y directions only combines the above two aspects. You can write your RLLE Sprite engine with the code above the code. The cropping of the X direction is most important. Remember your engine to stay some places below Sprite, so you can move * / * ----------------------------------------------- ------------------------- * // * | Draw A Sprite In a buffer without clipping | * // * ----- -------------------------------------------------- ----------------- * / void buff_draw_spritenc (sprite_system * ssys, int snum, buffer_rec * Obuff) {int frame = ssys-> sprites [snum] -> frame, x = SSYS-> SPRITES [SNUM] -> X; int y = ssys-> sprites [snum] -> y, bwidth = b_x_size (obuff) -ssys-> sprite_data [frame] -> width, height = ssys-> sprite_data [Frame] -> Height; ubyte * pattern = ssys-> sprite_data [frame] -> pattern, * data = ssys-> sprite_data [frame] -> data, * out = b_offset (OBUFF, Y) X; JLIB_ENTER "buff_draw_spritenc"); while (height--) {int width = * pattern ; while (width--) {ubyte Datum = * Pattern ; Spr_stencil_copy (Out, Data, Datum); OUT = (Datum & 15); DATA = (Datum & 15);} out = bwidth;} jlib_leave;} sevecol translation from 1999.10.18 * Expressed translation bad, translation ^ - ^ Since my English is not very good, this version has a large number of bugs , Heart disease and high blood pressure patients do not read: -)