Исходник написан на языке .NET C#. Графика приложения построена на базе графической библиотеки GDI+ и событии прорисовки окна OnPaint(...). Информационная графическая панель также выводит текст на поверхности GDI+, получая доступ к ней с помощью класса .NET Framework class Graphics
Для упрощения сопровождения кода исходник имеет модульную структуру, функциональность разделена на классы. Имеются модули настроек игры, сохранения настроек в двоичном формате и загрузка настроек из файла при запуске приложения.
class FormMain - сборочный класс приложения. Размещает на себе игровое поле состоящее из 100
графических элементов. Обеспечивает взаимодействие с пользователем, читает настройки игры из
файла и при закрытии приложения сохраняет настройки в файл.
class GraphItem - анимационный графический элемент. Образует ячейку с
геометрической фигурой в центре. Обеспечивает анимацию активности, анимацию исчезновения и изменения цвета геометрической
фигуры. Из объектов данного класса состоит игровое поле приложения.
class FormGameSetting - модальное окно настроек игры. Позволяет выбирать цвет и вид графической фигуры.
class FormPlayerName - модальное окно изменения имени игрока. В качестве иконки используется
единица графического элемента
Модуль глобальных переменных и хранения настроек игры. Основные настройки игры сохраняются в
файл в месте запуска приложения. Входят 3 класса - class Global, class GameSetting, class DataRecordsman
class FormEndGame - диалоговое окно окончания игры, оповещает пользователя об окончании игры и количестве набранных очков.
Модуль графического элемента class GraphItem представляет собой ячейку игрового поля. В центре графэлемента размещается цветная геометрическая фигура. Модуль показывает и скрывает фигуру, изменяет цвет и вид геометрической фигуры. Графэлемент также отвечает за анимацию фигур в режиме выбора и исчезновения при собирании в линию. Массив объектов класса GraphItem создает красочное игровое поле приложения.
Анимацию обеспечивают два таймера. Один таймер для визуальной активности выбранного элемента: происходит пульсация размеров геометрической фигуры. Второй таймер создаёт плавное исчезновение геометрических фигур при наборе линии из 5 и более элементов. Таймеры обеспечивают псевдомногопоточную работу приложения. Перерисовка графических элементов происходит без блокировки пользовательского интерфейса.
Листинг кода работы таймеров:
// Таймер активности (пульсирования)
private Timer timerActive = new Timer();
// Таймер исчезновения
private Timer timerVanish = new Timer();
// Изменения размера сторон геометрического элемента
// при пульсации и исчезновении.
private int deltaSize = 0;
/// <summary>
/// Координаты графэлемента.
/// </summary>
public Rectangle CellCoordinate;
int k = 1;
/// <summary>
/// Таймер активности периодически увеличивает и
/// уменьшает геометрическую фигуру,
/// создавая эффект активности.
/// </summary>
void TimerActive_Tick(object sender, EventArgs e)
{
deltaSize += 1 * k;
// Цикл уменьшения и увеличения размера
// геометрической фигуры при пульсировании.
if (deltaSize >= -2)
{
k = -1;
}
else if (deltaSize <= -7)
{
k = 1;
}
// Для экономии процессорных ресурсов
// обновляем только прямоугольник
// графического элемента.
Parent.Invalidate(CellCoordinate);
}
/// <summary>
/// Таймер исчезания, сначала графэлемент уменьшается,
/// а потом исчезает.
/// </summary>
void TimerVanish_Tick(object sender, EventArgs e)
{
deltaSize += -2;
if (deltaSize < -14)
{
timerVanish.Enabled = false;
visible = false;
vanish = false;
// После того как геометрическая фигура стала невидимой,
// возвращаем ей нормальные размеры.
deltaSize = inflateSize;
}
// Для экономии процессорных ресурсов
// обновляем только прямоугольник
// графического элемента.
Parent.Invalidate(CellCoordinate);
}
Графический элемент class GraphItem рисуется на клиентской части родительского окна средствами GDI+. Для этого в классе есть специальный метод void Draw(Graphics g). Данным методом создаются ячейки с различными геометрическими фигурками. Графэлементы перерисовываются стандартно при генерировании события OnPaint родительским окном. И принудительно перерисовываются вызовом события OnPaint таймерами активности и исчезновения.
Краткий листинг метода рисования графэлемента:
/// <summary>
/// Рисование графики на поверхности окна приложения.
/// </summary>
/// <param name="g">Поверхность GDI+</param>
public void Draw(Graphics g)
{
// Рисование ячейки, места для геометрической фигуры.
g.FillRectangle(BrushCell(), CellCoordinate.X + 1,
CellCoordinate.Y + 1, CellCoordinate.Width - 1, CellCoordinate.Height - 1);
// При невидимой геометрической фигуре прорисовывается только квадрат ячейки.
if (visible == false) return;
// Вспомогательный квадрат для эффекта исчезания и эффекта
// активности в выбранном состоянии.
Rectangle rectInflate = CellCoordinate;
rectInflate.Inflate(deltaSize, deltaSize);
..............
// Рисование текущей геометрической фигуры.
switch (CurrentTypeGraphItem)
{
case TypeGraphItem.Ellipse:
g.FillEllipse(pathBrush, rectInflate);
break;
case TypeGraphItem.Rectangle:
g.FillRectangle(pathBrush, rectInflate);
break;
case TypeGraphItem.Rhombus:
g.FillPolygon(pathBrush, pt);
break;
}
}
Листинг родительского метода события OnPaint:
private void FormMain_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
TextPanel(g);
// Прорисовка графических элементов.
for (int i = 0; i < Global.NumGraphItems; i++)
{
graphItems[i].Draw(g);
}
}
Класс BinaryFormatter для сохранения и чтения настроек используется
BinaryFormatter упрощает процедуру сохранения объекта или группы
объектов. Сохранение осуществляется в двоичном формате, достоинство такого формата - компактность и возможность сохранения объектов любой сложности, недостаток - невозможность непосредственного редактирования сохраненного файла.
// Сохранение настроек в файл .ini
void ToFileIni()
{
string filePath = Application.StartupPath + "\settings.lin";
FileStream fileStream = File.Create(filePath);
BinaryFormatter bf = new BinaryFormatter();
for (int i = 0; i < GameSet.DRH.Length; i++)
{
GameSet.DRH[i].CurrentPlayer = false;
}
bf.Serialize(fileStream, GameSet);
fileStream.Close();
}
// Чтение настроек из файла .ini
void FromFileIni()
{
FileStream fileStream = null;
string filePath = Application.StartupPath + "\settings.lin";
FileInfo fi = new FileInfo(filePath);
if (fi.Exists == false) return;
fileStream = File.OpenRead(filePath);
BinaryFormatter bf = new BinaryFormatter();
GameSet = (GameSetting)bf.Deserialize(fileStream);
.............
Array.Sort(GameSet.DRH, new SortRecordHolders());
fileStream.Close();
}
Для проверок последовательностей из 5 и более геометрических фигур в исходнике применяется класс
List появившийся в .NET Framework 2.0. Данный список удобен тем, что может содержать любые типы объектов, имеет простые процедуры добавления, удаления элементов, сортировки и при извлечении элементов не требуется приведения типов. На практике List очень удобный универсальный динамический массив.
bool HideGraphItems()
{
List<bool> listBool = new List<bool>();
listBool.Add(CheckColumn());
listBool.Add(CheckRow());
listBool.Add(CheckDiagonal());
listBool.Add(CheckDiagonal2());
for (int i = 0; i < listBool.Count; i++)
{
if (listBool[i] == true) return true;
}
return false;
}