Полный текст программы игры 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. Второе игровое поле видеоигры "салочки" -->