Главная страница
Навигация по странице:

  • Описание кода

  • Реализация кода

  • РГР. Лисова_РГР. Расчётнографическая работа на тему Pacman


    Скачать 58.26 Kb.
    НазваниеРасчётнографическая работа на тему Pacman
    Дата11.05.2022
    Размер58.26 Kb.
    Формат файлаdocx
    Имя файлаЛисова_РГР.docx
    ТипДокументы
    #521941

    Министерство образования и науки РФ

    ФГБОУ ВПО «Омский государственный технический университет»

    Кафедра «Информатика и вычислительная техника»

    Расчётно-графическая работа на тему:

    Pacman

    Выполнил: студент гр.

    Лисова. А

    Проверил: ст. преподаватель,

    Чебаненко Е.В

    Омск 2020

    Оглавление


    Введение 3

    Описание кода 4

    Реализация кода 14

    Файл Unit1.cpp 14

    Файл Unit2.cpp 25

    Файл Project1.cpp 25

    Файл Unit1.h 26

    Файл Unit2.h 27


    Введение


    Следующий пример кода — ремейк игры Pacman Брайана Постмы вышедшая в далеком 1979 году, и уже очень скоро она завоевала огромную популярность.

    Цель игры состоит в том, чтобы собрать все очки в лабиринте и избежать призраков. Pacman анимирован в двух направлениях: его положение в лабиринте и его тело. Мы оживляем его тело четырьмя изображениями, в зависимости от направления. Анимация используется для создания иллюзии Pacman открытия и закрытия рта. У Пакмана три жизни. Мы также считаем счет. Игра состоит из нескольких файлов.
    Реализовать:

    1. Обязательные функции

    1.1 На игровом поле не менее 50% экрана (можно в коде программы установить фиксированный большой размер) случайным образом расставляются «кусты» и «камни», по одному в ячейке. Пакмен, занимающий одну ячейку, управляется стрелками клавиатуры, может стоять на месте, «поедает» кусты (куст при этом исчезает) и получает за это очки. При столкновении с камнем – теряет жизнь.

    1.2 Пакмен анимирован, по крайней мере открывает/закрывает рот, когда движется.

    Описание кода


    Первые переменные являются константами и хранят информацию для работы с картой. Такие как высота и ширина поля, скорость и количества ячеек на поле. А также изменение координат по оси x и y.

    const byte Height = 13;

    const byte Width = 13;

    const int CellSize = 32;

    const int constMaxWay = CellSize / 3;

    const byte mpNone = 0;

    const byte mpSeed = 1;

    const byte mpEnergizer = 2;

    const byte mpPacmanStart = 4;
    const int dx[4] = {1, 0, -1, 0};

    const int dy[4] = {0, -1, 0, 1};

    Функция BreakWall (), это вспомогательная функция, которая отвечает за разбивание стен на уровне.

    oid BreakWall(int x, int y, int dx, int dy)

    //вспомогательная функция. разбивает стену

    {

    if (dx == -1) Maze[x][y].left_wall = '0';

    if (dx == 1) Maze[x + 1][y].left_wall = '0';

    if (dy == -1) Maze[x][y].up_wall = '0';

    if (dy == 1) Maze[x][y + 1].up_wall = '0';

    }

    В свою очередь функция PrimGenerateMaze() уже полностью генерирует уровень по алгоритму Прима. Устанавливая границы поля и выбирает локацию, с которой начнётся генерация.

    void PrimGenerateMaze()

    {

    Form1->Label1->Caption = "Идет генерация лабиринта по алгоритму Прима";
    const int Inside = 1;

    const int Border = 2;

    const int Outside = 0;
    int x, y;

    int xc, yc;

    int xloc, yloc;

    bool IsEnd;

    int counter;
    for (x = 0; x < Width; x++)

    for (y = 0; y < Height; y++)

    {

    Maze[x][y].attr = Outside;

    Maze[x][y].left_wall = '1';

    Maze[x][y].up_wall = '1';

    }


    for (byte i = 0; i < Height; i++)

    {

    Maze[i][Height].up_wall = '1';

    Maze[Height][i].left_wall = '1';

    }


    x = random(Width);

    y = random(Height);

    Maze[x][y].attr = Inside;
    for (int i = 0; i < 4; i++)

    {

    xc = x + dx[i];

    yc = y + dy[i];

    if ((xc >= 0) && (yc >= 0) && (xc < Width) && (yc < Height))

    Maze[xc][yc].attr = Border;

    }
    do

    {

    IsEnd = true;

    counter = 0;
    for (x = 0; x < Width; x++)

    for (y = 0; y < Height; y++)

    if (Maze[x][y].attr == Border)

    counter++;

    counter = random(counter) + 1;

    for (x = 0; x < Width; x++)

    for (y = 0; y < Height; y++)

    if (Maze[x][y].attr == Border)

    {

    counter--;

    if (counter == 0)

    {

    xloc = x;

    yloc = y;

    goto ExitFor1;

    }

    }
    ExitFor1:

    Maze[xloc][yloc].attr = Inside;

    counter = 0;

    for (int i = 0; i < 4; i++)

    {

    xc = xloc + dx[i];

    yc = yloc + dy[i];

    if ((xc >= 0) && (yc >= 0) && (xc < Width) && (yc < Height))

    {

    if (Maze[xc][yc].attr == Inside) counter++;

    if (Maze[xc][yc].attr == Outside) Maze[xc][yc].attr = Border;

    }

    }
    counter = random(counter) + 1;

    for (int i = 0; i < 4; i++)

    {

    xc = xloc + dx[i];

    yc = yloc + dy[i];

    if ((xc >= 0) && (yc >= 0) && (xc <= Width) && (yc <= Height) && (Maze[xc][yc].attr == Inside))

    {

    counter--;

    if (counter == 0)

    BreakWall(xloc, yloc, dx[i], dy[i]);

    }

    }
    for (x = 0; x < Width; x++)

    for (y = 0; y < Height; y++)

    if (Maze[x][y].attr == Border)

    {

    IsEnd = false;

    goto ExitFor2;

    }
    ExitFor2:

    ShowMaze();

    Sleep(50);

    Application->ProcessMessages();

    }

    while (!IsEnd);

    }

    Функция ShowMaze() рисует лабиринт и отображает его в форме Canvas

    ImageBack->Canvas->Brush->Color = clNavy;

    ImageBack->Canvas->Pen->Color = clYellow;

    ImageBack->Canvas->FillRect(Rect(0,0,Width * CellSize + 1, Height * CellSize + 1));
    Дальше в той же функции идет проверка на есть ли на локации стена, если да, то мы рисуем их со всех сторон.

    if (Maze[i][j].left_wall == '1')

    {

    ImageBack->Canvas->MoveTo(i * CellSize, j * CellSize);

    ImageBack->Canvas->LineTo(i * CellSize, (j + 1) * CellSize);

    }
    if (Maze[i][j].up_wall == '1')

    {

    ImageBack->Canvas->MoveTo(i * CellSize, j * CellSize);

    ImageBack->Canvas->LineTo((i+1) * CellSize, j * CellSize);

    }
    Здесь рисуем кружки на поле при генерации лабиринта.

    {

    ImageBack->Canvas->Brush->Color = clRed;

    ImageBack->Canvas->Ellipse((i + 0.5) * CellSize - 5, (j + 0.5) * CellSize - 5,(i + 0.5) * CellSize + 5, (j + 0.5) * CellSize + 5);

    }

    }

    Form1->Canvas->Draw(0,0,ImageBack);
    Следующим рассмотрим метод CreateMap()  Генерируем карту и заполняем всё её пространство, в углах ставим бонусы, а по центру pacman. Так же устанавливаем начальные параметры.

    void CreateMap()

    {

    LevelSeed = 0;

    LevelEnergizer = 0;

    Score = 0;
    Maze[0][0].map = mpEnergizer;

    Maze[0][Width-1].map = mpEnergizer;

    Maze[Height-1][0].map = mpEnergizer;

    Maze[Height-1][Width-1].map = mpEnergizer;

    LevelEnergizer = 4;
    Maze[Height/2][Width/2].map = mpPacmanStart;
    for (byte i = 0; i < Height; i++)

    for (byte j = 0; j < Width; j++)

    if (Maze[i][j].map == mpNone)

    {

    Maze[i][j].map = mpSeed;

    LevelSeed++;

    }

    }

    Функция ShowMap() рисует в ImageBack, уже сгенерированный лабиринт, карту. И устанавливает pacman начальные координаты. И вызываем метод CheckStartPlace() именно она определяет начальное положение игрока.

    void ShowMap()
    {

    for (byte i = 0; i < Height; i++)

    for (byte j = 0; j < Width; j++)

    switch (Maze[i][j].map)

    {

    case mpSeed : Form1->Sprites->Draw(ImageBack->Canvas, i * CellSize, j * CellSize, 60);

    break;

    case mpEnergizer : Form1->Sprites->Draw(ImageBack->Canvas, i * CellSize, j * CellSize, 61);

    break;

    case mpPacmanStart : Pacman.StartX = i * CellSize;

    Pacman.StartY = j * CellSize;

    break;

    }

    CheckStartPlace();

    }

    И

    oid CheckStartPlace()

    {

    Pacman.X = Pacman.StartX;

    Pacman.Y = Pacman.StartY;

    Pacman.Dir = 3;

    Pacman.NewDir = 3;

    for (int i=0; i<4; i++)

    Pacman.DirFlag[i] = false;

    Pacman.Active = false;

    Pacman.ActiveTime = 0;

    for (int a = 0; a < 4; a++)

    {

    Ghost[a].X = a * CellSize;

    Ghost[a].Y = a * CellSize;

    Ghost[a].Dir = 3;

    for (int i = 0; i < 4; i++)

    Ghost[a].DirFlag[i] = false;

    Ghost[a].Shy = false;

    Ghost[a].ShyTime = 0;

    }
    Bonus.Kind = 0;

    Bonus.Life = 0;

    }

    Метод LevelCreate() делает постобработку сгенерированного лабиринта и разбивает стены чтобы там появились проходы для pacman. Если путь из локации в соседнюю будет больше по убираем стену между локациями.

    oid LevelCreate()

    {

    Form1->TimersRun(false);

    PrimGenerateMaze();
    Sleep(200);

    for (int x = 1; x < Width; x++)

    for (int y = 1; y < Height; y++)

    {

    WaveTracingSolve(x,y);

    for (int i = 0; i < 4; i++)

    if (Maze[x + dx[i]][y + dy[i]].mark > constMaxWay)

    {

    BreakWall( x, y, dx[i], dy[i]);

    ShowMaze();

    Sleep(100);

    }

    }
    CreateMap();

    ShowMap();

    MediaPlayer[sNextLevel]->Play();

    Form1->TimersRun(true);

    }

    Класс TBonus() содержит в себе параметры для бонусов, которые может подбирать игрок. Бонусы имеет 4 вида с разными эффектами.

    class TBonus

    {

    public:

    int Kind;

    int Time;

    int Life;
    void Show()

    {

    if (Kind == 0)

    {

    switch (random(10))

    {

    case 0: case 1: case 2: case 3: Kind = 4; break;

    case 4: case 7: case 8: Kind = 3; break;

    case 5: case 6: Kind = 2; break;

    case 9: Kind = 1; break;

    }

    Time = (5 + random(10)) * 100;

    }

    else Time--;
    if ((Kind >= 0) && (Time == 0))

    {

    MediaPlayer[sShowBonus]->Play();

    Life = 1000;

    }
    if (Life != 0)

    {

    Form1->Sprites->Draw(ImageBack->Canvas,Height/2 * CellSize,Width /2 * CellSize,Kind + 61,true);

    Life--;

    if (Life == 0) Kind = 0;

    }

    }

    } Bonus;

    Метод TPacman() содежрит в себе все параметры pacman, его начальные координаты X и Y. Скорость движения и изменения координат на поле.

    class TPacman

    {

    public:

    int X;

    int Y;

    int StartX;

    int StartY;

    int Dir;

    int NewDir;

    int SpriteNum;

    bool Active;

    int ActiveTime;

    bool DirFlag[3];
    void VerifyDir()

    {

    if (Maze[X/CellSize][Y/CellSize].left_wall == '1') DirFlag[0] = false;

    else DirFlag[0] = true;

    if (Maze[X/CellSize][Y/CellSize].up_wall == '1') DirFlag[1] = false;

    else DirFlag[1] = true;

    if (Maze[X/CellSize + 1][Y/CellSize].left_wall == '1') DirFlag[2] = false;

    else DirFlag[2] = true;

    if (Maze[X/CellSize][Y/CellSize + 1].up_wall == '1') DirFlag[3] = false;

    else DirFlag[3] = true;

    }
    void Go()

    {

    Form1->Sprites->Draw(ImageBuffer->Canvas, X, Y, Dir * 3 + SpriteNum);

    if ((X % CellSize == 0) && (Y % CellSize == 0))

    {

    Dir = NewDir;

    if (Maze[X/CellSize][Y/CellSize].mark != 1) WaveTracingSolve(X/CellSize,Y/CellSize);
    switch (Maze[X/CellSize][Y/CellSize].map)

    {

    case mpSeed : MediaPlayer[sEatSeed]->Play();

    Score++;

    Maze[X/CellSize][Y/CellSize].map = mpNone;

    break;

    case mpEnergizer : MediaPlayer[sEatEnergizer]->Play();

    Score += 5;

    Active = true;

    ActiveTime = 20;

    Maze[X/CellSize][Y/CellSize].map = mpNone;

    break;

    case mpPacmanStart : if (Bonus.Life != 0)

    {

    MediaPlayer[sEatBonus]->Play();

    Active = true;

    ActiveTime = 20;

    Bonus.Kind = 0;

    Bonus.Life = 0;

    }

    break;

    }

    LevelRenewSeed();

    VerifyDir();

    }
    if (DirFlag[Dir] == true)

    switch (Dir)

    {

    case 0: X--; break;

    case 1: Y--; break;

    case 2: X++; break;

    case 3: Y++; break;

    }

    }

    } Pacman;

    Метод TGhost() содежрит в себе все параметры ghost, его начальные координаты X и Y. Скорость движения и изменения координат на поле и их количество.

    class TGhost

    {

    public:

    int X;

    int Y;

    int StartX;

    int StartY;

    int Dir;

    int SpriteNum;

    bool Shy;

    int ShyTime;

    int CurrN;

    bool DirFlag[3];
    void NextStep()

    {

    if ((Maze[X/CellSize - 1][Y/CellSize].mark == CurrN - 1) && (Maze[X/CellSize][Y/CellSize].left_wall == '0')) Dir = 0;

    if ((Maze[X/CellSize][Y/CellSize-1].mark == CurrN - 1) && (Maze[X/CellSize][Y/CellSize].up_wall == '0')) Dir = 1;

    if ((Maze[X/CellSize + 1][Y/CellSize].mark == CurrN - 1) && (Maze[X/CellSize+1][Y/CellSize].left_wall == '0')) Dir = 2;

    if ((Maze[X/CellSize][Y/CellSize+1].mark == CurrN - 1) && (Maze[X/CellSize][Y/CellSize+1].up_wall == '0')) Dir = 3;

    }
    void VerifyDir()

    {

    if (Maze[X/CellSize][Y/CellSize].left_wall == '1') DirFlag[0] = false;

    else DirFlag[0] = true;

    if (Maze[X/CellSize][Y/CellSize].up_wall == '1') DirFlag[1] = false;

    else DirFlag[1] = true;

    if (Maze[X/CellSize + 1][Y/CellSize].left_wall == '1') DirFlag[2] = false;

    else DirFlag[2] = true;

    if (Maze[X/CellSize][Y/CellSize + 1].up_wall == '1') DirFlag[3] = false;

    else DirFlag[3] = true;

    }
    void Go(int a)

    {

    if ((X % CellSize == 0) && (Y % CellSize == 0))

    {

    VerifyDir();

    if (random(a*2) == 0) {CurrN = Maze[X/CellSize][Y/CellSize].mark; NextStep();}

    else CurrN++;

    }

    if ((Shy == false) && (DirFlag[Dir] == true))

    switch (Dir)

    {

    case 0: X--; break;

    case 1: Y--; break;

    case 2: X++; break;

    case 3: Y++; break;

    }

    }

    } Ghost[3];

    Пример выполнения программы



    Рисунок 1. Выполнение программы PAC-MAN

    Реализация кода

    Файл Unit1.cpp



    #include

    #include

    #include

    #include

    #include
    #include
    #pragma hdrstop
    #include "Unit1.h"

    #include "Unit2.h"

    //---------------------------------------------------------------------------

    #pragma package(smart_init)

    #pragma resource "*.dfm"

    TForm1 *Form1;
    //---------------------КОНСТАНТЫ---------------------------------------------
    //для работы с картой
    const byte Height = 13;

    const byte Width = 13;

    const int CellSize = 32;

    const int constMaxWay = CellSize / 3;

    const byte mpNone = 0;

    const byte mpSeed = 1;

    const byte mpEnergizer = 2;

    const byte mpPacmanStart = 4;
    const int dx[4] = {1, 0, -1, 0}; // смещения, чтобы определить

    const int dy[4] = {0, -1, 0, 1}; // какую стену разбивать в BreakWall
    //для звуков
    TMediaPlayer *MediaPlayer[10];

    const byte sMove = 0;

    const byte sEatSeed = 1;

    const byte sEatEnergizer = 2;

    const byte sShowBonus = 3;

    const byte sEatBonus = 4;

    const byte sEatGhost = 5;

    const byte sDie = 6;

    const byte sLoose = 7;

    const byte sWin = 8;

    const byte sNextLevel = 9;
    //---------------------ПЕРЕМЕННЫЕ--------------------------------------------
    int N = 0;

    int LevelSeed = 0;

    int LevelEnergizer = 0;

    int Score = 0;
    //для графики
    Graphics::TBitmap* ImageBuffer; // буфер (все в него перед выводом на форму)

    Graphics::TBitmap* ImageSprites; //картинка со спрайтами

    Graphics::TBitmap* ImageBack; //фон + лабиринт + неизменяемые элементы
    //---------------------------------------------------------------------------
    struct Location

    {

    byte left_wall; //флаг наличия у данной локации левой и верхней стен

    byte up_wall; //правая и нижняя вычисляются через соседние локации

    int attr; //Outside = 0, Inside = 1, Border = 2.

    int mark; // хранят N при волновой трассировке

    int map; // карта

    }

    Maze[Height+1][Width+1];

    // +1 чтобы у ряда [Height][] была нижняя стена, а у [][Width] правая
    //---------------------------------------------------------------------------
    class TBonus

    {

    public:

    int Kind; // вид бонуса

    int Time; // время до появления следующего

    int Life; // время "жизни" бонуса
    void Show()

    {

    if (Kind == 0)

    {

    switch (random(10))

    {

    case 0: case 1: case 2: case 3: Kind = 4; break; // 40%

    case 4: case 7: case 8: Kind = 3; break; // 30%

    case 5: case 6: Kind = 2; break; // 20%

    case 9: Kind = 1; break; // 10%

    }

    Time = (5 + random(10)) * 100;

    }

    else Time--;
    if ((Kind >= 0) && (Time == 0))

    {

    MediaPlayer[sShowBonus]->Play();

    Life = 1000;

    }
    if (Life != 0)

    {

    Form1->Sprites->Draw(ImageBack->Canvas,Height/2 * CellSize,Width /2 * CellSize,Kind + 61,true);

    Life--;

    if (Life == 0) Kind = 0;

    }

    }

    } Bonus;
    //---------------------------------------------------------------------------
    class TPacman

    {

    public:

    int X;

    int Y;

    int StartX;

    int StartY;

    int Dir;

    int NewDir;

    int SpriteNum;

    bool Active;

    int ActiveTime;

    bool DirFlag[3];
    void VerifyDir()

    {

    if (Maze[X/CellSize][Y/CellSize].left_wall == '1') DirFlag[0] = false;

    else DirFlag[0] = true;

    if (Maze[X/CellSize][Y/CellSize].up_wall == '1') DirFlag[1] = false;

    else DirFlag[1] = true;

    if (Maze[X/CellSize + 1][Y/CellSize].left_wall == '1') DirFlag[2] = false;

    else DirFlag[2] = true;

    if (Maze[X/CellSize][Y/CellSize + 1].up_wall == '1') DirFlag[3] = false;

    else DirFlag[3] = true;

    }
    void Go()

    {

    Form1->Sprites->Draw(ImageBuffer->Canvas, X, Y, Dir * 3 + SpriteNum);

    if ((X % CellSize == 0) && (Y % CellSize == 0))

    {

    Dir = NewDir;

    if (Maze[X/CellSize][Y/CellSize].mark != 1) WaveTracingSolve(X/CellSize,Y/CellSize);
    switch (Maze[X/CellSize][Y/CellSize].map)

    {

    case mpSeed : MediaPlayer[sEatSeed]->Play();

    Score++;

    Maze[X/CellSize][Y/CellSize].map = mpNone;

    break;

    case mpEnergizer : MediaPlayer[sEatEnergizer]->Play();

    Score += 5;

    Active = true;

    ActiveTime = 20;

    Maze[X/CellSize][Y/CellSize].map = mpNone;

    break;

    case mpPacmanStart : if (Bonus.Life != 0)

    {

    MediaPlayer[sEatBonus]->Play();

    Active = true;

    ActiveTime = 20;

    Bonus.Kind = 0;

    Bonus.Life = 0;

    }

    break;

    }

    LevelRenewSeed();

    VerifyDir();

    }
    if (DirFlag[Dir] == true)

    switch (Dir)

    {

    case 0: X--; break;

    case 1: Y--; break;

    case 2: X++; break;

    case 3: Y++; break;

    }

    }

    } Pacman;
    //---------------------------------------------------------------------------
    class TGhost

    {

    public:

    int X;

    int Y;

    int StartX;

    int StartY;

    int Dir;

    int SpriteNum;

    bool Shy;

    int ShyTime;

    int CurrN;

    bool DirFlag[3];
    void NextStep()

    {

    if ((Maze[X/CellSize - 1][Y/CellSize].mark == CurrN - 1) && (Maze[X/CellSize][Y/CellSize].left_wall == '0')) Dir = 0;

    if ((Maze[X/CellSize][Y/CellSize-1].mark == CurrN - 1) && (Maze[X/CellSize][Y/CellSize].up_wall == '0')) Dir = 1;

    if ((Maze[X/CellSize + 1][Y/CellSize].mark == CurrN - 1) && (Maze[X/CellSize+1][Y/CellSize].left_wall == '0')) Dir = 2;

    if ((Maze[X/CellSize][Y/CellSize+1].mark == CurrN - 1) && (Maze[X/CellSize][Y/CellSize+1].up_wall == '0')) Dir = 3;

    }
    void VerifyDir()

    {

    if (Maze[X/CellSize][Y/CellSize].left_wall == '1') DirFlag[0] = false;

    else DirFlag[0] = true;

    if (Maze[X/CellSize][Y/CellSize].up_wall == '1') DirFlag[1] = false;

    else DirFlag[1] = true;

    if (Maze[X/CellSize + 1][Y/CellSize].left_wall == '1') DirFlag[2] = false;

    else DirFlag[2] = true;

    if (Maze[X/CellSize][Y/CellSize + 1].up_wall == '1') DirFlag[3] = false;

    else DirFlag[3] = true;

    }
    void Go(int a)

    {

    if ((X % CellSize == 0) && (Y % CellSize == 0))

    {

    VerifyDir();

    if (random(a*2) == 0) {CurrN = Maze[X/CellSize][Y/CellSize].mark; NextStep();}

    else CurrN++;

    }

    if ((Shy == false) && (DirFlag[Dir] == true))

    switch (Dir)

    {

    case 0: X--; break;

    case 1: Y--; break;

    case 2: X++; break;

    case 3: Y++; break;

    }

    }

    } Ghost[3];
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)

    : TForm(Owner)

    {

    }
    //---------------------ФУНКЦИИ-ФОРМЫ-----------------------------------------
    void __fastcall TForm1::FormCreate(TObject *Sender)

    {

    Form1->ClientWidth = ::Width * CellSize + 1;

    Form1->ClientHeight = ::Height * CellSize + Form1->Label1->Height + 1;
    for (int i = 0; i < 10; i++)

    {

    MediaPlayer[i] = new TMediaPlayer(this);

    MediaPlayer[i]->Parent = this;

    MediaPlayer[i]->Visible = false;

    MediaPlayer[i]->FileName ="sound" + IntToStr(i) + ".wav";

    MediaPlayer[i]->Open();

    }
    ImageBack = new Graphics::TBitmap();

    ImageBack->Width = ::Width * CellSize + 1;

    ImageBack->Height = ::Height * CellSize + 1;
    ImageBuffer = new Graphics::TBitmap();

    ImageBuffer->Width = ImageBack->Width;

    ImageBuffer->Height = ImageBack->Height;
    Randomize;

    Form1->DoubleBuffered = true;

    TimersRun(false);

    }
    //---------------------МЕНЮ-ФОРМЫ--------------------------------------------
    void __fastcall TForm1::MenuNewClick(TObject *Sender)

    {

    LevelCreate();

    }

    //---------------------------------------------------------------------------
    void __fastcall TForm1::MenuExitClick(TObject *Sender)

    {

    Form1->Close();

    }

    //---------------------ОБРАБОТКА-КЛАВИШ----------------------------------
    void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key,

    TShiftState Shift)

    {

    if ((Key >= 37) && (Key <= 40)) Pacman.NewDir = Key - 37;

    }
    //---------------------ТАЙМЕРЫ-----------------------------------------------
    void __fastcall TForm1::TimerMoveTimer(TObject *Sender)

    {

    ImageBuffer->Canvas->Draw(0,0,ImageBack); // выводим все в буфер
    Bonus.Show();

    Pacman.Go();
    for (int a = 0; a < 4; a++)

    {

    Ghost[a].Go(a);

    if (Ghost[a].Shy == false)

    Form1->Sprites->Draw(ImageBuffer->Canvas, Ghost[a].X, Ghost[a].Y, 12 * (a + 1) + Ghost[a].Dir * 3 + Ghost[a].SpriteNum);

    else

    Form1->Sprites->Draw(ImageBuffer->Canvas, Ghost[a].X, Ghost[a].Y, 12 * (random(3) + 1) + Ghost[a].Dir * 3 + Ghost[a].SpriteNum);
    if (((abs(Pacman.Y - Ghost[a].Y) < 10) && (abs(Pacman.X - Ghost[a].X) < 10))

    && (((Pacman.X % CellSize == 0) && (Ghost[a].X % CellSize == 0))

    || ((Pacman.Y % CellSize == 0) && (Ghost[a].Y % CellSize == 0))))

    {

    if (Pacman.Active == true)

    {

    MediaPlayer[sEatGhost]->Play();

    Ghost[a].Shy = true;

    Ghost[a].ShyTime = 15;

    }

    else

    {

    MediaPlayer[sDie]->Play();

    Form1->TimersRun(false);

    MessageDlg(" Вас съели !!! ", mtInformation, TMsgDlgButtons() << mbOK, 0);

    CheckStartPlace();

    Form1->TimersRun(true);

    }

    }

    }
    Label1->Caption = "Набрать очков для победы=" + IntToStr(LevelSeed + LevelEnergizer * 5) + "; Набрано очков=" + IntToStr(Score) + "; Время неуязвимости=" + IntToStr(Pacman.ActiveTime);
    // если съедены все зерна в уровне, то он пройден - грузим следующий

    if (Score == LevelSeed + LevelEnergizer * 5)

    {

    MediaPlayer[sWin]->Play();

    TimersRun(false);

    MessageDlg(" Вы победили. Следующий уровень !!! ", mtInformation, TMsgDlgButtons() << mbOK, 0);

    LevelCreate();

    }
    Form1->Canvas->Draw(0,0,ImageBuffer); // выводим все на экран

    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::TimerActiveTimer(TObject *Sender)

    {

    if (Pacman.ActiveTime > 0)

    Pacman.ActiveTime--;

    if (Pacman.ActiveTime == 0)

    Pacman.Active = false;
    for (int a = 0; a < 4; a++)

    {

    if (Ghost[a].ShyTime > 0)

    Ghost[a].ShyTime--;

    if (Ghost[a].ShyTime == 0)

    Ghost[a].Shy = false;

    }

    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::TimerSpriteTimer(TObject *Sender)

    {

    if (Pacman.SpriteNum < 2) Pacman.SpriteNum++;

    else

    {

    Pacman.SpriteNum = 0;

    MediaPlayer[sMove]->Play();

    }
    for (int a = 0; a < 4; a++)

    if (Ghost[a].SpriteNum < 2) Ghost[a].SpriteNum++;

    else Ghost[a].SpriteNum = 0;

    }
    //---------------------------------------------------------------------------
    void TForm1::TimersRun(bool active)

    {

    TimerMove->Enabled = active;

    TimerSprite->Enabled = active;

    TimerActive->Enabled = active;

    }
    //---------------------ОБЩИЕ-ФУНКЦИИ-----------------------------------------

    //-------------генерация лабиринта по алгоритму Прима------------------------
    void BreakWall(int x, int y, int dx, int dy)

    //вспомогательная функция. разбивает стену

    {

    if (dx == -1) Maze[x][y].left_wall = '0';

    if (dx == 1) Maze[x + 1][y].left_wall = '0';

    if (dy == -1) Maze[x][y].up_wall = '0';

    if (dy == 1) Maze[x][y + 1].up_wall = '0';

    }
    //---------------------------------------------------------------------------
    void PrimGenerateMaze()

    {

    Form1->Label1->Caption = "Идет генерация лабиринта по алгоритму Прима";
    const int Inside = 1;

    const int Border = 2;

    const int Outside = 0;
    int x, y;

    int xc, yc;

    int xloc, yloc;

    bool IsEnd;

    int counter;
    //вначале есть все стены и все локации внешние

    for (x = 0; x < Width; x++)

    for (y = 0; y < Height; y++)

    {

    Maze[x][y].attr = Outside;

    Maze[x][y].left_wall = '1';

    Maze[x][y].up_wall = '1';

    }
    //нижняя и правая границы

    for (byte i = 0; i < Height; i++)

    {

    Maze[i][Height].up_wall = '1';

    Maze[Height][i].left_wall = '1';

    }
    //выбираем локацию, с которой начнется генерация

    x = random(Width);

    y = random(Height);

    Maze[x][y].attr = Inside;
    for (int i = 0; i < 4; i++)

    {

    xc = x + dx[i];

    yc = y + dy[i];

    if ((xc >= 0) && (yc >= 0) && (xc < Width) && (yc < Height))

    Maze[xc][yc].attr = Border;

    }
    do

    {

    IsEnd = true;

    counter = 0;
    //выбираем случайную локацию с атрибутом Border

    for (x = 0; x < Width; x++)

    for (y = 0; y < Height; y++)

    if (Maze[x][y].attr == Border)

    counter++;

    counter = random(counter) + 1;

    for (x = 0; x < Width; x++)

    for (y = 0; y < Height; y++)

    if (Maze[x][y].attr == Border)

    {

    counter--;

    if (counter == 0)

    {

    xloc = x;

    yloc = y;

    goto ExitFor1;

    }

    }
    ExitFor1:

    //присваиваем ей атрибут Inside

    Maze[xloc][yloc].attr = Inside;

    counter = 0;

    for (int i = 0; i < 4; i++)

    {

    xc = xloc + dx[i];

    yc = yloc + dy[i];

    if ((xc >= 0) && (yc >= 0) && (xc < Width) && (yc < Height))

    {

    if (Maze[xc][yc].attr == Inside) counter++;

    if (Maze[xc][yc].attr == Outside) Maze[xc][yc].attr = Border;

    }

    }
    counter = random(counter) + 1;

    for (int i = 0; i < 4; i++)

    {

    xc = xloc + dx[i];

    yc = yloc + dy[i];

    if ((xc >= 0) && (yc >= 0) && (xc <= Width) && (yc <= Height) && (Maze[xc][yc].attr == Inside))

    {

    counter--;

    if (counter == 0)

    BreakWall(xloc, yloc, dx[i], dy[i]);

    }

    }
    for (x = 0; x < Width; x++)

    for (y = 0; y < Height; y++)

    if (Maze[x][y].attr == Border)

    {

    IsEnd = false;

    goto ExitFor2;

    }
    ExitFor2:

    ShowMaze();

    Sleep(50);

    Application->ProcessMessages();

    }

    while (!IsEnd);

    }

    //---------------------------------------------------------------------------
    void ShowMaze()

    //рисуем в ImageBack лабиринт и отображаем на канвасе формы

    {

    ImageBack->Canvas->Brush->Color = clNavy;

    ImageBack->Canvas->Pen->Color = clYellow;

    ImageBack->Canvas->FillRect(Rect(0,0,Width * CellSize + 1, Height * CellSize + 1));
    for (byte i = 0; i <= Height; i++)

    for (byte j = 0; j <= Width; j++)

    {

    if (Maze[i][j].left_wall == '1')

    //если у данной локации есть левая стена, то рисуем ее

    {

    ImageBack->Canvas->MoveTo(i * CellSize, j * CellSize);

    ImageBack->Canvas->LineTo(i * CellSize, (j + 1) * CellSize);

    }
    if (Maze[i][j].up_wall == '1')

    //соответственно если есть верхняя стена, то и ее рисуем

    {

    ImageBack->Canvas->MoveTo(i * CellSize, j * CellSize);

    ImageBack->Canvas->LineTo((i+1) * CellSize, j * CellSize);

    }
    if (Maze[i][j].attr == 2)

    //рисуем кружки в Border-локациях при генерации лабирнта

    {

    ImageBack->Canvas->Brush->Color = clRed;

    ImageBack->Canvas->Ellipse((i + 0.5) * CellSize - 5, (j + 0.5) * CellSize - 5,(i + 0.5) * CellSize + 5, (j + 0.5) * CellSize + 5);

    }

    }

    Form1->Canvas->Draw(0,0,ImageBack);

    }
    //---------------------------------------------------------------------------
    void CreateMap()

    // генерируем карту: заполняем все пространство Seed

    // в углах ставим бонусные Energizer

    // в центре mpPacmanStart

    // + считаем количество Seed и Energizer

    {

    LevelSeed = 0;

    LevelEnergizer = 0;

    Score = 0;
    Maze[0][0].map = mpEnergizer;

    Maze[0][Width-1].map = mpEnergizer;

    Maze[Height-1][0].map = mpEnergizer;

    Maze[Height-1][Width-1].map = mpEnergizer;

    LevelEnergizer = 4;
    Maze[Height/2][Width/2].map = mpPacmanStart;
    for (byte i = 0; i < Height; i++)

    for (byte j = 0; j < Width; j++)

    if (Maze[i][j].map == mpNone)

    {

    Maze[i][j].map = mpSeed;

    LevelSeed++;

    }

    }
    //---------------------------------------------------------------------------
    void ShowMap()

    // рисуем в ImageBack(там уже сгенерирован лабиринт) карту

    // инициализируем Pacman.StartX и StartY

    // вызываем CheckStartPlace()

    {

    for (byte i = 0; i < Height; i++)

    for (byte j = 0; j < Width; j++)

    switch (Maze[i][j].map)

    {

    case mpSeed : Form1->Sprites->Draw(ImageBack->Canvas, i * CellSize, j * CellSize, 60);

    break;

    case mpEnergizer : Form1->Sprites->Draw(ImageBack->Canvas, i * CellSize, j * CellSize, 61);

    break;

    case mpPacmanStart : Pacman.StartX = i * CellSize;

    Pacman.StartY = j * CellSize;

    break;

    }

    CheckStartPlace();

    }
    //---------------------------------------------------------------------------
    void LevelCreate()

    {

    Form1->TimersRun(false);

    PrimGenerateMaze();
    //постобработка сгенерированного лабиринта

    //разбиваем рэндомные стены чтоб были проходы

    Sleep(200);

    for (int x = 1; x < Width; x++)

    for (int y = 1; y < Height; y++)

    {

    //если путь из данной локации в соседнюю больше constMaxWay,

    //то разбиваем стену между этими локациями

    WaveTracingSolve(x,y);

    for (int i = 0; i < 4; i++)

    if (Maze[x + dx[i]][y + dy[i]].mark > constMaxWay)

    {

    BreakWall( x, y, dx[i], dy[i]);

    ShowMaze();

    Sleep(100);

    }

    }
    CreateMap();

    ShowMap();

    MediaPlayer[sNextLevel]->Play();

    Form1->TimersRun(true);

    }
    //---------------------------------------------------------------------------
    void CheckStartPlace()

    {

    Pacman.X = Pacman.StartX;

    Pacman.Y = Pacman.StartY;

    Pacman.Dir = 3;

    Pacman.NewDir = 3;

    for (int i=0; i<4; i++)

    Pacman.DirFlag[i] = false;

    Pacman.Active = false;

    Pacman.ActiveTime = 0;

    for (int a = 0; a < 4; a++)

    {

    Ghost[a].X = a * CellSize;

    Ghost[a].Y = a * CellSize;

    Ghost[a].Dir = 3;

    for (int i = 0; i < 4; i++)

    Ghost[a].DirFlag[i] = false;

    Ghost[a].Shy = false;

    Ghost[a].ShyTime = 0;

    }
    Bonus.Kind = 0;

    Bonus.Life = 0;

    }
    //---------------------------------------------------------------------------
    void LevelRenewSeed()

    {

    ImageBack->Canvas->Brush->Color = clNavy;

    ImageBack->Canvas->FillRect(Rect(Pacman.X + 1, Pacman.Y + 1, Pacman.X + CellSize, Pacman.Y + CellSize));

    }
    //---------------------------------------------------------------------------
    bool CanGo(int x, int y, int dx, int dy)

    {

    byte f = '0';
    if (dx == -1) f = Maze[x][y].left_wall;

    if (dx == 1) f = Maze[x + 1][y].left_wall;

    if (dy == -1) f = Maze[x][y].up_wall;

    if (dy == 1) f = Maze[x][y + 1].up_wall;
    if (f == '0')

    return true;

    return false;

    }
    //---------------------------------------------------------------------------
    void Solve()

    {

    bool FindNull;
    //{ начинаем с итерации номер 1 }

    do

    {

    FindNull = false; //положим нулей нет -> волну построили -> конец алгоритма

    for ( int x = 0; x < Width; x++)

    for ( int y = 0; y < Height; y++)

    {

    if (Maze[x][y].mark == N)

    //найти локации, помеченные числом N

    for (int i = 0; i < 4; i++)

    //просмотр соседних локаций

    if ((CanGo(x, y, dx[i], dy[i])) && (Maze[x + dx[i]][y + dy[i]].mark == 0))

    //локация доступна и помечена нулем -> помечаем ее числом N + 1

    Maze[x + dx[i]][y + dy[i]].mark = N + 1;

    if (Maze[x][y].mark == 0)

    FindNull = true; //нашли локации помеченные нулем => продолжаем строить волну

    }

    N++;

    }

    while (FindNull == true); //повторять, если есть непройденные локации

    }
    //---------------------------------------------------------------------------
    void WaveTracingSolve(int xs, int ys)

    {

    int x, y, xc, yc;

    for (int x = 0; x < Width; x++)

    for (int y = 0; y < Height; y++)

    Maze[x][y].mark = 0;
    Maze[xs][ys].mark = 1; //стартовой локации соответствует единица

    N = 1;

    Solve();

    Form1->Label1->Caption = "Алгоритм сработал";

    }
    //---------------------------------------------------------------------------

    void __fastcall TForm1::N4Click(TObject *Sender)

    {

    Form2->ShowModal();

    }

    //---------------------------------------------------------------------------

    Файл Unit2.cpp


    #include

    #pragma hdrstop
    #include "Unit2.h"

    //---------------------------------------------------------------------------

    #pragma package(smart_init)

    #pragma resource "*.dfm"

    TForm2 *Form2;

    //---------------------------------------------------------------------------

    __fastcall TForm2::TForm2(TComponent* Owner)

    : TForm(Owner)

    {

    }

    //---------------------------------------------------------------------------
    void __fastcall TForm2::Timer1Timer(TObject *Sender)

    {

    Label1->Caption=Date();

    Label2->Caption=Time();

    }

    Файл Project1.cpp


    #include

    #pragma hdrstop

    //---------------------------------------------------------------------------

    USEFORM("Unit1.cpp", Form1);

    USEFORM("Unit2.cpp", Form2);

    //---------------------------------------------------------------------------

    WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)

    {

    try

    {

    Application->Initialize();

    Application->CreateForm(__classid(TForm1), &Form1);

    Application->CreateForm(__classid(TForm2), &Form2);

    Application->Run();

    }

    catch (Exception &exception)

    {

    Application->ShowException(&exception);

    }

    catch (...)

    {

    try

    {

    throw Exception("");

    }

    catch (Exception &exception)

    {

    Application->ShowException(&exception);

    }

    }

    return 0;

    }

    Файл Unit1.h


    #ifndef Unit1H

    #define Unit1H

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    class TForm1 : public TForm

    {

    __published: // IDE-managed Components

    TMainMenu *MainMenu1;

    TLabel *Label1;

    TMenuItem *MenuGame;

    TMenuItem *MenuNew;

    TMenuItem *N5;

    TMenuItem *MenuExit;

    TImageList *Sprites;

    TTimer *TimerMove;

    TTimer *TimerSprite;

    TTimer *TimerActive;

    TMenuItem *N1;

    TMenuItem *N4;

    void __fastcall FormCreate(TObject *Sender);

    void __fastcall MenuNewClick(TObject *Sender);

    void __fastcall MenuExitClick(TObject *Sender);

    void __fastcall FormKeyDown(TObject *Sender, WORD &Key,

    TShiftState Shift);

    void __fastcall TimerMoveTimer(TObject *Sender);

    void __fastcall TimerActiveTimer(TObject *Sender);

    void __fastcall TimerSpriteTimer(TObject *Sender);

    void __fastcall N4Click(TObject *Sender);

    private: // User declarations

    public: // User declarations

    __fastcall TForm1(TComponent* Owner);
    void TimersRun(bool active);

    };
    void BreakWall(int x, int y, int dx, int dy);

    void PrimGenerateMaze();

    void ShowMaze();

    void CreateMap();

    void ShowMap();

    void LevelCreate();
    void CheckStartPlace();

    void LevelRenewSeed();
    bool CanGo(int x, int y, int dx, int dy);

    void Solve();

    void WaveTracingSolve(int xs, int ys);
    extern PACKAGE TForm1 *Form1;

    #endif

    Файл Unit2.h


    #ifndef Unit2H

    #define Unit2H

    //---------------------------------------------------------------------------

    #include

    #include

    #include

    #include

    #include

    #include

    //---------------------------------------------------------------------------

    class TForm2 : public TForm

    {

    __published: // IDE-managed Components

    TImage *Image1;

    TLabel *Label1;

    TLabel *Label2;

    TTimer *Timer1;

    TLabel *Label3;

    TLabel *Label4;

    TLabel *Label5;

    TLabel *Label6;

    void __fastcall Timer1Timer(TObject *Sender);

    private: // User declarations

    public: // User declarations

    __fastcall TForm2(TComponent* Owner);

    };

    //---------------------------------------------------------------------------

    extern PACKAGE TForm2 *Form2;

    //---------------------------------------------------------------------------

    #endif


    написать администратору сайта