Tetris – The Next Generation

 Очень хочется рассказать про мою самую любимую разработку – игру Тетрис. Начиналось всё с обычной проверки “смогу ли”. Это была как раз производственная практика в колледже, времени было полно. Практику я проходил с другом, по этому он мне подкинул идею добавить в игру бонусы и прочие мелочи.

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

На данный момент размер основного кода насчитывает более 8 тыс. строк.
Вот объявление основного игрового класса, связывающего все и вся. Он создает все объекты, подгружает графику, связывает события и конечно же отрисовывает всю игру.

  TTetrisGame = class                                                           //Игровой "двигатель"
   private                                                                      //Личные
    aEmpty:Byte;                                                                 //Пустая ячейка
    AlreadyShownButtons:Boolean;                                                 //Уже были показаны кнопки (при запуске)
    AnswerShut:Byte;                                                             //Переменная для ответа при завершении игры
    BonusAmountWidth:Byte;                                                       //Кол-во бонусов в ширину
    CanBeContinue:Boolean;                                                       //Игра может быть продолжена
    Confirm:Boolean;                                                             //Дан ответ или нет
    CreatedBoss:Boolean;                                                         //Создан босс
    Creating:Boolean;                                                            //Идет инициализация
    DebugEnabled:Boolean;                                                        //Отладка
    DoDrawFigure:TDrawType;                                                      //Состояние редактирования фигуры
    Drawing:Boolean;                                                             //Идет отрисовка
    FBoom:Byte;                                                                  //Сила тряски
    FButtonsHided:Boolean;                                                       //Кнопки скрыты
    FButtonsHiding:Boolean;                                                      //Кнопки скрываются
    FCols:Byte;                                                                  //Кол-во столбцов
    FDrawCanvas:TCanvas;                                                         //Холст для передачи
    FEditBoxActive:Boolean;                                                      //Поле для ввода имени активно (Статистика)
    FEditBoxText:string;                                                         //Текст поля для ввода (Статистика)
    FFPS:integer;                                                                //Показаталь FPS
    FGameKeyCount:Byte;                                                          //Кол-во игровых клавиш спец. обработки
    FGameState:TGameState;                                                       //Состояние игры
    FHelper:Boolean;                                                             //Бонус - "Помошник"
    FHeight:Byte;                                                                //Высота ячеек
    FieldWidth:Word;                                                             //Ширина поля
    FieldHeight:Word;                                                            //Высота поля
    FInfoMode:TInfoMode;                                                         //Режим инф. дисплея
    FirstUpGold:Boolean;                                                         //Первое пополнение золота
    FKeyIDDown:Byte;                                                             //ИД клавиши вниз
    FKeyIDLeft:Byte;                                                             //ИД клавиши влево
    FKeyIDRight:Byte;                                                            //ИД клавиши вправо
    FKeyIDRL:Byte;                                                               //ИД клавиши поворот влево
    FKeyIDRR:Byte;                                                               //ИД клавиши поворот вправо
    FKeyIDUP:Byte;                                                               //ИД клавиши вверх
    FLevel:Byte;                                                                 //Текущий уровень
    FLevels:TLevels;                                                             //Уровни
    FLines:Integer;                                                              //Собранные линии
    FPauseTutorial:Boolean;                                                      //Пауза для туториала
    FRows:Byte;                                                                  //Кол-во строк
    FShownTutScene:set of Byte;                                                  //Показанные сцены
    FSpeedRate:Smallint;                                                         //Повышение/понижение скорости
    FTimerActivate:Boolean;                                                      //Активность таймеров
    FWaitAmount:Word;                                                            //Кол-во ожиданий
    FWidth:Byte;                                                                 //Ширина ячеек
    GameKeys:TGameKeys;                                                          //Игровые клавиши
    Ghost:Boolean;                                                               //Режим "Призрачная фигура"
    IDDrawFigure:Byte;                                                           //ИД элемента фигуры
    OldIM:TInfoMode;                                                             //Перыдущий режим инф. дисплея
    SLeft:Integer;                                                               //Положение поля слева
    STop:Integer;                                                                //Положение поля справа
    TutorialImg:TPNGObject;                                                      //Страница туториала
    TutorialPos:Integer;                                                         //Позиция страницы по X
    WasGhostColl:Boolean;                                                        //Произошло столкновение "Призрака о дно"
    function GetFLevel(Index:Byte):Boolean;                                      //Пройденные уровни
    function GetLevel:Byte;                                                      //Текущий уровень
    function GetScaleLvl:Byte;                                                   //Получить значение кол-ва строк %
    function KeyIsDown(VK_KEY:Word):Boolean;                                     //Нажата ли клавиша
    procedure SetGameState(Value:TGameState);                                    //Установить состояние игры
    procedure SetLevel(Value:Byte);                                              //Установить уровень
    procedure SetLines(Value:Integer);                                           //Установить кол-во удаленных линий
    procedure SetHelper(Value:Boolean);                                          //Установить значение "Помошника"
    procedure SetIM(Value:TInfoMode);                                            //Установить режми
    procedure SetTimers(Value:Boolean);                                          //Установить активность таймеров
   public                                                                       //Общие
    ArrayOfBonuses:TBonuses;                                                     //Список бонусов
    ArrayOfBosses:TArrayOfFigure;                                                //Массив боссов
    ArrayOfButtons:TArrayOfButton;                                               //Список кнопок
    ArrayOfClears:TArrayOfClears;                                                //Список удалюящихся элементов
    ArrayOfExing:TArrayOfExing;                                                  //Список выполненных бонусов
    ArrayOfFigure:TArrayOfFigure;                                                //Массив имеющихся фигур
    ArrayOfPanels:TArrayOfPanels;                                                //Список панелей
    ArrayOfToDo:TBonuses;                                                        //Список бонусов на выполнение
    BadGameBonusCount:Word;                                                      //Кол-во пропущенных бонусов
    Bitmaps:TBitmaps;                                                            //Графические объекты
    CurFigure:TFigure;                                                           //Текущая фигура
    DoBoom:Boolean;                                                              //"Тряска"
    DrawBMP:TBitmap;                                                             //Холст
    ExecutingBonus:Boolean;                                                      //Выполняется одноразовый бонус
    FigureEnable:Boolean;                                                        //Фигура идет
    FontTextAutor:TFont;                                                         //Шрифт - автор
    FontTextBonuses:TFont;                                                       //Шрифт - таймер бонусов
    FontTextButtons:TFont;                                                       //Шрифт - кнопки
    FontTextDisplay:TFont;                                                       //Шрифт - инф. текст
    FontTextGameOver:TFont;                                                      //Шрифт - конец игры (ваш счет)
    ForcedCoord:TPoint;                                                          //Принудительные координаты
    ForcedCoordinates:Boolean;                                                   //Использовать принудительное смещение поля
    FPS:Integer;                                                                 //Показатель FPS
    Gold:Cardinal;                                                               //Золото
    GoldPos:TPoint;                                                              //Позиция золота
    Hint:TTextHint;                                                              //Подсказка
    IsCreating:Boolean;                                                          //Идет создание фигуры
    IsTheBoss:Boolean;                                                           //Идет босс
    IsWait:Boolean;                                                              //Ожидание
    LeftPos:Byte;                                                                //Позиция идущей фигуры слева
    LinesAmountForLevelUp:Byte;                                                  //Количество линия для повышения уровня
    MainTet:TTetArray;                                                           //Главный массив
    MoveTet:TTetArray;                                                           //Двигающийся массив
    NeedShot:Boolean;                                                            //Сделсть снимок
    NextFigure:TFigure;                                                          //Следуюшая фигура
    NextFigureOld:TFigure;                                                       //Старая "следующая фигура"
    NextID:Integer;                                                              //ID следующей фигуры
    MarshMode:Boolean;                                                           //Режмим "Болото"
    Mouse:TPoint;                                                                //Курсор
    OldLevel:Byte;                                                               //Предыдущий уровень
    Patched:TFigureItem;                                                         //Залатанный элемент
    RectForAutor:TRect;                                                          //Область для автора т.е. меня =)
    RectForBonuses:TRect;                                                        //Поле для бонусов
    RectForBonusesMouse:TRect;                                                   //Поле активности мыши для бонусов
    RectForButtons:TRect;                                                        //Поле для кнопок
    RectForChangeMode:TRect;                                                     //Поле для изменения режима инф. дисплея
    RectForExed:TRect;                                                           //Поле для исп. бонусов
    RectForInfoText:TRect;                                                       //Поле для текста
    RectForNextFigure:TRect;                                                     //Поле для след. фигуры
    Redraw:TRedrawing;                                                           //Класс перерисовки
    Score:Cardinal;                                                              //Дисплейный счет
    Shade:TShade;                                                                //"Тень"
    ShowCursos:Boolean;                                                          //Отрисовка собственного курсора
    Shutdowning:Boolean;                                                         //Идет завершение игры
    Sound:TSound;                                                                //Звуковое сопровождение
    StartGold:Cardinal;                                                          //Стартовое золото
    StartSpeed:Word;                                                             //Стартовое значение таймера шага
    Statistics:TStatistics;                                                      //Статистика
    TimerAnalysis:TTimer;                                                        //Таймер анализирования игры
    TimerAnimateFrames:TTimer;                                                   //Таймер аимации кадров персонажа
    TimerBG:TTimer;                                                              //Таймер смены фона
    TimerBonus:TTimer;                                                           //Таймер истечения времени бонусов
    TimerBonusCtrl:TTimer;                                                       //Таймер контроля выполнения бонусов
    TimerBoom:TTimer;                                                            //Таймер обработки тряски
    TimerDraw:TTimer;                                                            //Таймер отрисовки
    TimerStep: TTimer;                                                           //Таймер шага фигуры
    TimerUpValues:TTimer;                                                        //Таймер счета
    TheardDraw:TDrawThread;                                                      //Отдельный поток для отрисовки
    ToGold:Cardinal;                                                             //Золото
    TopPos:Byte;                                                                 //Позиция идущей фигуры сверху
    ToScore:Cardinal;                                                            //Счет
    Versa:Boolean;                                                               //Обратить управление
    UserFPS:Word;                                                                //Предел кадров в сек.
    ZeroGravity:Boolean;                                                         //Невесомость
    function BuyAndExcecute(ABonus:TBonus):Integer;                              //Купить и выполнить бонус (результат - затрата, 0 - не куплен)
    function CalcBrokenBonus:Word;                                               //Анализ игрового поля
    function CheckCollision(TetArray:TTetArray; ATop:Byte; IsShade:Boolean):Boolean; overload; //Проверить измен. фигуру на столкновение на определенной высоте
    function CheckCollision(TetArray:TTetArray; ATop, ALeft:Byte; IsShade:Boolean):Boolean; overload; //Проверить измен. фигуру на столкновение в опред. коорд.
    function CheckCollision(TetArray:TTetArray; IsShade:Boolean):Boolean; overload; //Проверить измен. фигуру на столкновение на высоте фигуры
    function CheckLine:Boolean;                                                  //Проверить на заполнение верхней (скрытой) части поля
    function CheckPause:Boolean;                                                 //Проверить на пауза и на завершение игры
    function CreateBMP(FName:string):TBitmap; overload;                          //Создать BMP
    function CreateBMP(DLL:Cardinal; ID:string):TBitmap; overload;               //Создать BMP из ресурса
    function CreateBonus(var Figure:TFigure):Boolean;                            //Создать бонусы в фигуре
    function CreateFigure(Deg:Word; FigureName:string):TFigure;                  //Создание фигуры (преобразование 10 to 2)
    function DeleteFilled(Row:Byte):Byte;                                        //Удалить заполненные линии, начиная с Row
    function ElemCount(Figure:TFigure):Byte;                                     //Объем фигуры
    function GetNextBoss:TFigure;                                                //Получить следующего босса
    function GetPreviewFigure:TFigure;                                           //Получить случайную фигуру
    function GetRandomFigure:TFigure;                                            //Получить случайную фигуру
    function GetSpeed:Word;                                                      //Текущая скорость
    function GetTop:Byte;                                                        //Узнать высоту заполнения поля
    function HeightOfFigure(AFigure:TFigure):Byte;                               //Высота фигуры
    function Load:Boolean;                                                       //Выполнить загрузку игры
    function LoadGame:Boolean;                                                   //Загрузка игры
    function Max(Val1, Val2:Integer):Integer;                                    //Максимальное из двух значение
    function Min(Val1, Val2:Integer):Integer;                                    //Минимальное из двух значение
    function RotateFigure(Figure:TFigure; OnSentry:Boolean):TFigure;             //Поворот фигуры (со смещением вверх, влево)
    function SaveGame:Boolean;                                                   //Сохранить игру
    function UpGold(Value:Word):Word;                                            //Добавить золота
    function UpScore(Value:Integer):Integer;                                     //Добавить к счету
    function WidthOfFigure(AFigure:TFigure):Byte;                                //Ширина фигуры
    procedure ActuateTimers;                                                     //Активировать необходимые таймеры
    procedure AddButton(AButton:TExtButton);                                     //Добавить кнопку
    procedure AddFigure(Figure:TFigure; var Dest:TArrayOfFigure);                //Добавить фигуру в массив фигур
    procedure AddToActionList(Bonus:TBonus);                                     //Добавить бонус к списку для выполнения в свободное время
    procedure AddToExed(Bonus:TBonus);                                           //Добавить бонус в список только что исп.
    procedure AnimateDelete(ATop:Integer); overload;                             //Выполнить удаление элементов в строке ATop
    procedure AnimateDelete(ATop:Integer; Elems:TFiguresL2); overload;           //Выполнить удаление некоторых элементов на высоте ATop
    procedure Boom(Size:Byte; BTime:Word);                                       //Тряска
    procedure BoomStop;                                                          //Остановить тряску
    procedure ContinueGame;                                                      //Продолжить сохраненную игру
    procedure CreateBonuses;                                                     //Заполнить список бонусов
    procedure CreateButtons;                                                     //Заполнить список кнопок
    procedure CreateFigures;                                                     //Создать фигуры
    procedure CreateFonts;                                                       //Создание шрифтов
    procedure CreateGameKeys;                                                    //Создание игровых клавиш
    procedure CreateGraphicsAndSound;                                            //Инициализация графики и звука
    procedure CreateHints;                                                       //Создание подсказок
    procedure CreateNextBoss;                                                    //Следующая фигура - босс
    procedure CreateNextFigure;                                                  //Создать следующую фигуру
    procedure CreatePanels;                                                      //Заполнить список панелей
    procedure CreateRectAreas;                                                   //Создание областей реагирования
    procedure CreateTimers;                                                      //Создание таймеров
    procedure ChangeBackground(ALevel:Byte);                                     //Сменить фон
    procedure ClearAll;                                                          //Очистить все поля
    procedure ClrChng(var Chng:TTetArray);                                       //Очистить изм. массив
    procedure DeactivateAllBonuses;                                              //Деактивировать все бонусы
    procedure DecGold(Cost:Word);                                                //Снять золото
    procedure DeleteSaved;                                                       //Удалить сохр. игру
    procedure Draw;                                                              //Отрисовка на холсте
    procedure DrawBonuses;                                                       //Рисовать бонусы
    procedure DrawingFigure;                                                     //Включить режим редактирования след. фигуры
    procedure DrawingFigureClose(State:TGameState);                              //Выключить режим ред. с выходом из игры
    procedure DrawingFigureEnd(State:TGameState);                                //Выключить режим ред.
    procedure ExecuteBonus(Bonus:TBonus);                                        //Выполнить бонус
    procedure ExecuteRandomBonus(TB:TTypeBonus);                                 //Выполнить случайный бонус
    procedure ExecutingDelete;                                                   //Проверить и удалить заполненные строки
    procedure Event(e, param1, param2:Integer);                                  //Событие
    procedure HideButtons(ShowAnimate:Boolean);                                  //Скрыть кнопки управления (Показывать анимацию скрытия)
    procedure KeyDown;                                                           //Действие клавиши вниз
    procedure KeyLeft;                                                           //Действие клавиши влево
    procedure KeyRight;                                                          //Действие клавиши вправо
    procedure KeyRotateLeft;                                                     //Действие клавиши поворот влево
    procedure KeyRotateRight;                                                    //Действие клавиши поворот вправо
    procedure KeyUp;                                                             //Действие клавиши вверх
    procedure LevelUp;                                                           //Увеличить уровень
    procedure LinesUp(Value:Integer);                                            //Увеличить кол-во удаленных линий
    procedure Merger;                                                            //Слияние осн. поля и фигуры
    procedure Move(Bottom:Byte);                                                 //Удалиние линии
    procedure MoveMouse;                                                         //Убрать мышь с поля
    procedure NeedDraw;                                                          //Принудительная отрисовка
    procedure NewFigure;                                                         //Новая фигура
    procedure NewGame;                                                           //Новая игра
    procedure Normalization(var Figure:TFigure);                                 //Нормализовать фигуру
    procedure OnBonusExecuted(Bonus:TBonus);                                     //После выполнения бонуса
    procedure OnBonusStartExecute(Bonus:TBonus);                                 //Перед выполнением
    procedure OnKeyDown(Key:Word; Shift:TShiftState);                            //При нажатии клавиши
    procedure OnKeyPress(Key:Char);                                              //При нажатии клавиши (Символ)
    procedure OnMouseDown(Button:TMouseButton; Shift:TShiftState; X, Y: Integer);//При нажатии кнопки мыши
    procedure OnMouseMove(Shift:TShiftState; X, Y: Integer);                     //При перемещении мыши
    procedure OnMouseUp(Button:TMouseButton; Shift:TShiftState; X, Y: Integer);  //При отпускинии кнопки мыши
    procedure PauseGame;                                                         //Пауза
    procedure Reset;                                                             //Сбросить значения
    procedure RotateGameFigure(OnSentry:Boolean);                                //Повернуть текущую фигуру
    procedure ShowAnimate(ID:Byte);                                              //Установить нужную анимацию
    procedure ShowButtons;                                                       //Показать кнопки
    procedure ShowFigureChanging(FStart, FEnd:TFigure);                          //Анимация изменения фигуры
    procedure ShowGoldDec(Size:Word);                                            //Показать сколько золота убыло (-Size)
    procedure ShowHideButtons;                                                   //Показать/скрыть кнопки
    procedure Shutdown;                                                          //Завершение работы программы
    procedure SpeedDown(Value:Byte);                                             //Понизить скорость
    procedure SpeedUp(Value:Byte);                                               //Повысить скорость
    procedure StepDown;                                                          //Упустить фигуру на одну линии (шаг)
    procedure StepDownBonuses;                                                   //Шаг таймеров бонусов
    procedure StepLeft;                                                          //Сместить влево
    procedure StepRight;                                                         //Сместить вправо
    procedure StopGame;                                                          //Закончить игру
    procedure StepUp;                                                            //Сместить вверх
    procedure TimerAnalysisTimer(Sender: TObject);                               //Обработка таймера для анализа игры
    procedure TimerAnimateFramesTimer(Sender: TObject);                          //Обработка анимационных кадров
    procedure TimerBGTimer(Sender: TObject);                                     //Обработка смены фона
    procedure TimerBonusCtrlTimer(Sender: TObject);                              //Обработка очереди бонусов
    procedure TimerBonusTimer(Sender: TObject);                                  //Обработка таймеров бонусов
    procedure TimerBoomTimer(Sender: TObject);                                   //Обработка тряски
    procedure TimerDownStart;                                                    //Запуск таймера движения
    procedure TimerDownStop;                                                     //Остановка таймера движения
    procedure TimerDrawTimer(Sender: TObject);                                   //Обработка отрисовки
    procedure TimerStepTimer(Sender: TObject);                                   //Обработка шага
    procedure TimerUpValuesTimer(Sender: TObject);                               //Обработка значений
    procedure Tutorial(Scene:Byte);                                              //Туториал определённой сцены
    procedure UpdateSpeed;                                                       //Обновить скорость движения фигуры
    procedure UseAllExcept(IDOfTheFigure:Byte);                                  //Исп. все фигуры кроме одной
    procedure UseAllFigures;                                                     //Исп. все фигуры
    procedure UseOnly(IDOfTheFigure:Byte);                                       //Исп. только один тип фигуры
    procedure Wait(MTime:Word);                                                  //Подождать
    procedure WaitWithoutStop(MTime:Word);                                       //Подождать без остановки игры
    procedure WriteDebug(Text:string);                                           //Запись в отладочный файл
    property ButtonsHided:Boolean read FButtonsHided;                            //Скрыты ли кнопки
    property Cols:Byte read FCols default 15;                                    //Кол-во столбцов
    property EditBoxActive:Boolean read FEditBoxActive;                          //Активность поля для ввода имени игрока (Статистика)
    property GameState:TGameState read FGameState write SetGameState;            //Состояние игры
    property Helper:Boolean read FHelper write SetHelper;                        //Помошник
    property InfoMode:TInfoMode read FInfoMode write SetIM;                      //Режим инф. дисп.
    property Level:Byte read GetLevel write SetLevel;                            //Уровень
    property Levels[Index :Byte]:Boolean read GetFLevel;                         //Список уровней
    property Lines:Integer read FLines write SetLines;                           //Собранные и удаленные линии
    property Rows:Byte read FRows default 23;                                    //Кол-во строк
    property ScaleLvl:Byte read GetScaleLvl;                                     //Шкала линий
    property SHeight:Byte read FHeight default 20;                               //Высота ячеек
    property SWidth:Byte read FWidth default 20;                                 //Ширина ячеек
    property Timers:Boolean read FTimerActivate write SetTimers;                 //Активность таймеров
    constructor Create(FCanvas:TCanvas);                                         //Конструктор
  end;

А вот некоторые типы и классы:

  TBitmaps     = class;                                                         //Графические объекты (картинки)
  TBonus       = class;                                                         //Основа бонуса
  TExtButton   = class;                                                         //Графическая кнопка (не control)
  THelpObject  = class;                                                         //Подсказка
  TLineClear   = class;                                                         //Линия удаления (для отрисовки анимированного стирания)
  TSimpleBonus = class;                                                         //Простой бонус
  TSound       = class;                                                         //Звуковое сопровождение (потоки звуков, bass.dll)
  TTetrisGame  = class;                                                         //Движок игры
  TTextHint    = class;                                                         //Простая подсказка
  TTextPanel   = class;                                                         //Текстовая панель
  TTimeBonus   = class;                                                         //Временной бонус
  TRedrawing   = class;                                                         //Клаасс перерисовки
  TStatistics  = class;                                                         //Статистика
  TAppendStat  = class;                                                         //Математика статистики
  TGameKey     = class;                                                         //Игровая клавиша

  TState = (bsEmpty, bsElement, bsBonus, bsBonusTiming, bsBonusBroken);         //Состояние элемента (Пусто, Элемент фигуры, Бонус, Бонус (Таймер), Бонус (Сломан))
  TFigureItem = record                                                          //Элемент фигуры
   ID:Byte;                                                                      //Идентификатор элемента (фигуры)
   State:TState;                                                                 //Состояние
   TimeLeft:Word;                                                                //Осталось времени (для бонуса)
  end;
  TClearFigureItem = record                                                     //Удаляемый элемент
   X, Y:Extended;                                                                //Текущие координаты
   Speed:Byte;                                                                   //Скорость
   Angle:Smallint;                                                               //Угол отклонения
  end;
  TExing = record                                                               //Элемент массива выполненных бонусов
   Bonus:TBonus;                                                                 //Бонус
   Active:Boolean;                                                               //Есть ли элемент в сетке
  end;
  TElements = array[1..GlSize, 1..GlSize] of TFigureItem;                       //Матрица элементов фигуры
  TFigure = record                                                              //Одна фигура
   Allowed:Boolean;                                                              //Доступность
   Elements:TElements;                                                           //Элементы фигуры
   Name:string;                                                                  //Название
  end;
  TStatRecord = record                                                          //Запись статистики
   Gold:Cardinal;                                                                //Кол-во золота
   Score:Cardinal;                                                               //Счет
   Lines:Cardinal;                                                               //Кол-во удаленных линии
   Figure:Cardinal;                                                              //Кол-во сброшенных фигур
   Level:Byte;                                                                   //Уровень
  end;
  TStatTop = record                                                             //Запись топ - игрока
   Name:string[255];                                                             //Имя
   Score:Cardinal;                                                               //Счет
  end;
  TGameKeyInfo = record                                                         //Структура информации о клавише
   Code:Word;                                                                    //Код клавиши
   FForceDown:Word;                                                              //Время в нажатом состоянии (мс)
   Name:string;                                                                  //Название
  end;


  TArrayOfButton = array of TExtButton;                                         //Массив кнопок
  TArrayOfClears = array[1..GlRows] of TLineClear;                              //Удаляющие классы
  TArrayOfExing  = array[1..GlExes] of TExing;                                  //Список выполннеых бонусов
  TArrayOfFigure = array of TFigure;                                            //Массив имеющихся фигур
  TArrayOfPanels = array of TTextPanel;                                         //Массив текстовых панелей
  TBonuses       = array of TBonus;                                             //Список бонусов
  TBonusType     = (btForAll, btForGame, btForUser);                            //Тип доступа к бонусам
  TDrawType      = (dtNotWork, dtNone, dtElement, dtEmpty);                     //Режим рисования (Не рисуем, ожидание, рисуем, стираем)
  TFiguresL1     = array[1..GlCols] of TClearFigureItem;                        //Список удаляющихся элементов
  TFiguresL2     = array[1..GlCols] of TFigureItem;                             //Список удаляемых элементов
  TGameKeys      = array of TGameKey;                                           //Список игровых клавиш
  TButtonState   = (bsNormal, bsOver, bsDown);                                  //Состояние кнопки
  TButtonType    = (btFigure, btPicture);                                       //Тип кнопки (Фигура, рисунок)
  TGameState     = (gsNone, gsPlay, gsPause, gsStop, gsDrawFigure, gsShutdown); //Состояние игры (Нет, Идет игра, На паузе, Конец игры, Рисует фигуру, Завершение игры)
  TInfoMode      = (imInfoText, imBonuses, imTransforming);                     //Режим инф. дисплея
  TLevels        = array[1..GlLvls] of Boolean;                                 //Массив уровней
  TPoints        = array[0..255] of TPoint;                                     //Массив точек для полигона (для кнопки)
  TProcedure     = procedure of object;                                         //Процедура
  TTetArray      = array[1..GlRows, 1..GlCols] of TFigureItem;                  //Основной тип - поле
  TTypeBonus     = (tbCare, tbBad, tbGood);                                     //Вид бонуса (Нейтральный, отрицательный, положительный)

Весь код, от начала до конца прокомментирован и объяснён (за исключением повторений и мелочей).

Как и все мои остальные графические приложения, игра Тетрис работает без стороннего графического движка, лишь средствами GUI и некоторых наработок и хитростей. Например, здесь отрисовка выполнена в отдельном потоке “TDrawThread” (при чем без синхронизации). Также управление осуществляется не с помощью событий от ОС, а по средством проверки нажатия клавиш классом “TGameKey” для каждой необходимой клавиши:

procedure TTetrisGame.CreateGameKeys;

  function AddKey(KC:Word; UN:string; AAction:TProcedure; FTime, MTime:Word):Byte;
  begin
   SetLength(GameKeys, Length(GameKeys) + 1);
   Result:=Length(GameKeys) - 1;
   GameKeys[Result]:=TGameKey.Create(Self);
   with GameKeys[Result] do
    begin
     with GameKeyInfo do
      begin
       Code:=KC;
       Name:=UN;
      end;
     Action:=AAction;
     StartTime:=FTime;
     MinTime:=MTime;
    end;
  end;

begin
 //Создаем специальные игровые клавиши управления
 FKeyIDDown:= AddKey(VK_DOWN,  'Вниз',   KeyDown, 100, 20);    //Стрелка вниз/"S"
 FKeyIDUP:=   AddKey(VK_UP,    'Вверх',  KeyUp, 150, 50);      //Стрелка вверх/"W"
 FKeyIDLeft:= AddKey(VK_LEFT,  'Влево',  KeyLeft, 150, 50);    //Стрелка влево/"A"
 FKeyIDRight:=AddKey(VK_RIGHT, 'Вправо', KeyRight, 150, 50);   //Стрелка вправо/"D"
 FKeyIDRL:=AddKey(Ord('Q'), 'Поворот фигуры против часовой стрелки', KeyRotateLeft, 200, 50);
 FKeyIDRR:=AddKey(Ord('E'), 'Поворот фигуры по часовой стрелке',     KeyRotateRight, 200, 50);
 //Укажем количество клавиш
 FGameKeyCount:=Length(GameKeys);
 //Установка противостоящих клавиш
 GameKeys[FKeyIDDown].Contradiction:=FKeyIDUP;
 GameKeys[FKeyIDUP].Contradiction:=FKeyIDDown;
 GameKeys[FKeyIDLeft].Contradiction:=FKeyIDRight;
 GameKeys[FKeyIDRight].Contradiction:=FKeyIDLeft;
 GameKeys[FKeyIDRL].Contradiction:=FKeyIDRR;
 GameKeys[FKeyIDRR].Contradiction:=FKeyIDRL;
end;

Что позволило реализовать ещё и степень “нажатия” на клавишу, подсчетом времени её в нажатом состоянии. Также это повысило отклик нажатий и устранило обработку окном и прочими элементами управления, которые могли бы этому помешать.

Таблица бонусов:

№ п/п Название Описание Оценка полезности Приватность $ Уровни
1 Заполнение Заполнить всё поле 120,00 Только игрок 1000 1-15
2 Очистка Очистить всё поле 110,00 Только игрок 500 1-15
3 Удар-пресс Сместить элементы вниз в пустые места 100,00 Общий 300 4-15
4 Невесомость Включить или выключить гравитацию 100,00 Только игрок 250 1-13
5 Град Рассыпать бонусы по фигурам 90,00 Общий 1300 1-13
6 Призрак Позволяет проходить сквозь элементы 55,00 Общий 200 1-13
7 Карандаш Позволяет отредактировать следующую фигуру 50,00 Только игрок 200 1-15
8 Дубликат Использовать только следующий тип фигур (20 сек) 40,00 Общий 150 1-13
9 Пластырь Залатать все одиночные «дыры» 30,00 Общий 100 2, 5-15
10 Помощник Отображает конечный пункт фигуры (2 мин) 20,00 Общий 90 1-15
11 Фигура Сменить следующую фигуру 20,00 Общий 80 1-15
12 Болото Активирует/деактивирует режим “Болото” 15,00 Общий 70 1-15
13 Нож Срезает самую верхнюю часть 10,00 Общий 50 1, 3-15
14 Лазер Срезает верхний слой каждого столбца 5,00 Общий 20 1-6, 10-15
15 Исключение Исключить один тип фигур (40 сек) 0,00 Только игра 1-13
16 Босс Вызвать босса текущего уровня -5,00 Только игра 1-15
17 Дождь Разбросать элементы поля -5,00 Только игра 1-13
18 Дробь Делает выстрел дробью -10,00 Только игра 1-15
19 Ой, ой Меняет местами кнопки управления -20,00 Только игра 1-13
20 Вылазка Выдавить фигуру со стороны поля -30,00 Только игра 1-15
21 Дьявол Сам дьявол управляет фигурой (22 сек) -40,00 Только игра 1-15

 

Скриншоты игры

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


123456

Совместно с написанием игры вёлся лог, который можно скачать здесь.

Скачать готовую игру

Tetris.rar10,9 МБ

Скачать исходники

Tetris_sources.rar15,2 МБ

You may also like...

4 комментария

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

Добавить комментарий

Войти с помощью: