The DOS Fish Tank
The original DOS version of the fish tank program runs in the 320x200 256-color "mode X" graphics mode (Fastgraph's mode 20) with four video pages. The program uses three of these video pages: pages 0 and 1 alternately serve as the visual page and workspace page in each animation frame, and page 2 always contains a clean copy of the coral background. Let's look at the source code:
/****************************************************************************\
* *
* Fish1.c *
* *
* This is the original DOS version of the Fastgraph Fish Tank. *
* *
\****************************************************************************/
#include
#include
#include
void main(void);
void GetFish(void);
void GoFish(void);
void PutFish(int,int,int,int);
#define MAX(x,y) ((x) > (y)) ? (x) : (y)
#define MIN(x,y) ((x) < (y)) ? (x) : (y)
#define NFISH 11
/****************************************************************************\
* *
* main program *
* *
\****************************************************************************/
void main()
{
// in case we're compiling for protected mode
fg_initpm();
// make sure the system supports video mode 20 with three pages
if (fg_testmode(20,3) == 0)
{
printf("This program requires VGA graphics.\n");
exit(0);
}
// initialize the video environment
fg_setmode(20);
// display the coral background on page 2 (which will always
// contain a clean copy of the background image)
fg_setpage(2);
fg_showpcx("CORAL.PCX",2);
// copy the background to the visual page
fg_copypage(2,0);
// get the fish
GetFish();
// make the fish go
GoFish();
// restore the original video state
fg_setmode(3);
fg_reset();
}
/****************************************************************************\
* *
* GetFish() *
* *
* Fill the fish bitmap arrays. *
* *
\****************************************************************************/
char Fish1[56*25];
char Fish2[54*38];
char Fish3[68*26];
char Fish4[56*30];
char Fish5[62*22];
char Fish6[68*36];
int FishX[] = { 0, 64,128,200, 0, 80}; /* location of fish x & y */
int FishY[] = {199,199,199,199,150,150};
int FishWidth[] = { 56, 54, 68, 56, 62, 68}; /* size of fish: width */
int FishHeight[] = { 25, 38, 26, 30, 22, 36}; /* size of fish: height */
char *Fishes[] = {Fish1, /* for convenience, an array of pointers to fishes */
Fish2,
Fish3,
Fish4,
Fish5,
Fish6};
void GetFish()
{
register int FishNum;
// get the fish bitmaps from a PCX file
fg_setpage(1);
fg_showpcx("FISH.PCX",2);
for (FishNum = 0; FishNum < 6; FishNum++)
{
fg_move(FishX[FishNum],FishY[FishNum]);
fg_getimage(Fishes[FishNum],FishWidth[FishNum],FishHeight[FishNum]);
}
}
/****************************************************************************\
* *
* GoFish() *
* *
* Make the fish swim around. *
* *
\****************************************************************************/
/* There are 11 fish total, and 6 different kinds of fish. These
* arrays keep track of what kind of fish each fish is, and how each
* fish moves:
*
* Fish[] -- which fish bitmap applies to this fish?
* xStart[] -- starting x coordinate
* yStart[] -- starting y coordinate
*
* xMin[] -- how far left (off screen) the fish can go
* xMax[] -- how far right (off screen) the fish can go
* xInc[] -- how fast the fish goes left and right
* Dir[] -- starting direction for each fish
*
* yMin[] -- how far up this fish can go
* yMax[] -- how far down this fish can go
* yInc[] -- how fast the fish moves up or down
* yTurn[] -- how long fish can go in the vertical direction
* before stopping or turning around
* yCount[] -- counter to compare to yTurn
*/
int Fish[] = { 1, 1, 2, 3, 3, 0, 0, 5, 4, 2, 3};
int xStart[] = {-100,-150,-450,-140,-200, 520, 620,-800, 800, 800,-300};
int yStart[] = { 40, 60, 150, 80, 70, 190, 180, 100, 30, 130, 92};
int xMin[] = {-300,-300,-800,-200,-200,-200,-300,-900,-900,-900,-400};
int xMax[] = { 600, 600,1100,1000,1000, 750, 800,1200,1400,1200, 900};
int xInc[] = { 2, 2, 8, 5, 5, -3, -3, 7, -8, -9, 6};
int Dir[] = { 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0};
int yMin[] = { 40, 60, 120, 70, 60, 160, 160, 80, 30, 110, 72};
int yMax[] = { 80, 100, 170, 110, 100, 199, 199, 120, 70, 150, 122};
int yTurn[] = { 50, 30, 10, 30, 20, 10, 10, 10, 30, 20, 10};
int yCount[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int yInc[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
void GoFish()
{
register int i;
int VisualPage, WorkPage;
unsigned char Key, Aux;
// initially page 0 is the visual page and page 1 is the workspace page
VisualPage = 0;
WorkPage = 1;
// make the fish swim around
do
{
// copy the background to the workspace page
fg_copypage(2,WorkPage);
// put all the fish in their new positions
for (i = 0; i < NFISH; i++)
{
yCount[i]++;
if (yCount[i] > yTurn[i])
{
yCount[i] = 0;
yInc[i] = (rand() % 3) - 1;
}
yStart[i] += yInc[i];
yStart[i] = MIN(yMax[i],MAX(yStart[i],yMin[i]));
if (xStart[i] >= -72 && xStart[i] < 320)
PutFish(Fish[i],xStart[i],yStart[i],Dir[i]);
xStart[i] += xInc[i];
if (xStart[i] <= xMin[i] || xStart[i] >= xMax[i])
{
xInc[i] = -xInc[i];
Dir[i] = 1 - Dir[i];
}
}
// page flip to display the new frame
VisualPage = WorkPage;
fg_setvpage(VisualPage);
// the old visual page becomes the workspace next frame
WorkPage = 1 - WorkPage;
fg_setpage(WorkPage);
// intercept a keystroke, if it is escape exit the program
fg_intkey(&Key,&Aux);
}
while (Key != 27);
}
/****************************************************************************\
* *
* PutFish() *
* *
* Draw one of the six fish anywhere you want. *
* *
\****************************************************************************/
void PutFish (int FishNum, int x, int y, int FishDir)
{
// move to position where the fish will appear
fg_move(x,y);
// draw a left- or right-facing fish, depending on FishDir
if (FishDir == 0)
fg_flpimage(Fishes[FishNum],FishWidth[FishNum],FishHeight[FishNum]);
else
fg_clpimage(Fishes[FishNum],FishWidth[FishNum],FishHeight[FishNum]);
}
The program first checks if the required video mode (mode 20) is available on the user's system, and exits if not. Otherwise, it calls fg_setmode() to set the video mode. Next, we load the coral background on page 2 and copy it to the visual page to give the user something to look at while the program performs the rest of the set up work. The GetFish() function loads the fish sprites on page 1 and uses fg_getimage() to retrieve each of the six fish into a 256-color bitmap.
At this point, we call GoFish() to start the animation. The GoFish() function makes the fish move by performing animation frames until the user presses the Escape key. Initially, page 0 is the visual page and page 1 is the workspace page; we keep track of which page is which in the VisualPage and WorkPage variables. The rest of GoFish() is a do/while loop that performs one frame per iteration. Each frame begins by copying the coral background from page 2 to the workspace page. Next, a for loop puts each of the 11 fish in their new positions on the workspace page (some of the fish may be completely off the page, so we won't always see all 11 of them). We're then ready to display the workspace page, so we set the VisualPage variable to the workspace page and call fg_setvpage() to display it. We complete the page flip by setting the WorkPage variable to the previous visual page number, and then call fg_setpage() to make it the new active video page. We repeat this process for each frame, with a check for the Escape key between frames. After GoFish() returns, the main program restores the original video mode and returns to DOS.
|