Игра "Ловушка"
4. Листинг программы
Main.cpp
#include <iostream.h>
#include <process.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#define N 4
#include "graphics.h"
#include "gameclass.h"
#include "menufunc.h"
main()
{
Menu m;
int gd = DETECT, gm;
initgraph(&gd, &gm, "");
m.StartGame();
closegraph();
return 0;
}
MenuFunc.h
//Структура для хранения имени и очков текущего игрока
struct namescore
{ char name[16];
int score;
}ns;
//Структура, служащая для работы с сохранениями.
struct savegame
{ int x[N+2];
int y[N+2];
int n, time, score, step;
}sg;
//Класс меню, содержащий в себе все функции программы
class Menu
{ protected:
char savepath[23];//переменная, которая позволяет помещать файлы сохранения в папку ./save/
public:
Menu() {}
~Menu(){}
void MenuGame(void); //Главное меню
void ExitOutGame(void); //Окно подтверждения выхода из игры
void MenuEnterKey(int); //Функция, отвечающая за нажатие "Enter" в Главном меню
void StartGame(void); //Заставка
void InputName(void); //Функция ввода имени
void Score(void); //Меню "Таблица результатов"
void About(void); //Меню "Об игре"
void Game(int); //Самая главная функция, осуществляющая игровой процесс
void Pause(void); //Меню "Паузы"
void AddScore(void); //Функция записи результата в файл рекордов
void PrintScore(void); //Функция печати рекордов в текстовый файл
};
void Menu::StartGame(void)
{ setcolor(3);
settextstyle(5, HORIZ_DIR, 16);
outtextxy(400,450,"Елохин Алексей, группа И512");
setcolor(GREEN);
settextstyle(DEFAULT_FONT, HORIZ_DIR, 16);
outtextxy(230,300,"[Нажмите любую клавишу]");
settextstyle(DEFAULT_FONT, HORIZ_DIR, 100);
setfillstyle(1,0);
int key=0;
int i=180;
//Небольшая анимация появления заставки в начале игры
while (key==0&&i>80)
{ key=getch();
setcolor(GREEN);
outtextxy(100,60,"ЛоВуШкА");
bar(0, 80, 640,i);
i--;
settextstyle(DEFAULT_FONT, HORIZ_DIR, 100);
setfillstyle(1,0);
sleep(50);
}
outtextxy(100,60,"ЛоВуШкА");
settextstyle(DEFAULT_FONT, HORIZ_DIR, 16);
outtextxy(230,300,"[Нажмите любую клавишу]");
bar(230,300,430,320);
InputName(); //Вызов функции ввода имени игрока
}
void Menu::MenuGame(void)
{
FILE *fin;
int x0=280,y0=220,i=0, key=0,pos=1,flagexit=1,p=1;
cleardevice();
fin=fopen("temp.dat","rb"); //Открываем файл, содержащий информацию текущего профиля
fread(&ns,sizeof(ns),1,fin); //Получаем из него данные
fclose(fin);
setcolor(3);
settextstyle(5, HORIZ_DIR, 16);
outtextxy(400,450,"Елохин Алексей, группа И512");
setcolor(GREEN);
settextstyle(DEFAULT_FONT, HORIZ_DIR, 100);
outtextxy(100,60,"ЛоВуШкА");
settextstyle(DEFAULT_FONT, HORIZ_DIR, 16);
setcolor(8);
outtextxy(x0+120,y0+20,ns.name); //Вывод имени текущего профиля в главном меню
setcolor(YELLOW);
fin=fopen(savepath,"rb");
//Вывод пунктов меню
if(fin) //Проверка на наличие сохраненной игры
{
outtextxy(x0,y0-20,"Продолжить");
p=0;
pos=0;
fclose(fin);
}
outtextxy(x0,y0,"Новая игра");
outtextxy(x0,y0+20,"Смена игрока:");
outtextxy(x0,y0+40,"Просмотр результатов");
outtextxy(x0,y0+60,"Правила игры");
outtextxy(x0,y0+80,"Выход");
setcolor(RED);
circle(x0-10,y0+10+(p-1)*20,4); //Указатель на пункт меню
while (flagexit)
{ key=getch();
switch (key)
{ case 38: { if (pos>p) { setcolor(BLACK); //Движение указателя вниз
circle(x0-10,y0+10+(pos-1)*20,4);
pos--;
setcolor(RED);
circle(x0-10,y0+10+(pos-1)*20,4);
}
break;
}
case 40: { if (pos<5) { setcolor(BLACK); //Движение указателя вверх
circle(x0-10,y0+10+(pos-1)*20,4);
pos++;
setcolor(RED);
circle(x0-10,y0+10+(pos-1)*20,4);
}
break;
}
case (27): {ExitOutGame();} //Вызов функции "Подтверждения выхода из игры", если нажали "Esc" в главном меню
case (13): {MenuEnterKey(pos);} //Вызов функции выбора пункта, если нажали "Enter"
}
}
}
void Menu::ExitOutGame(void) //Функция "Подтверждение выхода из игры
{
int x0=300,y0=200,i=0,flag=0;
cleardevice();
settextstyle(DEFAULT_FONT, HORIZ_DIR, 16);
setcolor(YELLOW);
outtextxy(x0,y0,"Хотите выйти?");
setcolor(GREEN);
outtextxy(x0,y0+20,"Нет");
outtextxy(x0,y0+40,"Да");
int key,pos=2,flagexit=1;
setcolor(RED);
circle(x0-10,y0+10+(pos-1)*20,4);
while (flag!=1)
{ key=getch();
switch (key)
{ case 38: { if (pos>2) { setcolor(BLACK); //Движение указателя вниз
circle(x0-10,y0+10+(pos-1)*20,4);
pos--;
setcolor(RED);
circle(x0-10,y0+10+(pos-1)*20,4);
}
break;
}
case 40: { if (pos<3) { setcolor(BLACK); //Движение указателя вверх
circle(x0-10,y0+10+(pos-1)*20,4);
pos++;
setcolor(RED);
circle(x0-10,y0+10+(pos-1)*20,4);
}
break;
}
case (27): {MenuGame();} //Возврат в главное меню
case (13): {if (pos==3) //Выход, если на позиции "Да"
{ remove("temp.dat");//При выходе удаляется временный файл, содержащий информацию о текущем профиле
_exit(1);
}
else MenuGame();//Возврат в главное меню, если на позиции "Нет"
}
}
}
}
void Menu::Score(void) //Таблица результатов
{
int x0=400,y0=300,i=0,flag=0,j=1;
FILE* fin;
char number[3];
cleardevice();
settextstyle(DEFAULT_FONT, HORIZ_DIR, 16);
//Вывод пунктов меню
setcolor(YELLOW);
outtextxy(x0,y0,"Рекорды");
setcolor(GREEN);
outtextxy(x0,y0+20,"Очистить");
outtextxy(x0,y0+40,"Печать результатов");
outtextxy(x0,y0+60,"Выйти в главное меню");
//Построение таблицы
setcolor(WHITE);
outtextxy(x0-295,y0-225,"№");
outtextxy(x0-270,y0-225,"Имя");
outtextxy(x0-95,y0-225,"Очки");
line(x0-300,y0-230,x0-300,y0+100);
line(x0-275,y0-230,x0-275,y0+100);
line(x0-100,y0-230,x0-100,y0+100);
line(x0-50,y0-230,x0-50,y0+100);
line(x0-300,y0-230,x0-50,y0-230);
line(x0-300,y0+100,x0-50,y0+100);
for (i=y0-200;i<y0+100;i+=30,j++)
{ line(x0-300,i,x0-50,i);
sprintf(number,"%d",j);
outtextxy(x0-295,i+5,number);
}
//Сам вывод результатов
fin=fopen("score.dat","rb");
if(fin)
{
for (i=y0-200;fread(&ns,sizeof(ns),1,fin);i+=30)
{ sprintf(number,"%d",ns.score);
outtextxy(x0-270,i+5,ns.name);
outtextxy(x0-95,i+5,number);
}
fclose(fin);
}
//Навигация по меню
int key,pos=3,flagexit=1;
setcolor(RED);
circle(x0-10,y0+10+(pos-1)*20,4);
while (flag!=1)
{ key=getch();
switch (key)
{ case 38: { if (pos>2) { setcolor(BLACK);
circle(x0-10,y0+10+(pos-1)*20,4);
pos--;
setcolor(RED);
circle(x0-10,y0+10+(pos-1)*20,4);
}
break;
}
case 40: { if (pos<4) { setcolor(BLACK);
circle(x0-10,y0+10+(pos-1)*20,4);
pos++;
setcolor(RED);
circle(x0-10,y0+10+(pos-1)*20,4);
}
break;
}
case (27): {MenuGame();}
case (13): {
if (pos==4) {MenuGame();break;} //Выйти в главное меню
if (pos==3) {PrintScore();break;} //Печать результатов
if (pos==2) { remove("score.dat"); //Очистка результатов
Score();
break;
}
}
}
}
}
void Menu::About(void) // Меню "Об игре"
{
int x0=300,y0=220,key=0;
Base *d;
cleardevice();
settextstyle(DEFAULT_FONT, HORIZ_DIR, 16);
setcolor(WHITE);
line(50,50,590,50);
line(50,50,50,430);
line(590,430,50,430);
line(590,430,590,50);
setcolor(GREEN);
outtextxy(60,60,"Управление");
outtextxy(300,60,"Обозначения");
outtextxy(250,170,"Правила игры");
outtextxy(250,330,"Приятной игры :)");
setcolor(BROWN);
outtextxy(60,80,"<- - Ловушка влево.");
outtextxy(60,100,"-> - Ловушка вправо.");
outtextxy(60,120,"Esc - Пауза, выход в меню.");
setcolor(3);
outtextxy(60,200,"С верхней части экрана падают шары. Управляя ловушкой, игрок");
outtextxy(60,220,"должен собрать как можно больше шаров за одну минуту. С течением ");
outtextxy(60,240,"времени, каждые 15 секунд, плотность падения шаров уменьшается,");
outtextxy(60,260,"а скорость увеличивается. Если игрок ловит Хороший шарик, то");
outtextxy(60,280,"прибавляется одно очко, если же Плохой шарик, то одно очко");
outtextxy(60,300,"вычитается.");
d = new NormalBall; d->show(550,92); outtextxy(300,80,"Хороший шарик, +1 очко");
d = new BadBall; d->show(550,112); outtextxy(300,100,"Плохой шарик, -1 очко");
d = new Catch; d->show(550,132); outtextxy(300,120,"Ловушка");
outtextxy(325,450,"Нажмите Esc для выхода в главное меню");
while (key==0)
{ key=getch();
}
delete d;
MenuGame();
}
void Menu::AddScore(void) //Запись результатов
{ FILE* fin;
namescore nss[10];
int i,j=0,n=0;
char temp[16];
fin=fopen("score.dat","rb");
while (fread(&nss[n],sizeof(ns),1,fin)&&n<=10) //Считываем данные и считаем количество уже записанных
{n++;}
fclose(fin);
for (i=0;i<=n-1 && (ns.score<=nss[i].score);i++) j++;//Находим позицию, куда вписать наш результат
for (i=n;i>=j+1;i--)
{ nss[i].score=nss[i-1].score;
sprintf(temp,"%s",nss[i-1].name);
sprintf(nss[i].name,"%s",temp);
}
//Запись результата в массив
nss[j].score=ns.score;
sprintf(temp,"%s",ns.name);
sprintf(nss[j].name,"%s",temp);
//Очистка файла и запись в него всех результатов
fin=fopen("score.dat","wb");
if (n==10) n--;
fwrite(&nss,sizeof(ns),n+1,fin);
getch();
fclose(fin);
}
void Menu::PrintScore(void) //Печать результатов
{ FILE* fin;
namescore nss[10];
int i,j=0,n=0;
char temp[16];
fin=fopen("score.dat","rb");
while (fread(&nss[n],sizeof(ns),1,fin)&&n<=10)
{n++;}
fclose(fin);
fin=fopen("score.txt","wt");
for (i=0;i<n;i++)
fprintf(fin,"%s %d ",nss[i].name,nss[i].score);
fclose(fin);
}
void Menu::Game(int g) //Функция "Игры"
{
FILE *fin, *save;
cleardevice();
int n=N, key=0,i,step=1,stt,st,sn, flag=0;//n-количество шариков
//key - "клавишная" переменная
//i - переменная для циклов
//step - скорость шаров
//stt - отчет времени (60 - если игра новая, или из сохранения)
//st - оставшееся время
//sn - количество очков
//flag - определение на "Паузу" или "Конец игры"
NormalBall *nb=new NormalBall;
BadBall *bb=new BadBall;
Catch *c= new Catch;
char time[3], score[3], level[2]; //Строковые переменные, для отображения в "информационной зоне"
fin=fopen("temp.dat","rb");//Считывание данных о текущем профиле
fread(&ns,sizeof(ns),1,fin);
fclose(fin);
clock_t t2,t1;
t1 = clock();//Время начала игры
if (g!=0) //проверка на "новая игра" или "продолжить"
{ save=fopen(savepath,"rb");//Продолжить, загрузка сохранения
fread(&sg,sizeof(sg),1,save);
st=sg.time;
n=sg.n;
sn=sg.score;
stt=sg.time;
step=sg.step;
fclose(save);
}
else //Новая игра, присвоение "Обычных" значений
{ for (i=0;i<=n-1;i++)
{ sg.x[i]=20+rand()%620;
sg.y[i]=0;
}
sg.x[5]=20+rand()%620;
sg.y[5]=0;
sg.x[N]=320;
sg.y[N]=400;
stt=60;
sn=0;
}
setfillstyle(1,GREEN); //Мертвая зона
bar(0,401,640,420);
//Информационная зона
setfillstyle(1,WHITE);
bar(0,420,640,480);
settextstyle(DEFAULT_FONT, HORIZ_DIR, 16);
outtextxy(10,420,"Time");
outtextxy(10,440,"Score");
outtextxy(100,420,"Level");
outtextxy(100,440,"Name");
outtextxy(300,420,"<1- - Ловушка влево.");
outtextxy(300,440,"-> - Ловушка вправо.");
outtextxy(300,460,"Esc - Пауза, выход в меню.");
setcolor(5);
outtextxy(150,440,ns.name);
//В принципе, игра начинается с этого момента, отрисовка объектов в начальных положениях
for (i=0;i<=n-1;i++)
nb->show(sg.x[i],sg.y[i]);
bb->show(sg.x[5],sg.y[5]);
c->show(sg.x[N],sg.y[N]);
while(!flag)
{ for (i=0;i<=n-1;i++) //Прячем все объекты
nb->hide(sg.x[i],sg.y[i]);
bb->hide(sg.x[5],sg.y[5]);
switch (st) //"временная" проверка
{
case 45: { step=2;//скорость
n=N-1; //количество шаров
break;
}
case 30: { step=4;// --/--
n=N-2; // --/--
break;
}
case 15: { step=6;// --/--
n=N-3; // --/--
break;
}
case 0 : { flag=1; //Конец игры
}
}
//Запись значений в структуру для осуществления сохранений
sg.n=n;
sg.time=st;
sg.score=sn;
sg.step=step;
key=getch();
switch (key)
{
case 37: { if (sg.x[N]!=20)//Ловушка влево
{ c->hide(sg.x[N],sg.y[N]);
sg.x[N]-=20;
c->show(sg.x[N],sg.y[N]);
}
break;
}
case 39: { if (sg.x[N]!=620)//Ловушка вправо
{ c->hide(sg.x[N],sg.y[N]);
sg.x[N]+=20;
c->show(sg.x[N],sg.y[N]);
}
break;
}
case 27: { save=fopen(savepath,"wb");//Пауза
fwrite(&sg,sizeof(sg),1,save);//Запись сохранения
fclose(save);
Pause();
break;
}
}
for (i=0;i<=n-1;i++)//Провека на столкновение шаров с ловушкой
if ( (sg.y[i]>=390) && (sg.x[i]>=sg.x[4]-20) && (sg.x[i]<=sg.x[4]+20) ) sn++; //Обычный шар
if ( sn>0 && (sg.y[5]>=390) && (sg.x[5]>=sg.x[4]-20) && (sg.x[5]<=sg.x[4]+20)) sn--; //Вредный шар
//проверка на дотяжение шаров "мертвой зоны"
for (i=0;i<=n-1;i++)
{ if (sg.y[i]<390) sg.y[i]+=(1+i)*step;
else {
sg.x[i]=20+rand()%620;
sg.y[i]=0;
}
}
if (sg.y[5]<390) sg.y[5]+=(1+i)*step;
else {
sg.x[5]=20+rand()%620;
sg.y[5]=0;}
//Отрисовка объектов
for (i=0;i<=n-1;i++)
{ nb->show(sg.x[i],sg.y[i]);
}
bb->show(sg.x[5],sg.y[5]);
// время
t2 = clock();//Текущее время
st=stt-(t2-t1)/CLOCKS_PER_SEC; //Вычисление оставшегося времени
sprintf(time,"%d",st);
sprintf(score,"%d",sn);
sprintf(level,"%d",N-n+1);
setfillstyle(1,WHITE);
bar(60,424,78,436);//Закрашивание старой информации
bar(60,444,78,456);
bar(150,424,160,436);
settextstyle(DEFAULT_FONT, HORIZ_DIR, 16);
setcolor(5);
setfillstyle(1,BLUE); //Запись новой информации
outtextxy(60,420,time);//Информационная зона, Время
outtextxy(60,440,score);//Информационная зона, Очки
outtextxy(150,420,level);//Информационная зона, Уровень
setfillstyle(1,GREEN);
bar(0,401,640,420);
sleep(10);
}
ns.score=sn; //Запись кол-ва набранных очков
cleardevice();
delete nb;
delete bb; //Вредный шар
delete c;
settextstyle(DEFAULT_FONT, HORIZ_DIR, 20);
setcolor(YELLOW);//Вывод окна "завершения игры"
outtextxy(60,60,"Игра окончена!");
outtextxy(60,120,"Вы набрали: ");
outtextxy(300,230,"очков");
outtextxy(60,400,"Нажмите любую клавишу...");
remove(savepath);//Удаление сохранения, так как игра закончена
settextstyle(DEFAULT_FONT, HORIZ_DIR, 50);
setcolor(GREEN);
outtextxy(230,200,score);//Вывод очков
key=0;
AddScore(); //Запись результатов
while (key==0)
{ key=getch();
}
Score(); //Вывод таблицы результатов
}
void Menu::Pause(void) //Функция "Паузы"
{
int x0=300,y0=220,i=0;
cleardevice();
bar(0,0,640,480);
setcolor(YELLOW);
outtextxy(x0,y0-20,"Пауза");
setcolor(GREEN);
outtextxy(x0,y0,"Продолжить");
outtextxy(x0,y0+20,"Заново");
outtextxy(x0,y0+40,"Выйти в главное меню");
int key=1,pos=1,flagexit=1;
setcolor(RED);
circle(x0-10,y0+12+(pos-1)*20,4);
while (flagexit)//Навигация по меню
{ key=getch();
switch (key)
{ case 38: { if (pos>1) { setcolor(BLACK);
circle(x0-10,y0+12+(pos-1)*20,4);
pos--;
setcolor(RED);
circle(x0-10,y0+12+(pos-1)*20,4);
}
break;
}
case 40: { if (pos<3) { setcolor(BLACK);
circle(x0-10,y0+12+(pos-1)*20,4);
pos++;
setcolor(RED);
circle(x0-10,y0+12+(pos-1)*20,4);
}
break;
}
case (27): {ExitOutGame();}
case (13): {if (pos==1) {Game(1);return;}
if (pos==2) {remove(savepath);Game(0);return;}
if (pos==3) {MenuGame();return;};
}
}
}
}
void Menu::MenuEnterKey(int pos) //Функция "Нажатия клавиши Enter"
{ int key=0;
switch (pos)
{ case 0: { Game(1);
break;
}
case 1: { remove(savepath);
Game(0);
break;
}
case 2: { cleardevice();
InputName();
break;
}
case 3: { Score();
break;
}
case 4: { About();
break;
}
case 5: {ExitOutGame();
}
}
}
void Menu::InputName () //Функция "Ввода имени профиля"
{
int i=0,x,ii=0;
char key;
savepath[0]= ;
settextstyle(1,1,16);
setcolor(YELLOW);
outtextxy(240,220,"Введите имя игрока:");
while (key!=13)
{ key=getch();
if (key==-67) { ns.name[i]=45;
ns.name[i+1]= ;
outtextxy(240,260,ns.name);
i++;
}
if (key==8) { setfillstyle(1,0); //Удаление символа
bar(240,250,400,290);
if (i>0) i--;
ns.name[i]= ;
outtextxy(240,260,ns.name);
}
if (i<15&&((key>=97&&key<=122)||(key>=65&&key<=90)||(key==32))) { ns.name[i]=key;
ns.name[i+1]= ;
outtextxy(240,260,ns.name);
i++;
}
}
if (i==0)
{ InputName();
return;
}
FILE *fin;
ns.score=0;
fin=fopen("temp.dat","wb");//temp.dat - временный файл, для хранения информации о текущем профиле
fwrite(&ns,sizeof(ns),1,fin);
strcat(savepath,"./save/");
strcat(savepath,ns.name);
fclose(fin);
cleardevice();
MenuGame();
}
Gameclass.h
class Base // Основной класс
{ public:
int x,y;
public:
Base() {}
virtual void show(int dx,int dy)
{ putpixel(dx,dy,WHITE);
}
virtual void hide(int dx,int dy)
{ putpixel(dx,dy,BLACK);
}
};
class NormalBall: public Base // Обычный шарик
{ public :
int R;
public :
NormalBall() { R=5;}
void show(int dx,int dy)
{
setcolor(WHITE);
setfillstyle(SOLID_FILL,WHITE);
circle(dx,dy,R);
}
void hide(int dx,int dy)
{ setcolor(BLACK);
setfillstyle(SOLID_FILL,BLACK);
circle(dx,dy,R);
}
};
class BadBall: public Base // Вредный шарик
{ public :
int R;
public :
BadBall()
{ R=5;
}
void show(int dx,int dy)
{
setcolor(YELLOW);
setfillstyle(SOLID_FILL,YELLOW);
circle(dx,dy,R);
}
void hide(int dx,int dy)
{ setcolor(BLACK);
setfillstyle(SOLID_FILL,BLACK);
circle(dx,dy,R);
}
};
class Catch: public Base // Ловушка
{ public:
int R;
public :
Catch() { R=5;}
void show(int dx,int dy)
{
setcolor(9);
setfillstyle(8, 9);
line(dx-10,dy,dx+10,dy);
line(dx-10,dy,dx-15,dy-R);
line(dx+10,dy,dx+15,dy-R);
line(dx-15,dy-R,dx+15,dy-R);
floodfill(dx,dy-4,9);
}
void hide(int dx,int dy)
{ setcolor(RED);
setfillstyle(8, BLACK);
line(dx-10,dy,dx+10,dy);
line(dx-10,dy,dx-15,dy-R);
line(dx+10,dy,dx+15,dy-R);
line(dx-15,dy-R,dx+15,dy-R);
floodfill(dx,dy-4,RED);
setcolor(BLACK);
line(dx-10,dy,dx+10,dy);
line(dx-10,dy,dx-15,dy-R);
line(dx+10,dy,dx+15,dy-R);
line(dx-15,dy-5,dx+15,dy-R);
}
};