| Форум| Гостевая| Ссылки| Программы| Исходные тексты| Наши партнеры|
   
| Главная| Рассылки| Услуги| Библиотека| Новости| Авторам| Программистам| Студентам|
delphi c++ assembler
 
  • Использование надстроек над 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.

    Глюки были, глюки есть, глюки будут.

     


    Rambler's Top100 Rambler's Top100

    ©  Adept Design Studio

    Используются технологии uCoz