Часто возникает необходимость перемещать объект по некоторой
траектории (например, рыбка должна двигаться по окружности). В
этом случае для определения новых точек кривой (по которой пере-
мещается объект) удобно использовать параметрическое уравнение
этой кривой1. Из курса математики известны некоторые кривые, при-
веденные в табл. 1.8 (вид этих кривых показан на рис. 1.11), и их зада-
ние с помощью параметрического уравнения.
Рис. 1.11. Вид кривых
Таблица 1.8. Параметрическое представление некоторых кривых
Рассмотрим пример, в котором перемещение объекта осуществля-
ется по заранее указанной траектории. В качестве траектории может
быть задана окружность, циклоида, астроида, спираль, восьмерка,
прямая линия. Вид формы показан на рис. 1.12.
Рис. 1.12. Форма программы, демонстрирующей перемещение объекта
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms, Dialogs, ExtCtrls, StdCtrls, Buttons;
type
TForm1 = class(TForm)
Shape1: TShape;
Timer1: TTimer;
Button1: TButton;
RadioGroup1: TRadioGroup;
Button2: TButton;
Label1: TLabel;
Label2: TLabel;
Button3: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure RadioGroup1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
const
r=20; //радиус круга - объекта вращения
rCircle=100; //радиус круга - траектории
rCikl=25; //параметр циклоиды
rAstr=200; //параметр астроиды
rOct=250; //параметр восьмерки
a1Max=10; //максимальное значение коэффициента a1
a2Max=10; //максимальное значение коэффициента a2
var
angle: integer = 0; //начальный угол или параметр прямой
dangle: integer = 5; //шаг изменения угла/параметра прямой
x0,y0: integer; //центр или начальная точка прямой
x,y: integer; //текущие координаты
a1, a2: integer; //координаты направляющего вектора прямой
//процедура вычисляет расстояние между двумя точками
//и выводит значение в Label2.Caption
procedure distance(x1,y1,x2,y2: integer);
var
d: real;
begin
d:=sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
Form1.Label2.Caption:=IntToStr(round(d));
end;
//событие, возникающее при создании формы
procedure TForm1.FormCreate(Sender: TObject);
begin
Label2.Caption:=''; //метка пуста
Timer1.Enabled:=false; //таймер выключен
Timer1.Interval:=100; //интервал таймера
Shape1.Shape:=stCircle; //вид фигуры Shape1
Shape1.Width:=2*r; //ширина фигуры Shape1
Shape1.Height:=2*r; //высота фигуры Shape1
//определение координат (x0, y0) центра формы
//относительно которой вращается фигура Shape1
x0:=Form1.ClientWidth div 2;
y0:=Form1.ClientHeight div 2;
Shape1.Left:= x0 - r; //положение Shape1 слева
Shape1.Top:= y0 - r; //положение Shape1 сверху
end;
//процедура рисует крестик с центром в точке (x0, y0)
procedure TForm1.Button1Click(Sender: TObject);
begin
Canvas.Pen.Width:=3; //толщина пера
Canvas.Pen.Color:=clRed; //цвет пера
Canvas.MoveTo(x0-10, y0);
Canvas.LineTo(x0+10,y0);
Canvas.MoveTo(x0, y0-10);
Canvas.LineTo(x0,y0+10);
end;
//обработчик нажатия на кнопку Запуск движения
procedure TForm1.Button2Click(Sender: TObject);
begin
Timer1.Enabled:=true; //запуск таймера
end;
//обработчик сигнала от таймера
procedure TForm1.Timer1Timer(Sender: TObject);
begin
randomize;
case RadioGroup1.ItemIndex of
0: begin //движение по кругу
Shape1.Visible:=false; //фигура Shape1 невидима
angle:=angle+dangle; //увеличиваем угол
//если угол сделал оборот в 360 градусов
//начинаем отсчет угла заново
if angle >= 360 then angle:=0;
//координаты новой точки
x:=x0+round(rCircle*cos(angle*pi/180));
y:=y0-round(rCircle*sin(angle*pi/180));
//положение фигуры Shape1
Shape1.Left:= x - r;
Shape1.Top:= y - r;
Shape1.Visible:=true; //фигура Shape1 видима
//расстояние от центра фигуры до центра формы
distance(x0, y0, x, y);
end;
1: begin //движение по циклоиде
Shape1.Visible:=false; //фигура Shape1 невидима
angle:=angle+dangle; //увеличиваем угол
//координаты новой точки
x:=x0+round(rCikl*(angle*pi/180 - sin(angle*pi/180)));
y:=y0-round(rCikl*(1-cos(angle*pi/180)));
//положение фигуры Shape1
Shape1.Left:= x - r;
Shape1.Top:= y - r;
Shape1.Visible:=true; //фигура Shape1 видима
//расстояние от центра фигуры до центра формы
distance(x0, y0, x, y);
40
//как только фигура дойдет до края формы
//прекращаем движение, остановив таймер
if x>Form1.ClientWidth-2*r
then Timer1.Enabled:=false;
end;
2: begin //движение по астроиде
Shape1.Visible:=false; //фигура Shape1 невидима
angle:=angle+dangle; //увеличиваем угол
//если угол сделал оборот в 360 градусов
//начинаем отсчет угла заново
if angle >= 360 then angle:=0;
//координаты новой точки
x:=x0+round(rAstr*sqr(cos(angle*pi/180))*
cos(angle*pi/180));
y:=y0-round(rAstr*sqr(sin(angle*pi/180))*
sin(angle*pi/180));
//положение фигуры Shape1
Shape1.Left:= x - r;
Shape1.Top:= y - r;
Shape1.Visible:=true; //фигура Shape1 видима
//расстояние от центра фигуры до центра формы
distance(x0, y0, x, y);
end;
3: begin //движение по спирали
Shape1.Visible:=false; //фигура Shape1 невидима
angle:=angle+dangle; //увеличиваем угол
//координаты новой точки
x:=x0+round(angle*pi/180*cos(angle*pi/180));
y:=y0-round(angle*pi/180*sin(angle*pi/180));
//положение фигуры Shape1
Shape1.Left:= x - r;
Shape1.Top:= y - r;
Shape1.Visible:=true; //фигура Shape1 видима
//расстояние от центра фигуры до центра формы
distance(x0, y0, x, y);
//как только фигура дойдет до края формы
//прекращаем движение, остановив таймер
if (x>Form1.ClientWidth-2*r) or
(y>Form1.ClientHeight-2*r)
then Timer1.Enabled:=false;
end;
4: begin //движение по восьмерке
Shape1.Visible:=false; //фигура Shape1 невидима
angle:=angle+dangle; //увеличиваем угол
//если угол сделал оборот в 360 градусов
//начинаем отсчет угла заново
if angle >= 360 then angle:=0;
//координаты новой точки
x:=x0+round(rOct*cos(angle*pi/180)*
sin(angle*pi/180)-r);
y:=y0-round(rOct*sin(angle*pi/180));
//положение фигуры Shape1
Shape1.Left:= x - r;
Shape1.Top:= y - r;
Shape1.Visible:=true; //фигура Shape1 видима
//расстояние от центра фигуры до центра формы
distance(x0, y0, x, y);
end;
5: begin //движение по прямой
Shape1.Visible:=false; //фигура Shape1 невидима
angle:=angle+dangle; //увеличиваем параметр
//координаты новой точки
x:=x0+a1*angle;
y:=y0-a2*angle;
//положение фигуры Shape1
Shape1.Left:= x - r;
Shape1.Top:= y - r;
Shape1.Visible:=true; //фигура Shape1 видима
if x<=r
then //достигнута левая граница формы
begin
//определяем случайным образом новые координаты
//напрвляющего вектора прямой
a1:=random(a1Max);
a2:=-random(a2Max)+random(a2Max);
//переносим начальную точку прямой
x0:=x;
y0:=y;
angle:=0;
end
else if x>=Form1.ClientWidth-2*r
then //достигнута правая граница формы
begin
a1:=-random(a1Max);
a2:=-random(a2Max)+random(a2Max);
x0:=x;
y0:=y;
angle:=0;
end
else if y<=r
then //достигнута верхняя граница формы
begin
a1:=-random(a1Max)+random(a1Max);
a2:=-random(a2Max);
x0:=x;
y0:=y;
angle:=0;
end
else if y>=Form1.ClientHeight-2*r
then//достигнута нижняя граница формы
42
begin
a1:=-random(a1Max)+random(a1Max);
a2:=random(a2Max);
x0:=x;
y0:=y;
angle:=0;
end;
end;
else begin //если не указан вид траектории движения
Timer1.Enabled:=false; //останавливаем таймер
MessageDlg('Укажите траекторию движения',
mtWarning, [mbOk], 0);
end;
end;
end;
//обработчик нажатия на кнопку Стоп
procedure TForm1.Button3Click(Sender: TObject);
begin
Timer1.Enabled:=false; //останавливаем таймер
end;
//обработчик выбора переключателя в RadioGroup1
procedure TForm1.RadioGroup1Click(Sender: TObject);
begin
//значение угла или параметра прямой в начале движения = 0
angle:=0;
randomize;
Label2.Caption:=''; //метка пуста
//если движение по спирали интервал для таймера = 10
if RadioGroup1.ItemIndex=3
then Timer1.Interval:=10;
if RadioGroup1.ItemIndex=5
then
begin
//если движение по прямой, случайным образом
//определяем координаты направляющего вектора
a1:=-random(a1Max)+random(a1Max);
a2:=-random(a2Max)+random(a2Max);
end
else
begin
//если движение не по прямой
//восстанавливаем центр формы
x0:=Form1.ClientWidth div 2;
y0:=Form1.ClientHeight div 2;
end
end;
end.
Сноски:
1 Всякую функцию можно задать параметрическим уравнением
1 Циклоида – это кривая, описываемая тоской окружности, катящейся без скольжения по
прямой линии
2 Астроида – это замкнутая линия, являющаяся траекторией точки, лежащей на окруж-
ности радиуса r, которая катится по внутренней стороне неподвижного круга радиуса а
(a=4r)
3 Спираль Архимеда – это кривая, которая получается как траектория точки, движущей-
ся равномерно по прямой, которая вращается вокруг точки, принадлежащей этой пря-
мой. В момент движения движущаяся точка совпадает с центром вращения прямой
|