Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Для новичков > Подскажите с управлением в "Змейке".


Автор: spamER 17.12.2008, 21:26
Народ, пожалуйста помогите.
Пытаюсь написать игру "Змейка". В качестве тела змеии использую массив из компонентов TShape (создаю их в отдельной процедуре - конструктором).

Сама змейка движется, только вот когда управляешь ей, она НЕ правильно движется. Например при движении вверх все Shape'ы начинают вдигатся как в тетрисе. А нада как в обычной змейке. что бы она умела поворачивать. 

Проблема : как сделать управление змейкой (Вверх, Вниз, Вправо, Влево) что бы она правильно поворачивала???


То что я написал: 

Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, Menus;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    MainMenu1: TMainMenu;
    Main: TMenuItem;
    NewGames: TMenuItem;
    N1: TMenuItem;
    Exit: TMenuItem;
    Cpravka: TMenuItem;
    About_program: TMenuItem;
    Image1: TImage;
    procedure Timer1Timer(Sender: TObject);
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure Vpravo();
    procedure VLevo();
    procedure VVerx();
    procedure Vniz();
    procedure CreateUdav();
  end;
const
  shag = 10;

var
  Form1: TForm1;
  napravlenie: string[1];
  mas:array[0..999] of TShape;
  i:integer;
implementation

uses MaskUtils, Math;

{$R *.dfm}

procedure TForm1.CreateUdav();
begin
for i:=0 to 2 do
begin
  mas[i]:=TShape.Create(self);
  mas[i].Left:=150;
  mas[i].Width:=10;
  mas[i].Height:=10;
  mas[i].Left:=mas[i].Left+i*10;
  mas[i].Top:=150;
  mas[i].Parent:=Form1;
end;
end;

procedure TForm1.Vpravo();
begin
for i:=0 to 2 do
  mas[i].Left:=mas[i].Left+shag;
end;

procedure TForm1.VLevo();
begin
for i:=0 to 2 do
  mas[i].Left:=mas[i].Left-shag;
end;

procedure TForm1.VVerx();
begin
for i:=0 to 2 do
  mas[i].Top:=mas[i].Top-shag;
end;

procedure TForm1.Vniz();
begin
for i:=0 to 2 do
  mas[i].Top:=mas[i].Top+shag;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if napravlenie = 'R' then Vpravo;
  if napravlenie = 'L' then VLevo;
  if napravlenie = 'D' then Vniz;
  if napravlenie = 'U' then VVerx;

end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
case key of
vk_RIGHT: napravlenie:='R';
VK_LEFT:  napravlenie:='L';
vk_DOWN:  napravlenie:='D';
VK_UP:    napravlenie:='U';
end;

end;

procedure TForm1.FormCreate(Sender: TObject);
begin
napravlenie := 'L';
CreateUdav();
end;

end.
 

Вот прикрепил исходник, плз помогите.

Автор: TForumUser 17.12.2008, 23:54
Твоя основная ошибка: ты применяешь направление движения сразу для всех сегментов змейки:
Код
for i:=0 to 2 do
  mas[i].Left:=mas[i].Left+shag;

попробуй сделать проще: не тягать всю змейку целиком, а переместить последний сегмент змейки (хвост) на новое положнение головы змейки.

Автор: spamER 18.12.2008, 00:17
Цитата(TForumUser @ 17.12.2008,  23:54)
Твоя основная ошибка: ты применяешь направление движения сразу для всех сегментов змейки:
Код
for i:=0 to 2 do
  mas[i].Left:=mas[i].Left+shag;

попробуй сделать проще: не тягать всю змейку целиком, а переместить последний сегмент змейки (хвост) на новое положнение головы змейки.

Можешь подсказать как это сделать.Если не тяжело приведи пример кода. ПЛЗ.

Автор: TForumUser 18.12.2008, 00:24
Код

var
 i, j: integer;
procedure TForm1.Vpravo();
begin
  mas[i].Top := mas[j].Top;                //меняем положение хвоста
  mas[i].Left := mas[j].Left + shag;
  j := i;                                               //теперь i-ый элемент массива - голова
  i := i - 1;                                         //i -1 - хвост
  if i < 1 then i = 2;
end;

где i -  (хвост змейки), j - голова змейки
В начале i=2  j=1
остальные - по аналогии
работает если изображение головы не отличается от изображения хвоста
То, что смог набросать без делфи... Если не получится, завтра ещё подумаю)

Автор: Christoph 18.12.2008, 00:47
а может переменные локальные? а цикл? или без цикла?

Автор: spamER 18.12.2008, 00:50
TForumUser чет оно не работает

Добавлено через 9 минут и 8 секунд
Народ ну помогите , плз.

Автор: Christoph 18.12.2008, 16:12
конечно оно не будет работать.....я ж писал выше  smile  сегодня попробую помочь

Автор: TForumUser 18.12.2008, 17:18
Ой, ну конечно работает, просто надо кое-то исправить
Код

var
 i, j: integer;
procedure TForm1.Vpravo();
begin
  mas[i].Top := mas[j].Top;
  mas[i].Left := mas[j].Left + shag;
  j := i;
  i := i + 1;
  if i > n then i := 1;
end;

при запусек программы i = 1, j = (количество сегментов)
n = (количество сегментов)
И переменный должны быть глобальными, потому что сама процедура должна делать только один шаг, по той же причине не нужен цикл, так что нечего минусовать сообщения... 

Автор: spamER 19.12.2008, 17:03
Чет оно не работает. Мож кто знает как правильно нада ???

Автор: TForumUser 19.12.2008, 17:47
как именно оно не работает? потому что у меня все норм

Автор: spamER 19.12.2008, 18:29
TForumUser оно даже не компилируется.

Если не тяжело прикрепи исходник(что бы уже рабочий был).

Автор: TForumUser 19.12.2008, 19:34
Знаете, при ошибке во время компиляции в нижней части окна с кодом появляется окошко, в котором описана суть ошибки. Обратив внимание на это окошко, можно догадаться, что вся проблема в повторном объявлении переменной. Если немного подстроить данный код под Вашу программу, можно получить рабочую программу:
Код
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, Menus;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    MainMenu1: TMainMenu;
    Main: TMenuItem;
    NewGames: TMenuItem;
    N1: TMenuItem;
    Exit: TMenuItem;
    Cpravka: TMenuItem;
    About_program: TMenuItem;
    Image1: TImage;
    procedure Timer1Timer(Sender: TObject);
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure Vpravo();
    procedure VLevo();
    procedure VVerx();
    procedure Vniz();
    procedure CreateUdav();
  end;
const
  shag = 10;

var
  Form1: TForm1;
  napravlenie: string[1];
  mas:array[0..999] of TShape;
  i, a, b, max, n: integer;
implementation

uses MaskUtils, Math;

{$R *.dfm}

procedure TForm1.CreateUdav();
begin
for i:=0 to 2 do
begin
  mas[i]:=TShape.Create(self);
  mas[i].Left:=150;
  mas[i].Width:=10;
  mas[i].Height:=10;
  mas[i].Top:=150;
  mas[i].Top:=mas[i].Top-i*10;
  mas[i].Parent:=Form1;
end;                       
a := 0;
max := 3;
b := max - 1;
n := max - 1;
end;

procedure TForm1.Vpravo();
begin
  mas[a].Top := mas[b].Top;
  mas[a].Left := mas[b].Left + shag;
  b := a;
  a := a + 1;
  if a > n  then a := 0;
end;

procedure TForm1.VLevo();
begin
  mas[a].Top := mas[b].Top;
  mas[a].Left := mas[b].Left - shag;
  b := a;
  a := a + 1;
  if a > n  then a := 0;
end;

procedure TForm1.VVerx();
begin
  mas[a].Top := mas[b].Top - shag;
  mas[a].Left := mas[b].Left;
  b := a;
  a := a + 1;
  if a > n  then a := 0;
end;

procedure TForm1.Vniz();
begin
  mas[a].Top := mas[b].Top + shag;
  mas[a].Left := mas[b].Left;
  b := a;
  a := a + 1;
  if a > n  then a := 0;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if napravlenie = 'R' then Vpravo;
  if napravlenie = 'L' then VLevo;
  if napravlenie = 'D' then Vniz;
  if napravlenie = 'U' then VVerx;

end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
case key of
vk_RIGHT: napravlenie:='R';
VK_LEFT:  napravlenie:='L';
vk_DOWN:  napravlenie:='D';
VK_UP:    napravlenie:='U';
end;

end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 napravlenie := 'U';
 CreateUdav();
end;

end.

И на будущее: на форуме не делают за вас всю работу, а наталкивают на мысль, так что привыкайте. Я же пишу за Вас программу лишь из-за того, что это мое сотое сообщение и я от осознания сего факта добрею.

Автор: NewDima 19.12.2008, 19:56
Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    procedure Timer1Timer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure CreateUdav;
    procedure Move;
    procedure goUp;
    procedure goDown;
    procedure goRight;
    procedure goLeft;
  end;
const
  startlen = 10;
  size = 10;
  step = 1;

var
  Form1: TForm1;
  currentcount: integer;
  mas:array[0..999] of TShape;
  deltax, deltay: integer;

implementation

{$R *.dfm}

procedure TForm1.CreateUdav;
var i: integer;
begin
for i:=0 to startlen-1 do
 begin
  mas[i] := TShape.Create(self);
  mas[i].Parent := self;
  mas[i].Left := i*size+3;
  mas[i].Top := 0;
  mas[i].Width := size;
  mas[i].Height := size;
 end;
 mas[0].Brush.Color := clRed;
 currentcount := startlen;
 deltax := step;
 deltay := 0;
end;

procedure TForm1.Move;
var i: integer;
begin
for i:=currentcount-1 downto 1 do
 begin
 mas[i].Left := mas[i-1].Left;
 mas[i].Top := mas[i-1].Top;
 end;
if (mas[0].Left+deltax*size<0) then mas[0].Left := ClientWidth else
if (mas[0].Left+deltax*size>ClientWidth) then mas[0].Left := 0 else
mas[0].Left := mas[0].Left + deltax*size;
if (mas[0].Top+deltay*size<0) then mas[0].Top := ClientHeight else
if (mas[0].Top+deltay*size>ClientHeight) then mas[0].Top := 0 else
mas[0].Top := mas[0].Top + deltay*size;
end;

procedure TForm1.goUp;
begin
if deltay<>0 then exit;
deltax := 0;
deltay := - step;
end;

procedure TForm1.goDown;
begin
if deltay<>0 then exit;
deltax := 0;
deltay := step;
end;
procedure TForm1.goRight;
begin
if deltax<>0 then exit;
deltax := step;
deltay := 0;
end;
procedure TForm1.goLeft;
begin
if deltax<>0 then exit;
deltax := - step;
deltay := 0;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
move();
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
CreateUdav();
end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
case Key of
VK_LEFT: goLeft;
VK_RIGHT: goRight;
VK_UP: goUp;
VK_DOWN: goDown;
end;
end;

end.


Добавлено через 2 минуты и 33 секунды
а мое 111-е ))

Автор: spamER 19.12.2008, 20:28
1.   TForumUser ОГРОМНОЕ спасибо.  
2.   NewDima  также ОГРОМНОЕ спасибо.

Не знаю даже как вас благодарить, спасибо.


Все работает smile  smile  smile 

Автор: NewDima 20.12.2008, 06:22
приучись закрывать тему, чтобы те, кто заходит сюда помочь, могли быстро увидеть, где еще не помогли.
Сверху надпись-ссылка есть

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)