Извините, ничего не найдено.

Не расстраивайся! Лучше выпей чайку!
Регистрация
Справка
Календарь

Вернуться   forum.boolean.name > Программирование игр для компьютеров > Delphi

Ответ
 
Опции темы
Старый 26.11.2010, 20:52   #1
МаркусФеникс
AnyKey`щик
 
Аватар для МаркусФеникс
 
Регистрация: 17.10.2009
Сообщений: 5
Написано одно полезное сообщение
(для 6 участников)
Пятнашки на Delphi

Всем привет!
Сегодня я вам расскажу, как на 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
А так же можно прикрутить систему рекордов..

Если что непонятно пишите отвечу
(Offline)
 
Ответить с цитированием
Эти 6 пользователя(ей) сказали Спасибо МаркусФеникс за это полезное сообщение:
Android (27.11.2010), Hurrit (26.11.2010), impersonalis (27.11.2010), midlet_pascal (29.01.2012), Nex (27.11.2010), pax (27.11.2010)
Старый 26.11.2010, 21:03   #2
impersonalis
Зануда с интернетом
 
Аватар для impersonalis
 
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений
(для 20,935 пользователей)
Ответ: Пятнашки на Delphi

БЛИН. Сразу бросается говнокод с кнопками. Нельзя что-ли было их указатели в массив загнать (создавать не в редакторе, а кодом)?

Но стремление - похвально
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
(Offline)
 
Ответить с цитированием
Эти 5 пользователя(ей) сказали Спасибо impersonalis за это полезное сообщение:
baton4ik (26.11.2010), Hurrit (26.11.2010), pax (27.11.2010), pepel (26.11.2010), Reks888 (27.11.2010)
Старый 27.11.2010, 01:21   #3
ffinder
Дэвелопер
 
Аватар для ffinder
 
Регистрация: 10.09.2007
Сообщений: 1,442
Написано 793 полезных сообщений
(для 1,460 пользователей)
Ответ: Пятнашки на Delphi

это не урок, а ужоснах
аффтар, пожалуйста, учи ООП, учи алгоритмы, рефактори код.
потом учи других.
(Offline)
 
Ответить с цитированием
Эти 2 пользователя(ей) сказали Спасибо ffinder за это полезное сообщение:
ARA (27.11.2010), Reks888 (27.11.2010)
Ответ


Опции темы

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


Часовой пояс GMT +4, время: 19:09.


vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot
Style crйe par Allan - vBulletin-Ressources.com