![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Столкновения прямоугольников. [D7, WinXP]
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. Это нужно для скромной игры.
скорее для сдачи зачета. т.к. писал бы для себя то хотел бы разобраться, и спрашивал по конкретно тому что не получается.