Компьютерная игра "KeyBoard Racer"

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


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

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

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

Содержание

  • Обозначения и сокращения
  • Введение
  • 1. Постановка задачи
  • 2. Технологии, методы, структуры, принципы положенные в основу алгоритма
  • 3. Разработка структуры программы
  • 3. 1 Структура программы
  • 3.2 Схема алгоритма № 1
  • 3.3 Схема алгоритма № 2
  • 3.5 Состав проекта
  • 4. Разработка программы
  • 4.1 Разработка метода private void MainForm_Load ()
  • 4. 2 Разработка метода private void RichTextBox_KeyPress ()
  • 5. Руководство пользователя
  • Заключение
  • Список использованных источников
  • Приложение A

Обозначения и сокращения

Проект1 — В Visual Studio 2013 проектом называется совокупность файлов, создаваемых в процессе разработки программы.

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

ПО3 - программное обеспечение.

ООП4 - объектно-ориентированное программирование.

Введение

KeyBoard Racer — компьютерная игра, которая позволяет быстрее и точнее научиться набирать тексты, используя соревновательный режим. Можно считать, что это пример «соло на клавиатуре» только используя сетевые возможности. Вы можете играть как один, так и вместе со своим другом, по сети.

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

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

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

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

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

В курсовом проекте требовалось разработать игру «Keyboard Racer». Курсовой проект (получивший рабочее название Keyboard Racer) выполнен в Visual Studio 2013.

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

Целью данной курсовой работы является разработка программы-игры «Keyboard Racer». В игре должны быть реализованы следующие моменты:

а) Играть можно вдвоем (по сети).

б) Реализация набора текста на скорость

в) Визуализация набора текста гоночной игрой

г) Возможность посмотреть игровую статистику

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

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

Реализовать подсчет скорости набора символов минуту и ошибочных вводов, а так же выводить затраченное время на экран.

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

Интерфейс программы должен быть сделан по возможности наиболее интуитивно понятным и эргономичным.

2. Технологии, методы, структуры, принципы положенные в основу алгоритма

Схема работа программы:

Рисунок 2.1 — Схема работы программы

Visual Studio 2013 позволяет программисту разрабатывать программы, которые могут выводить графику: схемы, чертежи, иллюстрации.

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

Перечень основных методов, которые потребуются при разработке программного игрового приложения «Keyboard Racer»:

void Graphics. DrawImage (Image image, int x, int y)

Метод DrawImage

Синтаксис:

Объект. DrawImage (Image image, int x, int y);

Где:

Объект — имя объекта (компонента), на поверхности которого выполняется вычерчивание, x, y — координаты x и y положения рисунка, image — картинка, которая будет прорисована.

Метод DrawImage рисует изображение, содержащееся в объекте, указанном параметром Image, сохраняя исходный размер изображеня в его источнике и перенося изображение в область объекта Graphics, верхний левый угол которой определяется параметрами x и y. Источник изображения может быть битовой матрицей, пиктограммой или метафайлом.

void TextBoxBase. Select (int start, int length)

Метод Select

Синтаксис:

Объект. Select (int start, int length)

Где:

компьютерная игра клиент сервер

Объект — имя объекта (компонента), на поверхности которого выполняется выделение, start — начальная позиция, length — количество символов которые требуется выделить.

Метод Select выделяет область текста в текст боксе задавая ее входными параметрами, начальная позиция области определяется параметром start, количество необходимых выделенных символов определяется параметром length, который указывает сколько символов нам нужно выделить начиная с позиции start.

При разработке программы основным компонентом является Timer, который вызывает событие через определенные интервалы времени. Этот компонент предназначен для среды Windows Forms, в которой и разрабатывалось данное приложение.

Длина интервалов определяется свойством Interval, значение которого исчисляется в миллисекундах. Когда компонент включен, событие Tick вызывается через каждый интервал. В этом месте следует добавить выполняемый код. Ключевыми методами компонента Timer являются Start и Stop, которые включают и выключают таймер. При выключении таймера его параметры сбрасываются; приостановить компонент Timer нельзя.

На основе данного компонента и была реализована возможность поставить игру на паузу.

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

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

Класс Socket придерживается шаблона имен платформы. net Framework для асинхронных методов. Например, синхронный метод Receive соответствует асинхронным методам BeginReceive и EndReceive.

Если используется протокол, ориентированный на установление соединения, такой как протокол TCP, сервер должен выполнять прослушивание подключений, используя метод Listen. Метод Accept обрабатывает любые входящие запросы на подключение и возвращает объект Socket, который может использоваться для передачи данных с удаленного узла. Используйте этот возвращенный объект Socket для вызова метода Send или Receive. Вызовите метод Bind, прежде чем производить обращение к методу Listen, если необходимо указать локальный IP-адрес или номер порта. Используйте нулевое значение для номера порта, если требуется, чтобы свободный порт был назначен основным поставщиком услуг. Если требуется произвести подключение к прослушивающему узлу, вызовите метод Connect. Для обмена данными вызовите метод Send или Receive.

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

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

Если применяется протокол, ориентированный на установление соединения, такой как протокол TCP, используйте методы Socket, BeginConnect и EndConnect для подключения к прослушивающему узлу. Для асинхронного обмена данными воспользуйтесь методами BeginSend и EndSend или методами BeginReceive и EndReceive. Входящие запросы на подключение могут быть обработаны с помощью методов BeginAccept и EndAccept.

Если используется протокол без установления соединения, такой как протокол UDP, можно воспользоваться для посылки датаграмм методами BeginSendTo и EndSendTo, а для получения датаграмм можно применить методы BeginReceiveFrom иEndReceiveFrom.

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

Когда прием и отправка данных завершены, используйте метод Shutdown для того, чтобы отключить объект Socket. После вызова метода Shutdown обратитесь к методу Close, чтобы освободить все связанные с объектом Socket ресурсы.

Класс Socket позволяет выполнить настройку объекта Socket с использованием метода SetSocketOption. Извлеките эти параметры, используя метод GetSocketOption.

Программное приложение «Keyboard Racer» является многопоточным.

Потоки позволяют программе Visual Basic или C# выполнять параллельную обработку, за счет чего появляется возможность одновременного выполнения нескольких операций. Например, потоки можно использовать для наблюдения ввода данных пользователем, выполнения фоновых задач и обработки одновременных потоков ввода.

Потоки имеют следующие свойства.

Потоки позволяют программе выполнять параллельную обработку.

Пространство имен. net Framework System. Threading упрощает использование потоков.

Потоки используют одни и те же ресурсы приложения.

По умолчанию программа на языке Visual Basic или C# имеет один поток. Однако параллельно основному потоку могут создаваться и использоваться вспомогательные потоки. Эти потоки часто называются рабочими потоками.

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

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

Обычно рабочие потоки используются для выполнения трудоемких или срочных задач, для которых не требуется большое количество ресурсов, используемых другими потоками. Естественно, некоторые используемые программой ресурсы должны быть доступны для нескольких потоков. В этих случаях пространство имен System. Threading предоставляет классы для синхронизации потоков. Эти классы включают Mutex, Monitor, Interlocked, AutoResetEvent и ManualResetEvent.

Можно использовать некоторые или все эти классы для синхронизации работы нескольких потоков, но некоторые многопоточные функции поддерживаются языками Visual Basic и C#. Например, инструкция Оператор SyncLock в Visual Basic и инструкция Lock в C# обеспечивают возможности синхронизации за счет неявного использования класса Monitor.

Программное приложение «Keyboard Racer» написано на объектно-ориентированном языке C# и соответствует принципам концепции ООП:

Концепция ООП возникла в середине 80-х годов. Главная ее идея в том, что программное приложение, как и окружающий нас мир, должно состоять из объектов, обладающих собственными свойствами и поведением. ООП объединяет исполняемый код программы и ее данные в объекты, что упрощает создание сложных программных приложений. Например, можно организовать коллективную работу над проектом, где каждый участник создает собственный класс объектов, который становится доступным другим участникам проекта.

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

Чтобы проект можно было считать объектно-ориентированным, объекты должны удовлетворять некоторым требованиям. Этими требованиями являются инкапсуляция, наследование и полиморфизм.

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

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

Полиморфизм - многие объекты могут иметь одноименные методы, которые могут выполнять разные действия для разных объектов. Например, оператор «+» для числовых величин выполняет сложение, а для текстовых — склеивание.

В ООП центральным является понятие класса. Класс — это шаблон, по которому создаются объекты определенного типа. Класс объединяет в себе данные и методы их обработки.

Объекты - это экземпляры определенного класса. Например, кнопки или текстовые поля, устанавливаемые на форме являются экземплярами соответствующих стандартных классов VB.

Создать собственный класс в VB можно с помощью модуля класса. Модуль класса состоит из элементов трех типов: свойств, методов, событий, оформляемых в виде описаний, процедур и функций внутри контейнера — модуля. У модуля класса нет собственного пользовательского интерфейса — формы, однако он может использовать контейнер формы, для чего должен содержать соответствующие методы.

Элементы управления - это объекты, используемые при разработке пользовательского интерфейса.

ООП характеризуется следующими принципами (по Алану Кею):

· все является объектом;

· вычисления осуществляются путем взаимодействия (обмена данными) между объектами, при котором один объект требует, чтобы другой объект выполнил некоторое действие; объекты взаимодействуют, посылая и получая сообщения; сообщение — это запрос на выполнение действия, дополненный набором аргументов, которые могут понадобиться при выполнении действия;

· каждый объект имеет независимую память, которая состоит из других объектов;

· каждый объект является представителем класса, который выражает общие свойства объектов данного типа;

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

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

3. Разработка структуры программы

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

Игровое приложение «Keyboard Racer» содержит следующие функции:

А) Запуск игры:

1. Установка выбранного текста;

2. Установка машин в начальное положение;

3. Вывод текущего статуса игры;

4. Установка связи между клиентом и сервером;

5. Обмен состоянием между клиентом и сервером;

Б) Перемещение объектов на форме:

1. Перемещение своей машины на форме;

2. Перемещение машины противника на форме;

В) Процесс игры:

1. Подсчет время затраченного на игру;

2. Подсчет количества не верных вводов;

3. Подсчет скорости печати символов в минуту;

4. Изменения фокуса на вводимый символ;

5. Окрашивание верно введенных символов;

6. Окрашивание не верно введенных символов;

Г) Завершение игры:

1. Итог игры (Победа/Проигрыш);

2. Остановка подсчета игровой статистики;

3. Возможность начать заново;

3.2 Схема алгоритма № 1

Генерация игровой формы

Рисунок 3.1 — Генерация игровой формы.

Описание алгоритма приведено в пункте «разработка программы».

3.3 Схема алгоритма № 2

Схема ввода символа с клавиатуры

Рисунок 3.2 — Схема ввода символа с клавиатуры

Описание алгоритма приведено в пункте «разработка программы».

3.5 Состав проекта

Проект «Keyboard Racer» состоит, помимо файлов, создаваемых системой программирования автоматически, из классов и библиотек.

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

Модуль MainForm, в котором идет описание главной формы программы, начальных значений переменных, создаваемых при ее запуске. В теле этого класса находятся исходные тексты обработчиков событий, порождаемых теми или иными действиями пользователя в главной форме программы, ссылки на библиотеки используемые для написание программы, необходимые пространства имен. Также описаны все методы, на основе которых строится работа программы.

Модуль About, является компонентом WindowsForm и содержит в себе информация о программном приложение «Keyboard Racer».

Модуль Finish, является компонентом WindowsForm и содержит в себе информация о статусе игры при ее завершении.

Модуль File, является компонентом WindowsForm и содержит в себе информация необходимую для выбора и загрузки текста на главную форму.

Модуль Server, является классом и содержит в себе методы и данные необходимые для создания объекта сервера и его автономной работы.

Модуль Client, является классом и содержи в себе методы и данные необходимые для создания объекта клиента и его автономной работы.

Модуль ThreadChat, является статическим классом и содержит в себе данные необходимые для общения между потоками.

4. Разработка программы

4.1 Разработка метода private void MainForm_Load ()

Разработка метода генерирования игровой формы (Схема алгоритма № 1).

Листинг процедуры находится в Приложении. В листинге метод будет иметь имя private void MainForm_Load (object sender, EventArgs e).

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

if (whoI == «server»)

{

LanTimer. Enabled = true;

tr = new StreamReader (pathFile, ASCIIEncoding. ASCII);

text = tr. ReadToEnd ();

ThreadChat. gameText = text;

tr. Close ();

}

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

if (whoI == «client»)

{

LanTimer. Enabled = true;

text = ThreadChat. gameText;

}

Затем метод устанавливает в форму для текста (RichTextBox), набор символов загруженных ранее в переменную text:

RichTextBox. Text = text;

Далее происходит присвоение переменной youLocation, которая отвечает за местоположение нашей машинки, начальных значений. После установка уже самой машины в положение заданной данной переменной.

youLocation. X = 20;

youLocation. Y = 67;

Car1. Location = youLocation;

Далее происходит тоже самое, только для машины противника.

opponentLocation. X = 20;

opponentLocation. Y = 116;

Car2. Location = opponentLocation;

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

RichTextBox. HideSelection = true;

ThreadChat. youStartGame = false;

4.2 Разработка метода private void RichTextBox_KeyPress ()

Разработка метода ввода символа с клавиатуры (Схема алгоритма № 2)

Листинг метода находится в Приложении. В листинге процедура будет иметь имя private void RichTextBox_KeyPress (object sender, KeyPressEventArgs e).

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

Следовательно, метод будет принимать параметром нажатую клавишу, в теле проверять его на соответствие с символом ввод которого ожидался, после чего, в зависимости от результата, выполнять определенные инструкции. Метод с помощью оператора условия If — Else разделяется на два блока.

if (RichTextBox. Text [i] == e. KeyChar)

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

{

StatusLabel. Text = «Набирайте текст»;

if (errorEnter == false)

{

RichTextBox. SelectionColor = Color. Blue;

}

i++;

errorEnter = false;

ChangeLocation (Car1, youLocation, i, true);

RichTextBox. Select (i, 1);

if (CheckFinish ())

{

Finish ();

}

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

{

StatusLabel. Text = «Исправьте ошибку»;

RichTextBox. Select (i, 1);

RichTextBox. SelectionColor = Color. Red;

errorCount++;

errorEnter = true;

ErrorCountLabel. Text = errorCount. ToString ();

}

Рассмотрим этот метод подробнее: метод принял параметром символ «А», а ожидаемый символ ввода — «о». Поток перейдет к выполнению второго блока кода, который установит текущий статус игры на «Исправьте ошибку», выделит ожидаемый символ, в форме текста, красным цветом. Далее счетчик ошибок увеличится на единицу, переменная неверного ввода устанавливается как «true», а на экран выведется информация о текущем количестве неверных вводов. При этом символ ожидаемого ввода останется в текущем положении.

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

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

Рисунок 1 — Меню программы

При запуске игры вы попадете в меню приложения, здесь можно осуществлять выбор нужного вам действия: Играть как сервер, Играть как клиент, показать окно «О программе», а также закрыть приложение. Здесь присутствует настройка сетевого соединения для клиента, которая позволяет задать IP и PORT для подключения к серверу.

При нажатии на кнопку «О программе» появляется окно с информацией о программе.

Рисунок 2 — Окно «О программе»

При нажатии на кнопку «Играть как сервер» появляется окно, которое позволяет задать параметр игры: вводимый текст.

Рисунок 3 — Окно для выбора текста

После нажатия клавиши «ОК», откроется главное окно программы, также это окно откроется сразу, если в меню выбрать пункт «Играть как клиент», это связано с тем, что текст клиента подгружается по сети от сервера, что делает их идентичными.

Рисунок 4 — Главное окно программы

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

Теперь нажимая на клавишу «СТАРТ!» можно начать игру, это автоматически приведет к старту игры у вашего противника, для того чтобы соперничество происходило в реальном времени.

Рисунок 5 — Главное окно в процессе игры

В процессе игры, в статусе гонки, можно наблюдать на сколько символов вы отстаете или опережаете своего противника. А также видеть его прогресс, который отображается с помощью гоночной машинки. Статус текста меняет свое значение, с «Набирайте текст» на «Исправьте ошибку», если был допущен не верный ввод, что также увеличит количество ошибок на единицу. После верного ввода, можно дальше продолжать набирать текст. Также ведется учет потраченного на набор текста времени (в секундах), и скорость набора символов в минуту. Если символ был набран с первого раза верно, то он примет синий цвет, если же первый ввод был ошибочный, то красный.

Рисунок 6 — Конец игры

Игра считается законченной, когда вы, либо ваш противник введет последний символ текста. За этим сразу же последует вывод окна «Finish», которое сообщит вам результаты игры. Закрыв его, можно вернуться на главное окно и посмотреть статистику, либо начать игру заново, кликнув по кнопке «СТАРТ!».

Клик по кнопке «Меню» приведет к возврату в меню программы.

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

Заключение

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

Идея данной игры является оригинальной. Главные особенности данной игры:

А. Маленький размер;

Б. Не требовательность к ресурсам компьютера;

В. Простой и понятный интерфейс;

Г. Нет необходимости в установке дополнительного ПО;

Д. Обладает «обучающими» свойствами, которые улучшат вашу скорость печати.

Программа может быть улучшена путём добавления различных функций, например:

А. Добавление возможности играть более чем с одним соперником.

Б. Реализация достижений и наград за них.

В. Возможность сохранения статистики.

При разработке проекта были значительным образом закреплены знания, полученные на лекциях по программированию, а так же знания о работе с различными компонентами в Visual Studio 2013.

Список использованных источников

1. Троелсен Э. — Язык программирования C# 2010 и платформа. net 4 — 2010

2. А. Хейлсберг, М. Торгерсен, С. Вилтамут, П. Голд. Язык программирования C#.

3. Чарльз Петцольд. Microsoft Windows Presentation Foundation. Базовый курс.

4. Мак-Дональд, Мэтью. Windows Presentation Foundation в. net 4.0 с примерами на С# 2010 для профессионалов

5. Справка MSDN.

Приложение A

Исходный код программы:

using System;

using System. Collections. Generic;

using System. componentModel;

using System. Data;

using System. Drawing;

using System. Linq;

using System. Text;

using System. Threading. Tasks;

using System. Windows. Forms;

using System. Threading;

namespace Клавагонки

{

public partial class MenuForm: Form

{

static public MenuForm myMenu;

public MenuForm ()

{

InitializeComponent ();

myMenu = this;

}

private void button1_Click (object sender, EventArgs e)

{

if (MainForm. whoI == «client»)

Client. clientThread. Abort ();

if (MainForm. whoI == «server»)

{

Server. Stop ();

}

Application. Exit ();

}

private void button2_Click (object sender, EventArgs e)

{

this. Visible = false;

FileForm myFile = new FileForm ();

myFile. ShowDialog ();

}

private void ClientButton_Click (object sender, EventArgs e)

{

ThreadChat. address = IPBOX. Text. ToString ();

ThreadChat. port = Convert. ToInt32 (PortBox. Text);

this. Visible = false;

Client client = new Client ();

Thread. Sleep (1000);

if (Client. mainForm. Visible == false)

Client. mainForm. Visible = true;

else

Client. mainForm. ShowDialog ();

}

private void AboutButton_Click (object sender, EventArgs e)

{

this. Visible = true;

(new About ()). ShowDialog ();

}

}

}

public partial class MainForm: Form

{

// Global var

static public string pathFile = «F: \Универ 3 курс\Курсовой_проект\Клавагонки\Клавагонки\bin\Debug\text. txt»;

String text; // текст из файла

TextReader tr; // потом чтения текста из файла

static private int i = 0; // количество верых вводов

int errorCount = 0; // количество ошибочных вводов

bool errorEnter = false;

// int speed = 0; // скорость машины

double speedOfPrint = 0; // скорость печати

int time = 0; // время в секундах

double path;

int leftOffset;

static public string whoI = «empty»;

Point youLocation; // положение нашей машины

Point opponentLocation; // машина оппонента

private string finish;

private bool singleFinish;

public void TextGo ()

{

Control. CheckForIllegalCrossThreadCalls = false;

StatusLabel. Text = «READY!!!»;

Thread. Sleep (1000);

StatusLabel. Text = «STEADY!!!»;

Thread. Sleep (1000);

StatusLabel. Text = «GO!»;

// textThread. Abort ();

}

public MainForm ()

{

InitializeComponent ();

}

private void MenuButton_Click (object sender, EventArgs e)

{

this. Visible = false;

MenuForm. myMenu. Visible = true;

}

private void MainForm_Load (object sender, EventArgs e)

{

if (whoI == «server»)

{

LanTimer. Enabled = true;

tr = new StreamReader (pathFile, ASCIIEncoding. ASCII);

text = tr. ReadToEnd ();

ThreadChat. gameText = text;

tr. Close ();

}

if (whoI == «client»)

{

LanTimer. Enabled = true;

text = ThreadChat. gameText;

}

RichTextBox. Text = text;

youLocation. X = 20;

youLocation. Y = 67;

Car1. Location = youLocation;

opponentLocation. X = 20;

opponentLocation. Y = 116;

Car2. Location = opponentLocation;

RichTextBox. HideSelection = false;

ThreadChat. youStartGame = false;

}

private void GetSpeed (int i) // скорость машины

{

path = i / (text. Length *1. 0);

leftOffset = (int) (20 + (850−55) * path);

}

private double GetSpeedOfPrint () // скорость печати (символов в минуту)

{

speedOfPrint = ((i / (double) time) * 60);

speedOfPrint = Math. Round (speedOfPrint);

return speedOfPrint;

}

static public int GetI ()

{

return i;

}

private void ChangeLocation (PictureBox car, Point location, int i, bool youCar) // перемещение машины

{

GetSpeed (i);

location = car. Location;

location. X = leftOffset;

car. Location = location;

if (youCar)

ThreadChat. youCar = location. X;

}

private bool CheckFinish () // проверка на конец игры

{

if (i == text. Length)

{

return true;

}

else

return false;

}

private void Start () // начало игры

{

// ThreadChat. youStartGame = false;

// ThreadChat. oppStartGame = false;

singleFinish = false;

i = 0;

time = 0;

errorCount = 0;

speedOfPrint = 0;

RichTextBox. Focus ();

// GetSpeed ();

RichTextBox. Text = ThreadChat. gameText;

RichTextBox. SelectAll ();

RichTextBox. SelectionColor = Color. Black;

RichTextBox. SelectAll ();

RichTextBox. SelectionColor = Color. Black;

RichTextBox. Select (i, 1);

GameTimer. Interval = 1000;

LanTimer. Interval = 10;

youLocation. X = 20;

youLocation. Y = 67;

Car1. Location = youLocation;

opponentLocation. X = 20;

opponentLocation. Y = 116;

Car2. Location = opponentLocation;

TimerLabel. Text = time. ToString ();

GameTimer. Enabled = true;

ErrorCountLabel. Text = errorCount. ToString ();

PositionLabelText (i, ThreadChat. oppI);

StatusLabel. Text = «READY!!!»;

}

private void Finish () // последствия конца игры

{

MenuButton. Focus ();

GameTimer. Enabled = false;

StatusLabel. Text = «Гонка завершена!»;

if (GetI () == RichTextBox. TextLength)

finish = «win»;

else

finish = «lose»;

Finish finishForm = new Finish (finish);

finishForm. ShowDialog ();

}

private void RichTextBox_KeyPress (object sender, KeyPressEventArgs e) // обработка ввода текста

{

if (RichTextBox. Text [i] == e. KeyChar)

{

StatusLabel. Text = «Набирайте текст»;

if (errorEnter == false)

{

RichTextBox. SelectionColor = Color. Blue;

}

i++;

errorEnter = false;

ChangeLocation (Car1, youLocation, i, true);

RichTextBox. Select (i, 1);

if (CheckFinish ())

{

Finish ();

}

}

else

{

RichTextBox. Select (i, 1);

RichTextBox. SelectionColor = Color. Red;

errorCount++;

errorEnter = true;

ErrorCountLabel. Text = errorCount. ToString ();

StatusLabel. Text = «Исправьте ошибку»;

}

}

private void StartButton_Click (object sender, EventArgs e)

{

Start ();

ThreadChat. youStartGame = true;

}

private void MainForm_FormClosed (object sender, FormClosedEventArgs e)

{

if (whoI == «client»)

Client. clientThread. Abort ();

if (whoI == «server»)

{

Server. Stop ();

}

Application. Exit ();

}

private void RichTextBox_Click (object sender, EventArgs e)

{

MenuButton. Focus ();

}

private void GameTimer_Tick (object sender, EventArgs e) // обработчик таймера

{

time++;

TimerLabel. Text = time. ToString ();

SpeedLabel. Text = GetSpeedOfPrint (). ToString ();

}

private void LanTimer_Tick (object sender, EventArgs e)

{

if (ThreadChat. oppStartGame)

{

ThreadChat. oppStartGame = false;

Start ();

}

if (ThreadChat. oppI == RichTextBox. TextLength & & singleFinish == false)

{

singleFinish = true;

Finish ();

}

ChangeLocation (Car2, opponentLocation, ThreadChat. oppI, false);

PositionLabelText (i, ThreadChat. oppI);

// PositionLabel. Text =

}

private void PositionLabelText (int youI, int oppI)

{

if (youI > oppI)

{

PositionLabel. Text = «Вы лидируете на «+ (youI — oppI) + «символ (ов)!»;

PositionLabel. ForeColor = Color. Blue;

}

if (youI < oppI)

{

PositionLabel. Text = «Вы отстаете на «+ (oppI — youI) + «символ (ов)!»;

PositionLabel. ForeColor = Color. Green;

}

if (youI == oppI & & youI! = 0)

{

PositionLabel. Text = «ВКЛЮЧАЙ НИТРО»;

PositionLabel. ForeColor = Color. Red;

}

if (youI == oppI & & youI == 0)

{

PositionLabel. Text = «Ждем старта»;

PositionLabel. ForeColor = Color. Black;

}

}

}

public partial class FileForm: Form

{

public FileForm ()

{

InitializeComponent ();

}

private void FileButton_Click (object sender, EventArgs e)

{

openFileDialog1. ShowDialog ();

PathBox. Text = openFileDialog1. FileName;

}

private void DoneButton_Click (object sender, EventArgs e)

{

MainForm. pathFile = PathBox. Text;

this. Visible = false;

Server server = new Server ();

if (Server. mainForm. Visible == false)

Server. mainForm. Visible = true;

else

Server. mainForm. ShowDialog ();

}

}

public partial class Finish: Form

{

private string status;

private int count = 0;

public Finish (string status)

{

InitializeComponent ();

this. status = status;

}

private void Finish_Load (object sender, EventArgs e)

{

if (status == «win»)

FinishLabel. Text = «ВЫnПОБЕДИТЕЛЬ!»;

else

FinishLabel. Text = «ВЫnПРОИГРАВШИЙ!»;

FinishTimer. Enabled = true;

}

private void Finish_FormClosed (object sender, FormClosedEventArgs e)

{

FinishTimer. Enabled = false;

}

private void FinishTimer_Tick (object sender, EventArgs e)

{

if (count == 0)

{

this. BackColor = Color. White;

this. FinishLabel. ForeColor = Color. Black;

}

if (count == 4)

{

this. BackColor = Color. Green;

this. FinishLabel. ForeColor = Color. Yellow;

}

if (count == 8)

{

this. BackColor = Color. Red;

this. FinishLabel. ForeColor = Color. Blue;

}

if (count == 12)

{

this. BackColor = Color. Yellow;

this. FinishLabel. ForeColor = Color. Red;

}

count++;

if (count > 16)

count = 0;

}

}

public class Server

{

static public MainForm mainForm = new MainForm ();

static public System. Threading. Thread serverThread;

static private bool isStiop;

public Server ()

{

// Control. CheckForIllegalCrossThreadCalls = false;

MainForm. whoI = «server»;

serverThread = new Thread (RunServer);

serverThread. IsBackground = true;

serverThread. Start ();

}

public void RunServer ()

{

// Устанавливаем для сокета локальную конечную точку

// Restart:

IPHostEntry ipHost = Dns. GetHostEntry («localhost»);

IPAddress ipAddr = ipHost. AddressList [0];

IPEndPoint ipEndPoint = new IPEndPoint (ipAddr, 11 000);

// Создаем сокет Tcp/Ip

Socket sListener = new Socket (ipAddr. AddressFamily, SocketType. Stream, ProtocolType. Tcp);

// Назначаем сокет локальной конечной точке и слушаем входящие сокеты

try

{

sListener. Bind (ipEndPoint);

sListener. Listen (10);

// Начинаем слушать соединения

while (isStiop==false)

{

// mainForm. testWORKING = 1;

ThreadChat. showMessage = «Ожидаем соединение через порт {0}» + ipEndPoint;

// Программа приостанавливается, ожидая входящее соединение

Socket handler = sListener. Accept ();

string data = null;

// Мы дождались клиента, пытающегося с нами соединиться

byte [] bytes = new byte [1024];

int bytesRec = handler. Receive (bytes);

data = Encoding. UTF8. GetString (bytes, 0, bytesRec);

if (data == «text»)

ThreadChat. syncText = true;

else

{

if (data == «start»)

ThreadChat. oppStartGame = true;

else

ThreadChat. oppI = Convert. ToInt32 (data);

}

// Показываем данные на консоли

// ThreadChat. showMessage = «Полученный текст: «+ data + «nn»;

// Отправляем ответ клиенту

string reply;

if (data == «text»)

{

reply = ThreadChat. gameText;

}

else

{

if (ThreadChat. youStartGame)

{

reply = «start»;

ThreadChat. youStartGame = false;

}

else

reply = MainForm. GetI (). ToString ();

}

byte [] msg = Encoding. UTF8. GetBytes (reply);

handler. Send (msg);

if (data. IndexOf («< TheEnd>») > - 1)

{

ThreadChat. showMessage = «Сервер завершил соединение с клиентом. «;

}

Thread. Sleep (10);

handler. Shutdown (SocketShutdown. Both);

handler. Close ();

}

}

catch (Exception ex)

{

ThreadChat. showMessage = ex. ToString ();

}

}

internal static void Stop ()

{

isStiop = true;

}

}

public class Client

{

static public MainForm mainForm = new MainForm ();

static public System. Threading. Thread clientThread;

private static string address;

private int port;

public Client ()

{

address = ThreadChat. address;

this. port = ThreadChat. port;

clientThread= new Thread (RunClient);

clientThread. Start ();

mainForm. TypeLabel. Text = «I'm a client, n BABY!»;

MainForm. whoI = «client»;

}

public void RunClient ()

{

try

{

SendMessageFromSocket (port);

}

catch (Exception ex)

{

ThreadChat. showMessage = ex. ToString ();

}

finally

{

// mainForm. testWORKING = «end»;

}

}

static void SendMessageFromSocket (int port)

{

// Буфер для входящих данных

byte [] bytes = new byte [1024];

string data;

// Соединяемся с удаленным устройством

// Устанавливаем удаленную точку для сокета

IPHostEntry ipHost = Dns. GetHostEntry (address);

IPAddress ipAddr = ipHost. AddressList [0];

IPEndPoint ipEndPoint = new IPEndPoint (ipAddr, port);

Socket sender = new Socket (ipAddr. AddressFamily, SocketType. Stream, ProtocolType. Tcp);

// Соединяем сокет с удаленной точкой

sender. Connect (ipEndPoint);

string message;

if (ThreadChat. syncText == false)

{

message = «text»;

}

else

{

if (ThreadChat. youStartGame)

{

message = «start»;

ThreadChat. youStartGame = false;

}

else

message = MainForm. GetI (). ToString ();

}

// ThreadChat. showMessage = «Сокет соединяется с {0} «+ sender. RemoteEndPoint. ToString ();

byte [] msg = Encoding. UTF8. GetBytes (message);

// Отправляем данные через сокет

int bytesSent = sender. Send (msg);

// MainForm. sendMessage = false;

// Получаем ответ от сервера

int bytesRec = sender. Receive (bytes);

data = Encoding. UTF8. GetString (bytes, 0, bytesRec);

if (ThreadChat. syncText == false)

{

ThreadChat. gameText = data;

ThreadChat. syncText = true;

}

else

{

if (data == «start»)

ThreadChat. oppStartGame = true;

else

ThreadChat. oppI = Convert. ToInt32 (data);

}

Thread. Sleep (10);

// Используем рекурсию для неоднократного вызова SendMessageFromSocket ()

if (message. IndexOf («< TheEnd>») == - 1)

SendMessageFromSocket (port);

// Освобождаем сокет

sender. Shutdown (SocketShutdown. Both);

sender. Close ();

}

}

static class ThreadChat

{

volatile public static bool sendMessage = false;

volatile public static string showMessage = «Сообщение сети»;

volatile public static string outMessage = «lol»;

volatile public static string gameText = «ada»;

volatile public static bool syncText = false;

static public bool youStartGame = false;

static volatile public bool oppStartGame = false;

volatile public static int youCar = 20;

volatile public static int opponentCar = 20;

volatile public static int oppI = 0;

volatile public static int port = 11 000;

volatile public static string address = «127.0.0. 1»;

}

static class Program

{

// / < summary>

// / Главная точка входа для приложения.

// / < /summary>

[STAThread]

static void Main ()

{

Application. EnableVisualStyles ();

Application. SetCompatibleTextRenderingDefault (false);

Application. run (new MenuForm ());

}

}

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