Попросил меня однажды один человек помочь ему с курсовой. Все делали что-то простенькое, а он вот решил выделиться, замахнулся на игру, даже начал, но потом он понял, что как-то не понимает некоторых вещей, поэтому обратился за помощью ко мне 🙂
Ну а я что… Помог ему, конечно же! Да и самому было интересно! А теперь расскажу о некоторых подробностях и «возможностях» игры, а также ниже можно будет ссылку на исходники найти 🙂
Если честно, до этого мало дел имел с паскалем, к тому же, с паскалем .net!
Открыв наброски, которые тот человек уже сделал, увидел модули GraphABC, ABCObjects, с которыми раньше не приходилось работать.
Но до меня уже была часть работы сделана, а именно создание окна нужного размера и размещение «сетки» квадратиков 4х4.
Это облегчило задачу, потому что я увидел, что много схожестей есть с обычными паскалевскими объектами или графическими примитивами, а тут ещё удобство было в том, что все эти объекты (квадратики, кружочки и другие штуки) сами отвечают за свою прорисовку, не нужно рисовать на canvas-е и т.д., тут можно просто указать новую позицию или ещё как-то изменить объект, а перерисуется он уже сам!
И тут началась разработка! Никогда не приходилось до этого делать игру 2048, но найдя на просторах интернетов браузерную реализацию данной игры, пришлось поиграть в неё, опробовать разные ситуации, чтобы наглядно ознакомиться с правилами. Оттуда же были стянуты цвета и записаны в несколько чудном формате, потому что оказалось, что данный паскаль не поддерживает запись цветов через $, как это сделано в том же Delphi, например )
Вот такой вышел код, который возвращал нужный цвет текста и фона, в зависимости от цифры.
//получить цвет в зависимости от цифры function getSquareColorByNumber(num: integer): TSquareColor; begin case num of 2: result := createColor(rgb(238, 228, 218), rgb(119, 110, 101)); 4: result := createColor(rgb(237, 224, 200), rgb(119, 110, 101)); 8: result := createColor(rgb(242, 177, 121), rgb(249, 246, 242)); 16: result := createColor(rgb(245, 149, 99), rgb(249, 246, 242)); 32: result := createColor(rgb(246, 124, 95), rgb(249, 246, 242)); 64: result := createColor(rgb(246, 94, 59), rgb(249, 246, 242)); 128: result := createColor(rgb(237, 207, 114), rgb(249, 246, 242)); 256: result := createColor(rgb(237, 204, 97), rgb(249, 246, 242)); 512: result := createColor(rgb(237, 200, 80), rgb(249, 246, 242)); 1024: result := createColor(rgb(237, 197, 63), rgb(249, 246, 242)); 2048: result := createColor(rgb(237, 194, 46), rgb(249, 246, 242)); 4096: result := createColor(rgb(60, 58, 50), rgb(249, 246, 242)); else result := createColor(rgb(238, 228, 218), rgb(119, 110, 101)); end; end;
TSquareColor — это запись, хранящая в себе фоновый цвет и цвет текста. Функция createColor принимает на вход первым параметром цвет фона, а вторым — цвет текста и возвращает уже заполненную запись TSquareColor, которая потом уже используется для задания цвета определённой клеточки )
Вообще, код неплохо откомментирован. В некоторых местах даже избыточно, т.к. это курсовая работа, пришлось комментировать почти всё 🙂
А некоторые куски кода, которые можно было бы оптимизировать и вынести в отдельную функцию, лишь изменяя некоторые параметры, пришлось оставить так, как есть, задублированными… )
Поэтому всякие объяснения можно найти в коде!
Сразу скажу, что настройки размера поля, отступов клеточек друг от друга, другие отступы, настройки анимации и т.д. можно задавать тоже в коде, эти константы вынесены специально для этих целей )
Настало время показать, как это дело выглядит! А вот так:
Ничего особенного. Всё как обычно )
А в заголовке отображается ещё и количество очков. Управление то же самое, как и в классической реализации игры. Поведение тоже )
При появлении и сложении клеточек есть анимация небольшая, которая порой работает кривовато… Тут уж был задействован таймер, а также изменение размеров этих блоков. Иногда просто почему-то размер не доходит до начального состояния, и поэтому некоторые клеточки так и остаются немного больше или меньше, но это происходит редко )
Также был написан небольшой класс для показа «диалоговых» окон, который содержит в себе простенькую реализацию некоего подобия окна подтверждения (которое содержит вопрос и кнопки ОК и Отмена). Суть в том, что можно динамически создавать эти диалоговые окошки, модально показывать их, реагируют они также на нажатия клавиши Esc (отмена) и Enter (ок).
Также можно показывать просто уведомление с кнопкой Ок!
Простенько, но большего и не нужно.. ) Даже это уже было лишним 🙂
Код класса этого находится в файле controlUtils.pas, который тоже находится в архиве 🙂
Выглядят окошки примерно вот так:
Про модальные диалоги я, конечно, загнул немножко )
Вся модальность работает вот так:
procedure KeyDown(Key: integer); begin //если открыто какое-то диалоговое окно! if dialogs.modalVisible then begin case Key of VK_RETURN: dialogs.pressOK; VK_ESCAPE: dialogs.closeLastDialog(); end; exit; end; //если нет открытого диалогового окна case Key of VK_UP: move(tdUp); VK_DOWN: move(tdDown); VK_LEFT: move(tdLeft); VK_RIGHT: move(tdRight); VK_Escape: dialogs.showConfirm('Вы действительно хотите начать заново?', newGame); end; end;
Обрабатываются нажатия в главном окне программы, а там уже идёт проверка, если открыто какое-то диалоговое окно, то нужно обрабатывать нажатия несколько иначе, а если же нет никаких окон, то там уж управлять игрой нужно )
При нажатии мышкой на кнопку ОК или Enter на клавиатуре срабатывает уже определённое заданное событие, которое передаётся как callback (типа того) при вызове функции dialogs.showConfirm. Как-то так оно и работает… )
Прикольно, в общем. Остальное можно найти в коде и в комментариях, которых там, как уже было сказано выше, предостаточно.
Были некоторые идеи, типа сохранения состояния игры при закрытии и восстановление при открытии, но как-то не было в этом необходимости, да и интерес через некоторое время пропал, поэтому всё осталось на таком уровне, на котором есть сейчас. К тому же, для курсовой тому человеку всех этих окошек диалоговых не нужно, поэтому на каком-то этапе он просто оставил старую версию и стал дорабатывать её по-своему )
Скачать исходник и готовый ехе-шник, который, кстати, весит довольно мало из-за .Net, можно вот в этом замечательном архиве: http://shpirat.net/etc/2048_PascalABC.NET.zip
Сделано это всё было ещё осенью, но сейчас стало можно это опубликовать, может, ещё кому-то пригодится или же просто интересно будет 🙂