Методы TPoint
достаточно простые:
Constructor
Init
заполняет О-поля объекта; процедура
Rotate вычисляет новые координаты точки
по формулам геометрического поворота вокруг заданной оси на угол
step,
величина которого зависит от требуемой скорости вращения объекта и процедура
Show
скорее служит прототипом для дальнейшего наследования, чем для самостоятельного
использования. Роль
Destructor’a
обсуждалась ранее.
В Constructor’e
TLine
обратите внимание, что объекты
pn
и
pk
инициализируются отдельно, поскольку каждый из них должен быть связан с таблицей
VMT
типа
TPoint,
а в методе Show
значение входного параметра
col
определяет рисование или стирание линии.
Аналогично осуществляется инициализация сторон квадрата в
TSquare
и
перекрытие виртуальных методов
Show
и
Rotate собственными. После инициализации
положение квадрата соответствует верхнему левому углу экрана.
(******** Методы TPoint
********************)
Constructor TPoint .Init ( xx, yy :Real; col :Byte
);
Begin x:=xx; y:=yy; Pcolor := col; End;
{---------------------------------------------------------------}
Procedure TPoint .Rotate ( xOs,yOs :Integer );
Var xx, yy :Real;
Begin xx := (x - xOs)*Cos(step) - (y - yOs)*Sin(step) +
xOs;
yy := (x - xOs)*Sin (step) + (y - yOs)*Cos(step) +
yOs;
x :=xx; y:=yy;
End;
{---------------------------------------------------------------}
Procedure TPoint .Show ( col :Byte );
Begin PutPixel ( Round(x), Round(y), Pcolor ); End;
{---------------------------------------------------------------}
Destructor TPoint .Done;
Begin End;
(******** Методы TLine ********************)
Constructor TLine .Init ( x1,y1,x2,y2 :Real; col :Byte
);
Begin pn.Init(x1,y1,col); pk.Init(x2,y2,col);
Lcolor:=col; End;
{---------------------------------------------------------------}
Procedure TLine .Rotate ( xOs,yOs :Integer );
Begin pn.Rotate( xOs,yOs ); pk.Rotate( xOs,yOs ); End;
{---------------------------------------------------------------}
Procedure TLine .Show ( col :Byte );
Begin If col=0 Then SetColor ( col ) Else SetColor ( Lcolor
) ;
Line(Round(pn.x),Round(pn.y),Round(pk.x),Round(pk.y));
End;
{---------------------------------------------------------------}
Destructor TLine .Done;
Begin End;
(***************** Методы TSquare
****************************)
Constructor TSquare .Init ( aa, colK :Byte );
Begin
as := aa;
{ установка размера стороны квадрата}
Sides[0]. Init ( as, as, 0, as, colK ); {
инициализация сторон квадрата }
Sides[1]. Init ( 0, as, 0, 0, colK );
Sides[2]. Init ( 0, 0, as, 0, colK );
Sides[3]. Init ( as, 0, as, as, colK );
Scolor := colK;
End;
{----------------------------------------------------------------}
Procedure TSquare .Rotate ( xOs, yOs :Integer );
{
реализует вращение квадрата путем поворота каждой из его сторон вокруг оси }
Var i :Byte;
Begin For i:=0 To kv-1 Do Sides[i] .Rotate ( xOs,yOs ); End;
{----------------------------------------------------------------}
Procedure TSquare .Show( col :Byte ); {
рисует(стирает) изображение
квадрата }
Var i :Byte;
Begin For i := 0 To kv-1 Do Sides[i].Show ( col ); End;
{----------------------------------------------------------------}
Destructor TSquare .Done;
Begin End;
(***************** Методы TScreen
******************************)
Constructor TScreen .Init ( aa, colK, colG :Byte; dG
:Integer );
Var i :Byte;
Begin
GraphInit; {
инициализация графического режима VGAHi }
Inherited Init ( aa,
colK ); { инициализация родителя }
Gdisp := dG;
{ задание Y-смещения поверхности качения }
For i := 0 To kv-1 Do With Sides[i] Do Begin {перенос
квадрата на поверхность}
pn.y := pn.y + Gdisp - as;
pk.y := pk.y + Gdisp - as;
End;
Gcolor := colG;
{ задание цвета поверхности качения }
OsX := as;
OsY := Gdisp; { задание
начальных координат оси вращения }
angle := 0; { задание
начального значения угла поворота }
DrawGround; { рисование
поверхности качения }
End;
{---------------------------------------------------------------}
Procedure TScreen .GraphInit;
{ инициализация графического режима VGAHi }
Var gd, gm, ErrorCode :Integer;
Begin gd := Detect;
InitGraph ( gd, gm, '');
ErrorCode := GraphResult;
If ErrorCode <> grOk Then Begin
Writeln('Ошибка графики:', GraphErrorMsg ( ErrorCode )
);
Halt(1);
End;
End;
{---------------------------------------------------------------}
Procedure TScreen .DrawGround; {
рисование поверхности качения
}
Begin SetColor ( Gcolor );
Line ( 0, Round( Gdisp + 1 ), GetMaxX, Round( Gdisp + 1
) );
End;
{---------------------------------------------------------------}
Function TScreen .ShiftOsXY :Boolean;
{
определяет момент и реализует смещение оси вращения квадрата по оси
X}
Begin If angle >
pi/2 { если наступил
момент переноса оси поворота, }
Then Begin OsX := OsX + as; ShiftOsXY := True; End {
то сместить ось по X на as}
Else ShiftOsXY := False;
End;
{----------------------------------------------------------------------}
Procedure TScreen .Go; {реализует движение
квадрата и анимацию его изображения}
Begin
Repeat
{ цикл возобновления сцены }
Repeat { цикл качения
по поверхности и анимации }
angle := angle +
step; { накопление угла поворота}
If
ShiftOsXY { если была смена оси вращения, }
Then Begin angle:=0; Continue;
End; { то пропустить вращение и анимацию }
Rotate ( OsX,
OsY ); { вращение квадрата вокруг текущей оси
}
Show(Scolor);
{ рисует изображение квадрата }
Delay( ms
); { задержка }
Show(0); {
стирает изображение квадрата }
If KeyPressed Then Exit; { если клавиша
нажата, то выход из процедуры}
Until OsX > GetMaxX;
{ если квадрат достиг правого края экрана, то }
Init ( as, Scolor, Gcolor, Gdisp ); {
возобновление сцены }
DrawGround; {
рисование поверхности качения }
Until
False; { повторение работы до
нажатия любой клавиши }
End;
{----------------------------------------------------------------------}
Destructor TScreen .Done;
Begin CloseGraph; End; {закрытие
графического режима }
{----------------------------------------------------------------------}
Более сложные действия выполняются в
Constructor’e
TScreen.
После перехода в графический режим осуществляется инициализация квадрата
оператором Inherited
Init
( aa,
colK
); , где ключевое слово
Inherited
означает – унаследованный, то есть
происходит вызов
Constructor’a
типа
TSquare.
Отметим, что вызов унаследованного
Constructor’a
при проектировании
Constructor’ов дочерних типов
считается хорошим стилем в ООП-программировании. Далее квадрат
«устанавливается» на поверхность качения путем коррекции координат
Y
его вершин на величину смещения этой
поверхности на экране. Обратите внимание на оператор
With,
который, как и при обработке записей, позволяет вынести имя объекта в заголовок
и избавляет от необходимости писать длинные составные имена. После этого
назначаются координаты оси вращения
OsX,
OsY,
совпадающие с координатами вершины 1 квадрата (см. рис. 8). Поскольку рисунок
рельефа является статической частью сцены и, при движении квадрата остается
неизменной, в конце процедуры следует прорисовка поверхности виртуальным
методом DrawGround.
Виртуальность метода обусловлена возможностью изменения формы (а значит и метода
прорисовки) поверхности качения у потомков. По этой же причине виртуальны метод
ShifOsXY(
контролирующий положение оси вращения по мере движения квадрата по поверхности)
и метод Go.
В последнем реализуются основные действия, происходящие на экране. Метод состоит
из двух вложенных циклов: во внутреннем моделируется качение квадрата начиная с
левого края до правого края экрана и анимация его изображения, во внешнем –
обновление всей сцены и повторение указанных действий. Остальные подробности
алгоритмов описанных методов даны в приведенных их текстах. |