|
Использование надстроек над OpenGL
Простой и эффективный алгоритм скелетной анимации с обратной кинематикой
Хитрости MAX Script для записи движений в файл
Простой 2D движок для игр по типу Дигера и графического NetHack
2D графика
Использование Microsoft Agent в Delphi
Фенечки
GLScene - создай свою 3D игру.
САГА О ГЛЮКАХ
Использование надстроек над OpenGL.
Автор: Константин Артемьев
Признайтесь, что на "чистом" OpenGL программировать не всегда
приятно. Много рутинной работы. А вспомните, как было хорошо в
3D Studio! Тягаешь туда-сюда, что надо, загружаешь разные форматы,
изменяешь, поворачиваешь... Вы скажете, что это неудачные параллели?
А нельзя ли превратить процесс работы с OpenGL тоже в своего рода
конструктор? Оказывается, можно. Существуют так называемые надстройки
над OpenGL. С помощью них можно легко манипулировать объектами,
загружать их из разных форматов и делать ещё много чего, свойственного
только конструкторам. Если это вас заинтересовало, то я могу порекомендовать
две надстройки. На сайте http://www.mda.hotmail.ru/ TSceneGL, а на
сайте glscene.org
(не пугайтесь, сайт не на немецком!) скачайте GLScene. Между прочим,
всё это под Delphi.
Простой и эффективный алгоритм скелетной
анимации
Автор: Константин Артемьев
Ну вот, теперь об алгоритме скелетной анимации без скелета. Как
так? А вот так- для хорошей анимации вам даже не нужно создавать
скелетов! Делаем так... Создаём наш родной скелет с мясом в 3DS
MAX, анимируем, всё, как обычно. Дальше расчленяем полученное
чучело на составные части (шея-пятка-кисть). С помощью MAX Script
пишем программу, которая последовательно выводит каждый кадр (как
писать - см. в след. статье) в файл по такому принципу xположение
yположение zположение xповорот yповорот zповорот-левая
кисть xположение yположение zположение xповорот yповорот
zповорот-правая кисть xположение yположение zположение xповорот
yповорот zповорот-шея ......... и т.д. Потом пишите в своей крутой
игре или проге алгоритм обработки этого файла. ПРОСТО, БЫСТРО,
ЭФФЕКТИВНО.
Хитрости MAX Script для записи движений
в файл
Автор: Константин Артемьев
Вот некоторые нужные команды:
f=openfile "c:\a.txt" mode:"a" //Открываем файл, если не существует, то
создаём print "agh" to: f
//Заносим в файл данные
(-: box.width=10 //меняем ширину бокса
a = $box.transform.rotationpart as
eulerAngles; //Присваиваем а значение
угла поворота бокса rx = a.x
//Выделяем в отдельные переменные составляющие угла ry= a.y
//поворота объекта по соответствующим осям в градусах rz= a.z b = $box.pos
//Выделяем позицию бокса mx=
b.x
//Выделяем составные координаты боксы my= b.y mz= b.z
Надеюсь, этой информации вам хватит, чтобы написать полноценный
скрипт.
Внимание! Если у вас русифицированный МАХ, то советую не использовать
в именах объектов русские буквы! Русификаторы, похоже попытались
перевести и сам язык программирования, а что в этом случае происходит,
мы знаем на примере Паскаля.
Простой 2D движок для игр по типу Дигера
и графического NetHack
Автор: Константин Артемьев
Просто, быстро, надёжно. Достаточно, чтобы быстро
создать двумерную игрушку. Игровое поле представлено массивом. Решите какого
размера поле вам нужно. Далее в тексте, SX - ширина поля в клетках, SY - длина
поля в клетках. Выбирите размер каждой клетки, PX и PY - длина и ширина клетки в
пикселах. Размещаете Image на форму. Ставите ему ширину = SX*PX, SY*PY - длина.
Ставите на форму таймер. Задержка = подберёте сами, она влияет на скорость
движка. Далее пишем:>
В начале кода
.........................
implementation
var
Form1:TForm1;
mas:array[1..SX,1..SY] of char;
mask:array[1..SX,1..SY] of char;
..................................
timer1.ontimer(sender:tobject);//Реализуем сам движок
var
x,y,xu,yu:integer;
bit:tbitmap;
begin
xu:=-PX;
yu:=-PY;
for x:=1 to SX do begin
xu:=xu+PX;
for y:=1 to SY do begin
yu:=yu+PY;
if yu=PY*SY then yu:=0;
if mas[x,y]<>mask[x,y] then
begin
//Если с прошлого вывода клетка не изменялась, то
bit:=tbitmap.create;
//незачем прорисовывать её снова,
bit.loadfromfile(mas[x,y]+'.bmp');
//это экономит ресурсы
image1.canvas.draw(ux,uy,bit);
end;
end;
end;
for x:=1 to SX do begin
//Эта часть обеспечивает ускорение движка
for y:=1 to SY do begin
//Без этого всё будет тормозить при больших картах
mask[x,y]:=mas[x,y]
end;
end;
end;
Условьтесь, что, например А - это дерево, и создайте битмэп А.bmp
с изображением дерева и размерами PX на PY пикселов; В - это земля;
С-это человек и т.д. Вот участок примерного массива:
1 2 3
1 АВВ
2 ВСВ
3 ВАВ
Допустим, мы хотим, чтобы человек с клетки 22 передвинулся на клетку
23. Значит мы должны написать:
mas[2,2]:='B'; //На месте, где стоял человек, ставим землю, иначе
он раздвоится
mas[2,3]:='C';
Вот и всё. Остальное сделает движок.
2D Графика
Luchkin Alexey
От авторов ...
Данный файл содержит обобщенную
и апробированную авторами информацию по решению некоторых задач,
возникающих при программировании на Delphi. Мы не претендуем на
авторство, вся эта информация собрана из различных источников,
но все примеры и советы, приведенные здесь были предварительно
проверены под разными версиями Delphi, поэтому особое внимание
следует обратить на примечания относительно версии, для которой
это разработано или проверено.
Как
работать с палитрой в Delphi? На форме установлен TImage и видна
картинка (*.BMP файл), как изменить у
него палитру цветов ?
Палитра в TBitmap и TMetaFile доступна
через property Palette. Если палитра имеется (что совсем необязательно), то
Palette<>0: procedure TMain.BitBtnClick(Sender:
TObject); var Palette : HPalette; PaletteSize : Integer; LogSize:
Integer; LogPalette: PLogPalette; Red : Byte; begin Palette :=
Image.Picture.Bitmap.ReleasePalette; // здесь можно использовать просто
Image.Picture.Bitmap.Palette, но я не // знаю, удаляются ли ненужные палитры
автоматически
if Palette=0 then exit; //Палитра
отсутствует PaletteSize := 0; if GetObject(Palette, SizeOf(PaletteSize),
@PaletteSize) = 0 then Exit; // Количество элементов в палитре =
paletteSize if PaletteSize = 0 then Exit; // палитра пустая // определение
размера палитры LogSize := SizeOf(TLogPalette) + (PaletteSize - 1) *
SizeOf(TPaletteEntry); GetMem(LogPalette, LogSize); try // заполнение
полей логической палитры with LogPalette^ do begin palVersion := $0300;
palNumEntries := PaletteSize; GetPaletteEntries(Palette, 0, PaletteSize,
palPalEntry); // делаете что нужно с палитрой, например: Red :=
palPalEntry[PaletteSize-1].peRed; Edit1.Text := 'Красная составляющего
последнего элемента палитры
='+IntToStr(Red); palPalEntry[PaletteSize-1].peRed :=
0; //....................................... end; // завершение
работы Image.Picture.Bitmap.Palette :=
CreatePalette(LogPalette^); finally FreeMem(LogPalette, LogSize); // я
должен позаботиться сам об удалении Released
Palette DeleteObject(Palette); end; end;
{ Этот модуль
заполняет фон формы рисунком bor6.bmp (256 цветов) и меняет его палитру при
нажатии кнопки } unit bmpformu; interface uses Windows, Messages,
SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type TBmpForm = class(TForm) Button1:
TButton; procedure FormDestroy(Sender: TObject); procedure
FormPaint(Sender: TObject); procedure Button1Click(Sender:
TObject); procedure FormCreate(Sender: TObject); private Bitmap:
TBitmap; procedure ScrambleBitmap; procedure WMEraseBkgnd(var m:
TWMEraseBkgnd); message WM_ERASEBKGND; end;
var BmpForm:
TBmpForm;
implementation {$R *.DFM} procedure
TBmpForm.FormCreate(Sender: TObject); begin Bitmap :=
TBitmap.Create; Bitmap.LoadFromFile('bor6.bmp'); end;
procedure
TBmpForm.FormDestroy(Sender:
TObject); begin Bitmap.Free; end;
// since we're going to be
painting the whole form, handling this // message will suppress the
uneccessary repainting of the background // which can result in
flicker. procedure TBmpform.WMEraseBkgnd(var m :
TWMEraseBkgnd); begin m.Result := LRESULT(False); end;
procedure
TBmpForm.FormPaint(Sender: TObject); var x, y: Integer; begin y :=
0; while y < Height do begin x := 0; while x < Width do
begin Canvas.Draw(x, y, Bitmap); x := x + Bitmap.Width; end; y := y
+ Bitmap.Height; end; end;
procedure TBmpForm.Button1Click(Sender:
TObject); begin ScrambleBitmap; Invalidate; end;
// scrambling
the bitmap is easy when it's has 256 colors: // we just need to change each
of the color in the palette // to some other value. procedure
TBmpForm.ScrambleBitmap; var pal: PLogPalette; hpal: HPALETTE; i:
Integer; begin pal := nil; try GetMem(pal, sizeof(TLogPalette) +
sizeof(TPaletteEntry) * 255); pal.palVersion := $300; pal.palNumEntries :=
256; for i := 0 to 255 do begin pal.palPalEntry[i].peRed :=
Random(255); pal.palPalEntry[i].peGreen :=
Random(255); pal.palPalEntry[i].peBlue := Random(255); end; hpal :=
CreatePalette(pal^); if hpal <> 0 then Bitmap.Palette :=
hpal; finally FreeMem(pal); end; end;
end.
Заполняет
Canvas рисунком с рабочего стола, учитывая координаты.
Function PaintDesktop(HDC) :
boolean; Например: PaintDesktop(form1.Canvas.Handle);
Как вставить растровое
изображение в компонент ListBox?
Для этого необходимо установить в
инспекторе объектов поле Style в lbOwnerDrawFixed, при фиксированной высоте
строки, или в lbOwnerDrawVariable, при переменной, и установить собственный
обработчик события для OnDrawItem. В этом обработчике и надо рисовать растровое
изображение. Пример: Рисуются изображения размером 32*16 (размер
стандартного глифа для Delphi). Очень полезно при поиске нужного изображения для
кнопок! Установить в инспекторе объектов для ListBox поле ItemHeight = 19, а
поле Color = clBtnFace. { Загрузить список
файлов в ListBox1 при нажатии на кнопку Load (например)} procedure
TForm1.bLoadClick(Sender: TObject); VAR S :
String; begin ListBox1.Clear; {чистим список} S := '*.bmp'#0; {задаем
шаблон} ListBox1.Perform(LB_DIR, DDL_ReadWrite, Longint(@S[1])); {заполняем
список} end; ............
{Отобразить изображения и имена файлов в
ListBox} procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index:
Integer; Rect: TRect; State: DrawState); VAR Bitmap :
TBitmap; Offset : Integer; BMPRect: TRect; begin WITH (Control AS
TListBox).Canvas DO BEGIN FillRect(Rect); Bitmap :=
TBitmap.Create; Bitmap.LoadFromFile(ListBox1.Items[Index]); Offset :=
0; IF Bitmap <> NIL THEN BEGIN BMPRect := Bounds(Rect.Left+2,
Rect.Top+2, (Rect.Bottom-Rect.Top-2)*2,
Rect.Bottom-Rect.Top-2); {StretchDraw(BMPRect, Bitmap); Можно просто
нарисовать, но лучше сначала убрать фон} BrushCopy(BMPRect,Bitmap, Bounds(0,
0, Bitmap.Width, Bitmap.Height), Bitmap.Canvas.Pixels[0,
Bitmap.Height-1]); Offset :=
(Rect.Bottom-Rect.Top+1)*2; END; TextOut(Rect.Left+Offset, Rect.Top,
ListBox1.Items[Index]); Bitmap.Free; END; end;
Данный пример
работает медленно, но оптимизация, для ускорения, вызвала бы трудность в
понимании общего принципа его работы.
Можно ли из Delphi рисовать в любой
части экрана или в чужом окне?
Для этого надо воспользоваться функциями
API. Получить контекст чужого окна, либо всего экрана: function GetDC(Wnd:
HWnd): HDC; где Wnd - указатель на нужное окно, или 0 для получения контекста
всего экрана. И далее, пользуясь функциями API, нарисовать все что
надо. Пример:
PROCEDURE DrawOnScreen; VAR ScreenDC:
hDC; BEGIN ScreenDC := GetDC(0); {получить контекст
экрана} Ellipse(ScreenDC, 0, 0, 200, 200);
{нарисовать} ReleaseDC(0,ScreenDC); {освободить контекст} END;
Не
забывайте после своих манипуляций посылать пострадавшим (или всем) окнам
сообщение о необходимости перерисовки, для восстановления их первоначального
вида.
Написание текста под углом
{ Эта процедура устанавливает угол вывода
текста для указанного Canvas, угол в градусах } { Шрифт
должен быть TrueType ! } procedure CanvasSetTextAngle(c: TCanvas; d:
single); var LogRec: TLOGFONT; {
Информация о шрифте } begin {Читаем текущюю инф. о шрифте
} GetObject(c.Font.Handle,SizeOf(LogRec) ,Addr(LogRec) ); { Изменяем угол
} LogRec.lfEscapement := round(d*10); { Устанавливаем новые параметры
} c.Font.Handle := CreateFontIndirect(LogRec); end;
Преобразование цвета RGB <-> HLS
{ Максимальные значения
} Const HLSMAX = 240; RGBMAX = 255; UNDEFINED = (HLSMAX*2) div
3; Var H, L, S : integer; { H-оттенок, L-яркость, S-насыщенность } R,
G, B : integer; { цвета }
procedure RGBtoHLS; Var cMax,cMin :
integer; Rdelta,Gdelta,Bdelta : single; Begin cMax := max( max(R,G),
B); cMin := min( min(R,G), B); L := round( ( ((cMax+cMin)*HLSMAX) + RGBMAX
)/(2*RGBMAX) );
if (cMax = cMin) then begin S := 0; H :=
UNDEFINED; end else begin if (L <= (HLSMAX/2)) then S := round( (
((cMax-cMin)*HLSMAX) + ((cMax+cMin)/2) ) / (cMax+cMin) ) else S := round(
( ((cMax-cMin)*HLSMAX) + ((2*RGBMAX-cMax-cMin)/2) ) / (2*RGBMAX-cMax-cMin)
); Rdelta := ( ((cMax-R)*(HLSMAX/6)) + ((cMax-cMin)/2) ) /
(cMax-cMin); Gdelta := ( ((cMax-G)*(HLSMAX/6)) + ((cMax-cMin)/2) ) /
(cMax-cMin); Bdelta := ( ((cMax-B)*(HLSMAX/6)) + ((cMax-cMin)/2) ) /
(cMax-cMin); if (R = cMax) then H := round(Bdelta - Gdelta) else if (G =
cMax) then H := round( (HLSMAX/3) + Rdelta - Bdelta) else H := round(
((2*HLSMAX)/3) + Gdelta - Rdelta ); if (H < 0) then H:=H + HLSMAX; if
(H > HLSMAX) then H:= H - HLSMAX; end; if S<0 then S:=0; if
S>HLSMAX then S:=HLSMAX; if L<0 then L:=0; if L>HLSMAX then
L:=HLSMAX; end;
procedure HLStoRGB; Var Magic1,Magic2 :
single;
function HueToRGB(n1,n2,hue : single) : single; begin if
(hue < 0) then hue := hue+HLSMAX; if (hue > HLSMAX) then hue:=hue
-HLSMAX; if (hue < (HLSMAX/6)) then result:= ( n1 +
(((n2-n1)*hue+(HLSMAX/12))/(HLSMAX/6)) ) else if (hue < (HLSMAX/2))
then result:=n2 else if (hue < ((HLSMAX*2)/3)) then result:= ( n1 +
(((n2-n1)*(((HLSMAX*2)/3)-hue)+(HLSMAX/12))/(HLSMAX/6))) else result:= ( n1
); end;
begin if (S = 0) then begin B:=round( (L*RGBMAX)/HLSMAX
); R:=B; G:=B; end else begin if (L <= (HLSMAX/2)) then Magic2 :=
(L*(HLSMAX + S) + (HLSMAX/2))/HLSMAX else Magic2 := L + S - ((L*S) +
(HLSMAX/2))/HLSMAX; Magic1 := 2*L-Magic2; R := round(
(HueToRGB(Magic1,Magic2,H+(HLSMAX/3))*RGBMAX + (HLSMAX/2))/HLSMAX ); G :=
round( (HueToRGB(Magic1,Magic2,H)*RGBMAX + (HLSMAX/2)) / HLSMAX ); B :=
round( (HueToRGB(Magic1,Magic2,H-(HLSMAX/3))*RGBMAX + (HLSMAX/2))/HLSMAX
); end; if R<0 then R:=0; if R>RGBMAX then R:=RGBMAX; if G<0
then G:=0; if G>RGBMAX then G:=RGBMAX; if B<0 then B:=0; if B>RGBMAX
then B:=RGBMAX; end;
Число цветов (цветовая палитра) у данного
компьютера
Эта функция возвращает число бит на точку
у данного компьютера. Так, например, 8 - 256 цветов, 4 - 16 цветов
...
function GetDisplayColors : integer; var tHDC :
hdc; begin tHDC:=GetDC(0); result:=GetDeviceCaps(tHDC, 12)*
GetDeviceCaps(tHDC, 14); ReleaseDC(0, tHDC); end;
Копирование экрана
unit ScrnCap; interface uses
WinTypes, WinProcs, Forms, Classes, Graphics, Controls;
{ Копирует
прямоугольную область экрана } function CaptureScreenRect(ARect : TRect) :
TBitmap; { Копирование всего экрана } function CaptureScreen :
TBitmap; { Копирование клиентской области формы или элемента } function
CaptureClientImage(Control : TControl) : TBitmap; { Копирование всей формы
элемента } function CaptureControlImage(Control : TControl) :
TBitmap;
{==================================================} implementation function
GetSystemPalette : HPalette; var PaletteSize : integer; LogSize :
integer; LogPalette : PLogPalette; DC : HDC; Focus :
HWND; begin result:=0; Focus:=GetFocus; DC:=GetDC(Focus); try PaletteSize:=GetDeviceCaps(DC,
SIZEPALETTE); LogSize:=SizeOf(TLogPalette)+(PaletteSize-1)*SizeOf(TPaletteEntry); GetMem(LogPalette,
LogSize); try with LogPalette^
do begin palVersion:=$0300; palNumEntries:=PaletteSize; GetSystemPaletteEntries(DC,
0, PaletteSize,
palPalEntry); end; result:=CreatePalette(LogPalette^); finally FreeMem(LogPalette,
LogSize); end; finally ReleaseDC(Focus,
DC); end; end;
function CaptureScreenRect(ARect : TRect) :
TBitmap; var ScreenDC : HDC; begin Result:=TBitmap.Create; with
result, ARect do
begin Width:=Right-Left; Height:=Bottom-Top; ScreenDC:=GetDC(0); try BitBlt(Canvas.Handle,
0,0,Width,Height,ScreenDC, Left, Top, SRCCOPY
); finally ReleaseDC(0,
ScreenDC); end; Palette:=GetSystemPalette; end; end;
function
CaptureScreen : TBitmap; begin with Screen
do Result:=CaptureScreenRect(Rect(0,0,Width,Height)); end;
function
CaptureClientImage(Control : TControl) : TBitmap; begin with Control,
Control.ClientOrigin
do result:=CaptureScreenRect(Bounds(X,Y,ClientWidth,ClientHeight)); end;
function
CaptureControlImage(Control : TControl) : TBitmap; begin with Control
do if Parent=Nil
then result:=CaptureScreenRect(Bounds(Left,Top,Width,Height)) else with
Parent.ClientToScreen(Point(Left, Top))
do result:=CaptureScreenRect(Bounds(X,Y,Width,Height)); end; end.
Draw disable text
{************************ Draw Disabled
Text ************** ***** This function draws text in "disabled" style.
***** ***** i.e. the text is grayed .
***** **********************************************************} function
DrawDisabledText (Canvas : tCanvas; Str: PChar; Count: Integer; var Rect:
TRect; Format: Word): Integer; begin SetBkMode(Canvas.Handle,
TRANSPARENT);
OffsetRect(Rect, 1, 1); Canvas.Font.color:=
ClbtnHighlight; DrawText (Canvas.Handle, Str, Count,
Rect,Format);
Canvas.Font.Color:= ClbtnShadow; OffsetRect(Rect, -1,
-1); DrawText (Canvas.Handle, Str, Count, Rect,
Format); end;
Как менять разрешение экрана по ходу
выполнения программы
function SetFullscreenMode:Boolean; var
DeviceMode : TDevMode; begin with DeviceMode do
begin dmSize:=SizeOf(DeviceMode); dmBitsPerPel:=16; dmPelsWidth:=640; dmPelsHeight:=480; dmFields:=DM_BITSPERPEL
or DM_PELSWIDTH or DM_PELSHEIGHT; result:=False; if
ChangeDisplaySettings(DeviceMode,CDS_TEST or CDS_FULLSCREEN) <>
DISP_CHANGE_SUCCESSFUL then
Exit; Result:=ChangeDisplaySettings(DeviceMode,CDS_FULLSCREEN) =
DISP_CHANGE_SUCCESSFUL; end; end;
procedure
RestoreDefaultMode; var T : TDevMode absolute
0; begin ChangeDisplaySettings(T,CDS_FULLSCREEN); end;
procedure
TForm1.Button1Click(Sender: TObject); begin if setFullScreenMode then
begin sleep(7000); RestoreDefaultMode; end; end;
Как поместить картинку из базы данных,
например MsSQL, в компонент TIMAGE ?
1) Предполагается, что поле BLOB
(например, Pict) 2) в запросе Query.SQL пишется что-то вроде 'select Pict
from sometable where somefield=somevalue' 3) запрос открывается 4)
делается
"присваивание": Image1.Picture.Assing(TBlobField(Query.FieldByName('Pict')) или,
если известно, что эта картинка - Bitmap, то
можно Image1.Picture.Bitmap.Assing(TBlobField(Query.FieldByName('Pict'))
А
можно воспользоваться компонентом TDBImage.
lel@dts.ru
Часть 1 Введение Иногда хочется сделать свои приложения более
красивыми, интерактивными, т.е. добавить в них дополнительные и необычные
возможности. Неужели компания Microsoft не сделала, для разработчиков никаких
подобных средств? Сделала и очень даже неплохое, называется эта технология
Microsoft Agent. Microsoft Agent - сервис, который позволяет использовать
интерактивных анимированных персонажей для улучшения интерфейса ваших
приложений. Разработчики могут использовать эти персонажи как интерактивных
помощников в своих программах, примером такого персонажа является всем известная
скрепка в пакете Microsoft Office. Агенты могут также внедряться в ваши
Веб-страницы. И естественно было бы совсем неправильно, если бы такое хорошее
средство обошло стороной программистов использующих Delphi. Но благодаря тому,
что в Delphi имеется прекрасные возможности работы с COM технологиями,
использование агентов в Delphi превращается в приятное развлечение. Для
начала работы с агентами, вам естественно нужно установить MS Agent (Microsoft
Agent входит в состав операционной системы WINDOWS 2000), скачать его можно
отсюда
MsAgent (395 кб)
также для работы понадобится
какой-нибудь характер (Microsoft свободно распостаняет 4), их вы можете найти,
тут же (а также и другие расширения MsAgent):
Скачать jenni.acs
(3,9Мб)
http://msdn.microsoft.com/workshop/imedia/agent/agentdl.asp или
http://agentry.net http://www.rohitab.com/freevoice/gallery.html http://www.msagentring.org
отличные
агенты на
http://desktopmates.com/gallery.html
но это
за деньги, у меня есть полная версия jenni (демонстрационная версия с урезанными
анимациями доступна на сайте), которая на картинке , мне прислал один хороший
человек из за бугра. И если кто то видел где то других агентов этой фирмы
(свободных для скачивания) или купил их, просьба выслать мне или сообщить, где
можно их взять.
Неплохие агенты находятся на корейском
сайте
http://www.staravatar.co.kr/member/index.asp
Но будем
считать , что вы сделали все действия и успешно установили MSAgent у себя в
системе , что же нужно сделать , чтобы использовать его в Delphi.Все очень
просто, нужно просто импортировать библиотеку типов tlb. Эту операцию опишу
поподробней.
Запускаете Delphi, в меню выбираете в
меню:
Component->Import ActiveX Control.
Дальше выбираете
из списка Microsoft Agent Control 2.0 и нажимаете Install. Потом выберети
переключатель в новый пакет, введи названия пакета(MsAgent.dpk) и название
палитры(это как угодно, у меня стоит в палитре ActiveX), описания пакета если
нужно и жмете ОК. Все значок агента, должен появиться у Вас в
палитре.
Теперь кидайте компонент на форму и можете уже писать приложения
с использованием агентов.
А вот и пример, создайте новый проект, киньте
компонент агента, вставьте приведенный ниже код и наслаждайтесь как ваш агент
бегает по экрану.
unit Unit1; interface uses Windows, Messages,
SysUtils, Classes, Graphics, Forms, AgentObjects_TLB, Controls, OleCtrls
; type TForm1 = class(TForm) Agent1: TAgent; procedure
FormCreate(Sender: TObject); private { Private declarations } procedure
WaitFor(Request:IAgentCtlRequest); public { Public declarations
} end; var Form1: TForm1;
implementation {$R
*.DFM} var Character:IAgentCtlCharacter; Request:
IAgentCtlRequest; Const AGENT ='nn'; AGENTPATH = 'D:\Chars\nn.acs'; //
здесь нужно прописать путь где находится ваш агент
procedure
TForm1.WaitFor(Request:IAgentCtlRequest); var Status:LongInt; begin repeat Application.ProcessMessages; Status
:= Request.Get_Status; until (Status <> 2) and (Status <>
4); end;
procedure TForm1.FormCreate(Sender:
TObject); begin Agent1.Connected:=true; Request:=Agent1.Characters.Load(Agent,AgentPath); Character:=Agent1.Characters.Character(Agent); Request
:= Character.MoveTo(640,365, 0); Request :=
Character.Show(False); WaitFor(Request); Request :=
Character.Speak('Привет',EmptyParam); Request :=
Character.Play('Greet'); Request := Character.MoveTo(0,365, 1500); Request
:= Character.Play('Announce'); Request := Character.MoveTo(0,0,
1500); Request := Character.Play('Suggest'); Request :=
Character.MoveTo(300,300, 1500); Request := Character.MoveTo(100,300,
1500); Request :=
Character.GestureAt(800,300); end; end.
Каждый агент имеет
определенное количество поддерживаемых анимаций, их вы можете узнать или на
сайте разработчика, или в документации к агенту. Также ваши агенты могут
разговаривать с Вами, если вы установите соответствующие компоненты. Анимации
используемые в примере поддерживаются как правило всеми агентами, если у вас
возникнут проблемы с выполнением данного кода, просто удалите строчку, на
которую ругается компилятор.
На этом я заканчиваю ознакомительную часть
по работе с агентами в Delphi, в следующих частях я расскажу по подробнее о том
что делает приведенный здесь пример и естественно расширю его функциональность,
мы рассмотрим свойства, методы, события, ошибки анимации. Нетерпеливых сразу
отошлю к MSDN, где подробно описаны возможности использования технологии
MSAgent.
Если вы тоже, как и я стали фанатом MSAgent, вы можете
подписаться на эхо-конференции посвященные этой
технологии
spacemans.ne.mediaone.net
microsoft.agent.fun
msnews.microsoft.com
microsoft.public.msagent
Кроме того вы можете сами стать разработчиком
персонажей для MSAgent, подробности найдете все на том же сайте
Microsoft.
Если вы до конца прочитали эту статью, то добро
пожаловать в мир агентов. С удовольствием выслушаю все комментария, замечание по
поводу данной статьи.
Использование Microsoft Agent в Delphi Часть
2 Свойства, события и методы В прошлой статье я обещал рассказать про
события, свойства и методы агентов, но что ж начнем. Опубликованных свойств
всего 11, из них нам интересны только 2, остальные являются наследуемыми и Вы не
раз сталкивались с ними.
Connected: Показывает или устанавливает
соединение с сервером управления Агента, если True соединение
установлено.
RaiseRequestErrors: Это свойство включает генерацию
ошибок (по умолчанию True). Например, если ваш агент не поддерживает анимацию,
которую вы хотите использовать, будет возбуждена ошибка (и показана на экране)
если значения свойства True (Истина).
Теперь рассмотрим события, их
гораздо больше, а точнее 26, но и в кратце о них, а о некоторых, даже и
поподробней:
OnClick: Ну это и понятно, когда кликнете на агенте
мышкой.
OnDblClick: При двойном клике.
OnDragStart: При начале
перетаскивания агента.
OnDragComplete: При завершение
перетаскивания.
OnShow: Агент появился на экране.
OnHide:
Агент скрыт с экрана.
OnRequestStart: Начало выполнения
запроса.
OnRequestComplete: Запрос выполнен.
OnRestart: Не знаю,
применения этому событию , я пока не нашел, если кто узнает для чего это просьба
сообщить мне.
OnShutdown: Пользователь закрыл MSAgent.
OnBookmark:
В команде speak достигнут тэг закладки.
OnCommand: Пользователь выбрал
команду в сплывающем меню или голосом.
OnIdleStart: При впадение агента в
спячку.
OnIdleComplete: При прекращение спячки агента.
OnMove:
Агент перемещен.
OnSize: Изменены размеры агента.
OnBalloonShow:
Область текста показана.
OnBalloonHide: : Область текста
скрыта.
OnHelpComplete: Пользователь вышел из
справки.
OnListenStart: Начало выполнение метода
Listen.
OnListenComplete:Метод Listen
завершен.
OnDefaultCharacterChange: Свойства агента по умолчанию
изменены.
OnAgentPropertyChange: Свойства агента
изменены.
OnActiveClientChange: Активная клиентская область
изменена.
OnActivateInput: Ввод активирован.
OnDeactivateInput:
Ввод деактивирован.
В примере вы можете посмотреть какие события, когда
происходят.
Теперь рассмотрим основные методы агента, большую часть из
них я использовал в примере к прошлой статье и вы должны быть с ними
знакомы.
Show(Fast: OleVariant): IAgentCtlRequest; Выводит
изображения агента на экран, ее единственный параметр, опрделяет показывать
агента с анимацией(False) или сразу(True). Request :=
Character.Show(False);
Hide(Fast: OleVariant):
IAgentCtlRequest; Скрывает изображения агента с экрана, его параметр
аналогичен по свойству и целям параметру метода Show. Request :=
Character.Hide(False);
MoveTo(x: Smallint; y: Smallint; Speed:
OleVariant): IAgentCtlRequest; Перемещает фигурку агента в заданные
координаты экрана в параметрах x,y и с заданной скоростью перемещения параметром
Speed. Если параметр 0 персонаж сразу же окажеться в указонном месте экрана. Чем
больше число Speed, тем медленее персонаж будет перемещаться. Во время движения
проигрываеться анимации группы Moving. Request := Character.MoveTo(640,365,
0);
GestureAt(x: Smallint; y: Smallint): IAgentCtlRequest; При
выполнение этого метода агент указывает в направление заданных координат экрана
параметрами x,y. При этом используется определенный набор анимаций, который вы
также можете использовать в методе Play. Request := Character. GestureAt(0,
0);
Play(const Animation: WideString): IAgentCtlRequest; Метод Play
проигрывает указанную анимацию , название которой передается строкой в параметре
Animation. Request := Character.Play('Announce');
Speak(Text:
OleVariant; Url: OleVariant): IAgentCtlRequest; Проговаривает фразу , первый
параметр задает текст который будет в окно вывода Baloon, а второй параметр
задает имя файла или адрес URL где находится аудиофайла с помощью которого может
быть произнесена эта фраза. Любой из параметров необязателен, но один параметр
нужно задать. Если второй параметр не задан и установлен звуковой движок агента,
звук будет сгенерирован в соответствие с текстом. Также первый параметр может
содержать теги Speech MSAgent, которые задают свойства произносимого текста, о
них поподробнее.Пишутся все теги в заключенными в обратные слеши, всего их
11.Некотрые персонажи могут не поддерживать определенные теги, и все теги
требуют установленный движок TTS. Chr, Ctx, Emp, Lst, Map, Mrk, Pau, Pit,
Rst, Spd, Vol Chr Определяет тон произносимого текста "Normal" По
умолчанию нормальный голос "Monotone" Монотонно. "Whisper"
Шепотом. \Chr="Monotone"\ Ctx Опрделяет значения произносимого после
этого текста ,используется для сокращений ,адресов. "Address" Адреса и/или
телефонные номераone. "Email" Электронная почта. "Unknown" По
умолчанию значение неизвестно. \Ctx="Addres"\ Emp На следующем за
ним слове будет сделано ударение. \Emp\ Lst Произнесенный текст будет
повторен. \Lst\ Map Позволяет произносить один текст, а выводить в
рамку текста Balloon другой. Первый параметр произносимый текст, второй текст
в рамке. \Map="Привет"="Здраствуй" Mrk Устанавливает закладку в
тексте. Когда тег закладки достигнут происходит событие
onBookMark. \Mrk=1\ Pau Пауза, параметр должен содержать число
миллисекунд длительности паузы \Pau=1000\ Pit Устанавливает частоту
произносимого текста в Герцах \Pit=22400\ Rst Сбрасывает и
устанавливает значения по умолчанию для всех
тегов. \Rst\ Spd Устанвливает среднюю скорость произносимых слов в
минуту. \Spd=100\ Vol Устанавливает громкость произносимого текста,
значение параметра от 0 до 65535. \Vol=4000\ Request :=
Character.Speak('Привет \Mrk=1\ ну ты и мужик',EmptyParam);
Think(const
Text: WideString): IAgentCtlRequest; Параметр задает текст, а ваш персонаж
делает вид , что думает, текст появляется в чуть измененом окне Balloon, а
звукового сопровождения при этом нет. Request := Character.Think('и это
жизнь.');
Wait(const WaitForRequest: IDispatch):
IAgentCtlRequest; Указывает на запрос другого агента, завершения которого
ожидает второй персонаж. Используйте этот метод только, когда вы используете
одновременно нескольких персонажей и вам нужно следить за их взаимодействие. Для
единственного персонажа каждый запрос анимации запускаются последовательно -
после того, как предыдущий запрос завершается. Это выглядит примерно
так. var Character2:IAgentCtlCharacterEx; Request1:
IAgentCtlRequest; Request11:
IAgentCtlRequest; Character1:IAgentCtlCharacterEx; Request2:
IAgentCtlRequest; Request22:
IAgentCtlRequest; Begin Request1:=Agent1.Characters.Load(Agent1,AgentPath1); Character1:=Agent1.Characters.Character(Agent1); Request2:=Agent1.Characters.Load(Agent2,AgentPath2); Character2:=Agent1.Characters.Character(Agent2); Request1
:= Character1.Show(False); Request2 :=
Character2.Show(False); Character2.Wait(Character1.Speak ('Сколько
время???')); Request2 := Character2.Think('Да
уж...'); End;
Напоследок код который определяет все возможные
анимации агента, для этого нужно добавить в uses модуль ActiveX и использовать
интерфейс IagentCtlCharacterEx, использую код который мне прислал Илья Троицкий,
но если он будет против, могу выложить свой, просто его код получился короче и
понятнее моего, хотя смысл точно такой же. procedure
TForm1.Button1Click(Sender: TObject); var AnimNames:
IAgentCtlAnimationNames; Enum: IEnumVariant; Str: OleVariant; Len:
LongWord; begin AnimNames := Character.AnimationNames; Enum :=
AnimNames.Enum as IEnumVariant; Len := 0; While (Succeeded(Enum.Next(1,
Str, Len)) and (Len >
0))do ListBox1.Items.Add(String(Str)); end;
Ну вот и все...на
данный момент....А то много получилось... В следующей части мы рассмотрим
интерфейсы MSAgent и все, что с этим связано, а также я выложу пример ко второй
и третьей части. Вообщем ждите...
С удовольствием выслушаю все
комментария и замечания по поводу данной статьи. Сразу хочу предупредить, я не
отвечаю на письма где меня просят выслать что либо или будет ли продолжение(и
подобные письма не несущие какой-то содержательной части), я их читаю, но
отвечать на них у меня времени нет. Также , если кто обнаружит неточности, да и
просто грамматические ошибки в статье, за это прошу заранее извинение.
ФЕНЕЧКИ
kovalev@mcsa.ru
Немного об пользовательских интерфейсах. Часть 1. Когда я
возвращаюсь с работы домой, то почти каждый день, недовольно бурчу, по поводу
того, что жена моя, всегда отключает мой любимый скин в winamp. Дескать, очень
уж неудобный он для неё - кнопки мелкие, почти не различимые, мышкой с первого
раза не попадешь. Так, что она всегда старается поскорее избавиться от него и
привести winamp в "естественное" состояние. Вообще, надо отметить, жене моей от
домашнего компьютера только если что и нужно - то тот самый winamp, который она
вместо музыкального центра использует. Вы когда-нибудь задумывались о
том, что использование некоторых современных возможностей интерфейса (например,
тех же скинов), не всегда оправдано. Особенно в том случае, если ваша программа,
безусловно, коммерческая и предназначена на продажу. И средний возраст
пользователей, к примеру, в районе 30-40 лет. Вообще, конечно, использовать все
возможности графического интерфейса Windows (под интерфейсом здесь понимается
все совокупность построения "взаимоотношений" программного продукта и
пользователя - от метафоры "рабочего стола" до диалоговых окон) желательно, а
порой и просто необходимо, но вот навешивать собственные "примочки" не
рекомендую. Если конечно, эти самые "примочки" и "фенечки" не являются самоцелью
программы.
С появлением таких визуальных средств разработки (RAD), как
Delphi и прочие, когда стало возможно создавать программу, "рисуя её мышкой",
внедрение этих самых "фенек" в программные продукты стало расти в геометрической
прогрессии. Не берусь утверждать, но, по-моему, большинство независимых
компонентов для Delphi предназначено именно для этих, весьма надо сказать
специфических целей.
Нет, конечно, это хорошо, и нечего предосудительного
я в этом не вижу - в самом деле, некоторые интерфейсные "ухищрения" давно стали
нормой и практикой - начиная от формирования пользователем собственной, удобной
ему панели инструментов с быстрым доступом к необходимым возможностям программы,
кончая расширенным представлением диалоговых окон. Но все это допустимо в той
степени пока не начнет перекрывать стандартные особенности операционной среды и
выработанную привычку взаимодействия пользователя с программным обеспечением.
Представьте, что вместо обычного окна для сохранения или открытия файла,
программы будут выдавать исключительно собственные и нестандартные? Что в
привычном месте у пользователя вдруг не вызываться контекстное меню, и
стандартные нажатия клавиш Ctrl+C и Ctr+V, в какой-либо из программ работать не
будут. Кстати, последние, случается часто. Понятно, что у разработчиков
программы могут быть свои пристрастия, но подменять, убирать стандартные,
привычные для пользователя способы взаимодействия с компьютером нельзя - это на
самом деле способно вызвать лишь отторжение к данному продукту, неприятие его.
Согласитесь, если программа ведет себя "непривычно", то это замедляет
как процесс её "освоения", так и эксплуатации.
Такое понятие как
юзабилити, сейчас начинает активно использоваться применительно к веб-сайтам, но
не следует забывать, что первоначально оно касалось исключительно программных
продуктов, средств взаимодействия пользователя и компьютера. Не следует забывать
то, что графическая операционная система (будь то Windows, MacOS или X-Windows)
и есть максимальная точка приложения юзабилити. Разработанные еще в середине
семидесятых годов такие понятия как "рабочий стол", "окна", "меню", были
востребованы только в начале девяностых в персональных
компьютерах.
Разработка программного обеспечения, порой весьма трудоемкая
задача, и у программистов иногда просто "не доходят руки" сделать свою программу
еще и удобной, логически понятной для пользователя. Вместо этого начинается
непонятное её "украшательство", когда в программу вводятся нестандартные
элементы интерфейса. Распространение быстрых визуальных средств программирования
только способствует этому - порой люди, работающие с Delphi плохо представляют
основы объектно-ориентированного программирования, но зато их "шедевры"
изобилуют множеством нестандартных для Windows кнопок, меню и пр.
Правда
есть и другая сторона этой медали. Дело в том, что все эти новомодные "примочки"
к интерфейсу могут оказаться полезными, если сам программный продукт
ориентирован на другой круг пользователей, например молодежь, склонную ко
всякого рода экспериментам. Например, тот же winamp снискал свою популярность,
именно предложив пользователям менять его внешний вид по усмотрению. То есть
если программа служит исключительно развлекательным целям, то некоторые
"нестандартности" интерфейса могут сыграть и на руку. За примерами далеко ходить
не надо - самые разнообразные виды интерфейсов можно найти в компьютерных
играх.
Не стоит забывать и постепенной интеграции некоторых
особенностей навигации, что привнес интернет. То есть заимствование некоторых
элементов из привычного "веб-интерфеса" в программные продукты, может быть
полезна. Как пример - многие справочные системы, распространяемые сегодня, почти
не включают такие вещи как перекрестные ссылки, поиск, возможности перехода по
документам, историю их просмотра в своих программах. Это плохо - потому как
понятие гипертекста собственно для этого было и предназначено, а уж то, что это
теперь сплелось с интернетом - совсем другое дело.
И все же в
качестве рекомендации - постарайтесь избегать применения "нестандартного
интерфейса" в своих программных продуктах. Помимо неудобства для пользователя,
вы создаете проблемы и для себя - ведь никто не гарантирует, что все эти
"примочки" будут способствовать устойчивости программы, да и окажутся ли они
совместимыми с новыми версиями операционной системы? Или наоборот, некоторые
стандартные возможности интерфейса в операционной системе изменятся так
разительно, что ваши новомодные "фенечки" покажутся "детским
лепетом"?
Если все же, тяга к новым к новым "выразительным"
средствам велика, то лучше сделайте в программе возможность "отката" к
стандартным, определенным операционной системой функциям и элементам интерфейса.
А еще, не используйте их больше, чем, например, есть в пакете Microsoft Office -
надо заметить, что корпорация Microsoft тратит довольно большие суммы, что бы
выяснить каков "потолок" введения новых возможностей интерфейса без вызова
"отторжения" у пользователей. Так используете же эти знания себе на
пользу.
Константин Артемьев
Начинающим программистам нет смысла создавать свой 3D движок -
в Инете можно набрать кучи бесплатных 3D движков разной степени глюченности и с
разными возможностями. Наиболее известные из них - OpenFX и Genesis 3D. С
помощью них любой C++ программер может быстро и легко (если руки из правильного
места растут) сделать свой 3D шедевр. А Delphi-кодеры как всегда остались
неудел...
Я думаю, моё мнение о том, что Делфи - идеальное средство
создания компьютерных игр, разделят многие. Неужели нас опять обделили? Но есть
на свете справедливость. Хорошим парням из Германии и Франции такое
пренебрежение к любимому языку программировния тоже не понравилось, и они,
почесав затылки, выдали на-гора великолепный 3D движок для Делфи - GLScene. На
самом деле, GLScene был создан Майком Лисчке как надстройка над OpenGL. К
сожалению, где-то на рубеже 0.5 версии Майк бросил этот проект, и так бы мы и
остались без движка, если бы не Эрик Гранж - человек, которые сейчас
разрабатывает и апгрейдит GLScene. Именно он, честь ему и хвала, довёл
простёнькую, в общем-то, надстройку до состояния, когда её можно назвать
полнофункциональным движком наравне с тем же Genesis 3D. GLScene абсолютно
бесплатен, но возможности его огромны. Он создан на базе OpenGL, следовательно
за нас играет большая, по сравнению с Direct 3D производительность и скорость
(Джон Кармак, как известно, признаёт только OpenGL). Вот фичи, которые в нашем
распоряжении в текущей (0.82) версии GLScene: иерархическая объектная структура,
мощный аппарат манипуляции объектами, множество преопределённых типов объектов,
импорт файлов формата 3DS, MD2, STL, TIN, полнофункциональный модуль работы с
материалами (мультитекстурирование и бит-блиттинг тоже есть), множество
поддерживаемых форматов текстур, каркасное сглаживание, интерполяция кадров в
анимации, физические эффекты, работа с ландшафтами, контроль столкновений,
спецэффекты (огонь, молнии, системы частиц и т.д.), мощная поддержка трёхмерного
звука (A3D, EAX, FMOD, BASS), поддержка джойстика, продвинутая векторная
геометрия, системная синхронизация событий, удобный интерфейс, продвинутая
работа с клавой и мышью и многое другое. Как видишь, есть где порезвиться.
Движок регулярно обновляется. Вот-вот должен быть готов модуль скелетной
анимации. Сама библиотека построена таким образом, что ты можешь
создать сцену, не написав ни одной строчки кода! В конце статьи смотри адреса,
где можно скачать как саму библиотеку, так и множество дополнений: удобный 3D
редактор сцен, редактор материалов, редактор ландшафтных поверхностей и много
чего ещё. Работать с движком очень легко, даже если про OpenGL ты знаешь только
то, что он существует. Очень помогут более 50 демок с открытым кодом, в которых
использованы все компоненты. А если ты ас в OpenGL, то тебя приведут в священный
экстаз модули OpenGL12.pas и geometry.pas. О таких великолепных функциях для
работы с векторами и тонким 3D рендерингом ты и не мечтал! Вижу, товарищ, слюнки
у тебя уже потекли. А раз ты дошли до кондиции, от теории перейдём к
практике.
Что нам стоит дом построить? Нарисуем - будем
жить!
Вначале не было ничего. Но великий Создатель поместил на форму
GLScene и GLSceneViewer, создал камеру, и появился мир. Но вокруг была тьма. И
тогда Создатель сотворил TGLLight и GLDisc ака Землю. Но всё было серым и
блёклым, как на Луне. И натянул Создатель на диск текстуру с цветочками
(GLDisc1.Material.texture.disabled:=false;GLDisc1.Material.texture.image.loadfromfile('zemlia.jpg').),
и Земля расцвела. Но темно было над головой. И тогда Создатель сотворил
TGLSkyDome и поплыли облачка на голубом небе. Но не было на Земле ни души. И
сотворил Создатель TActor, и загрузил туда MD2 файл персонажа из Quake, и задал
анимацию Run, и побежал квакер по матушке земле. Вдруг на пути квакера возникла
китайская ваза (TFreeForm позволяет загрузить файл 3D Studio MAX. Если для
текстуры вы установите режим tmmodulate, то она обернёт вазу и, если tmdecal -
наложится в соответствии с координатами, заданными в файле 3ds). И выстрелил
квакер в вазу (огонь можно создать, добовив объекту TGLFireBehavior и
ассоциировав с ним FireFXManager), и разбилась она вдребезги (столкновение
определяется событием OnCollision у TCollisionManager, возвращаются указатели на
столкнувшиеся объекты. У каждого объекта, участвующего в проверке столкновения
должен быть установлен TCollisionBehavior). Но не успокоился квакер. Увидел он
пальму (простые объекты можно задавать спрайтами - объект TSprite). И нацелился
он на пальму. Но тут Создатель разозлился на неуёмного квакера, и опустился
туман на Землю (свойство Fog у TGLSceneViewer), и шибанул Создатель квакера
молнией по темечку (TThorFX, аналогично TFireFX). Загремел реквием (TWaveOut), и
запылала на мониторе надпись "Game Over" (THUDText вкупе с
TBitmapFont).
И на последок...
Несколько общих идей: 1)
Behavior - набор особых свойств, присущих объекту. Сейчас доступны следующие
бехавиоры: collision, inertia, FireFX, ThorFX. Для каждого бехавиора требуется
своеобразный программный контролер - менеджер. Например для collision требуется
CollisionManager (определяет общие свойства и события всех бехавиоров) и т.д.
Только Inertia самодостаточен. 2) Счётчик FPS работает не совсем корректно:
занижает результат, если расстояние от камеры до основной массы объектов сцены
велико. Учти также, что FPS - число не реальных выводов на экран за секунду, а
потенциальных. То есть, если FPS = 40, то это вовсе не значит, что сцена
рендерилась сорок раз в секунду. Это означает только, что в случае необходимости
такая скорость может быть достигнута. 3) Не используй GLScene совместно
с собственным OpenGL кодом. Есть вероятность того, что рендер, навязываемый
GLScene перекроет твои команды. 4) Потрясающего эффекта можно добиться,
экспериментируя с туманом и системами частиц. 5) Параметры Up, Direction и
Rotation заданы единичными векторами, что не совсем удобно. Если тебе надо
повернуть объект на определённых градус, используй Roll, Turn и Pitch. 6)
Очень приличные пейзажи, горы, долины и прочие ландшафты можно создать с помощью
TLandscapeRenderer. Оy работает по принципы bump mapping, карта высот задаётся
объектом THeightField ,берётся из внешнего битмэпа по принципу: чем светлее
участок, тем выше точка поверхности.
САГА О ГЛЮКАХ
Автор: Константин Артемьев
К сожалению, даже самая замечательная программа время от времени
глючит, даже самый полезный компонент иногда "висит". Это относится
и к GLScene. Но не будем всерьёз грустить об этом, достаточно
соблюдать простые правила и всё будет работать как надо. Первый
и, пожалуй, самый нудный глюк состоит в том, что во время разработки
приложения область OpenGL вывода смещается, перекрывает другие
компоненты и окна, смешивает цвета и на вашей форме наступает
полный кавардак. Лечение: к сожалению, только перезапуск Делфи.
Совет: поменьше двигайте область вывода и не помещайте на неё
другие компоненты. Если появилось сообщение, вроде "Failed to
invoke GLSwapBuffers", то немедленно перезапустите Делфи, иначе
начнутся глюки. Вы понимаете, что лучше сохранить ваше приложение
ДО начала глюков. Далее, если вы работаете с полноэкранным GLScene
приложением, а оно не подаёт признаков жизни, то по ctrl-alt-del
снимайте не ваше приложение, а Делфи! Это очень важно, так как
если вы попытаетесь снять приложение, в 50% случаев зависнет ВЕСЬ
Windows. А если вы снимете Делфи, то всё скорее всего пройдёт
гладко. Никогда не пытайтесь снимать зависшее Delphi приложение
с помощью таких средств, как Norton CrashGuard. Последствия могут
быть плачевными. Разумеется,. всё это относится к тому случаю,
когда вы запускаете свой опус из IDE. Кстати, хороший совет: если
программа плохо работает под IDE, то попробуйте скомпилировать
её, а запустить вне Делфи. Иногда помогает. Кроме того, если вы
очень много раз запускали ваше приложение или при запуске производились
громоздкие подсчёты, то производительность всех программ, использующих
OpenGL, и запущенных после вашей программы, снизится в 10 раз!
Это связано с переполнением внутренних буферов Windows. Совет:
если хотите запустить "левую" игру после работы с GLScene, лучше
перезагрузитесь. Или используйте программу принудительной очистки
оперативной памяти, как например RamBooster.
Глюки были, глюки есть, глюки будут.
|