С для профессиональных программистов

       

Полный текст программы игры TAG.


В данном разделе приведен текст программы игры TAG, похожей на русские "салочки". Вы можете ввести ее в свой компьютер, если он снабжен графическим адаптером.

/* Пример мультипликации игры "салочки"

Объектом в игре является "человек", который догоняет другого "человека".

Ваш "человек"- зеленый,"человек" компьютера­желтый. Все, что окрашено в красный цвет, пересекать нельзя.

Для смены ролей догоняющего и догоняемого необходимо, чтобы "люди" пересеклись хотя бы в одной точке растра  */

#define COMPUTER 0

#define HUMAN 1

#define IDLE 0

#define DOWN 1

#define UP -1

#define LEFT -1

#define RIGHT 1

#include "dos.h"

#include "stdio.h"

#include "math.h"

#include "time.h"



void mode(), line();

void mempoint(), palette(), xhairs();

void goto_xy(),show_score();

void display_object(),update_object();

void it_comp_move(),not_it_comp_move(); void save_pic(), load_pic(); unsigned char read_point();

int human[4][4] =  /* ваш спрайт */ 1,6,6,6,

4,2,3,9,

9,1,6,6,

9,11,6,6

;

int human2[4][4] =

1,6,6,6,

4,2,3,9,

9,3,6,6,

9,9,6,6

;

int computer[4][4] =  /* спрайт компьютера */

180,6,185,6,

183,2,182,9,

188,1,185,6,

188,11,185,6

;

int computer2[4][4] =

180,6,185,6,

183,2,182,9,

188,3,185,6,

188,9,185,6

;

int directx,directy; /* направление  */

main()

union k

char c[2];

int i;

 key;

int deltax=0,deltay=0;

int swaph=0,swapc=0;

int it=COMPUTER;

long htime,ctime,starttime,curtime;

int count;

mode(4); /* установка 4 режима графики CGA/EGA */

palette(0); /* палитра 0 */

load_pic(); /* ввод игрового поля */

time(&starttime); /* установка времени */

htime=ctime=0;

display_object(human,4,1);

display_object(computer,4,3);

count=0;

/* главный цикл игры */

do

/* вычисление текущего счета  */

time(&curtime);

if (it==COMPUTER) htime+=curtime-starttime;

else ctime+=curtime-starttime;

time(&starttime);

show_score(it,htime,ctime);


if (bioskey(1))  /* если нажата клавиша */

directx=directy=IDLE; /* устанавливает

направление перемещения */

key.i = bioskey(0);

deltax=0;deltay=0;

if(!key.c[0]) switch(key.c[1])

case 75: /* влево */

deltay= -1;

directy=LEFT;

break;

case 77: /* вправо */

deltay=1;

directy=RIGHT;

break;

case 72: /* вверх */

deltax= -1;

directx=UP;

deltax= -1;

directx=UP;

break;

case 80: /* вниз */

deltax=1;

directx=DOWN;

break;

case 71: /* вверх и влево */

deltay= -1;

directy=LEFT;

deltax= -1;

directx=UP;

break;

case 73: /* вверх и вправо */

deltay=1;

directy=RIGHT;

deltax=-1;

directx=UP;

break;

case 79: /* вниз и влево */

deltay= -1;

directy=LEFT;

deltax=1;

directx=DOWN;

break;

case 81: /* вниз и вправо */

deltay=1;

directy=RIGHT;

deltax=1;

directx=DOWN;

break;

/* смена типа спрайта игрока  */

if (!swaph) displаy_object(human,4,1);

else displey_object(human2,4,1);

if (is_legal(human,deltax,deltay,4))

update_object(human,deltax,deltay,4);

update_object(human2,deltax,deltay,4);

/* проверяет: попался ли убегающий */

if (!count && tag(human,computer))

it=!it; /* смена амплуа */

count=6;

swaph= !swaph; /* смена фигур, имитирующих бег */

/* вывод "человека" в новой позиции */

if (!swaph) displаy_object(human,4,1);

else displаy_object(human2,4,1);

if (!swapc) displаy_object(computer,4,3);

else displаy_object(computer2,4,3);

/* генерация движения спрайта компютера */

if (it==COMPUTER)

it_comp_move(computer,computer2,human,4);

else not_it_comp_move(computer,computer2,directx,directy,4);

if (!count && tag(human,computer))

it= !it;

count=6;

/* компьютер догоняет; изменение координаты Х на 2

так, чтобы быстрей стать догоняемым */

if(is_legal(computer, 2, 0, 4))

update_object(computer, 2, 0, 4); update_object(computer2, 2, 0, 4);

else

update_object(computer, -2, 0, 4);

update_object(computer2, -2, 0, 4);

swapc = !swapc; /* заменить тип спрайта */



/* вывод на экран спрайта компьютера */

if(!swapc) display_object(computer, 4, 3);

else                      display_object(computer2, 4, 3);

if(count) count--;

while (key.c[0] !='q' && htime<999 && ctime<999);

getchar();

mode(2);

if(ctime>htime)

printf("Компьютер выиграл!");

else

printf("Вы победили!");

/* Вывод на экран терминала счета */

void shou_score(it, htime, ctime)

int it;

long htime, ctime;

goto_xy(24, 6);

if(it==COMPUTER)

printf("ВЫ:%ld", htime);

else

printf("вы:%ld", htime);

goto_xy(24, 26);

if(it==HUMAN)

printf("Я:%ld", ctime);

else

printf("я:%ld", ctime);

/* Выбор палитры */

void palette(pnum)

int pnum;

union REGS r;

r.h.bh = 1; /* код 4-го графического режима */

r.h.bl = pnum;

r.h.ah = 11;

int86(0x10, &r, &r);

/* Выбор режима */

void mode(mode_code)

int mode_code;

union REGS r;

r.h.al = mode_code;

r.h.ah = 0;

int86(0x10, &r, &r);

/* изображение линии заданного цвета с использованием

алгоритма Брезенхама */

void line(startx,starty,endx,endy,color)

int startx,starty,endx,endy,color;

register int t,distance;

int x=0,y=0,delta_x,delta_y;

int incx,incy;

/* вычисление расстояния в обоих направлениях                                                      */

delta_x=endx-startx;

delta_y=endy-starty;

/* определение  направления  шага,  шаг  вычисляется  либо   по

вертикальной,  либо  горизонтальной  линии */

if (delta_x>0) incx=1;

else if (delta_x==0) incx=0; else incx=-1;

if (delta_y>0) incy=1;

else  if (delta_y==0) incy=0;

else  incy=-1;

/* определение какое расстояние больше */

delta_x=abs(delta_x);

delta_y=abs(delta_y);

if (delta_x>delta_y) distance=delta_x;

else distance=delta_y;

/* изображение линии */

for (t=0; t<=distance+1; t++)

mempoint(startx,starty,color);

x+=delta_x;

y+=delta_y;

if (x>distance)

x-=distance;



startx+=incx;

if (y>distance)

y-=distance;

starty+=incy;

 

/* запись точки в CGA/EGA */

void mempoint(x,y,color_code)

int x,y,color_code;

union mask

char c[2];

int i;

 bit_mask;

int i,index,bit_position;

unsigned char t;

char xor; /* "исключающее ИЛИ" цвета в случае его

изменения */

char far *ptr=(char far *) 0xB8000000; /* точка в

памяти CGA */ bit_mask.i=0xFF3F; /* 11111111 00111111 в

двоичном виде */

if (x<0 || x>199 || y<0 || y>319) return;

xor=color_code & 128; /* проверка, устанавливался ли

режим "исключающего ИЛИ" */ color_code=color_code & 127; /* маска старших битов */

/*  установка битовой маски и битов режима цвета

в правую позицию */

bit_position=y%4; /* вычисление нужной позиции

в байте */ color_code<<=2*(3-bit_position); /* сдвиг кода цвета

в нужную позицию */ bit_mask.i>>=2*bit_position; /* сдвиг битовой маски в

нужную позицию */

/* определение требуемого байта в памяти терминала */

index=x*40+(y%4);

if (x%2) index+=8152; /* если нечетный, используется

второй блок */

/* запись цвета */

if (!xor)   /* режим изменения цвета */

t=*(ptr+index) & bit_mask.c[0];

*(ptr+index)=t|color_code;

else

t=*(ptr+index) | (char)0;

*(ptr+index)=t & color_code;

/* чтение байта из оперативной памяти CGA/EGA */

unsigned char read_point(x,y)

int x,y;

union mask

char c[2];

int i;

 bit_mask;

int i,index,bit_position;

unsigned char t;

char xor; /* "исключающее ИЛИ" цвета в случае его

изменения */

char far *ptr=(char far *) 0xB8000000; /* точка в

памяти CGA */ bit_mask.i=3; /* 11111111 00111111 в

двоичном виде */

if (x<0 || x>199 || y<0 || y>319) return 0;

/*  установка битовой маски и битов режима цвета

в правую позицию */

bit_position=y%4; /* вычисление нужной позиции

в байте */ bit_mask.i<<=2*(3-bit_position);

/* определение требуемого байта в памяти терминала */

index=x*40+(y>>4);



if (x%2) index+=8152; /* если нечетный, используется

второй блок */

/* запись цвета */

t=*(ptr+index) & bit_mask.c[0];

t>>=2*(3-bit_position);

return t;

/* загрузка изображения */

void load_pic()

char fname[80];

FILE *fp; register int i,j;

char far *ptr=(char far *) 0xB8000000; /* точка в памяти   CGA  */

char far *temp;

unsigned char buf[14][80]; /* содержит образ экрана */

temp=ptr;

/* сохранение верхних строк текущего содержимого экрана */

for (i=0;i<14;++i)

for (j=0;j<80;j+=2)

buf[i][j]=*temp;

buf[i][j+1]=*(temp+8152);

*temp=0; *(temp+8152)=0;/*чистка позиций экрана*/

temp++;

goto_xy(0,0);

printf("Имя файла:");

gets(fname);

if (!(fp=fopen(fname,"rb")))

goto_xy(0,0);

printf("Файл не может быть открыт\n");

temp=ptr;

/* восстановление содержимого экрана */

for (i=0;i<14;++i)

for (j=0;j<80;j+=2)

*temp= buf[i][j];

*(temp+8125)=buf[i][j+1];

temp++;

return;

/* загрузка изображения из файла */

for (i=0;i<8152;i++)

*ptr=getc(fp); /* четный байт */

*(ptr+8125)=getc(fp); /* нечетный байт */

ptr++;

fclose(fp);

/* поместить курсор в заданное положение */

void goto_xy(x,y)

int x,y;

r.h.ah=2; /* адресация курсора */

r.h.dl=y; /* координата столбца */

r.h.dh=x; /* координата строки */

r.h.bh=0; /* видео-страница */

int86(0x10,&r,&r);

/* отображение объекта на экране */

void display_object(ob, sides,cc)

double ob[][4];

int sides,cc;

register int i;

for(i=0; i<sides; i++)

line((int)ob[i][0], (int)ob[i][1],

(int)ob[i][2], (int)ob[i][3], cc|128);

/* Смещение (параллельный перенос) объекта в направлении,

определенном x и y

*/

void update_object(ob, x, y, sides)

int ob[][4];                                  /* объект */

int x, y;                                        /* направление смещения */

register int sides; /* количество сторон объекта */

sides--;

for(; sides>=0; sides--)



ob[sides][0] += x;

ob[sides][1] += y;

ob[sides][2] += x;

ob[sides][3] += y;

/* Определение  допустимости перемещения объекта. Возвращает

1, если перемещение допустимо, 0 - в противном случае */ is_legal(ob, x, y, sides)

int ob[][4];                                  /* объект */

int x, y;                                        /* шаг перемещения */

int sides;                                     /* число сторон объекта */

if(x==0 && y==0)

return 1;                            /* пустое перемещение всегда допустимо*/

sides--;

for(; sides>=0; sides--)

/* контроль выхода за допустимую область */

if(ob[sides][0]+x>199 || ob[sides][1]+y>319)

return 0;

if(ob[sides][2]+x<0 || ob[sides][3]+y<0)

return 0;

if(read_point(ob[sides][0]+x, ob[sides][1]+y)==2)

return 0;

if(read_point(ob[sides][2]+x, ob[sides][3]+y)==2)

return 0;

return 1;

/* генерация движения спрайта компьютера, когда он догоняет */

void it_comp_move(ob1,  ob2,  human, sides)

int ob1[][4],ob2[][4], human[][4], sides;

register int x, y, d; /* d = direction */

static skip = 0;

skip++;

if(skip==3)

skip=0;

return;

/* уменьшение времени реакции компютера */

x = 0;

y = 0;

/* движение к игроку */

if(human[0][0]<ob1[0][0])

x = -1;

else

if(human[0][0]>ob1[0][0])

x = 1;

if(human[0][1]<ob1[0][1])

y = -1;

else

if(human[0][1]>ob1[0][1])

y = 1;

if(is_legal(ob1, x, y, sides))

update_object(ob1, x, y, sides);

update_object(ob2, x, y, sides);

else

if(x && is_legal(ob1, x, 0, sides))

update_object(ob1, x, 0, sides);

update_object(ob2, x, 0, sides);

else

if(is_legal(ob1, 0, y, sides))

update_object(ob1, 0, y, sides);

update_object(ob2, 0, y, sides);

/* генерация движения спрайта компьютера, когда

он убегает                    */

void not_it_comp_move(ob1, ob2, dx, dy, sides)

int ob1[][4], ob2[][4];



int dx, dy; /* направление последнего перемещения

"человека" */

int sides;

register int x, y, d;

static skip = 1;

skip++;

if (skip==3)

skip = 0;

return;

/* уменьшение времени реакции компьютера в 3 раза */

x = 0;

y = 0;

/* перемещение в противоположном направлении */

x = -dx;

y = -dy;

if (is_legal(ob1, x, y, sides))

updаte_object(ob1, x, y, sides);

updаte_object(ob2, x, y, sides);

else

if (x && is_legal(ob1, x, 0, sides))

updаte_object(ob1, x, 0, sides);

updаte_object(ob2, x, 0, sides);

else if (is_legal(ob1, 0, y, sides))  updаte_object(ob1, 0, y, sides); updаte_object(ob2, 0, y, sides);

/*  проверяет наличие контакта между спрайтами */

tag(ob1, ob2)

int ob1[][4], ob2[][4];

register int i;

/* для смены амплуа необходимо, чтобы спрайты

имели хотя бы одну общую точку растра */

for (i=-1; i<2; i++)

if (ob1[0][0]==ob2[0][0]+i && ob1[0][1]==ob2[0][2]+i)

return 1;

return 0;

 

Для использования игры вы должны создать одно или несколько игровых полей, используя функции, описанные в главе 4. Используйте красный цвет для изображения препятствий. Желтый и зеленый цвета можно использовать для фона. Эти цвета не несут нагрузки, поэтому могут использоваться в декоративных целях. На рисунках 5-1 и 5-2 показаны два варианта игровых полей в таком виде, в котором они отображаются на экране вашего терминала.

Быстродействие компьютеров, таких моделей как AT или PS/2 моделей 50, 60 или 80, вполне достаточно для данной игры. Темп игры будет несколько снижен на обычном компьютере PC. Однако вам уже известно, как может быть повышена динамичность игры.

_________________________________________________________________

Рис. 5-1 на стр. 205 имеющимися средствами воспроизведен быть не может. (Ред. пер. И.Бычковский.)

_________________________________________________________________

Рис. 5-1. Первое игровое поле видеоигры "салочки"

_________________________________________________________________

Рис. 5-2 на стр. 205 имеющимися средствами воспроизведен быть не может. (Ред. пер. И.Бычковский.)

_________________________________________________________________

Рис. 5-2. Второе игровое поле видеоигры "салочки" -->


Содержание раздела