Как сделать калькулятор в Delphi?

Delphi - объектно-ориентированный язык программирования, разработанный компанией Borland в 1995 году. Он основан на языке программирования Pascal, но имеет более расширенные возможности и добавлены новые функции.

Как Delphi реализует многоплатформенную разработку?

Delphi является интегрированной средой разработки (IDE), которая позволяет разрабатывать программное обеспечение для различных платформ, включая Windows, macOS, Android и iOS. Delphi достигает многоплатформенности с помощью...

Создание игры Пятнашки

Статьи » Графика и игры » Создание игры Пятнашки

Можно ли в Delphi создать что-нибудь непохожее на базы данных? «Нет! — ехидно скажут программисты на Си, — Все непохожее на базы данных пишеться на СиСи+». Хотя это еще как сказать. Мне несколько раз подряд попадались исходные тексты некоторых игр, «написанные на Си», в которых самого Си было максимум процентов 5-10, а все остальное — чистой воды Ассемблер!

Случайность это или все-таки закономерность? На мой взгляд, с таким же успехом можно использовать связку Delphi-Ассемблер. Тем более, что в Delphi есть все для создания крупномасштабных проектов, в том числе и игр (например, поддержка OpenGL — для работы с 3D-графикой; OpenGL, кстати, использовался при создании Quake III). Я, конечно, не собираюсь в этой статье рассказывать, как создать в Delphi Quake III (не по мне такие задачи). Речь пойдет о более приземленных вещах. А именно, о маленькой простой игре, которой можно дополнить набор мелкомягких игр, устанавливаемых вместе с Windows. Эта игра в народе называется «пятнашки» — очень популярная раньше настольная (вернее даже, наручная) игра, которая продавалась в квадратных коробочках с большой цифрой 15 на крышке, в которой нужно было расставить квадратики с числами в порядке от 1 до 15. Ну что, вспомнили? Нет!?… Да, трудное у вас было детство… Ну да ладно. Итак, значит, будем писать «пятнашки» в Delphi.

Для начала приступим к созданию интерфейса. Здесь все полностью зависит от вашей фантазии. Но я остановлюсь на праздном сером оформлении (см. Рис. 1). Теперь о том, как получить такой образец серости и примитивизма. Сначала на форме располагается компонент TPanel со свойствами BevelInner и BevelOuter, равными bvLowered, для создания эффекта бордюра по краям формы. Затем на полученную панель ставится еще одна панель меньшего размера со свойством BevelOuter равным bvRaised, BevelInner —bvLowered, а цвет Color —clBlack. Эта вторая панель будет фоном для кнопок с цифрами. Затем добавляются кнопки (компоненты TButton или TSpeedButton) с названиями about, game, exit и кнопка начать игру (компонент TSpeedButton). Расположение их показано на рисунке. Теперь надо создать те самые квадратики с цифрами. Эту роль играют компоненты TButton. Расположите их на второй панели именно так, как показано на рисунке, то есть, кнопка с цифрой (Caption) 1 должна иметь имя (Name) Button1, кнопка 2 —Button2 и т.д. Это важно. Объясняю, почему. При добавлении компонента на форму он автоматически заносится в список (массив) компонентов формы и получает индекс начиная с 0. В дальнейшем взаимодействие с кнопками программой будет осуществляться через их индексы. Поэтому если у вас кнопка с именем Button1 будет иметь Caption 2, вам просто будет сложнее работать с ней. Что касается размеров кнопок, то я установил параметры Heigth и Width каждой по 50. Да, еще. Чтобы посмотреть индекс кнопки, размещенной на форме, в ее процедуре-обработчике события (Event), например, OnClick, наберите:

form1.caption:=inttostr((sender as tbutton).componentindex);

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

Теперь, когда интерфейс программы готов, можно перейти непосредственно к программированию. Опишем глобальные переменные модуля. В разделе var (там, где написано Form1: TForm1) напишите:

a:array

[1..16]of

byte; i,k,fl,rn,p,m:byte; x,y,x1,y1,num,pos,lr,td,lr1,td1:integer; flag:boolean;

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

procedure

rndarr; begin

for

k:=1 to

16 do

a[k]:=0; randomize; i:=1; repeat

rn:=random(16)+1; fl:=0; k:=1; while

(a[k]<>rn) and

(k<>17) do

inc(k); if

k=17 then begin

a[i]:=rn; Inc(i); end;

until

i=17; end;

Обращаю ваше внимание на то, что приведенная выше процедура не является обработчиком какого-либо события, поэтому не нужно ее объявлять в интерфейсной части модуля. Просто наберите ее как есть после Implementation {$R *.DFM}. Такие процедуры называются пользовательскими. (Для того чтобы узнать, какие числа появляются в массиве после выполнения этой процедуры, можно использовать окно Watch).

Визуализация массива


На этом принципе работают многие игры. Например, тот же тетрис: имеется некий двумерный массив (стакан), в котором нули — пустые позиции, единицы — квадратики, из которых строятся фигуры тетриса. Далее в массиве эти единицы сдвигаются, и массив выводится на экран с заменой 0 и 1 на графические элементы. Это повторяется несколько раз, что создает эффект падения фигур. В данном случае все должно происходить аналогичным образом: все перемещения производятся в массиве, а в соответствии числам из массива располагаются сами «пятнашки». Для того чтобы это осуществить, нужно написать процедуру, в которой читаются элементы массива, соответствующие индексам компонентов-кнопок с цифрами. Затем происходит обращение к этим кнопкам по их индексу и размещение их соответственно значениям в массиве. То есть, если первым элементом массива является число 15, то первой кнопкой в левом верхнем углу будет кнопка с цифрой 15 и т.д. Вот эта процедура (наберите ее после первой):

procedure

drawarr; begin

p:=0; for

i:=0 to

3 do

for

k:=0 to

3 do

begin

p:=p+1; if

a[p]<>16 then

begin with

TButton(form1.components[a[p]+5]) do begin

left:=k*50+2; top:=i*50+2; end; end; end; end;

Так как у меня первая кнопка в массиве компонентов формы имеет индекс 6 (:-)), то я при обращении к кнопкам прибавляю к значению из массива число 5, чтобы получить их индексы:

TButton(form1.components[a[p]+5]));

Кнопки имеют размер 5050, первая из них расположена правее на 2 пикселя от левого края черной (второй) панели и на 2 пикселя ниже от верхнего ее края, поэтому, чтобы правильно их расположить, будем умножать переменные i и k на 50 и прибавлять 2. Таким образом, если, например, i и k равны 0, то координаты первой кнопки в левом верхнем углу, по отношению к черной панели, равны (2,2), если i=0, k=1, то координаты —(2,52), и т.д.
Начать игру



Начнем работу с процедурами-обработчиками событий. Первая из них — обработчик события OnClick кнопки (TSpeedButton) «Начать игру». Дважды щелкните по этой кнопке. При этом откроется редактор кода с таким заголовком процедуры:

procedure

TForm1.SpeedButton2Click(Sender: TObject); begin

rndarr; drawarr; form1.speedbutton2.caption:='Начать игру заново'; end;

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


Предпоследний этап. Нужно сделать так, чтобы при нажатии на кнопку с цифрой определялось направление ее движения, т.е. то место, где нет другой кнопки. Для этого клацните дважды, например, по кнопке 15 и в появившейся процедуре-обработчике события OnClick (как и в предыдущий раз) между Begin и End наберите:

if

flag then

exit; {если flag=true — выход из процедуры} pos:=0;m:=0;num:=0; num:=(sender as

tbutton).componentindex-5; {num — номер нажатой кнопки} for

i:=1 to

16 do

if

a[i]=num then

pos:=i; {определение ее позиции в массиве} {определение направления движения} if

(pos-1>0)and

(pos-1<>4)and

(pos-1<>8)and

(pos-1<>12)and

(a[pos-1]=16)then

m:=1; if

(pos+1<17)and

(pos+1<>5)and

(pos+1<>9)and

(pos+1<>13)and

(a[pos+1]=16)then

m:=2; if

(pos-4>0)and

(a[pos-4]=16)then

m:=3; if

(pos+4<17)and

(a[pos+4]=16)then

m:=4; if

m=0 then

exit; {если вокруг кнопки пустой позиции нет — выход} flag:=true; {установливаем флаг, означающий, что кнопка в движении} lr1:=(sender as

tbutton).left; {сохраняем в lr1 и td1 начальные координаты} td1:=(sender as

tbutton).top; lr:=0;td:=0; form1.move(sender); {вызов процедуры перемещения кнопки}

В Object Inspector в разделе Events для остальных кнопок с цифрами напротив события OnClick укажите эту процедуру. Таким образом, она будет выполняться при нажатии любой кнопки с цифрой. В этой процедуре определяется, есть ли рядом с нажатой кнопкой пустая позиция. Если таковая слева, то m:=1, справа —m:=2, сверху —m:=3, снизу —m:=4. Определение «слева или справа» происходит путем вычета или прибавления к позиции нажатой кнопки единицы, определение «сверху или снизу» — через вычет или прибавление 4. Переменная Flag служит для того чтобы определить, движется ли какая-либо кнопка или нет. Если движется — процедура не должна выполняться. Процедура перемещения кнопки form1.move описана далее.
Двигай кнопкой



Чтобы как-то «оживить» игру, требуется движение. В данном случае — движение кнопок. Для реализации заметного человеческому глазу и более-менее плавного движения потребуется компонент TTimer. Выберите его из списка компонентов и расположите в любом месте формы. Установите его свойство Interval равным 1. Затем в его единственном событии OnTimer в Object Inspector напишите move и нажмите Enter. На экране появится тело процедуры-обработчика этого события:

procedure

TForm1.move(Sender: TObject); begin

timer1.enabled:=true; {включение таймера} case

m of

{исходя из направления движения} 1:dec(lr,5); {уменьшаем на 5 lr} 2:inc(lr,5); {увеличиваем на 5 lr} 3:dec(td,5); 4:inc(td,5); end

; with

TButton(components[num+5])do

begin

{перемещаем компонент} left:=lr1+lr;top:=td1+td;end

; if

(abs(lr)=50) or

(abs(td)=50) then

{когда пройдено 50 шагов} begin

timer1.enabled:=false; {выключаем таймер} lr:=0; td:=0; flag:=false; case

m of

{перестановка чисел в массиве} 1:begin

a[pos-1]:=a[pos];a[pos]:=16;end

; 2:begin

a[pos+1]:=a[pos];a[pos]:=16;end

; 3:begin

a[pos-4]:=a[pos];a[pos]:=16;end

; 4:begin

a[pos+4]:=a[pos];a[pos]:=16;end

; end

; fl:=0; for

i:=1 to

16 do

if

a[i]<>i then

fl:=1; {определяем, расставлены ли кнопки по порядку от 1 до 15} if

fl=0 then

showmessage('Вы выиграли!'); {если кнопки расставлены как надо — сообщение «Вы выиграли!»} end

; end

;

Основная часть программы уже написана. Осталось внести последние штрихи. Создайте форму AboutBox и в процедуре-обработчике события OnClick кнопки About напишите: AboutBox.Show. Аналогично, для кнопки Exit напишите Close — для выхода из программы. Да, еще. В Object Inspector в параметре формы BorderStyle выберите bsDialog — форму с таким стилем невозможно развернуть или изменить ее размер. Также, по желанию, можно сделать меню (компонент TPopUpMenu) для кнопки Game.

Другое по теме:

Категории

Статьи

Советы

Copyright © 2024 - All Rights Reserved - www.delphirus.com