Всем привет!
Сегодня я вам расскажу, как на Delphi написать игру Пятнашки.
Это мой первый урок, прошу сильно не пинать…
Ну что ж приступим.
Из теории…, что нужно знать о пятнашках?? В первую очередь это то что представляет из себя игра как таковая. Имеется поле 4х4 в котором располагается 15 кубиков и 1 пустая клетка. Задача расположить их (кубики) по порядку от 1 до 15. Ну пожалуй пока все, а дальше посмотрим.
Создаем новый проект
File->new->VCL Forms Application Delphi
Далее зададим размеры формы.
ClientHeight:=246, ClientWidth:=246
Ну и
Caption на ваше усмотрение, я написал «Пятнашки»
Теперь «кидаем» на форму 15 кнопок (Button) со вкладки Standard. И даем свойству Caption 1,2,3…15 соответственно, главное что бы Button1 соответствовал Caption:=1, Button2.Caption:=2 и т.д. Далее всем кнопкам назначаем ширину и высоту. Она будет ровна следующим значениям.
Button.Height:=57 Button.Width:=57.
Зная размерность нашего поля (4х4),выставляем кнопки следующим образом.
Button1.Left:=0, икаждому последующему кубику в ряду назначаем значение большее на 63, т.е. Button2.Left:=63.. Button4.Left:=189. Точно также делаем и с высотой (свойство Top).
Таким образом у нас получилась готовая форма. Осталось её запрограммировать
Теперь надо подумать как мы будем хранить номера кнопок??
Предлагаю следующий вариант: заведем массив размерностью [0..3,0..3] типа integer в котором будем хранить кубики в соответствующем порядке, пустая ячейка будет хранить 0 т.е.
A[0,0]:=0; a[0,1]:=1 и т.д.
A[1,0]:=5 …
Так же нам понадобится следующие переменные
- переменная «флажок» типа Boolean, которая будет хранить true если кнопка нажата и false если кнопка не нажата.
- переменные
Gx,Gy : integer – будут хранить координаты курсора
-
GxB,GyB – координаты кнопки т.е. свойства Left и Top
TempI,TempJ – I,J нашего массива, подробнее потом…
TEMP – integer, здесь будем хранить временное значение нашего массива
На этом с переменными пока всё. Далее мы добавим еще несколько переменных.
При программировании мы будем использовать события кнопок. Нам понадобятся следующие Evets’ы :
OnMouseDown, OnMouseUp и OnMouseMove.
Теперь подумаем что мы будем писать в данных событиях. Писать в каждом событии для каждой кнопки какие либо действия не удобно, и громосткость кода при этом сильно увеличиться, поэтому мы напишем функции и процедуры которые впоследствии будем вызывать в наших событиях. Для
OnMouseDown мы не будем писать функцию, её мы опишем просто.
Пишем следующий код в событии
OnMouseDown
procedure TForm1.Button1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
k:=true; // переставляем флаг в true т.е. кнопка нажата
Gx:=x; Gy:=y; // запоминаем координаты мышки
GxB:=Button1.Left; // запоминаем позицию кнопки
GyB:=Button1.Top;
tempJ:=Trunc(Button1.Left/63); // вот здесь высчитываем в какой строке находится кнопка т.е. i
tempI:=Trunc(Button1.Top/63); // вот здесь высчитываем в каком столбце находится кнопка т.е. j
TEMP:=a[tempI,tempJ]; //запоминаем значение данной ячейки массива
a[tempI,tempJ]:=0; // и присваиваем этой ячейки 0, подробнее потом
end;
Это вы должны написать для каждой кнопки !!!
Первая функция которую мы напишем это будет функция под названием
MoveX. И так добавляем в наш класс TForm1 приватную функцию
function MoveX(PosX,LeftPos:integer): integer;
где:
PosX – будет координата курсора по Х.
LeftPos – Расположение кнопки т.е. туда мы будем передавать Button.Left.
теперь нажимаем Ctrl+Shift+c и пишем процедуру.
function TForm1.MoveX(PosX, LeftPos: integer):integer;
begin
if LeftPos<>0 then /// если кубик не находится в нулевой позиции (первом столбце)
begin
if a[tempi,tempj-1]=0 then // проверяем если пустая ячейка слева от позиции нажатой кнопки
begin
if (PosX<Gx) then // если позиция мышки левее чем при нажатии на кнопку т.е. двигаем влево
begin
if (GxB-LeftPos)<63 then // если разница между координатой при нажатии и текущей<63 т.е. //мы не можем передвинуть кубик далее 63 пикселей
begin
LeftPos:=LeftPos-(Gx-PosX); тут мы уже перезаписываем координату по Х которую будем возвращать
end;
end;
if PosX>Gx then // тоже самое только направление вправо
begin
if (LeftPos-GxB)<0 then
begin
LeftPos:=LeftPos+(PosX-Gx);
end;
end;
end;
end;
if LeftPos<>189 then /// если кубик не находится в последнем столбце
begin
if a[tempi,tempj+1]=0 then
begin
if PosX>Gx then
begin
if (LeftPos-GxB)<63 then
begin
LeftPos:=LeftPos+(PosX-Gx);
end;
end;
if (PosX<Gx) then // направление влево
begin
if (GxB-LeftPos)<0 then
begin
LeftPos:=LeftPos-(Gx-PosX);
end;
end;
end;
end;
result:=leftPos; // возвращаем значение функции
end;
теперь опишем функцию
MoveY(PosY,TopPos:integer): integer; в ней примерно тоже самое только по оси Y я думаю разобраться не составит труда
function TForm1.MoveY(PosY, TopPos: integer): integer;
var temp: integer;
begin
temp:=TopPos;
if TopPos<>0 then // вниз
begin
if (a[tempi-1,tempj]=0) then
begin
if PosY<Gy then
begin
if (GyB-TopPos)<63 then
TopPos:=TopPos-(Gy-PosY);
end;
if PosY>Gy then
begin
if (TopPos-GyB)<0 then
TopPos:=TopPos+(PosY-Gy);
end;
end;
end;
if TopPos<>189 then //вверх
begin
if (a[tempi+1,tempj]=0) then
begin
if PosY>Gy then
begin
if (TopPos-GyB)<63 then
TopPos:=TopPos+(PosY-Gy);
end;
if PosY<Gy then
begin
if (GyB-TopPos)<0 then
TopPos:=TopPos-(Gy-PosY);
end;
end;
end;
result:=TopPos
end;
Теперь опишем событие
OnMouseMove:
procedure TForm1.Button1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
if (k=true) then //Если кнопка нажата
begin
Button1.Left:=MoveX(x,Button1.Left); // передаем координату мышки и координату позиции кнопки
Button1.Top:=MoveY(y,Button1.Top);
end; // k=true
end;
и это нужно будет написать для каждой кнопки !!!
Далее у нас идет OnMouseUp, в ней мы будем проверять сместился ли кубик и сместился ли до конца, т.е. нужно будет довести его в нужную позицию вместо пользователя, если пользователь его сместил более чем на половину.
procedure TForm1.Button1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
k:=false; // переставляем флаг в false кнопка не нажата
a[tempI,tempJ]:=TEMP; // присваем TEMP т.е. то что мызаписывали при нажатии, если в процедурах finish и finish мы узнаем что кубик не сместился то оставляем старое значение
Button1.Left:=finishX(Button1.Left);
Button1.Top:=finishY(Button1.Top);
end;
Теперь опишем процедуры FinishX и FinishY
function finishX(i:integer): integer; в качестве I передаем текущую позицию кнопки
function TForm1.finishX(i: integer):integer;
begin
if i<GxB then // проверка на направление, если кнопка находится левее чем исходная позиция кнопки (при нажатии)
begin
if (GxB-i)<32 then // направление влево, если мы передвинули кнопку меньше чем на половину то возвращаем кнопку в исходную позицию
begin
i:=GxB;
end
else //если же более чем на половину
begin
i:=GxB-63; // от исходной позиции вычитаем 63 и присваиваем I переменной которая будет возвращена функцией
a[tempI,tempJ-1]:=TEMP; // производим изменения в массиве
a[tempI,tempJ]:=0;
end;
end
else
begin
if (i-GxB)<32 then // направление вправо
i:=GxB
else
begin
i:=GxB+63;
a[tempI,tempJ+1]:=TEMP;
a[tempI,tempJ]:=0;
end;
end;
result:=i; // возвращаем значение
end;
ну и
FinishY.
function TForm1.finishY(i: integer): integer;
begin
if i<GyB then // вверх
begin
if (GyB-i)<32 then
begin
i:=GyB;
end
else
begin
i:=GyB-63;
a[tempI-1,tempJ]:=TEMP;
a[tempI,tempJ]:=0;
end
end
else
begin
if (i-GyB)<32 then // направление вниз
i:=GyB
else
begin
i:=GyB+63;
a[tempI+1,tempJ]:=TEMP;
a[tempI,tempJ]:=0;
end;
end;
result:=i;
end;
Теперь нам нужно заполнить наш массив случайными, неповторяющимися цифрами от 0 до 15.
Сделаем событие
OnCreate для нашей формы.
А и еще одно нам нужно в глобальные переменные добавить массив размерностью 16
Mas: array [0..15] of integer
Его мы будим заполнять случайными числами
procedure TForm1.FormCreate(Sender: TObject);
var i,j:integer;
begin
mas[0]:=random(16); // присваиваем первому значению случайное число
for I := 1 to 15 do // организуем цикл от 1 до 15
begin
mas[i]:=random(16); каждому последующему значению присваиваем случайное значение
j:=0;
while j<=i-1 do //организуем цикл для проверки на совпадение значений
begin
if mas[i]=mas[j] then // если они равны то заново присваиваем случайное значение и так до тех пор пока все значения не будут случайными
begin
mas[i]:=random(16);
j:=-1;
end;
j:=j+1;
end;
end;
// теперь переносим наши случайные значения в двумерный массив
a[0,0]:=mas[0]; a[0,1]:=mas[1]; a[0,2]:=mas[2]; a[0,3]:=mas[3];
a[1,0]:=mas[4]; a[1,1]:=mas[5]; a[1,2]:=mas[6]; a[1,3]:=mas[7];
a[2,0]:=mas[8]; a[2,1]:=mas[9]; a[2,2]:=mas[10]; a[2,3]:=mas[11];
a[3,0]:=mas[12]; a[3,1]:=mas[13]; a[3,2]:=mas[14]; a[3,3]:=mas[15];
// ну и тут присваиваем координаты кнопкам в зависимости от их расположения
for I := 0 to 3 do
begin
for j := 0 to 3 do
begin
if a[i,j]=1 then
begin
Button1.Top:=i*63;
Button1.Left:=j*63;
end;
if a[i,j]=2 then
begin
Button2.Top:=i*63;
Button2.Left:=j*63;
end;
if a[i,j]=3 then
begin
Button3.Top:=i*63;
Button3.Left:=j*63;
end;
if a[i,j]=4 then
begin
Button4.Top:=i*63;
Button4.Left:=j*63;
end;
if a[i,j]=5 then
begin
Button5.Top:=i*63;
Button5.Left:=j*63;
end;
if a[i,j]=6 then
begin
Button6.Top:=i*63;
Button6.Left:=j*63;
end;
if a[i,j]=7 then
begin
Button7.Top:=i*63;
Button7.Left:=j*63;
end;
if a[i,j]=8 then
begin
Button8.Top:=i*63;
Button8.Left:=j*63;
end;
if a[i,j]=9 then
begin
Button9.Top:=i*63;
Button9.Left:=j*63;
end;
if a[i,j]=10 then
begin
Button10.Top:=i*63;
Button10.Left:=j*63;
end;
if a[i,j]=11 then
begin
Button11.Top:=i*63;
Button11.Left:=j*63;
end;
if a[i,j]=12 then
begin
Button12.Top:=i*63;
Button12.Left:=j*63;
end;
if a[i,j]=13 then
begin
Button13.Top:=i*63;
Button13.Left:=j*63;
end;
if a[i,j]=14 then
begin
Button14.Top:=i*63;
Button14.Left:=j*63;
end;
if a[i,j]=15 then
begin
Button15.Top:=i*63;
Button15.Left:=j*63;
end;
end;
end;
end;
И последнее проверка на выигрыш. Кидаем на форму таймер
TTimer со вкладки System
Выставляем интервал в 50 и создаем событии OnTimer и пишем в ней следующее:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
if a[3,3]=0 then
begin
if (Button1.Left and Button5.Left and Button9.Left and Button13.Left)=0 then
if (Button2.Left and Button6.Left and Button10.Left and Button14.Left)=63 then
if (Button3.Left and Button7.Left and Button11.Left and Button15.Left)=126 then
if (Button4.Left and Button8.Left and Button12.Left)=189 then
if (Button1.Top and Button2.Top and Button3.Top and Button4.Top)=0 then
if (Button5.Top and Button6.Top and Button7.Top and Button8.Top)=63 then
if (Button9.Top and Button10.Top and Button11.Top and Button12.Top)=126 then
if (Button13.Top and Button14.Top and Button15.Top)=189 then
begin
ShowMessage(‘Вы выиграли!!!’)
end;
end;
end;
на этом все!
При желании можно сделать меню в котором можно добавить кнопку Новая игра, и перенести туда код из события OnCreate
А так же можно прикрутить систему рекордов..
Если что непонятно пишите отвечу