Приложение "Тетрис"

Тип работы:
Курсовая
Предмет:
Программирование


Узнать стоимость

Детальная информация о работе

Выдержка из работы

СОДЕРЖАНИЕ

1. ТЕХНИЧЕСКОЕ ЗАДАНИЕ5

1.1 Введение5

1.2 Назначение системы5

1.3 Требования к программному проекту5

1.3.1 Требования к функциональным характеристикам5

1.3.2 Требования к надежности5

1.3.3 Требования к эксплуатации6

1.3.4 Требования к информационной и программной совместимости6

1.3.5 Требования к техническому обеспечению6

2. ИССЛЕДОВАЛЕЛЬСКАЯ ЧАСТЬ7

2.1 Постановка задачи7

2.2 Описание тематики7

2.2.1 Пользовательский интерфейс7

2.2.2 Оконный интерфейс8

2.2.3 Интерфейс программирования приложений (API)9

2.2.4 Windows API13

3. КОНСТРУКТОРСКАЯ ЧАСТЬ15

3.1 Общие сведения15

3.2 Описание логической структуры программы15

3.2.1 Структура программы15

3.2.2 Структуры данных модели15

3.2.3 Функции для работы с приложением17

3.3 Руководство программиста20

3.3.1 Назначение программы20

3.3.2 Условия выполнения программы20

3.3.3 Тестирование программы20

3.3.4 Обращение к программе21

4. ТЕХНОЛОГИЧЕСКАЯ ЧАСТЬ22

4.1 Входные данные22

4.2 Выходные данные22

4.3 Руководство пользователя22

4.3.1 Назначение программы22

4.3.2 Требования к аппаратной и программной средам22

4.3.3 Выполнение программы23

4.3.4 Сообщения оператору. 25

ЛИТЕРАТУРА26

ПРИЛОЖЕНИЕ

1. ТЕХНИЧЕСКОЕ ЗАДАНИЕ

приложение тетрис программа

1.1 Введение

Данный проект представляет собой приложение «Тетрис», осуществляющее вывод различных фигур на экран случайным образом и их падение.

1.2 Назначение системы

Разрабатываемое приложение предназначено для развлечения играющих, совершенствование их координации и логического мышления. Приложение может применяться в качестве игры на разных типах персональных компьютеров.

1.3 Требования к программному проекту

1.3.1 Требования к функциональным характеристикам

В состав приложения входят функции отображения на экране движущихся фигур, параллельного переноса их вправо и влево, поворота вокруг собственной оси, ускорения падения на дно игрового поля. А также функции сохранения и загрузки игры и ряд вспомогательных функций (контроль наложения фигур, учет количества стертых линий, текущего уровня и скорости движения фигур, и т. д.).

1.3.2 Требования к надежности

Надежное функционирование программы обеспечивается проверкой наложения при перемещении фигур и ограничением, накладываемым на набор входных данных (коды нажатых клавиш игнорируются, если эти клавиши не являются управляющими в игре).

1.3.3 Требования к эксплуатации

Эксплуатация программного обеспечения может выполняться без специальной подготовки пользователем, имеющим базовые навыки работы с компьютером в системе семейства MS Windows.

1.3.4 Требования к информационной и программной совместимости

Среда проектирования, используемая при разработке данного проекта — Microsoft Visual Studio 2010. Для работы с приложением требуется установленная операционная система Windows XP или более поздняя версия, приложение совместимо только с ОС семейства Windows. Работа продукта основана на стандартных библиотеках системы, и не требует установки дополнительных компонентов.

1.3.5 Требования к техническому обеспечению

Для нормального функционирования данного программного продукта необходимо наличие:

оперативной памяти не менее 32 Мб

процессора, с частотой не менее 300 МГц

не менее 108 Кб (для x64 185 Кб) свободного места на жестком диске

клавиатуры

мыши

монитора

2. ИССЛЕДОВАЛЕЛЬСКАЯ ЧАСТЬ

2.1 Постановка задачи

Реализовать программу, представляющую собой игру «Тетрис». Программа должна осуществлять падение фигур, наложение их друг на друга, а также подсчет и стирание заполненных линий. Также необходимо реализовать возможность сохранения и загрузки сохраненной игры и увеличения скорости падения фигур в зависимости от полученного уровня. Должен быть предоставлен пользователю понятный и удобный интерфейс для работы с программой. Среда проектирования — Microsoft Visual Studio 2010 с использованием средств Win32 API.

2.2 Описание тематики

2.2.1 Пользовательский интерфейс

Пользовательский интерфейс -- разновидность интерфейсов, в котором одна сторона представлена человеком (пользователем), другая -- машиной/устройством. Представляет собой совокупность средств и методов, при помощи которых пользователь взаимодействует с различными, чаще всего сложными, машинами, устройствами и аппаратурой.

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

Интерфейс двунаправленный (интерактивный) -- устройство, получив команды от пользователя и исполнив их, выдаёт информацию пользователю наличествующими у неё средствами -- визуальными, звуковыми, тактильными и т. п. (приняв которую, пользователь выдаёт устройству последующие команды предоставленными в его распоряжение средствами: кнопки, переключатели, регуляторы, сенсоры, голосом, и т. д.).

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

2.2.2 Оконный интерфейс

Оконный интерфейс -- способ организации полноэкранного интерфейса программы, в котором каждая интегральная часть располагается в окне -- собственном субэкранном пространстве, находящемся в произвольном месте «над» основным экраном. Несколько окон, одновременно располагающихся на экране, могут перекрываться, виртуально находясь «выше» или «ниже» друг относительно друга.

Оконный интерфейс реализуется как в графическом, так и в текстовом режиме. Однако наибольшую популярность он завоевал благодаря операционным системам с графическими оконными оболочками (ОС Mac, ОС Windows) и в настоящее время является самым популярным видом пользовательского интерфейса.

Программы с классической (полноэкранной) организацией экрана могут использовать элементы оконного интерфейса (субокна) для: организации меню, окон сообщений и диалогов.

Программы с полной реализацией оконного интерфейса раздельно работают с отдельными подзадачами в разных окнах. Такая программа может одновременно открывать/работать с несколькими документами, помещая их в отдельные субокна. Организацию этих субокон в подобных программах реализуют несколькими способами:

однооконный режим (SDI)

многооконный режим (MDI, TDI)

псевдомногооконный режим (PMDI)

Также однооконный режим может поддерживать систему фреймов, при которой общее окно разбито на несколько функционально независимых областей, фреймов.

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

Также существует разновидность окон (называемых модальными), которые «монополизируют» фокус пользовательского внимания, и продолжить работу с программой можно лишь после закрытия (выполнения запроса) такого «модального» окна.

Большинство современных операционных систем имеют неотъемлемый или опциональный оконный графический пользовательский интерфейс, реализующий окно в качестве основы взаимодействия с пользователем.

Оконная операционная система позволяет пользователю одновременно работать с различными программами. Каждая программа работает в отдельном окне, занимающем отдельное пространство на экране, обычно в форме прямоугольника. Большинство операционных систем предоставляют пользователю основные функции работы с окнами: перенос, изменение размера окна, фокуса окна и так далее.

2.2.3 Интерфейс программирования приложений (API)

Интерфейс программирования приложений (англ. application programming interface, API) -- набор готовых классов, процедур, функций, структур и констант, предоставляемых приложением (библиотекой, сервисом) для использования во внешних программных продуктах. Используется программистами для написания всевозможных приложений.

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

Программные компоненты взаимодействуют друг с другом посредством API. При этом обычно компоненты образуют иерархию -- высокоуровневые компоненты используют API низкоуровневых компонентов, а те, в свою очередь, используют API ещё более низкоуровневых компонентов.

По такому принципу построены протоколы передачи данных по Интернет. Стандартный стек протоколов (сетевая модель OSI) содержит 7 уровней (от физического уровня передачи бит до уровня протоколов приложений, подобных протоколам HTTP и IMAP). Каждый уровень пользуется функциональностью предыдущего уровня передачи данных и, в свою очередь, предоставляет нужную функциональность следующему уровню.

Важно заметить, что понятие протокола близко по смыслу к понятию API. И то и другое является абстракцией функциональности, только в первом случае речь идёт о передаче данных, а во втором -- о взаимодействии приложений.

API библиотеки функций и классов включает в себя описание сигнатур и семантики функций.

Сигнатура функции -- часть общего объявления функции, позволяющая средствам трансляции идентифицировать функцию среди других. В различных языках программирования существуют разные представления о сигнатуре функции, что также тесно связано с возможностями перегрузки функции в этих языках.

Иногда различают сигнатуру вызова и сигнатуру реализации функции. Сигнатура вызова обычно составляется по синтаксической конструкции вызова функции с учётом сигнатуры области видимости данной функции, имени функции, последовательности фактических типов аргументов в вызове и типе результата. В сигнатуре реализации обычно участвуют некоторые элементы из синтаксической конструкции объявления функции: спецификатор области видимости функции, её имя и последовательность формальных типов аргументов.

В языке программирования C++ простая функция однозначно опознаётся компилятором по её имени и последовательности типов её аргументов, что составляет сигнатуру функции в этом языке. Если функция является методом некоторого класса, то в сигнатуре будет участвовать и имя класса.

В языке программирования Java сигнатуру метода составляет его имя и последовательность типов параметров; тип значения в сигнатуре не участвует.

Семантика функции -- это описание того, что данная функция делает. Семантика функции включает в себя описание того, что является результатом вычисления функции, как и от чего этот результат зависит. Обычно результат выполнения зависит только от значений аргументов функции, но в некоторых модулях есть понятие состояния. Тогда результат функции может зависеть от этого состояния, и, кроме того, результатом может стать изменение состояния. Логика этих зависимостей и изменений относится к семантике функции. Полным описанием семантики функций является исполняемый код функции или математическое определение функции.

Практически все операционные системы (Unix, Windows, Mac OS, и т. д.) имеют API, с помощью которого программисты могут создавать приложения для этой операционной системы. Главный API операционных систем -- это множество системных вызовов.

В индустрии программного обеспечения общие стандартные API для стандартной функциональности имеют важную роль, так как они гарантируют, что все программы, использующие общий API, будут работать одинаково хорошо или, по крайней мере, типичным привычным образом. В случае API графических интерфейсов это означает, что программы будут иметь похожий пользовательский интерфейс, что облегчает процесс освоения новых программных продуктов.

С другой стороны, отличия в API различных операционных систем существенно затрудняют перенос приложений между платформами. Существуют различные методы обхода этой сложности -- написание «промежуточных» API (API графических интерфейсов WxWidgets, Qt, Gtk, и т. п.), написание библиотек, которые отображают системные вызовы одной ОС в системные вызовы другой ОС (такие среды исполнения, как Wine, cygwin, и т. п.), введение стандартов кодирования в языках программирования (например, стандартная библиотекаязыка C), написание интерпретируемых языков, реализуемых на разных платформах (sh, python, perl, php, tcl, Java, и т. д.).

Также необходимо отметить, что в распоряжении программиста часто находится несколько различных API, позволяющих добиться одного и того же результата. При этом каждый API обычно реализован с использованием API программных компонент более низкого уровня абстракции.

Например: для того, чтобы увидеть в браузере строчку «Hello, world!», достаточно лишь создать HTML-документ с минимальным заголовком и простейшим телом, содержащим данную строку. Когда браузер откроет этот документ, программа-браузер передаст имя файла (или уже открытый дескриптор файла) библиотеке, обрабатывающей HTML-документы, та, в свою очередь, при помощи API операционной системы прочитает этот файл и разберётся в его устройстве, затем последовательно вызовет через API библиотеки стандартных графических примитивов операции типа «очистить окошко», «написать выбранным шрифтом «Hello, world!». Во время выполнения этих операций библиотека графических примитивов обратится к библиотеке оконного интерфейса с соответствующими запросами, уже эта библиотека обратится к API операционной системы, чтобы записать данные в буфер видеокарты.

При этом практически на каждом из уровней реально существует несколько возможных альтернативных API. Например: мы могли бы писать исходный документ не на HTML, а наLaTeX, для отображения могли бы использовать любой браузер. Различные браузеры, вообще говоря, используют различные HTML-библиотеки, и, кроме того, всё это может быть (вообще говоря) собрано с использованием различных библиотек примитивов и на различных операционных системах.

Основными сложностями существующих многоуровневых систем API, таким образом, являются:

Сложность портирования программного кода с одной системы API на другую (например, при смене ОС);

Потеря функциональности при переходе с более низкого уровня на более высокий. Грубо говоря, каждый «слой» API создаётся для облегчения выполнения некоторого стандартного набора операций. Но при этом реально затрудняется, либо становится принципиально невозможным выполнение некоторых других операций, которые предоставляет более низкий уровень API.

2.2.4 Windows API

Windows API -- общее наименование целого набора базовых функций интерфейсов программирования приложений операционных систем семейств Microsoft Windows корпорации «Майкрософт» и совместимой с ними свободной бесплатной операционной системы ReactOS. Является самым прямым способом взаимодействия приложений с Windows и ReactOS. Для создания программ, использующих Windows API, «Майкрософт» выпускает комплект разработчика программного обеспечения, который называется Platform SDK, и содержит документацию, набор библиотек, утилит и других инструментальных средств для разработки.

Windows API был изначально спроектирован для использования в программах, написанных на языке Си или C++. Работа через Windows API -- это наиболее близкий к системе способ взаимодействия с ней из прикладных программ. Более низкий уровень доступа, необходимый только для драйверов устройств, в текущих версиях Windows предоставляется через Windows Driver Model.

3. КОНСТРУКТОРСКАЯ ЧАСТЬ

3.1 Общие сведения

Данный курсовой проект представляет собой программу, созданную в среде Microsoft Visual Studio 2010 с полным её описанием. Цель проекта — реализация системного приложения «Тетрис».

3.2 Описание логической структуры программы

3.2.1 Структура программы

Программа состоит из следующих модульных частей:

Tetris. cpp — главный модуль программы. Содержит основной код приложения, включая ресурсы;

3.2.2 Структуры данных модели

Константные значения

HORIZONTAL_LINE — количество клеток игрового поля по горизонтали.

VERTICAL_LINE — количество клеток игрового поля по вертикали.

FIGUR_COUNT — число различных фигур.

SPEED — начальная скорость падения фигуры.

SIZE_WINDOW_X — размер окна по горизонтали.

SIZE_WINDOW_Y — размер окна по вертикали.

Переменные для работы с приложениями

HINSTANCE hInstance — дескриптор экземпляра приложения.

BOOL g_bFigure[4][4], g_bNextFigur[4][4] - массивы описывающие текущую и следующую фигуры.

int g_iStok[HORIZONTAL_LINE][VERTICAL_LINE] - массив описывающий положение фигур на игровом поле.

POINT g_pPozFigure — массив описывающий перемещение фигуры.

enum enumFigure{line=0, cube, lright, lleft, tfigur, zleft, zright, cross, Tfigur, Cfigur, Zleft, Zright, corner, Corner, point, Wfigur} - перечисление видов фигур.

int g_iLvlup[15] = {3, 8, 15, 24, 30, 40, 55, 75, 100, 150, 300, 500, 750, 1000, 1500} - массив количества стертых линий, необходимых для следующего уровня.

Переменные для работы с интерфейсом программы

HMENU hMenu — дескриптор главного меню окна;

WCHAR szScore[100] - строка для хранения заголовка окна приложения;

HWND hWnd — дескриптор окна приложения;

Реализация пользовательского интерфейса программы

Функция int WINAPI WinMain (HINSTANCE hInst, HINSTANCE, LPSTR, int)

Данная функция создана для выполнения основных задач:

регистрация оконного класса, создание окна программы, отображение его на экране, организация цикла обработки сообщений;

создание меню;

инициализации дочерних окон;

производится установка таймера;

производится обработка сообщений клавиатуры;

Функция LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam).

Это оконная функция, обрабатывающая сообщения основного окна программы.

Функция LRESULT CALLBACK WndStokProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam).

Это оконная функция, обрабатывающая сообщения игрового поля.

3.2.3 Функции для работы с приложением

Функции WinApi, используемые в приложении

Функция int wsprintf (LPSTR lpBuffer, LPCTSTR lpszFormatString, [arguments])

Данная функция используется в программе для вывода текущего счета, уровня и количества очков для следующего уровня.

Функция wsprintf () форматирует данные ([arguments]) с использованием заданной строки формата (lpszFormatString) и размещает полученные данные в символьном буфере (lpBuffer).

Второй аргумент lpszFormatString — это указатель на строку с нулевым символом в конце, которая содержит формат выходного результата.

Третий параметр [arguments] - это список элементов данных, которые должны форматироваться и пересылаться в символьный буфер.

Функция BOOL GetWindowRect (HWND hWnd, LPRECT lpRect)

С помощью данной функции получаются координаты в пикселях окна игрового поля и окна следующей фигуры, относительно левого верхнего угла экрана.

HWND hWnd — дескриптор дочернего окна панели инструментов.

LPRECT lpRect — адрес структурной переменной типа RECT.

Функция VOID ZeroMemory (PVOID Destination, DWORD Length)

Данная функция заполняет указанный блок памяти нулями.

PVOID Destination — указатель на начальный адрес заполняемого блока памяти.

DWORD Length — размер заполняемого блока памяти, в байтах.

Макрос HANDLE_MSG (hwnd, message, fn)

case (message): return HANDLE_##message ((hwnd),(wParam),(lParam),(fn)

Данная группа макросов описана в заголовочном файле Windowsx. h и используется в данной программе для упрощения ее структуры. При использовании этих макросов все процедуры обработки сообщений выделяются в отдельные функции.

Пользовательские функции

Функция void GetFigure (int Figure)

Данная функция предназначена для создания следующей фигуры.

Функция void DrawStok ()

Данная функция прорисовывает игровое поле.

Функция int Speed (int g_iScore)

Данная функция возвращает значение скорости падения фигур, в зависимости от текущего счета.

Функция void DrawFigure ()

Данная функция прорисовывает фигуры.

Функция void Repaint ()

Данная функция перерисовывает игровое поле и фигуры, используя две предыдущие функции.

Функция void ClearFigure (BOOL *iArray)

Данная функция очищает массив, которым задается фигура. Входным параметром является указатель на массив, которым задается фигура.

Функция void CopyFigure (BOOL *iSrcArray, BOOL *iDstArray)

Данная функция копирует значения массива, которым задается одна фигура в другой массив.

Функция void NextFigure ()

Данная функция задает по таймеру следующую фигуру, используя две предыдущие функции.

Функция void NewGame ()

Данная функция задает начальные значения и следующую фигуру, включает таймер и прорисовывает игровое поле и фигуру.

Функция BOOL isImpact (BOOL *iArray)

Данная функция проверяет столкновение с дном, границами и другими фигурами.

Функция void SaveGame ()

Данная функция записывает текущее состояние игрового поля и текущий счет в файл.

Функция void LoadGame ()

Данная функция считывает из файла значения массива игрового поля и счет игры.

Функция BOOL OnCreate (HWND hwnd, LPCREATESTRUCT lpCreateStruct)

Данная функция создает главное меню.

Функция void OnGetMinMaxInfo (HWND hwnd, LPMINMAXINFO lpMinMaxInfo)

Данная функция задает минимальный и максимальный размер окна.

Функция void OnPaint (HWND hwnd)

Данная функция рисует в окне игровое поле.

Функция void EraseOldFigur ()

Данная функция стирает фигуру из области следующей фигуры.

Функция void PaintNewFigur ()

Данная функция рисует фигуру в области следующей фигуры.

Функция void LineClear ()

Данная функция проверяет, есть ли заполненные линии, и если есть, то стирает их и смещает вниз содержимое игрового поля.

Функция void OnTimer (HWND hwnd, UNIT id)

Данная функция реализует таймер.

Функция void MoveRight ()

Данная функция реализует сдвиг фигуры вправо.

Функция void MoveLeft ()

Данная функция реализует сдвиг фигуры влево.

Функция void MoveDown ()

Данная функция реализует сдвиг фигуры вниз.

Функция void Rotate ()

Данная функция реализует поворот фигуры.

Функция void OnKeyDown (HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags)

Данная функция связывает вызов предыдущих четырех функций с нажатием на стрелки клавиатуры.

Функция void OnCommand (HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)

Данная функция позволяет по нажатию на пункты меню начать, сохранить, загрузить, выйти из игры.

3.3 Руководство программиста

3.3.1 Назначение программы

Данная программа создана в среде Microsoft Visual Studio 2010. Она позволяет пользователю играть в «Тетрис».

3.3.2 Условия выполнения программы

Программа может быть запущена на любом компьютере, на котором установлена одна из операционных систем Windows XP/Vista/7. Программа занимает 108 КБ (версия x64 — 185 Кб) дискового пространства.

3.3.3 Тестирование программы

Для выполнения тестирования программы следует произвести следующие действия:

Запустить файл «Tetris_x86. exe «(или для x64 «Tetris_x64. exe «).

Выбрать в меню File пункт New Game.

Управлять фигурами с помощью клавиш со стрелками, и стереть несколько линий (при стирании 3 линий увеличится уровень и немного увеличится скорость падения фигур). Для тестирования работоспособности приложения нужно проверить: падение фигуры до дна, не выходит ли фигура за границы игрового поля, сдвиг фигур и поворот вблизи от границ (при этом фигура не должна накладываться на границу игрового поля), не стирается ли линия, содержащая пустые ячейки.

Выбрать пункт Save меню File, чтобы сохранить игру. При этом должно отобразиться сообщение, что игра успешно сохранена.

Выбрать пункт Load меню File, чтобы загрузить игру.

После выполнения всех вышеперечисленных действий программа будет окончена протестирована.

Далее необходимо выполнить выход из программы, выбрав пункт Exit меню File, или нажать закрыть в правом верхнем углу окна приложения.

3.3.4 Обращение к программе

Для обращения к программе необходимо запустить файл «Tetris_x86. exe «(для x64 «Tetris_x64. exe «) с гибкого или жёсткого магнитного диска.

4. ТЕХНОЛОГИЧЕСКАЯ ЧАСТЬ

4.1 Входные данные

Входными данными являются коды клавиш со стрелками на клавиатуре.

4.2 Выходные данные

Выходными данными является графическая информация, выводимая на экран.

4.3 Руководство пользователя

4.3.1 Назначение программы

Программный продукт должен предназначаться для развлечения играющих. Программа должна включать в себя средства сохранения и загрузки текущего прогресса игры.

4.3.2 Требования к аппаратной и программной средам

Условия выполнения программы, полученной в результате реализации данного проекта, должны отвечать следующим требованиям:

программа должна выполняться в одной из операционных систем Windows XP/Vista/7;

программа может выполняться на компьютере с процессором не ниже Intel/AMD не ниже 300МГц;

для нормального функционирования программы необходим минимальный размер оперативной памяти 32 Мб;

для программы необходимо наличие 108 Кб (для x64 185 Кб) свободного места на жестком диске;

для работы с программой необходимо наличие устройств ввода (клавиатура, «мышь»);

для отображения результатов работы программы необходимо наличие устройства вывода (монитор);

4.3.3 Выполнение программы

Запуск программы.

Запуск программы происходит после двойного щелчка кнопкой мыши по иконке приложения. После запуска приложения появится окно (Рис. 1.).

Рис. 1. Главное окно программы

Начало игры

Для начала игры нужно открыть меню File (Рис. 2.) и выбрать пункт New Game, после чего появится игровое поле (Рис. 3.), затем управляя клавишами со стрелками можно будет перемещать, разворачивать и ускорять падение фигур.

Рис. 2. Меню File

Рис. 3. Игровое поле

Сохранение игры

Для сохранения игры в меню File нужно выбрать пункт Save.

Загрузка сохраненной игры

Для загрузки сохраненной игры в меню File нужно выбрать пункт Load.

Выход из программы

Завершение программы происходит после щелчка левой кнопки мыши по кнопке с крестиком в верхнем правом углу окна программы или при выборе пункта Exit в меню File.

Сообщения оператору.

При сохранении игры пользователю выдается сообщение, что игра сохранена. (Рис. 4)

Рис. 4. Игра сохранена.

Если игровое поле полностью заполнится, то отобразится сообщение, что игра окончена. (Рис. 5)

Рис. 5. Игра окончена.

ЛИТЕРАТУРА

Щупак Ю.А., «Win32 API. Эффективная разработка приложений», Питер, 2007 г., 576с.; ил.

Финогенов К.Г., «Win32. Основы программирования», Диалог-МИФИ, 2006 г., 416с.; ил.

Безруков В.А., «Win32 API. Программирование / Учебное пособие», СПбГУ ИТМО, 2009 г., 90с.

Джеффри Рихтер, «Windows для профессионалов. Создание эффективных Win32-пpилoжeний с учетом специфики 64-разрядной версии Windows. «, Питер, Русская Редакция, 2001 г., 752с.

Курс лекций «Программирование в Windows» Белов Ю. С.

Курс лекций «Системное программирование» Вершинин Е. В.

ПРИЛОЖЕНИЕ

Tetris. cpp

#define WIN32_LEAN_AND_MEAN

#include < stdlib. h>

#include < windows. h>

#include < windowsx. h>

#include < fstream>

#pragma comment (linker,"-merge:. rdata=. text")

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

#defineID_MENU_NEW_GAMEWM_USER+1

#define ID_MENU_SAVE WM_USER+2

#define ID_MENU_LOAD WM_USER+3

#defineID_MENU_EXITWM_USER+4

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

#defineHORIZONTAL_LINE15

#defineVERTICAL_LINE30

#defineFIGUR_COUNT16

#define SPEED 400

#defineSIZE_WINDOW_X525

#defineSIZE_WINDOW_Y720

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

HINSTANCEg_hinstance;

HWNDg_hwnd, g_hStok, g_hFigure;

HMENUg_hMenu;

BOOLg_bFigure[4][4], g_bNextFigur[4][4];

intg_iStok[HORIZONTAL_LINE][VERTICAL_LINE];

POINTg_pPozFigure;

intg_iColor, g_iFigure, g_iNextFigure, g_iScore, g_iSpeed, g_iInc=0;

enumenumFigure{line=0, cube, lright, lleft, tfigur, zleft, zright, cross, Tfigur, Cfigur, Zleft, Zright, corner, Corner, point, Wfigur}; //Виды фигур

bool g_flag=false;

int g_iLvlup[15] = {3, 8, 15, 24, 30, 40, 55, 75, 100, 150, 300, 500, 750, 1000, 1500};

using namespace std;

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

void GetFigure (int eFigure)

{

switch (eFigure)

{

case line:

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

{

g_bNextFigur[c][0]=TRUE;

}

break;

case tfigur:

for (int c=0; c<3;c++)

g_bNextFigur[c][0]=TRUE;

g_bNextFigur[1][1]=TRUE;

break;

case cube:

for (int c=0; c<2;c++)

for (int c2=0; c2<2;c2++)

g_bNextFigur[c][c2]=TRUE;

break;

case lright:

for (int c=0; c< 3; c++)

g_bNextFigur[0][c]=TRUE;

g_bNextFigur[1][0]=TRUE;

break;

case lleft:

for (int c=0; c< 3; c++)

g_bNextFigur[0][c]=TRUE;

g_bNextFigur[1][2]=TRUE;

break;

case zleft: g_bNextFigur[0][0]=TRUE;

g_bNextFigur[1][0]=TRUE;

g_bNextFigur[1][1]=TRUE;

g_bNextFigur[2][1]=TRUE;

break;

case zright:

g_bNextFigur[0][1]=TRUE;

g_bNextFigur[1][0]=TRUE;

g_bNextFigur[1][1]=TRUE;

g_bNextFigur[2][0]=TRUE;

break;

case cross:

g_bNextFigur[0][1]=TRUE;

g_bNextFigur[1][0]=TRUE;

g_bNextFigur[1][1]=TRUE;

g_bNextFigur[2][1]=TRUE;

g_bNextFigur[1][2]=TRUE;

break;

case Tfigur:

g_bNextFigur[0][0]=TRUE;

g_bNextFigur[0][1]=TRUE;

g_bNextFigur[0][2]=TRUE;

g_bNextFigur[1][1]=TRUE;

g_bNextFigur[2][1]=TRUE;

break;

case Cfigur:

g_bNextFigur[0][0]=TRUE;

g_bNextFigur[0][1]=TRUE;

g_bNextFigur[0][2]=TRUE;

g_bNextFigur[1][0]=TRUE;

g_bNextFigur[1][2]=TRUE;

break;

case Zleft:

g_bNextFigur[0][0]=TRUE;

g_bNextFigur[1][0]=TRUE;

g_bNextFigur[1][1]=TRUE;

g_bNextFigur[1][2]=TRUE;

g_bNextFigur[2][2]=TRUE;

break;

case Zright:

g_bNextFigur[0][0]=TRUE;

g_bNextFigur[1][0]=TRUE;

g_bNextFigur[1][1]=TRUE;

g_bNextFigur[1][2]=TRUE;

g_bNextFigur[2][0]=TRUE;

break;

case corner:

g_bNextFigur[0][0]=TRUE;

g_bNextFigur[0][1]=TRUE;

g_bNextFigur[1][1]=TRUE;

break;

case Corner:

g_bNextFigur[0][0]=TRUE;

g_bNextFigur[1][0]=TRUE;

g_bNextFigur[2][0]=TRUE;

g_bNextFigur[2][1]=TRUE;

g_bNextFigur[2][2]=TRUE;

break;

case point:

g_bNextFigur[0][0]=TRUE;

break;

case Wfigur:

g_bNextFigur[0][0]=TRUE;

g_bNextFigur[1][0]=TRUE;

g_bNextFigur[1][1]=TRUE;

g_bNextFigur[2][1]=TRUE;

g_bNextFigur[2][2]=TRUE;

break;

}

g_iColor=(rand ()%100)+100;

}

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

void DrawStok ()

{

HDC dc=GetDC (g_hStok);

RECTrectWndStok;

GetWindowRect (g_hStok,& rectWndStok);

int x=(rectWndStok. right-rectWndStok. left)/HORIZONTAL_LINE;

int y=(rectWndStok. bottom-rectWndStok. top)/VERTICAL_LINE;

int br;

for (int c1=0; c1<HORIZONTAL_LINE;c1++)

for (int c2=0; c2<VERTICAL_LINE;c2++)

{

br=g_iStok[c1][c2];

HBRUSH hBrash=CreateSolidBrush (RGB (br, br, br));

HBRUSH hOldBrach=SelectBrush (dc, hBrash);

Rectangle (dc, c1*x, c2*y,(c1*x)+x,(c2*y)+y);

DeleteBrush (SelectBrush (dc, hOldBrach));

}

ReleaseDC (g_hFigure, dc);

ValidateRect (g_hStok,& rectWndStok);

}

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

int Speed (int g_iScore)

{

return (SPEED-((g_iInc+1)*15));

}

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

void DrawFigure ()

{

HDC dc=GetDC (g_hFigure);

RECTrectWndFigure;

GetWindowRect (g_hFigure,& rectWndFigure);

HBRUSH hOldBrach;

HBRUSHhBrash=CreateSolidBrush (RGB (100,100,100));

HBRUSHhBlackBrash=GetStockBrush (BLACK_BRUSH);

int x=(rectWndFigure. right-rectWndFigure. left)/4;

int y=(rectWndFigure. bottom-rectWndFigure. top)/4;

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

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

{

if (g_bNextFigur[c1][c2])

{

hOldBrach=SelectBrush (dc, hBrash);

Rectangle (dc, c1*x, c2*y,((c1+1)*x)+x,(c2*y)+y);

hBrash=SelectBrush (dc, hOldBrach);

}

else

{

hOldBrach=SelectBrush (dc, hBlackBrash);

Rectangle (dc, c1*x, c2*y,((c1+1)*x)+x,(c2*y)+y);

SelectBrush (dc, hOldBrach);

}

}

DeleteBrush (SelectBrush (dc, hOldBrach));

ReleaseDC (g_hFigure, dc);

ValidateRect (g_hFigure,& rectWndFigure);

}

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

voidRepaint ()

{

DrawStok ();

DrawFigure ();

}

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

void ClearFigure (BOOL *iArray)

{

for (int c1=0; c1<4*4;c1++)

*(iArray+c1)=FALSE;

}

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

void CopyFigure (BOOL *iSrcArray, BOOL *iDstArray)

{

for (int c1=0; c1<4*4;c1++)

*(iDstArray+c1)=*(iSrcArray+c1);

}

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

void NextFigure ()

{

CopyFigure (& g_bNextFigur[0][0],&g_bFigure[0][0]);

ClearFigure (& g_bNextFigur[0][0]);

g_iFigure=g_iNextFigure;

g_iNextFigure=rand ()%FIGUR_COUNT;

GetFigure (g_iNextFigure);

g_pPozFigure. x=HORIZONTAL_LINE/2;

g_pPozFigure. y=0;

SetTimer (g_hwnd,(UINT)NULL, Speed (g_iScore), NULL);

}

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

void NewGame ()

{

srand (GetTickCount ()%100);

g_iScore=0;

ClearFigure (& g_bNextFigur[0][0]);

g_iNextFigure=rand ()%FIGUR_COUNT;

GetFigure (g_iNextFigure);

for (int c1=0; c1<HORIZONTAL_LINE;c1++)

for (int c2=0; c2<VERTICAL_LINE;c2++)

g_iStok[c1][c2]=30;

NextFigure ();

Repaint ();

}

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

BOOL IsImpact () //Проверяем столкновения с дном и линией

{

int imp=0;

int y;

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

{

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

{

if (g_bFigure[c1][c2])

{

y=c2;

imp=2;

if (c2+g_pPozFigure. y+1==VERTICAL_LINE)// Дно

{

return TRUE;

}

}

}

if (imp==2)

{

if (g_iStok[c1+g_pPozFigure. x][y+g_pPozFigure. y+1]>30) //Линия

return TRUE;

}

imp=0;

}

return FALSE;

}

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

void SaveGame ()

ofstream sgt («Tetr. txt», ios: out

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

void LoadGame ()

{

WCHARszScore[100];

int ii;

ii=0;

int SQR;

g_iInc=0;

SQR=HORIZONTAL_LINE*VERTICAL_LINE;

int SAr[451];

ifstream sgt («Tetr. txt», ios: :in);

while (!sgt. eof ()){

sgt > > SAr[ii];

ii++;

}

sgt > > SAr[SQR];

sgt. close ();

g_iScore = SAr[SQR];

while (g_iScore >= g_iLvlup[g_iInc])

{

g_iInc++;

}

wsprintf (szScore, TEXT («Tetris Score: %d / %d lvl %d»), g_iScore, g_iLvlup[g_iInc], (g_iInc+1));

SetWindowText (g_hwnd, szScore);

ii=0;

srand (GetTickCount ()%100);

ClearFigure (& g_bNextFigur[0][0]);

g_iNextFigure=rand ()%FIGUR_COUNT;

GetFigure (g_iNextFigure);

for (int c1=0; c1<HORIZONTAL_LINE;c1++)

for (int c2=0; c2<VERTICAL_LINE;c2++)

{

g_iStok[c1][c2]=SAr[ii];

ii++;

}

NextFigure ();

Repaint ();

}

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

BOOL OnCreate (HWND hwnd, LPCREATESTRUCT lpCreateStruct)

{

g_hwnd=hwnd;

g_hMenu=CreateMenu ();

HMENUhMenuPopapFile=CreatePopupMenu ();

AppendMenu (hMenuPopapFile, MF_STRING, ID_MENU_NEW_GAME, TEXT («New game»));

AppendMenu (hMenuPopapFile, MF_STRING, ID_MENU_SAVE, TEXT («Save»));

AppendMenu (hMenuPopapFile, MF_STRING, ID_MENU_LOAD, TEXT («Load»));

AppendMenu (hMenuPopapFile, MF_STRING, ID_MENU_EXIT, TEXT («Exit»));

AppendMenu (g_hMenu, MF_POPUP,(UINT)hMenuPopapFile, TEXT («File»));

SetMenu (hwnd, g_hMenu);

return TRUE;

}

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

void OnGetMinMaxInfo (HWND hwnd, LPMINMAXINFO lpMinMaxInfo)

{

lpMinMaxInfo-> ptMaxTrackSize. x=SIZE_WINDOW_X;

lpMinMaxInfo-> ptMaxTrackSize. y=SIZE_WINDOW_Y;

lpMinMaxInfo-> ptMinTrackSize. x=SIZE_WINDOW_X;

lpMinMaxInfo-> ptMinTrackSize. y=SIZE_WINDOW_Y;

}

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

void OnPaint (HWND hwnd)

{

DrawStok ();

DrawFigure ();

PAINTSTRUCT ps;

BeginPaint (hwnd,& ps);

EndPaint (hwnd,& ps);

}

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

void EraseOldFigur ()

{

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

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

if (g_bFigure[c1][c2])

{

g_iStok[c1+g_pPozFigure. x][c2+g_pPozFigure. y]=30;

}

}

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

void PaintNewFigur ()

{

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

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

if (g_bFigure[c1][c2])

{

g_iStok[c1+g_pPozFigure. x][c2+g_pPozFigure. y]=g_iColor;

}

}

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

void LineClear ()

{

BOOLbLineFill=FALSE;

WCHARszScore[100];

int c1, c2;

do

{

for (c1=0; c1<VERTICAL_LINE;c1++)

{

for (c2=0; c2<HORIZONTAL_LINE;c2++)

{

if (g_iStok[c2][c1]> 30)

{

bLineFill=TRUE;

}

else

{

bLineFill=FALSE;

break;

}

}

if (bLineFill)break;

bLineFill=FALSE;

}

if (bLineFill)

{

for (; c1>0;c1--)

{

for (c2=0; c2<HORIZONTAL_LINE;c2++)

{

g_iStok[c2][c1]=g_iStok[c2][c1−1];

}

}

g_iScore++;

if (g_iScore >= g_iLvlup[g_iInc]) g_iInc++;

wsprintf (szScore, TEXT («Tetris Score: %d / %d lvl %d»), g_iScore, g_iLvlup[g_iInc], (g_iInc+1)); //Обновляем счёт

SetWindowText (g_hwnd, szScore);

}

}while (bLineFill);

}

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

void OnTimer (HWND hwnd, UINT id)

{

if (IsImpact ())

{

if (g_flag==true)

{

SaveGame ();

g_flag=false;

}

KillTimer (g_hwnd,(UINT)NULL);

LineClear ();

NextFigure ();

PaintNewFigur ();

if (IsImpact ())

{

KillTimer (g_hwnd,(UINT)NULL);

MessageBox (NULL, TEXT («Game Over. «), TEXT ("Exit»), MB_OK);

}

else Repaint ();

return;

}

EraseOldFigur ();

if (g_pPozFigure. y<VERTICAL_LINE)g_pPozFigure. y++;

PaintNewFigur ();

DrawStok ();

}

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

void MoveRight ()

{

int tms=0;

int maxim=0;

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

{

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

{

if (g_bFigure[c1][c2]==TRUE)tms=c1;

}

maxim=max (maxim, tms);

tms=0;

}

maxim++;

EraseOldFigur ();

if (g_pPozFigure. x<HORIZONTAL_LINE-maxim)g_pPozFigure. x++;

PaintNewFigur ();

DrawStok ();

}

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

void MoveLeft ()

{

EraseOldFigur ();

if (g_pPozFigure. x>0)g_pPozFigure. x--;

PaintNewFigur ();

DrawStok ();

}

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

void MoveDown ()

{

if (IsImpact ())return;

EraseOldFigur ();

if (g_pPozFigure. y<VERTICAL_LINE)g_pPozFigure. y++;

PaintNewFigur ();

DrawStok ();

}

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

void OverRight ()

{

int tms=0;

int maxim=0;

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

{

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

{

if (g_bFigure[c2][c1]==TRUE)tms=c2;

}

maxim=max (maxim, tms);

tms=0;

}

if ((g_pPozFigure. x+maxim)>=HORIZONTAL_LINE)

{

int x=HORIZONTAL_LINE-g_pPozFigure. x;

maxim++;

maxim-=x;

g_pPozFigure. x-=maxim;

}

}

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

void Rotate ()

{

EraseOldFigur ();

switch (g_iFigure)

{

caseline:

if (g_bFigure[1][0]==TRUE)

{

ClearFigure (& g_bFigure[0][0]);

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

g_bFigure[0][c]=TRUE;

}

else

{

ClearFigure (& g_bFigure[0][0]);

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

g_bFigure[c][0]=TRUE;

}

OverRight ();

case cube: return;

}

BOOLtmpFigur[4][4];

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

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

tmpFigur[c1][c2]=FALSE;

for (int j=2, c=0; j> =0; j--, c++)

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

tmpFigur[c][i]=g_bFigure[i][j];

int left=1;

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

{

if (tmpFigur[0][c1])

{

left=0; break;

}

}

ClearFigure (& g_bFigure[0][0]);

for (int f=0; f< 3; f++)

for (int d=0; d< 3; d++)

{

g_bFigure[f][d]=tmpFigur[f+left][d];

}

OverRight ();

}

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

void OnKeyDown (HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags)

{

switch (vk)

{

case VK_RIGHT:

MoveRight ();

break;

case VK_LEFT:

MoveLeft ();

break;

case VK_DOWN:

MoveDown ();

break;

case VK_UP:

Rotate ();

PaintNewFigur ();

DrawStok ();

break;

}

}

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

void OnCommand (HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)

{

WCHAR szScore[100];

switch (id)

{

case ID_MENU_NEW_GAME:

{

NewGame ();

g_iInc=0;

g_iScore=0;

wsprintf (szScore, TEXT («Tetris Score: %d / %d lvl %d»), g_iScore, g_iLvlup[g_iInc], (int (g_iScore / g_iLvlup[g_iInc])));

SetWindowText (g_hwnd, szScore);

break;

}

case ID_MENU_SAVE:

{

g_flag=true;

KillTimer (g_hwnd,(UINT)NULL);

MessageBox (NULL, TEXT («Game Saved. «), TEXT ("Continue»), MB_OK);

SetTimer (g_hwnd,(UINT)NULL, Speed (g_iScore), NULL);

break;

}

case ID_MENU_LOAD:

{

LoadGame ();

LineClear ();

break;

}

case ID_MENU_EXIT:

{

ExitProcess (TRUE);

break;

}

}

}

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

LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

switch (msg){

case WM_DESTROY:

PostQuitMessage (0);

return 0;

HANDLE_MSG (hwnd, WM_CREATE, OnCreate);

HANDLE_MSG (hwnd, WM_PAINT, OnPaint);

HANDLE_MSG (hwnd, WM_COMMAND, OnCommand);

HANDLE_MSG (hwnd, WM_GETMINMAXINFO, OnGetMinMaxInfo);

HANDLE_MSG (hwnd, WM_TIMER, OnTimer);

HANDLE_MSG (hwnd, WM_KEYDOWN, OnKeyDown);

default: return (DefWindowProc (hwnd, msg, wParam, lParam));

}

}

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

LRESULT CALLBACK WndStokProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

switch (msg){

case WM_DESTROY:

PostQuitMessage (0);

return 0;

default: return (DefWindowProc (hwnd, msg, wParam, lParam));

}

}

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

int WINAPI WinMain (HINSTANCE hInst, HINSTANCE, LPSTR, int)

//extern «C» void WinMainCRTStartup ()

{

//HINSTANCE hInst=GetModuleHandle (NULL);

g_hinstance=hInst;

TCHAR szClassName[]=TEXT («MainWindows»);

TCHAR szTitle[]=TEXT («Tetris Score:0 / 3 lvl 0»);

MSG Msg;

WNDCLASS wc;

ZeroMemory (& wc, sizeof (wc));

wc. lpfnWndProc=WndProc;

wc. style=CS_HREDRAW|CS_VREDRAW;

wc. hInstance=hInst;

wc. hIcon=LoadIcon (NULL, IDI_APPLICATION);

wc. hCursor=LoadCursor (NULL, IDC_ARROW);

wc. hbrBackground=(HBRUSH)CreateSolidBrush (RGB (0,0,0));

wc. lpszClassName=szClassName;

RegisterClass (& wc);

wc. lpszClassName=TEXT («WndFigure»);

wc. lpfnWndProc=WndStokProc;

RegisterClass (& wc);

wc. lpszClassName=TEXT («WndStok»);

RegisterClass (& wc);

g_hwnd=CreateWindow (szClassName, szTitle, WS_OVERLAPPEDWINDOW,

0,0,SIZE_WINDOW_X, SIZE_WINDOW_Y, HWND_DESKTOP, NULL, hInst, NULL);

g_hStok=CreateWindow (TEXT («WndStok»), szTitle, WS_VISIBLE|WS_BORDER|WS_CHILD ,

20,20,300,600,g_hwnd, NULL, hInst, NULL);

g_hFigure=CreateWindow (TEXT («WndFigure»), szTitle, WS_VISIBLE|WS_BORDER|WS_CHILD,

SIZE_WINDOW_X-120,30,100,100,g_hwnd, NULL, hInst, NULL);

ShowWindow (g_hwnd, SW_SHOWNORMAL);

while (GetMessage (& Msg, NULL, 0,0))

{

DispatchMessage (& Msg);

}

//ExitProcess (0);

return 0;

}

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

ПоказатьСвернуть
Заполнить форму текущей работой