Как сделать ограничение на перемещение? Или я не знаю как называется это правильно. (См. внутри)

ArtemK

Если нажимать на кнопки ВПРАВО ВЛЕВО ВВЕРХ ВНИЗ робот Петька перемещается соответственно этим кнопкам. А как сделать так, чтобы Петька не заезжал на другие кнопки? Чтобы выдавалось, например, сообщение "Не могу дальше". Ну или без сообщения, просто чтобы остановился около других объектов на форме. Что и где нужно прописать?
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, Buttons;
type
  TForm1 = class(TForm)
    SpeedButton1: TSpeedButton;
    Label1: TLabel;
    Shape1: TShape;
    SpeedButton2: TSpeedButton;
    SpeedButton3: TSpeedButton;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    SpeedButton4: TSpeedButton;
    procedure SpeedButton2Click(Sender: TObject);
    procedure SpeedButton3Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure SpeedButton1Click(Sender: TObject);
    procedure SpeedButton4Click(Sender: TObject);
     private
    { Private declarations }
  public
    { Public declarations }
  end;
  var
  Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button2Click(Sender: TObject);
begin
button1.Top:=button1.Top-1;
if (button1.Top<0)  then
    begin
         button1.Top:=0;
    end;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
    button1.Top:=button1.Top+1;
if (button1.Top>471)  then
   begin
         button1.Top:=471;
        end;
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
button1.Left:=button1.Left+1;
if (button1.left>649) then
begin
  button1.Left:=649;
end;
end;
procedure TForm1.Button5Click(Sender: TObject);
begin
button1.Left:=button1.Left-1;
if button1.Left<0 then
begin
  button1.left:=0;
end;
end;
procedure TForm1.SpeedButton1Click(Sender: TObject);
var
CH,CW:integer;
begin
randomize;
  CH:=random(ClientHeight-speedbutton1.Height);
  CW:=random(ClientWidth-speedbutton1.Width);
  if (CH<0) or (CW<0)  then
    begin
     CH:=CH+speedbutton1.Height;
     CW:=CW+speedbutton1.Width;
     speedbutton1.Top:=CH;
     speedbutton1.Left:=CW;
    end
  else
    speedbutton1.Top:=CH;
    speedbutton1.Left:=CW;
end;
procedure TForm1.SpeedButton2Click(Sender: TObject);
begin
shape1.width:=shape1.width + 1;
shape1.height:=shape1.height + 1;
end;
procedure TForm1.SpeedButton3Click(Sender: TObject);
begin
shape1.width:=shape1.width - 1;
shape1.height:=shape1.height - 1;
end;
procedure TForm1.SpeedButton4Click(Sender: TObject);
begin
close;
end;
end.
14 ответов

ArtemK

if (button1.top+button1.height>Button2.top) and (button1.top<Button2.top+button2.height) and (button1.left+button1.width>Button2.left) and (button1.left<Button2.left+button2.width) then
Примерно так, чтобы кнопка 1 не залазила на кнопку 2


ArtemK

Перед каждым шагом проверяй (есть такая функция IntersectRect) не будет ли BoundsRect твоего "Петьки" пересекаться с BoundsRect-ами других объектов, лежащих на форме (проверять все компоненты, прямо в цикле). Если проверка покажет, что IntersectRect новой позиции робота с BoundsRect какого-то другого контрола даст True - значит, позиции пересекутся, то есть, робот наедет на этот контрол. Шаг в таком случае не должен быть произведён.zuxa-zuxa, на форме как минимум 8 объектов, которые надо проверить. Ничего не отвалится, пока будешь все эти условия прописывать? Что за привычка, схватить первое доступное решение (причем не самое хорошее), и тут же его предлагать?


ArtemK

Перед каждым шагом проверяй (есть такая функция IntersectRect) не будет ли BoundsRect твоего "Петьки" пересекаться с BoundsRect-ами других объектов, лежащих на форме (проверять все компоненты, прямо в цикле). Если проверка покажет, что IntersectRect новой позиции робота с BoundsRect какого-то другого контрола даст True - значит, позиции пересекутся, то есть, робот наедет на этот контрол. Шаг в таком случае не должен быть произведён.zuxa-zuxa, на форме как минимум 8 объектов, которые надо проверить. Ничего не отвалится, пока будешь все эти условия прописывать? Что за привычка, схватить первое доступное решение (причем не самое хорошее), и тут же его предлагать?
А как пользоваться этой функцией в моей задаче?


ArtemK

Используешь ComponentCount и Components для поиска всех контролов на форме
var
  I : Integer;
  aRect : TRect;
begin
  for I := 0 to ComponentCount - 1 do
    if Components[I] is TShape) then
      Continue
    else if IntersectRect(aRect, TControl(Components[I]).BoundsRect, Shape1.BoundsRect) then
      // Производим нужные действия.
За основу робота взял TShape, измени на что нужно.


ArtemK

Используешь ComponentCount и Components для поиска всех контролов на форме
Что за ComponentCount? Я просто не совсем еще в delphi разбираюсь. И куда нужно это прописывать?


ArtemK

Что за привычка, схватить первое доступное решение (причем не самое хорошее), и тут же его предлагать?
Ну хоть такая)) Я других и не знал...


ArtemK

Что за ComponentCount?... И куда нужно это прописывать?
1. Смотри встроенную справку. 2. Чтобы не вписывать этот код в каждую кнопку, создай отдельную процедуру и пропиши её декларацию в секцию public, саму процедуру вызывай из "кнопок передвижения", где производишь перемещения робота.


ArtemK

Я хотел предложить то же самое, но в несколько другом варианте. Причём в более лучшем. Но спорить с модераторами у меня нет никакой охоты. Они черезчур заносчивы и у них слишком много прав, и когда их перекашивает от злобы, если что скажешь поперёк, они начанют трясти мускулами. В данном случаем каждый раз обращатся к компоненту, это лишняя трата времени, поэтому в моём предложении, при создании формы все данные о координатах компонентов заносились в массив, а в обработчике события нажатия клавиши формы, в цикле производилось работа с этим массивом.


ArtemK

Можно согласиться и с таким вариантом, но при этом любое изменение размеров формы может привести к неработоспособности программы, так как данные о контролах (BoundsRect) может не совпадать с данными в массиве при использовании Свойств Anchors, Align.


ArtemK

Можно согласиться и с таким вариантом, но при этом любое изменение размеров формы может привести к неработоспособности программы, так как данные о контролах (BoundsRect) может не совпадать с данными в массиве при использовании Свойств Anchors, Align.
А причём тут BoundsRect? Размеры формы меняй как хошь, а компоненты останутся на месте. Единственное что изменится, так координаты нижней точки окна. А координаты робота, они в своей перменной. И вообще, в графике, если допускается измение каких либо параметров контекста вывода, например в играх, да и не только в них, все необходимые данные инициализируются заново. У формы есть свойство ресайз. Оно изменилось, так нужно задать его новые координаты. Если оно свернулось, то через соответсвующее свойство флагом запретить все манипуляции, с программой. Я думал это общеизвестно и не стал говорить об этом.


ArtemK

А причём тут BoundsRect? Размеры формы меняй как хошь, а компоненты останутся на месте. Единственное что изменится, так координаты нижней точки окна. А координаты робота, они в своей перменной. И вообще, в графике, если допускается измение каких либо параметров контекста вывода, например в играх, да и не только в них, все необходимые данные инициализируются заново. У формы есть свойство ресайз. Оно изменилось, так нужно задать его новые координаты. Если оно свернулось, то через соответсвующее свойство флагом запретить все манипуляции, с программой. Я думал это общеизвестно и не стал говорить об этом.
Может я на самом деле тупой, но я так и не понял что прописать в коде.((((
А причём тут BoundsRect? Размеры формы меняй как хошь, а компоненты останутся на месте. Единственное что изменится, так координаты нижней точки окна. А координаты робота, они в своей перменной. И вообще, в графике, если допускается измение каких либо параметров контекста вывода, например в играх, да и не только в них, все необходимые данные инициализируются заново. У формы есть свойство ресайз. Оно изменилось, так нужно задать его новые координаты. Если оно свернулось, то через соответсвующее свойство флагом запретить все манипуляции, с программой. Я думал это общеизвестно и не стал говорить об этом.
Может я на самом деле тупой, но я так и не понял что прописать в коде.((((
Перед каждым шагом проверяй (есть такая функция IntersectRect) не будет ли BoundsRect твоего "Петьки" пересекаться с BoundsRect-ами других объектов, лежащих на форме (проверять все компоненты, прямо в цикле). Если проверка покажет, что IntersectRect новой позиции робота с BoundsRect какого-то другого контрола даст True - значит, позиции пересекутся, то есть, робот наедет на этот контрол. Шаг в таком случае не должен быть произведён.zuxa-zuxa, на форме как минимум 8 объектов, которые надо проверить. Ничего не отвалится, пока будешь все эти условия прописывать? Что за привычка, схватить первое доступное решение (причем не самое хорошее), и тут же его предлагать?
Я так и не понял что нужно сделать.(((


ArtemK

ArtemK, Есть такая штука как TRect В ней сохранятся такие вещи как координаты верхнего левого угла и нижнего правого некого объекта. У любого компонента есть такие праметры как Left Top Width и Height Для ваших целей вам не важно что за компонент, важно место, которое он занимает. В TRect Left Top Bootom Right У вас 11 обьектов + сама форма Создаём массив на эти 11 обьектов mass:= array [1..11] of TRect; При создании формы нужно заполнить массив данными о координатах объектов. Это можно сделать или через цикл тем методом, корый предложил UI Или тупо присвоить Вот например у вас кнопка But1 Скажем это первый объект mass[1]:=(Rect(But1.left, But1.Top, But1.left + But1.Width, But1.Top + But1.Height)); потом другой элемент mass[2]:=........................... И так все 11Потом, когда работаем с кнопками. У нас есть TRect Персонажа, то есть робота. у него меняются только перменные Left и Top Изменяя их вы передвигаете робота.Но перед тем тем как иди, в цикле проверяем TRect робота имеющего новые предполагаемые координаты (они только предполагаются но не изменяются) с каждым TRect массива. То есть прямоугольник персонажа проверяется на предмет вторжения в зону компонента. Если это происходит, выдаётся сообщение. если же нет - робот не натыкается на компонент и не персекает его, и ещё нужно сделать пороверку на пересечение границ окна - Left и Top в его Rect меняются и робот пермещается.


ArtemK

ArtemK, Есть такая штука как TRect В ней сохранятся такие вещи как координаты верхнего левого угла и нижнего правого некого объекта. У любого компонента есть такие праметры как Left Top Width и Height Для ваших целей вам не важно что за компонент, важно место, которое он занимает. В TRect Left Top Bootom Right У вас 11 обьектов + сама форма Создаём массив на эти 11 обьектов mass:= array [1..11] of TRect; При создании формы нужно заполнить массив данными о координатах объектов. Это можно сделать или через цикл тем методом, корый предложил UI Или тупо присвоить Вот например у вас кнопка But1 Скажем это первый объект mass[1]:=(Rect(But1.left, But1.Top, But1.left + But1.Width, But1.Top + But1.Height)); потом другой элемент mass[2]:=........................... И так все 11Потом, когда работаем с кнопками. У нас есть TRect Персонажа, то есть робота. у него меняются только перменные Left и Top Изменяя их вы передвигаете робота.Но перед тем тем как иди, в цикле проверяем TRect робота имеющего новые предполагаемые координаты (они только предполагаются но не изменяются) с каждым TRect массива. То есть прямоугольник персонажа проверяется на предмет вторжения в зону компонента. Если это происходит, выдаётся сообщение. если же нет - робот не натыкается на компонент и не персекает его, и ещё нужно сделать пороверку на пересечение границ окна - Left и Top в его Rect меняются и робот пермещается.
Я прописал, как вы говорили. Но у меня ничего не работает. Проверьте пожалуйста, что не так???
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, Buttons;
type
  TForm1 = class(TForm)
    SpeedButton1: TSpeedButton;
    Label1: TLabel;
    Shape1: TShape;
    SpeedButton2: TSpeedButton;
    SpeedButton3: TSpeedButton;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    SpeedButton4: TSpeedButton;
    procedure SpeedButton2Click(Sender: TObject);
    procedure SpeedButton3Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure SpeedButton1Click(Sender: TObject);
    procedure SpeedButton4Click(Sender: TObject);
    procedure Label1Click(Sender: TObject);
    procedure Shape1ContextPopup(Sender: TObject; MousePos: TPoint;
      var Handled: Boolean);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
  var
  Form1: TForm1; mass: array[1..11] of TRect;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
mass[11]:=(Rect(button1.left, button1.Top,button1.left + button1.Width,button1.Top + button1.Height));
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
mass[1]:=(Rect(button2.left, button2.Top, button2.left + button2.Width, button2.Top + button2.Height));
button1.Top:=button1.Top-1;
//if (button1.Top<0)  then
//begin
//button1.Top:=0;
//end;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
mass[2]:=(Rect(button3.left, button3.Top, button3.left + button3.Width, button3.Top + button3.Height));
button1.Top:=button1.Top+1;
//if (button1.Top>471)  thenbegin button1.Top:=471;end;
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
mass[4]:=(Rect(button4.left, button4.Top, button4.left + button4.Width, button4.Top + button4.Height));
button1.Left:=button1.Left+1;
end;
procedure TForm1.Button5Click(Sender: TObject);
begin
mass[3]:=(Rect(button5.left, button5.Top, button5.left + button5.Width, button5.Top + button5.Height));
button1.Left:=button1.Left-1;
end;
procedure TForm1.Label1Click(Sender: TObject);
begin
mass[7]:=(Rect(label1.left, label1.Top, label1.left + label1.Width, label1.Top + label1.Height));
end;
procedure TForm1.Shape1ContextPopup(Sender: TObject; MousePos: TPoint;
  var Handled: Boolean);
begin
mass[8]:=(Rect(shape1.left, shape1.Top, shape1.left + shape1.Width, shape1.Top + shape1.Height));
end;
procedure TForm1.SpeedButton1Click(Sender: TObject);
var
CH,CW:integer;
begin
mass[6]:=(Rect(speedbutton1.left, speedbutton1.Top, speedbutton1.left + speedbutton1.Width, speedbutton1.Top + speedbutton1.Height));
randomize;
  CH:=random(ClientHeight-speedbutton1.Height);
  CW:=random(ClientWidth-speedbutton1.Width);
  if (CH<0) or (CW<0)  then
    begin
     CH:=CH+speedbutton1.Height;
     CW:=CW+speedbutton1.Width;
     speedbutton1.Top:=CH;
     speedbutton1.Left:=CW;
    end
  else
    speedbutton1.Top:=CH;
    speedbutton1.Left:=CW;
end;
procedure TForm1.SpeedButton2Click(Sender: TObject);
begin
mass[9]:=(Rect(speedbutton2.left, speedbutton2.Top, speedbutton2.left + speedbutton2.Width, speedbutton2.Top + speedbutton2.Height));
shape1.width:=shape1.width + 1;
shape1.height:=shape1.height + 1;
end;
procedure TForm1.SpeedButton3Click(Sender: TObject);
begin
mass[10]:=(Rect(speedbutton3.left, speedbutton3.Top, speedbutton3.left + speedbutton3.Width, speedbutton3.Top + speedbutton3.Height));
shape1.width:=shape1.width - 1;
shape1.height:=shape1.height - 1;
end;
procedure TForm1.SpeedButton4Click(Sender: TObject);
begin
mass[5]:=(Rect(speedbutton4.left, speedbutton4.Top, speedbutton4.left + speedbutton4.Width, speedbutton4.Top + speedbutton4.Height));
close;
end;
end.


ArtemK

А причём тут BoundsRect?
При том, если у ТС всё сделано по дефолту, то никаких нареканий к твоему методу, но, к примеру, он захотел при ресайзе формы чтобы один из контролов был прижат к нижнему краю. И что дальше с твоим методом? Всё он уже бесполезен.Всё ещё используешь этот код?
...
  CH:=random(ClientHeight-speedbutton1.Height);
  CW:=random(ClientWidth-speedbutton1.Width);
  if (CH<0) or (CW<0)  then
    begin
     CH:=CH+speedbutton1.Height;
     CW:=CW+speedbutton1.Width;
     speedbutton1.Top:=CH;
     speedbutton1.Left:=CW;
    end
...
Я уже говорил автору этих строк что проверка
  if (CH<0) or (CW<0)  then
бессмысленна, так как никогда не произойдёт. Random не может сгенерировать число меньше 0.