Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Столкновения прямоугольников. [D7, WinXP]


Страницы:   1 2

IPranker ©   (2011-06-05 20:16:00) 

Всем привет! :)

Вот никак не могу написАть програмку столкновения 2-х прямоугольников. Т.е. передвигаем один прямоугольник, а как
столкнулись с другим (преграда), то не даем ему проехать сквозь него. Наш прямоугольник должен в него какбы упереться.

P.S. Можете "протестить" данный код, надо только положить на форму TTimer с интервалом в 1.
P.S.S. Это нужно для скромной игры.


var
 FR    : TRect;                     // Местоположение преграды.
 FX, FY: LongWord;                  // Наши координаты.
 FW, FH: LongWord;                  // Наши ширина и высота.
 FKeys : array [0..255] of boolean; // Массив клавиш клавиатуры.

function KDown(Key: byte): boolean;  // Проверка нажатой клавиши.
begin
 Result:= FKeys[Key];
end;

procedure ObjectMove(OffSet: LongWord); // Передвигаемся.
begin
 If KDown(VK_UP)    then Dec(FY, OffSet) else
 If KDown(VK_DOWN)  then Inc(FY, OffSet) else
 If KDown(VK_LEFT)  then Dec(FX, OffSet) else
 If KDown(VK_RIGHT) then Inc(FX, OffSet);
end;

function IsCollide: boolean;            // Функция проверяет пересечение с преградой.
var
 R: TRect;
begin
 Result:= InterSectRect(R, Rect(FX, FY, FX + FW, FY + FH), FR);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
 ObjectMove(10);   // Двигаемся со скоростью в 10 единиц.

 If IsCollide then // Проверяем столкновение с преградой.
 begin
   Caption:= '1';

 end else
   Caption:= '0';

 Invalidate;
end;

procedure TForm1.FormPaint(Sender: TObject);
begin
 // Очищаем фон.
 Canvas.Brush.Color:= clWhite;
 Canvas.FillRect(Canvas.ClipRect);

 // Рисуем наш прямоугольльник.
 Canvas.Brush.Color:= clRed;
 Canvas.Rectangle(Rect(FX, FY, FX + FW, FY + FH));

 // Рисуем преграду.
 Canvas.Brush.Color:= clBlue;
 Canvas.Rectangle(FR);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 // Задаём наше местоположение и размеры.
 FX:= ClientWidth  div 2;
 FY:= ClientHeight div 2;
 FW:= 50;
 FH:= 50;

 // Задаём местоположение и размеры преграды.
 SetRect(FR, 100, 100, 356, 567);

 DoubleBuffered:= True;
end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
 FKeys[Key]:= True;
end;

procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
 FKeys[Key]:= False;
end;


Inovet   (2011-06-06 19:36:00) [21]

> [16] sniknik ©   (06.06.11 19:31)
> делов то там (для писавшего код) раз плюнуть

Врёт он, что писал.


sniknik   (2011-06-06 19:31:00) [22]

> прямоугольник почему-то упирается не до конца.
ну так "упри" его... "молоточком постучи". делов то там (для писавшего код) раз плюнуть.


sniknik   (2011-06-06 19:29:00) [23]

> Ввёл новую переменную - направление.
???
какое направление, блин, вот честно, чувствуется разница исходного кода и твоих "вставок"

было
ObjectMove(10);

чтобы вернуть
ObjectMove(-10);
все что нужно. не вводя новых сущностей в лаконичный, и правильный в общем код... убрал бы там нажатия клавиш, нафига дублировать системные... переменные "россыпью" свел бы в рект, а то как то странно для одного набора он используется для другого нет, + переменные функции из глобальных сделал объектными. а так ничего нормальный код, твои вставки на порядок хуже, - не лаконичные.


Inovet   (2011-06-06 19:18:00) [24]

> [13] IPranker ©   (06.06.11 19:09)
> Прямоугольник имеет 4 степени свободы.

Очень интересно в каких это 4-х направлениях. В плоскости у него 3 степени свободы.


IPranker   (2011-06-06 19:09:00) [25]


> Dimka Maslov ©   (06.06.11 19:05) [12]


Прямоугольник имеет 4 степени свободы.
Может т.е. двигаться только в 4х направлениях.
Как в классических танчиках.

-----

Мой вопрос в силе, прямоугольник почему-то упирается не до конца.


Dimka Maslov   (2011-06-06 19:05:00) [26]


> Inovet ©   (06.06.11 18:57) [11]


Согласен, облажался, 90° тут не причём. Следует читать поворачивается от препятствия


> IPranker ©   (06.06.11 18:56) [10]


Дело не в направлении вектора скорости до удара. А во взаимном положении препятствия и вектора скорости.

При решении подобного рода задач надо начинать не с программирования, а с построения математической модели. И если программа, написанная с использованием математической модели работает неправильно, нужно корректировать математическую модель, а не программу.


Inovet   (2011-06-06 18:57:00) [27]

> [9] Dimka Maslov ©   (06.06.11 18:50)
> вектор скорости прямоугольника поворачивается на 90° от препятствия

а как же

> [9] Dimka Maslov ©   (06.06.11 18:50)
> "угол падения равен углу отражения"


IPranker   (2011-06-06 18:56:00) [28]


> Dimka Maslov ©   (06.06.11 18:50) [9]
>
> согласно теории "угол падения равен углу отражения". При
> ударе абсолютно твёрдого тела об абсолютно твёрдое неподвижное
> тело это правило справедливо. Следовательно, вектор скорости
> прямоугольника поворачивается на 90° от препятствия.


Так и сделал.
Если ехали вверх и врезались, то отъезжаем на противоположную сторону, т.е.
вниз. Инвертировано получается.


Dimka Maslov   (2011-06-06 18:50:00) [29]

согласно теории "угол падения равен углу отражения". При ударе абсолютно твёрдого тела об абсолютно твёрдое неподвижное тело это правило справедливо. Следовательно, вектор скорости прямоугольника поворачивается на 90° от препятствия.


IPranker   (2011-06-06 18:46:00) [30]

>sniknik ©   (06.06.11 18:07) [7]

Да я всё время не мог додумать, чего ж не хватает то.
Ведь не понятно в какую сторону вернуть координаты назад.

Ввёл новую переменную - направление.
Всё вроде работает, через преграду наш прямоугольник пройти больше не может.

Но он упирается в нескольких пикселях от преграды, а должен ПЛОТНО упираться.

Помогите додумать, помогите советом. :)


type
 TDir = (dirNone, dirUp, dirDown, dirLeft, dirRight);

var
 FR    : TRect;                     // Местоположение преграды.
 FR2   : TRect;                     // Местоположение преграды 2.
 FDir  : TDir;                      // Направление движения.
 FX, FY: LongWord;                  // Наши координаты.
 FW, FH: LongWord;                  // Наши ширина и высота.
 FKeys : array [0..255] of boolean; // Массив клавиш клавиатуры.

function KDown(Key: byte): boolean;  // Проверка нажатой клавиши.
begin
 Result:= FKeys[Key];
end;

procedure ObjectMove(OffSet: LongWord); // Передвигаемся.
begin
 If KDown(VK_UP)    then FDir:= dirUp    else
 If KDown(VK_DOWN)  then FDir:= dirDown  else
 If KDown(VK_LEFT)  then FDir:= dirLeft  else
 If KDown(VK_RIGHT) then FDir:= dirRight else
                         FDir:= dirNone;

 Case FDir of
   dirUp   : Dec(FY, OffSet);
   dirDown : Inc(FY, OffSet);
   dirLeft : Dec(FX, OffSet);
   dirRight: Inc(FX, OffSet);
 end;
end;

procedure BackMove(OffSet: LongWord);
begin
 Case FDir of
   dirUp   : Inc(FY, OffSet);
   dirDown : Dec(FY, OffSet);
   dirLeft : Inc(FX, OffSet);
   dirRight: Dec(FX, OffSet);
 end;
end;

function IsCollide(AR: TRect): boolean;            // Функция проверяет пересечение с преградой.
var
 R: TRect;
begin
 Result:= InterSectRect(R, Rect(FX, FY, FX + FW, FY + FH), AR);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
 ObjectMove(30);   // Двигаемся со скоростью в 10 единиц.

 If IsCollide(FR) or IsCollide(FR2) then // Проверяем столкновение с преградой.
 begin
   Caption:= '1';
   BackMove(30);
 end else
   Caption:= '0';

 Invalidate;
end;

procedure TForm1.FormPaint(Sender: TObject);
begin
 // Очищаем фон.
 Canvas.Brush.Color:= clWhite;
 Canvas.FillRect(Canvas.ClipRect);

 // Рисуем наш прямоугольльник.
 Canvas.Brush.Color:= clRed;
 Canvas.Rectangle(Rect(FX, FY, FX + FW, FY + FH));

 // Рисуем преграду.
 Canvas.Brush.Color:= clBlue;
 Canvas.Rectangle(FR);

 Canvas.Rectangle(FR2);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 // Задаём наше местоположение и размеры.
 FX:= ClientWidth  div 2;
 FY:= ClientHeight div 2;
 FW:= 50;
 FH:= 50;

 // Задаём местоположение и размеры преграды.
 SetRect(FR,  100, 100, 156, 367);
 SetRect(FR2, 500, 300, 600, 600);

 DoubleBuffered:= True;
end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
 FKeys[Key]:= True;
end;

procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
 FKeys[Key]:= False;
end;


sniknik   (2011-06-06 18:07:00) [31]

> Но не смог сделать возможность "упереться" в преграду.
т.е. если "столкнулись" то "вернуть координаты назад" не смог реализовать? это шутка юмора такой?


IPranker   (2011-06-06 18:04:00) [32]


> Рассматривай преграду как дополнительный неподвижный прямоугольник
> с которым надо определять столкновение.


В коде так и сделано.
Преграда - неподвижный прямоугольник синего цвета.
Наш прямоугольник красный и двигается.


Dimka Maslov   (2011-06-06 17:54:00) [33]

Рассматривай преграду как дополнительный неподвижный прямоугольник с которым надо определять столкновение.


IPranker   (2011-06-06 16:44:00) [34]

Я сделал в коде возможность движения прямоугольника.
Проверку наличия столкновения. Т.е. все условия для тестов.
Но не смог сделать возможность "упереться" в преграду.

Как это сделать?


sniknik   (2011-06-05 22:11:00) [35]

> Это мой код.
тогда как такое возможно, написав проверку, не "мочь" ее использовать? т.е. проверить светофор на "красный" и сказать "это красный" можешь, а не идти по нему через улицу нет... странно.
вот как то так.


IPranker   (2011-06-05 22:04:00) [36]

Это мой код.
Комментарии сделал специально, чтобы этот маленький код был понятен любому.
Вот так вот.


sniknik   (2011-06-05 21:40:00) [37]

> Вот никак не могу написАть програмку столкновения 2-х прямоугольников.
странные слова рядом с кодом уже написанной программки, в которой все есть (расчеты), и она работает...
откуда тогда "не могу"? или "нарыл" где то код, или на другом форуме дали, но немного не то... и хочешь чтобы его здесь "подогнали"?

> P.S.S. Это нужно для скромной игры.
скорее для сдачи зачета. т.к. писал бы для себя то хотел бы разобраться, и спрашивал по конкретно тому что не получается.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо