10

2D графика

В этой главе я собираюсь объяснить, как рисовать 2D графику с помощью PureBasic. Термин 2D графика охватывает довольно большую тему. Когда я рассказываю о 2D-графике в этой книге, я имею в виду простую, двумерную графику, которую можно изобразить  на экране в GUI, изображении в ОЗУ или даже принтере. Эта графика  может содержать различные типы сложности, от одного пикселя, вплоть до большого многопиксельного цветного изображения. Вся 2D графика двумерная, это можно понять по названию. Есть еще 3D-графика, которая отображает 3D модели, и имеет трехмерный вид. Используя 2D-графику, можно добиться весьма впечатляющих визуальных эффектов, и как следствие, множество игр , заставок и демосцен, были созданы с помощью PureBasic. Надеюсь, вы сможете обучиться и данные примеры из этой главы, станут началом для создания великолепной графики в ващих программах.


2D команды для рисования

PureBasic содержит команды, которые позволяют использовать стандартные формы и цвета в ваших программах. Эти простые 2D команды для рисования описываются в главе 2D Drawing справки по PureBasic (Helpfile: ReferenceManual->General Libraries->2DDrawing). Эти команды являются полезными для рисования простых фигур и текста в разные цвета и даже есть пара команд, которые рисуют ранее созданные или загруженные изображения.

Способы рисования

Встроенные 2D команды можно использовать для рисования таких элементов как: графического оконного интерфейса пользователя, зарисовок экрана, спрайта, только что созданного образа в памяти, текстуры 3D модели  или прямо на принтер. Этих шести методов достаточно, чтобы охватывать все, связанное с 2D и в то же время использовать их одинаково просто. Вам достаточно раз указать, где вы хотите выводить рисунок(1 из шести методов, описанных выше), а дальше с помощью команд рисования выводить нужное в эту область. Все шесть применительных методов, используют приблизительно один и тот же синтаксис.

Рисование по окну

В этом первом примере я покажу вам, как нарисовать 2D-графику непосредственно на окно. Вы, наверное, никогда не будет использовать такой способ, но это поможет понять и изучить синтаксис. Посмотрите на этот кусок кода:

#WINDOW_MAIN = 1
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WINDOW_MAIN, 0, 0, 200, 240, "Window Drawing", #FLAGS)
    If StartDrawing(WindowOutput(#WINDOW_MAIN))
        Box(15, 15, 75, 75, RGB(255, 0, 0))
        Circle(140, 125, 45, RGB(35, 158, 70))
        ;The next 2D drawing commands draw a triangle
        LineXY(62, 140, 112, 220, RGB(0, 0, 255))
        LineXY(112, 220, 12, 220, RGB(0, 0, 255))
        LineXY(12, 220, 62, 140, RGB(0, 0, 255))
        FillArea(62, 180, RGB(0, 0, 255), RGB(0, 0, 255))
    StopDrawing()
EndIf
    Repeat
        Event.l = WaitWindowEvent()
    Until Event = #PB_Event_CloseWindow
EndIf
End

Если вы запустите приведенный выше пример, можете увидеть окно, подобное изображенному ниже на рисунке. В нем отображены:  красный квадрат, зеленый круг и синий треугольник. Эти формы отображаются в окне без всяких гаджетов. Для того, чтобы вы в полной мере поняли код выше, я должен подробно объяснить синтаксис команд из прошлого примера.

Во-первых, вы увидите, я использовал новую команду с названием StartDrawing(). Эта команда сообщает PureBasic о начале рисования, используя 2D графику. А так же определяет    каким методом рисовать. Если вы посмотрите в справку (Helpfile:Reference Manual->General Libraries->2DDrawing->StartDrawing) , вы увидите, что эта команда может принимать в качестве параметра одну из шести команд, которая отвечает за метод вывода рисунка. Эти команды:

WindowOutput()

Используется для рисования  на окнах PureBasic. При этом методе необходимо указать идентификатор окна.

ScreenOutput()

Используется для рисования непосредственно на экран PureBasic.

SpriteOutput()

Используется для рисования на спрайтах. При этом методе необходимо указать идентификатор спрайта.

ImageOutput()

Используется для рисования на загруженных или вновь созданных изображениях в памяти. При этом методе необходимо указать идентификатор изображения.

PrinterOutput()

Используется для рисования непосредственно в принтер.

TextureOutput()

Используется для рисования на текстуры 3D модели. При этом методе необходимо указать идентификатор текстуры.

В моем примере я я дал указание рисовать на окне:

...
StartDrawing(WindowOutput(#WINDOW_MAIN))
...

Как только я настроил вывод рисунка с помощью команды WindowOutput, я могу начать рисовать с помощью различных 2D команд. Теперь все команды записанные в блок StarDrawing(WindowOutput())-----StopDrawing будут выводить рисунок на окно. Обязательно при использовании команды StartDrawing(), после инструкций рисования, необходимо завершить блок командой StopDrawing. Это позволит компилятору PureBasic отказаться от использования 2D команд рисования, и продолжать работать с остальной частью программы. Это необходимо делать, иначе возникнут ошибки в программе. Внутри блока, я использовал четыре 2D команды для рисования фигур на окне:  Box()  Circle() LineXY()  FillArea(). Все эти 2D команды подробно описаны в справке (Helpfile:Reference Manual->General Libraries->2DDrawing). Почти все 2D команды имеют сходные параметры. Этими параметрами чаще всего выступают: начальная позиция, размеры и цвет. Если мы возьмем к примеру команду Box(), то первые два параметра это начальная позиция прямоугольника на окне. Третий и четвертый параметры ширины и высоты прямоугольника. Пятый параметр это его цвет.

Работа с цветами

Цвета в PureBasic задаются с помощью 24-битного значения цветности . Эти значения являются различными сочетаниями красного, зеленого и синего цветов. Для получения 24 бит значения цвета, можно использовать команду RGB(). Эта команда получает три параметра, которые указывают значения красного, зеленого и синего цветов по отдельности. Каждый из этих показателей имеет диапазон значений от 0 до 255. С их помощью возможно получить более 16,7 млн 24-битного значения цветности. Вот как я использовал команду в прошлом примере:

...
Box(15, 15, 75, 75, RGB(255, 0, 0))
...

Здесь, я использовал команду RGB() встроенную в качестве параметра в команду Box(). Если внимательно присмотреться, можно увидеть, что я указал максимальное значение для параметра красный, и нулевое значение для зеленого и синего цветов. Это означает, что RGB() команда возвращает 24 битное значение красного цвета не смешанного с двумя другими цветами. Таким же способом и для треугольника:

 ...
LineXY(62, 140, 112, 220, RGB(0, 0, 255))
LineXY(112, 220, 12, 220, RGB(0, 0, 255))
LineXY(12, 220, 62, 140, RGB(0, 0, 255))
FillArea(62, 180, RGB(0, 0, 255), RGB(0, 0, 255))
...

Эти четыре строчки составляют синий треугольник из прошлого примера. Первые три являются командами  LineXY() которые рисуют три стороны треугольника. Последняя команда FillArea() берет отправную точку в центре треугольника, и наполняет область тем же цветом, что и стороны. Вы можете видеть цвет же во всех этих четырех командах рисования. Первый и второй параметры команды RGB() представляющие красный и зеленый, а третий параметр представляет синий. В данном примере видно, что последний параметр равен 255, а первые два 0,значит отобразится синий цвет без примесей. Зеленый кружок из примера, немного отличается тем, что я использую все три цвета, чтобы достичь желаемого зеленого цвета, например:

...
Circle(140, 125, 45, RGB(35, 158, 70))
...

Здесь я использовал сочетание красного, зеленого и синего, чтобы добиться зеленого цвета. Использование цветов довольно просто в PureBasic, поэтому у новичков не должно возникнуть проблем с пониманием. Использование команды RGB()  может вернуть практически любой цвет, различаемый человеческим глазом.

Команда RGB() может устанавливать нужный цвет из  красного, зеленого и синего параметров 24 битного значения. Может случится так, что вам надо будет вернуть используемый цвет в числовой эквивалент. Для этого можно воспользоваться командами Red()  Green()  Blue() Вот пример:

ColorValue.l = RGB(35, 158, 70)
Debug "The 24 bit color value is made up of: "
Debug "Red: " + Str(Red(ColorValue))
Debug "Green: " + Str(Green(ColorValue))
Debug "Blue: " + Str(Blue(ColorValue))

Каждая из команд Red()  Green()  Blue()  возвращает соответствующее значение компонента цвета. Первым параметром в команде RGB() идет число 35. Если я захочу получить значение красного компонента позднее, я попросту воспользуюсь командой Red() . C другими цветами поступаем аналогично.

Почему нет предпочтений для рисования на окнах в Windows

Из-за внутренней обработки событий, что происходит в Microsoft Windows, рисунок нанесенный непосредственно на окно при переходе между окнами, либо свертыванием окна, попросту затирается. Конечно можно заставить графику перерисовываться, но для этого нужны знания API. Более удобный способ отображения графики,  это создавать новый образ в памяти, рисовать в нем, а затем поместить это изображение с помощью гаджета в вашем окне. Использование гаджета (ImageGadget()) гарантирует, что нужное изображение автоматически перерисовывается. Из-за этого на изображение не влияют такие действия, как свертывания окна, переключения между окнами и т д.

Рисование на изображениях

Работа с новыми изображениями в PureBasic легка, так как есть целая библиотека написанная исключительно для создания и манипулирования этими образами. В следующем примере, я создам похожую программу с треугольником, прямоугольником и кругом, но все же у этих примеров есть разница. Я собираюсь создать новый образ, используя команду CreateImage() для рисования цветных форм на него, а потом отправить конечный результат в ImageGadget(). Это поможет избежать проблем с обновлением окна. Вы можете больше узнать об  ImageGadget() в справке (Helpfile:Reference Manual->General Libraries->Image). А вот пример:

Enumeration
#WINDOW_MAIN
#IMAGE_GADGET
#IMAGE_MAIN
EndEnumeration


If CreateImage(#IMAGE_MAIN, 180, 220)
    If StartDrawing(ImageOutput(#IMAGE_MAIN))
        ;Because a new image has a Black background, draw a white one instead:
        Box(0, 0, 180, 220, RGB(255, 255, 255))
        ;Now, continue drawing the shapes:
        Box(5, 5, 75, 75, RGB(255, 0, 0))
        Circle(130, 115, 45, RGB(35, 158, 70))
        LineXY(52, 130, 102, 210, RGB(0, 0, 255))
        LineXY(102, 210, 2, 210, RGB(0, 0, 255))
        LineXY(2, 210, 52, 130, RGB(0, 0, 255))
        FillArea(52, 170, RGB(0, 0, 255), RGB(0, 0, 255))
        StopDrawing()
    EndIf
EndIf
#FLAGS=#PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WINDOW_MAIN, 0, 0, 200, 240, "Drawing On A New Image", #FLAGS)
    If CreateGadgetList(WindowID(#WINDOW_MAIN))
        ImageGadget(#IMAGE_GADGET, 10, 10, 180, 220, ImageID(#IMAGE_MAIN))
        Repeat
            Event.l=WaitWindowEvent()
        Until Event=#PB_Event_CloseWindow
    EndIf
EndIf
End

 

Основная часть этого кода должна быть понятна, потому что единственное различие с кодом из последнего примера, это то что мы здесь создаем новое изображение, используя команду CreateImage() и рисуем на нем, а не на окне. Команда CreateImage() принимает четыре параметра. Первый это идентификатор нового изображения. Второй и третий ширина и высота (в пикселях) нового образа, и четвертый параметр глубина цветности. Этот параметр не является обязательным. Если четвертый параметр не используется, как в моем примере, то он использует ту же самую глубину цвета, которая используется для рабочего стола. После создания нового образа, я командую программе начать рисовать на нем с помощью этой строки:

...
StartDrawing(ImageOutput(#IMAGE_MAIN))
...

Здесь, используя команду StartDrawing(), я указал метод рисования ImageOutput(), который будет выводить рисование на изображение с идентификатором # IMAGE_MAIN. В этом способе нет ограничения на рисование только нового созданного изображения. Вы можете так же легко загрузить любое фото в программу и используя идентификатор изображения, начать рисовать на нем.

После того как изображение было создано и выбран метод рисования, можно непосредственно рисовать на нем. Поскольку все вновь созданные изображения в PureBasic имеют  черный фон, первой операцией рисования я решил сделать изменение цвета фона на белый. Я делаю это с помощью команды Box(0, 0, 180, 220, RGB(255, 255, 255)), которая покрывает черное изображение белым фоном. После этого, я нарисовал квадрат, круг и треугольник так же, как в прошлом примере. Когда я закончил все необходимые операции рисования, я вызываю команду StopDrawing(). Чтобы отобразить это изображение правильно и избежать проблем при перерисовках(обновлении рисунка)  я использую ImageGadget. Это позволяет операционной системе заботиться о вашем изображении при свертывании, переключении фокуса окон, перемещении окна за грань экрана и т.д.

О глубине изображения.

Каждый пиксель на дисплее компьютера или цифрового изображения описывается двоичным числом, как в принципе и любая информация на компьютере. Большее количество бит (или двоичных цифр) используемое для описания одного пикселя, позволяет этому пикселю, иметь  более широкую цветовую гамму. Количество бит, описывающих отдельный пиксель в том или ином цифровом изображении или компьютерного монитора, называется глубиной цвета. Используются: 1 бит, 8 бит, 16 бит, 24 бит, 32 бит. Изображения 1 бит может описать только черно-белые(2 цвета) изображения. В зависимости от разрядности этого бита(0 или 1) будет черный или белый цвет. Пиксели с глубиной 32 бит способны отображать больше цветов, чем человеческий глаз может распознать, поэтому этот формат регулярно используется в изображениях для цифровых кинофильмов, цифровых фотографий, реалистичных компьютерных игр и т.д. Современные компьютеры в настоящее время, как правило, используют только 32 бит на пиксель.

 

Изменение режима рисования

В следующем примере я покажу вам, как изменить режим рисования некоторых команд, включая текст. Использовав команду DrawingMode() вы можете переключиться на режим команды для набросков форм, рисовать текст с прозрачным фоном, или даже смешивать(XOR) пиксели рисунка с пикселями фона. Вот пример с режимом рисования:

Enumeration
#WINDOW_MAIN
#IMAGE_GADGET
#IMAGE_MAIN
#FONT_MAIN
EndEnumeration


Global ImageWidth=401
Global ImageHeight=201
Global XPos.l, YPos.l, Width.l, Height.l, Red.l, Green.l, Blue.l
Global Text.s="PureBasic - 2D Drawing Example"
Procedure.l MyRandom(Maximum.l)
  Repeat
    Number.l=Random(Maximum)
  Until (Number % 10)=0
  ProcedureReturn Number
EndProcedure
If CreateImage(#IMAGE_MAIN, ImageWidth, ImageHeight)
  If StartDrawing(ImageOutput(#IMAGE_MAIN))
     For x.l=0 To 1500
        XPos.l=MyRandom(ImageWidth)+1
        YPos.l=MyRandom(ImageHeight)+1
        Width.l=(MyRandom(100)-1)+10
        Height.l=(MyRandom(100)-1)+10
        Red.l=Random(255)
        Green.l=Random(255)
        Blue.l=Random(255)
        Box(XPos, YPos, Width, Height, RGB(Red, Green, Blue))
        DrawingMode(#PB_2DDrawing_Outlined)
        Box(XPos-1, YPos-1, Width+2, Height+2, RGB(0, 0, 0))
        DrawingMode(#PB_2DDrawing_Default)
     Next x
        LineXY(ImageWidth-1, 0, ImageWidth-1, ImageHeight, RGB(0, 0, 0))
        LineXY(0, ImageHeight-1, ImageWidth, ImageHeight-1, RGB(0, 0, 0))
        Box(10, 10, 230, 30, RGB(90, 105, 134))
        DrawingMode(#PB_2DDrawing_Outlined)
        Box(10, 10, 231, 31, RGB(0, 0, 0))
        DrawingMode(#PB_2DDrawing_Transparent)
        DrawText(21, 18, Text, RGB(0, 0, 0))
        DrawText(19, 18, Text, RGB(0, 0, 0))
        DrawText(21, 16, Text, RGB(0, 0, 0))
        DrawText(19, 16, Text, RGB(0, 0, 0))
        DrawText(20, 17, Text, RGB(255, 255, 255))
      StopDrawing()
  EndIf
EndIf
#FLAGS=#PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WINDOW_MAIN, 0, 0, ImageWidth+20, ImageHeight+20, "Abstract", #FLAGS)
    If CreateGadgetList(WindowID(#WINDOW_MAIN))
        ImageGadget(#IMAGE_GADGET, 10, 10, ImageWidth, ImageHeight, ImageID(#IMAGE_MAIN))
    EndIf
    Repeat
        Event.l=WaitWindowEvent()
    Until Event=#PB_Event_CloseWindow
EndIf
End

 

Этот пример, в основном расширенная версия прошлого. В нем я так же создал новый образ, и в этом образе нарисовал нужное. Кол-во форм, созданных с помощью BOX() здесь большое, и появление их на экране случайно, то есть случайны их размеры, цвет и нахождение на нашем образе. В каждом прямоугольнике я рисовал, переключая режим рисования, при этом намечая черный контур с такими же размерами сверху. Это делает прямоугольники выделяющимися. Мало того, что каждый прямоугольник имеет случайный цвет, но каждый из них так же имеет черный контур. Для переключения режимов во время рисования, вы можете использовать команду DrawingMode() вместе с одной из нескольких констант, которые используются в качестве параметра. Вот эти константы, а так же возможности, связанные с ними:

#PB_2DDrawing_Default

Этот режим по умолчанию, текст отображается с цветом фона и графические формы заполнены.

 #PB_2DDrawing_Outlined

Этот режим позволяет делать наброски форм, для таких команд, как Box() Circle() и Ellipse()

#PB_2DDrawing_Transparent

Устанавливает фон текста прозрачным, поэтому и используется только для команды  DrawText()

#PB_2DDrawing_XOr

Это режим XOR, который означает, что вся графика будет преобразована(Поксорена) с  текущим фоном.

Использовать эти команды очень просто. Если вы хотите изменить рисунок, нужно вызвать команду StartDrawing() с константами по своему выбору. Эти константы могут быть объединены с помощью побитового оператора OR. Взглянув на код, вы можете увидеть, что я много раз включал режимы.

 После запуска этого примера вы увидите окно, очень похожее на рисунок ниже. В нем показываются красочные прямоугольники, в комплекте с черными очертаниями и белым текстом в левом верхнем углу.

Я использовал режим рисования #PB_2DDrawing_Transparent, когда я выводил текст на изображении, получая текст с прозрачным фоном, вместо сплошного цвета. Чтобы рисовать текст, я использовал команду DrawText(). Она имеет пять параметров:  х и у позиция на выходе, String рисуемая строка, и два цветовых параметра(цвет текста и цвет фона текста). Поскольку я использовал прозрачный фон, пятый параметр игнорируется. Черные контуры текста на рисунке были сделаны с помощью таких же команд DrawText(), но со смещением в координатах. Режим # PB_2DDrawing_Outlined не поддерживает текст, поэтому были применены четыре дополнительные команды для контура текста.

Рисование текста

Рисование текста на выходе достигается с помощью команды DrawText() (Helpfile:Reference Manual->General Libraries->2DDrawing->DrawText). Если вы посмотрите на последний пример, вы можете увидеть, что я использовал эту команду несколько раз. Все ее параметры я описал чуть выше. Скажу лишь, если два последние параметра(цвет текста и цвет фона, являющимися необязательными) не используются, то информация берется из значения по умолчанию, которые могут меняться с помощью команд FrontColor() и BackColor().  Эти цветовые параметры 24 битного значения цвета,  легко, ставятся с помощью команды RGB().

Рисуем с помощью изображений

В последних примерах, я показал, как рисовать простые формы и линии, используя встроенные 2D команды рисования, но на этом 2D графика не ограничивается. В следующем примере я покажу вам, как можно взять изображение и нарисовать его на другой только что созданный образ, в любой позиции, какой хотите:

Enumeration
  #WINDOW_MAIN
  #IMAGE_GADGET
  #IMAGE_SMALL
  #IMAGE_MAIN
  #FONT_MAIN
EndEnumeration

Global ImageWidth=400
Global ImageHeight=200
Global XPos.l, YPos.l, LoadedImageWidth.l, LoadedImageHeight.l
Global File.s
Global RequesterText.s="Choose an image"
Global DefaultFile.s=""
Global Pattern.s="Bitmap (*.bmp)|*.bmp|Icon (*.ico)|*.ico"
File=OpenFileRequester(RequesterText, DefaultFile, Pattern, 0)
If File
  LoadImage(#IMAGE_SMALL, File)
  LoadedImageWidth=ImageWidth(#IMAGE_SMALL)
  LoadedImageHeight=ImageHeight(#IMAGE_SMALL)
  If CreateImage(#IMAGE_MAIN, ImageWidth, ImageHeight)
    If StartDrawing(ImageOutput(#IMAGE_MAIN))
        Box(0, 0, ImageWidth, ImageHeight, RGB(255, 255, 255))
        For x.l=1 To 1000
            XPos=Random(ImageWidth)-(ImageWidth(#IMAGE_SMALL)/2)
            YPos=Random(ImageHeight)-(ImageHeight(#IMAGE_SMALL)/2)
            DrawImage(ImageID(#IMAGE_SMALL), XPos, YPos)
        Next x
        DrawingMode(#PB_2DDrawing_Outlined)
        Box(0, 0, ImageWidth, ImageHeight, RGB(0, 0, 0))
        StopDrawing()
    EndIf
  EndIf
  #TEXT="Drawing Using Images"
  #FLAGS=#PB_Window_SystemMenu | #PB_Window_ScreenCentered

  If OpenWindow(#WINDOW_MAIN, 0, 0, ImageWidth+20, ImageHeight+20, #TEXT, #FLAGS)
    If CreateGadgetList(WindowID(#WINDOW_MAIN))
        ImageGadget(#IMAGE_GADGET, 10, 10, ImageWidth, ImageHeight, ImageID(#IMAGE_MAIN))
    EndIf
    Repeat
        Event.l=WaitWindowEvent()
    Until Event=#PB_Event_CloseWindow
  EndIf
End
EndIf

В приведенном выше коде, я даю пользователю возможность, с помощью команды OpenFileRequester() открыть изображение в форматах Bitmap или Icon. После этого запроса, при правильном возвращении имени файла изображения, я загружаю файл, с помощью команды LoadImage(). После того как файл будет загружен, я могу создать новый образ и нарисовать на него изображения множество раз. Делается это с помощью команды DrawImage(). Полученное изображение выводится на окне, используя ImageGadget(). Если вы посмотрите на рисунок ниже, вы можете видеть, как он выглядит после того, как загрузили небольшой значок, который затем случайно рисуется во всем созданном образе и отображается.

 

Если вы хотите рисовать загруженные изображения на вновь созданный образ, вы используете команду DrawImage(). Эта команда принимает пять параметров, которые несложно понять. Первый это идентификатор ОС изображения, которое нужно для рисования. Устанавливается с помощью команды ImageID(). Второй и третий параметры задают горизонтальное и вертикальное положение для рисования изображения в пикселях. Четвертый и пятый параметры являются необязательными, и я не использовал их здесь, но это ширина и высота рисуемого изображения в пикселях. Последними параметрами вы пользуетесь, если вам нужно изменить размер изображения динамически перед рисованием. В моем примере, я большинство параметров делал случайными с помощью команды Random(). И как результат: случайное заполнение образа тысячами экземпляров загруженного изображения. Скорее всего вы в первый раз, увидели команду OpenFileRequester(), поэтому я поясню. Эта команда открывает стандартный запрос для выбора файла пользователем. После того как файл был выбран, команда OpenFileRequester() возвращает его имя в виде строки. Это может быть продемонстрировано с помощью небольшого фрагмента кода:

Global File.s
Global RequesterText.s = "Choose an image"
Global DefaultFile.s = ""
Global Pattern.s = "Bitmap (*.bmp)|*.bmp|Icon (*.ico)|*.ico"
File = OpenFileRequester(RequesterText, DefaultFile, Pattern, 0)
Debug File

Если вы посмотрите в файл справки(Helpfile:Reference Manual->GeneralLibraries->Requester->OpenFileRequester) по команде OpenFileRequester(), то увидите, что эта команда имеет четыре параметра. Первым из них является текст, отображаемый в заголовке окна. Второй параметр, это ожидаемое имя файла при запросе. Данный параметр можно указывать как ""(двойные кавычки). В этом случае ничего отображено в имени ожидаемого файла не будет. Третий параметр представляет собой  шаблон для выбранных файлов, который позволяют программисту определить, какие файлы должны или не должны быть отображены для отбора в запрос. Четвертый параметр определяет, тип файла из шаблона по номеру индекса. В нашем фрагменте, будет показан Bitmap, поскольку он стоит первым в шаблоне, а индексный файл шаблона начинается с 0.

Файл шаблона поначалу выглядит довольно сложным, но его не трудно понять. Типы файлов разбиты на куски в строке шаблона, и разделяются с помощью побитового оператора. Части каждого расширения работают в паре, для того чтобы иметь возможность указать строку, описывающую расширение файла, а затем собственно само расширение. Например, в приведенном выше фрагменте, картина выглядит следующим образом:

"Bitmap (*.bmp)|*.bmp | Icon (*.ico)|*.ico"

Если мы разъединим эти куски с помощью пробелов в качестве разделителей, мы можем более отчетливо увидеть, что указано:

 Bitmap (*.bmp)          *.bmp           Icon (*.ico)             *.ico

Первый кусок это строка, сообщающая пользователю какой тип файла нужен для выбора, в данном случае это все BMP файлы. Вторая часть это непосредственно расширение, которое задает нужный тип файла для выбора в окне(остальные отсеиваются).  Помните, звездочка используется  здесь для обозначения строки с любым именем. Третий кусок это часть другого расширения для отображения пользователю и четвертый как и второй указывает непосредственно само расширение. Во втором случае это все иконки. Если вам нужно задать множество расширений для конкретного типа файла, можно использовать точку с запятой для разделения, вот так:

"JPEG |*.jpg ;*.jpeg"

Это будет отображать любые файлы с расширениями .JPG или .JPEG. Вы должны помнить, что если вы хотите загрузить несколько видов изображений, кроме растровых изображений или иконок, вам придется использовать другой декодер изображения, как описано в главе 9.

Рисование изображения с альфа-каналом 

Иногда вам может понадобиться нарисовать изображение, которое содержит альфа-канал, для сохранения теней или, может быть, прозрачных частей изображения. В прошлом рисунке с использованием значка, рисуемом в созданном образе, PureBasic сохраняет стандартную информацию об  альфа-канале, которая находится внутри этой иконки. Но что произойдет, если вам нужно нарисовать из Tiff или Png формата изображения и сохранить его альфа-канал? Для этого используется команда DrawAlphaImage(). Эта команда будет сохранять найденный в графическом формате альфа-канал. Команда DrawAlphaImage() используется точно так же, как и команда DrawImage(), с той лишь разницей в том, что DrawAlphaImage() имеет три параметра, поэтому не позволяет динамических изменений размера изображения, во время рисования. Вот пример того, как команда может быть использована:

...
DrawAlphaImage(ImageID(#IMAGE_PNG), XPos, YPos)
...

Команда выше, будет отображать формат изображения Png и сохранять его альфа-канал, рисуя его над любым фоном. И конечно следует всегда помнить, что при загрузке изображений, кроме Bitmap или Icon форматов, вы должны использовать соответствующую команду декодер, как описано в главе 9.

Сохранение изображений

Как только вы создали образ в вашей программе, вы можете сохранить его на диск. В PureBasic решить эту задачу легко с помощью команды SaveImage() (Helpfile:Reference Manual->GeneralLibraries->Image->SaveImage). Эта команда сохранит изображение, имея его идентификатор. Команда SaveImage() принимает четыре параметра. Первый это идентификатор  изображения, которое вы хотите сохранить. Второй это имя файла, которое вы хотите закрепить за изображением. Третий параметр является необязательным, и все таки он определяет формат изображения, в который этот образ должен быть сохранен. Четвертый параметр это дополнительное значение для выбранного формата(качество сохраненного изображения) Если мы хотим сохранить изображение, созданное в последнем примере, мы можем добавить следующую строку кода в конец кода примера . После того как программа закончит, она сохранит наш образ:

...
SaveImage(#IMAGE_MAIN, "Image.bmp")
...

По умолчанию, PureBasic будет сохранять в формат BMP(Bitmap) при использовании этой команды без последних двух дополнительных параметров. Файлу надо задавать правильное расширение (*. BMP), при сохранении.

Сохранение изображений в других форматах

Вы можете сохранять изображения в другие графические форматы, указав одну из трех встроенных констант в качестве третьего параметра:

#PB_ImagePlugin_BMP

Сохранить изображение в формате Bitmap. Это значение по умолчанию, и указывать константу нет необходимости.

 #PB_ImagePlugin_JPEG

Сохранить изображение в формате Jpeg. (Для правильной работы вначале должна вызываться команда UseJPEGImageEncoder()  )

#PB_ImagePlugin_PNG

Сохранить изображение в формате PNG. (Для правильной работы вначале должна вызываться команда UsePNGImageEncoder()  )

При сохранении изображений с использованием  #PB_ImagePlugin_JPEG или #PB_ImagePlugin_PNG надо поставить соответствующую команду кодировщик в верхней части исходного кода, прежде чем использовать  SaveImage(). Кодеры достаточно вызвать один раз, чтобы добавить необходимые функции по всей программе. Вот они:

UseJPEGImageEncoder()

Этот кодер добавляет поддержку для изображений JPEG (*. JPG / *. JPEG) форматов.

UsePNGImageEncoder()

Этот кодер добавляет поддержку изображений PNG (*. PNG) формата.

Используя UseJPEGImageEncoder() и тем самым добавляя поддержку Jpeg, вы можете при желании использовать четвертый параметр для команды SaveImage(). Этот параметр указывает значение сжатия  сохраненного изображения. Это единственный тип изображения, который в настоящее время поддерживает этот четвертый параметр.

Вот несколько примеров использования команды SaveImage():

SaveImage(#IMAGE_MAIN, "Image.bmp")

Этот первый пример сохраняет изображение под названием Image.bmp (по умолчанию 24bit формате Bitmap). Обратите внимание, что кодер не нужен потому, что PureBasic поддерживает изображения в формате Bitmap в качестве стандарта.

UseJPEGImageEncoder()
...
SaveImage(#IMAGE_MAIN, "Image.jpg", #PB_ImagePlugin_JPEG)

Второй пример сохраняет изображение с названием Image.jpg ( в формате JPEG используя для сжатия значение по умолчанию 7 , потому что мы не указали его сами).

UseJPEGImageEncoder()
...
SaveImage(#IMAGE_MAIN, "Image.jpg", #PB_ImagePlugin_JPEG, 10)

Третий пример сохраняет изображение с названием Image.jpg ( в формате JPEG используя для сжатия наибольшее значение 10).

UsePNGImageEncoder()
...
SaveImage(#IMAGE_MAIN, "Image.png", #PB_ImagePlugin_PNG)

Это четвертый пример сохранения изображения с названием  Image.png (сохраняет в формате PNG).

 

Понимание экрана

Если вы когда-нибудь захотите создать свою собственную игру или написать свою собственную заставку с использованием PureBasic, то вы всегда должны начинать с открытия экрана. Экран этот попросту чисто графическая среда, созданная с одной целью, для отображения графики: таких как выход 2D рисунка, загруженных изображений, загруженных спрайтов, загруженных 3D моделей и миров.

Что такое Sprite(спрайт)?

Спрайты изначально использовались при специальном аппаратном ускорении изображения, и применялись для создания меняющейся 2D-графики в компьютерных играх. Так как вычислительная мощность компьютеров увеличилась на протяжении многих лет, специальное оборудование, которое использовалось для перемещения и использования этих изображений стало не нужным. Тем не менее, даже сегодня, название Спрайт до сих пор остается в употреблении для описания 2D изображений нарисованных на экране для создания игр и тому подобного. Сегодня спрайт можно охарактеризовать как небольшую графическую (обычно содержащую прозрачный фон) картинку, которая может быть размещена и нарисована независимо от экрана, чтобы имитировать анимацию или для предоставления статической графики.

Экраны, как правило, открыты полностью на всю ширину и высоту экрана, но если есть необходимость, можно также открыть в созданном окне. Это называется оконный режим. Только один тип экрана может быть открыт в одно время, либо полный экран, либо экран с оконным режимом. Причина, по которой экраны предпочитают для отображения графики (а не просто вывод рисунка на окна) для создания игр и т.п., является то, что экраны быстры, ... очень быстры! На каждой платформе в PureBasiс, доступны ее экраны и  оптимизированы для максимально возможной производительности, вне зависимости от операционной системы.

Открытие первого экрана

Чтобы создавать и открывать экран в PureBasic нужно следовать основному шаблонному коду. Экран и обработка спрайтов очень тесно связаны, так что вы всегда должны инициализировать механизм спрайта до открытия экрана. Необходимо, чтобы все было правильно инициализировано и после этого экран будет готов к операции рисования. После того, как механизм спрайта был инициализирован и экран открыт, необходимо, чтобы главный цикл обеспечивал осуществление этой программы, так же как и у графического интерфейса программы. Код ниже показывает скелет программы экран со всеми решающими частями: инициализация механизма спрайта, открытие экрана, создание основного цикла и инициализация команд клавиатуры, для того, чтобы обеспечить закрытие программы.

Global Quit.b=#False
;Simple error checking procedure
Procedure HandleError(Result.l, Text.s)
 If Result=0
    MessageRequester("Error", Text, #PB_MessageRequester_Ok)
    End
 EndIf
EndProcedure
HandleError(InitSprite(), "InitSprite() command failed.")
HandleError(InitKeyboard(), "InitKeyboard() command failed.")
HandleError(OpenScreen(1024, 768, 32, "Fullscreen"), "Could not open screen.")
Repeat
  ClearScreen(RGB(0, 0, 0))
  ;Drawing operations go here
  FlipBuffers(2)
  ExamineKeyboard()
  If KeyboardReleased(#PB_Key_Escape)
     Quit=#True
  EndIf
Until Quit=#True
End

Если вы посмотрите в раздел справки (Helpfile:ReferenceManual->2D Games Libraries->Sprite & Screen) вы сможете найти более подробную информацию обо всех новых командах, используемых в этом примере. В этом примере на самом деле ничего не происходит, кроме открытого пустого экрана. Для выхода из программы достаточно нажать Esc на клавиатуре компьютера. Этот пример является скелетом всех игр, созданных для экрана, так что остановимся здесь для детального изучения. Для начала я создал простую процедуру проверки ошибок, как описано в главе 8. Она отлавливает ошибки при установке команд: InitSprite()   InitKeyboard()   OpenScreen() Если какая то команда вернет ноль, произойдет выход из программы. При возникновении сбоя по какой-либо причине, всегда лучше закрыть программу и информировать пользователя о проблеме. В противном случае, если ваша программа будет продолжаться, есть риск крупной аварии. Команды, необходимые для инициализации механизма спрайта и клавиатуры InitSprite() и InitKeyboard(). Помните, что нам нужно инициализировать механизм спрайта, прежде чем открывать экран. Команда OpenScreen() принимает четыре параметра, это ширина, высота, глубина цвета экрана, а также текст(его подпись). Эта подпись будет отображаться в панели задач, если экран будет минимизирован.

Использовать клавиатуру?

В этих примерах я использовал несколько клавиатурных команд для инициализации клавиатуры и обнаружения клавиш. Все описания можно найти в справке  (Helpfile:Reference Manual->GeneralLibraries->Keyboard). Это очень маленькая и простая в использовании библиотека команд, так что вы должны легко ее разобрать.

Команда InitKeyboard() ( инициализация клавиатуры) должна вызываться перед любой другой командой клавиатуры. Команда ExamineKeyboard () обновляет состояние клавиатуры. Команды  KeyboardReleased() и KeyboardPushed() возвращают истину, если данная клавиша отжата, либо нажата соответственно. Эти команды задаются со встроенными константами, отвечающими за клавиши. Полный список найдете в справке.

Параметры ширина, высота и глубина цвета очень важны, так как они определяют, какой размер и глубина цвета будут у  экрана. Независимо от компьютера перед запуском программы следует убедиться, что компьютер в состоянии поддерживать нужный размер и глубину цвета. Значения ширины и высоты вместе известны как разрешение, и это должно быть поддержано полностью за счет видеокарты и монитора, иначе команда OpenScreen() вернет ошибку. В этом примере я использовал значения, которые поддерживают большинство компьютеров, так что не должно быть никаких проблем. Рисунок ниже показывает, разрешения экрана и глубину цветопередачи, которые должны работать практически на любом современном компьютере. Вы знает уже наверно, что компьютерные игры с большим разрешением экрана, имеют более четкое отображение, но поскольку приходится рисовать больше пикселей, это может замедлять программу. Кроме того чем выше глубина цветопередачи, тем более реалистичная графика может быть отображена.

Конечно, лучше перед использованием программы проверить способность компьютера, использовать эти значения. Вы можете получить список различных разрешений и глубину цветопередачи, которые может использовать компьютер, запустив следующий код:

InitSprite()
If ExamineScreenModes()
  While NextScreenMode()
    Width.l=ScreenModeWidth()
    Height.l=ScreenModeHeight()
    BitDepth.l=ScreenModeDepth()
    Debug Str(Width)+" x "+Str(Height)+" x "+Str(BitDepth)
  Wend
EndIf

Опять же в этом фрагменте мы инициализируем механизм спрайта , прежде чем использовать команду ExamineScreenModes(). Теперь все правильно, и мы можем использовать  основные команды экрана. Далее я использую цикл While-Wend, в котором с помощью команд ScreenModeWidth()  ScreenModeHeight()  ScreenModeDepth(), получаю каждый поддерживаемый экран и вывожу информацию в отладочное окно. Это простой пример для понимания, больше читайте в справке (Helpfile:Reference Manual->2D Games Libraries->Sprite & Screen).

Двойной буферизированный рендеринг

Использование отображения графики необходимо связывать с основным циклом, чтобы обеспечить осуществление этой программы. Рисование графики, тестирование пользовательского ввода и т.д.,  должно следовать с использованием шаблона экрана. Вот основной цикл взят из скелета программы Экран,  описанной выше:

...
Repeat
  ClearScreen(0)
  ;Drawing operations go here
  FlipBuffers(2)
  ExamineKeyboard()
  If KeyboardReleased(#PB_Key_Escape)
    Quit = #True
  EndIf
Until Quit = #True
...

 

На первый взгляд кажется нормальный основной цикл, как и в любой другой программе, но есть несколько различий. Есть две команды очень важные, для правильной организации графики экрана ClearScreen() и FlipBuffers(). Прежде чем я расскажу о них более подробно, я должен пояснить о двойной буферизации. Двойная буферизация используется экраном PureBasic для избежания некачественного отображения графики и мерцающего дисплея. Поскольку компьютерные мониторы постоянно перерисовывают экран монитора обычно шестьдесят-семьдесят (иногда больше) раз в секунду, трудно вносить изменения на экране, такие как перемещение или показ новой графики, прежде завершения имеющейся. Это вызывает результаты поврежденных графических эффектов и других плохих ненужных визуальных эффектов. Если вы хотите избежать этой проблемы, нужно очищать экран каждый раз перед перерисовкой экрана, он будет убирать ненужную графику, но появится мерцание экрана. Использование двойной буферизации PureBasic решает эти проблемы. Когда экран открыт, автоматически назначаются два видео-буфера в памяти, точно такого же размера, как открытый экран. Когда вы рисуете графику на экране, используя команды для графики, на самом деле вы это делаете в заднем буфере, в то время как передний буфер отображает на экране. Когда монитор закончил показывать передний буфер и операции с рисунком закончены, заполнив задний буфер, они меняются местами. Теперь передний буфер становится назад, а задний будет отображаться. Тот буфер, который опять задан на рисование, перед этим полностью очищается стандартной процедурой для очистки буфера,  используя один цвет (обычно черный), прежде чем начать рисовать на ней еще раз. Рисунок ниже показывает эту технику в действии. Показ трех циклов буферов:

 

1) Открытие экрана и начинается рисование в заднем буфере. (Передний буфер отображается на экране)

2) Буферы поменялись. Передний буфер теперь сзади очищается и перерисовывает обновленную графику. (Задний буфер отображается на экране)

3) Буферы опять поменялись местами

На этой диаграмме вы могли увидеть, что при запуске программы (обозначается шаг 1),  передний буфер (Buffer A) не имеет графики и ничего не отображается на экране. Когда мы рисуем, мы делаем это на задний буфер, обозначенный(Buffer B). После того, как все нарисовано, мы можем вызвать команду FlipBuffers() и буферы поменяются местами. Это показано в шаге 2. Теперь (Buffer B) отображается на экране, а мы продолжаем рисовать в переднем буфере. Опять же, когда все операции с рисунком проделаны, мы можем перевернуть буферы местами еще раз, используя команду FlipBuffers() и мы оказываемся на шаге 3, и так можно проделывать циклически. При  создании иллюзии движения, мы должны будем очищать и перерисовать нужный рисунок, прежде использования FlipBuffers(). Для удаления старой графики мы используем команду ClearScreen(), она принимает один параметр: 24 битное значение цвета, для очистки экрана. Это можно получить, используя команду RGB(). Команда FlipBuffers()  (Helpfile:Reference Manual->2D Games Libraries->Sprite & Screen->FlipBuffers) также имеет необязательный параметр и может принимать следующие значения:

0: Отключение вертикальной синхронизации монитора

1: Включение  вертикальной синхронизации монитора(по умолчанию)

2: Включение  вертикальной синхронизации монитора, использование режима экономии процессора (только в полноэкранном режиме).

Если 0 в качестве параметра, то FlipBuffers() меняет местами буферы так быстро, как от него зависит для достижения наивысшей частоты кадров. Единственным негативом для этого является то, что частота обновления монитора может быть не достаточно быстра, чтобы показывать новую графику в реальном времени, так что некоторые визуальные разрывы могут произойти, поскольку монитор все же пытается идти в ногу с перевертыванием буферов.

Если  1  используется в качестве параметра, команда FlipBuffers() перевертывает буферы в полной синхронизации с частотой обновления монитора, чтобы вся графика рисовалась правильно и согласовываясь с монитором. Единственным недостатком является то, что частота кадров не может превышать за частоту обновления монитора. Это режим по умолчанию, если нет параметра.

Использование 2 в качестве параметра, будет иметь тот же эффект, как использование 1 , но будет энергосберегающий режим процессора, не дающий процессору работать на сто процентов, кроме того другие программы не имеют возможности выполняться.

Рисование на экран

Вот пример с двойной буфферизацией и анимацией созданного рисунка, обновление графики с помощью команды FlipBuffers() (выход из этой программы, нажатие Esc на клавиатуре)

#IMAGE_MAIN=1
;Set the width, height and bit depth of the screen
;Abbreviated variables are used here due to page width constraints :(
Global ScrW.l=1024
Global ScrH.l=768
Global ScrD.l=32
Global Quit.b=#False
XOrigin.f=(ScrW/2)-64 : YOrigin.f=(ScrH/2)-64
;Simple error checking procedure


Procedure HandleError(Result.l, Text.s)
    If Result=0
        MessageRequester("Error", Text, #PB_MessageRequester_Ok)
        End
    EndIf
EndProcedure


;Initialize environment
HandleError(InitSprite(), "InitSprite() command failed.")
HandleError(InitKeyboard(), "InitKeyboard() command failed.")
HandleError(OpenScreen(ScrW, ScrH, ScrD, "Blobs"), "Could not open screen.")
SetFrameRate(60)
;Create an image
If CreateImage(#IMAGE_MAIN, 128, 128)
    If StartDrawing(ImageOutput(#IMAGE_MAIN))
        For x.l=255 To 0 Step-1
            Circle(64, 64, x/4, RGB(0, 0, 255-x))
        Next x
        StopDrawing()
    EndIf
EndIf
;Convert Degrees to Radians


Procedure.f DegToRad(Angle.f)
    ProcedureReturn Angle.f*#PI/180
EndProcedure


;Main loop
Repeat
    ClearScreen(RGB(0, 0, 0))
    Angle.f+2.0
    Radius.f=((ScrH/2)-100)*Sin(DegToRad(Angle))
    StartDrawing(ScreenOutput())
        For x.l=0 To 359 Step 45
            XPos.f=XOrigin+(Radius*Cos(DegToRad(Angle+x)))
            YPos.f=YOrigin+(Radius*Sin(DegToRad(Angle+x)))
            DrawImage(ImageID(#IMAGE_MAIN), XPos, YPos)
        Next x
    StopDrawing()
    FlipBuffers()
    ExamineKeyboard()
    If KeyboardReleased(#PB_Key_Escape)
        Quit=#True
    EndIf
Until Quit=#True
End

В этом примере я создал новый образ, используя команду CreateImage(), а потом вывожу этот образ на экран, используя блок StartDrawing(). Хотя этот код выглядит немного сложнее, особенно при расчетах Х и У значений,  этот пример является чисто, чтобы продемонстрировать переворот буферов.

Вы можете увидеть в основном цикле, что первое, что я делаю, очищаю экран с помощью команды ClearScreen(). Это дает мне возможность начать на четком буфере, так чтобы ни одна старая графика, не осталась от предыдущей операции рисования. После этого я использую математику, чтобы вычислить новые координаты моих пятен на рисунке и использую цикл для их рисования. После того как они нарисованы, они находятся на заднем буфере, так что я должен использовать команду FlipBuffers(), чтобы отобразить их на экране. И так далее, очистка, оформление и отражение, а также между каждым сальто, я могу изменять положение графики.

Вы могли заметить еще одну новую команду, которую я использовал в этом примере, это SetFrameRate() (Helpfile:Reference Manual->2D Games Libraries->Sprite & Screen->SetFrameRate). Эта команда имеет один параметр, который определяет какое количество раз FlipBuffers() может быть выполнен в секунду. Это создание стандартной частоты кадров на других компьютерах, которые могли бы запустить этот код. Данный пример ограничивает обновление для отображения графики до шестидесяти раз в секунду. Вся анимация произведенная на компьютерах, очень похожа на мультфильмы или кинофильмы. Ничего фактически не движется на экране, это лишь демонстрация слайдов различных изображений (буфера), в которых графика находится в немного различных позициях. Поскольку все это случается очень быстро (шестьдесят раз в секунду), нам кажется, что  изображения начинают двигаться.

Простое звездное небо

Это один из эффектов для игр или демосцен, каждый программист в принципе знает, как рисовать подобное. Звездное небо, примерно такое как это, было использовано в сотнях игр и демосцен, поскольку здесь есть эффект перемещения в пространстве. Это эффект, который оживляет сотни пикселей на экране, используя разные оттенки цвета, создает иллюзию глубины и движения. Существуют различные пути программирования этого эффекта, а вот мой пример:

#APP_NAME="Stars v1.0"
#NUMBER_OF_STARS=10000
;Set the width, height and bit depth of the screen
;Abbreviated variables are used here due to page width constraints :(
Global ScrW.l=1024
Global ScrH.l=768
Global ScrD.l=32
Global Quit.b=#False


Structure STAR
    xPos.f
    yPos.f
    xStep.f
    Color.l
EndStructure


Global Dim Stars.STAR(#NUMBER_OF_STARS)
;Simple error checking procedure


Procedure HandleError(Result.l, Text.s)
    If Result=0
        MessageRequester("Error", Text, #PB_MessageRequester_Ok)
        End
    EndIf
EndProcedure


;init stars


Procedure InitializeStars()
    For x=0 To #NUMBER_OF_STARS
        Stars(x) \xPos=Random(ScrW-1)
        Stars(x) \yPos=Random(ScrH-1)
        If x<#NUMBER_OF_STARS/3
            Stars(x) \xStep=(Random(10)/100)+0.2
            Stars(x) \Color=RGB(40, 40, 40)
        ElseIf x>=#NUMBER_OF_STARS/3 And x<(#NUMBER_OF_STARS/3)*2
            Stars(x) \xStep=(Random(10)/100)+0.6
            Stars(x) \Color=RGB(100, 100, 100)
        Else
            Stars(x) \xStep=(Random(10)/100)+1.2
            Stars(x) \Color=RGB(255, 255, 255)
        EndIf
    Next x
EndProcedure


;move stars on the 'x' axis


Procedure MoveStarsX()
    For x=0 To #NUMBER_OF_STARS
        Stars(x) \xPos-Stars(x) \xStep
        If Stars(x) \xPos<0
            Stars(x) \xPos=ScrW-1
            Stars(x) \yPos=Random(ScrH-1)
        EndIf
    Next x
EndProcedure


;Initialize environment
HandleError(InitSprite(), "InitSprite() command failed.")
HandleError(InitKeyboard(), "InitKeyboard() command failed.")
HandleError(OpenScreen(ScrW, ScrH, ScrD, #APP_NAME), "Could not open screen.")
SetFrameRate(60)
InitializeStars()


Repeat
    ClearScreen(RGB(0, 0, 0))
    StartDrawing(ScreenOutput())
        For x=0 To #NUMBER_OF_STARS
            Plot(Stars(x) \xPos, Stars(x) \yPos, Stars(x) \Color)
        Next x
        DrawingMode(#PB_2DDrawing_Transparent)
        DrawText(20, 20, #APP_NAME, #White)
        DrawText(20, 40, Str(#NUMBER_OF_STARS)+" Animated stars", #White)
        DrawText(20, 60, "Screen Resolution: "+Str(ScrW)+" x "+Str(ScrH), #White)
        DrawText(20, 80, "Screen Bit depth: "+Str(ScrD)+"bit", #White)
    StopDrawing()
    FlipBuffers()
    MoveStarsX()
    ExamineKeyboard()
    If KeyboardReleased(#PB_Key_Escape)
        Quit=1
    EndIf
Until Quit=1
End

Этот пример использует 2D команду  рисования  Plot(), для рисования точек (Helpfile:Reference Manual->General Libraries->2DDrawing->Plot). Эта команда использует три параметра, из которых третий не является обязательным. Этими параметрами являются  Х и У расположение, и третий цвет пикселя. Если последний параметр не используется, то эта команда использует цвет по умолчанию, который устанавливается с помощью команды FrontColor() . В приведенном выше примере, я использовал структуру, чтобы сохранить все сведения об одном пикселе вместе. Затем создается массив переменных использующий эту структуру. Каждый из элементов массива описывает положение, цвет и величину шага всех отдельных пикселей. Затем я с помощью цикла прохожу по массиву, получая каждый рисуемый мной пиксель на экране, используя информацию о точках (положение, цвет и т.д.), содержащихся внутри каждого структурированного элемента массива. После того как рисунок завершен, я переварачиваю буферы и обновляю позиции пикселей в массиве, используя соответствующие значения шага. Как только это будет сделано, я очищаю экран и перерисовываю, ... и так далее. Используя такое положение вещей в коде, делает код понятным, запоминающимся и позволяет его легко обновлять позднее.

Открытие экрана в окне

Иногда вы хотели бы открыть экран в окне, особенно если вы хотите, чтобы игра или демо были оконными. Вы можете сделать это, используя команду OpenWindowedScreen(). Чтобы открыть экран в окне, вы должны сначала создать окно, а затем обрабатывать события из этого окна в главном цикле, а также рисунок. Вот пример использования оконного экрана:

#WINDOW_MAIN=1
#IMAGE_MAIN=1
;Set the width, height and bit depth of the screen
;Abbreviated variables are used here due to page width constraints :(
Global ScrW.l=800
Global ScrH.l=600
Global ScrD.l=32
Global Quit.b=#False
Global XOrigin.f=(ScrW/2)-64
Global YOrigin.f=(ScrH/2)-64
;Simple error checking procedure


Procedure HandleError(Result.l, Text.s)
    If Result=0
        MessageRequester("Error", Text, #PB_MessageRequester_Ok)
        End
    EndIf
EndProcedure


;Convert Degrees to Radians


Procedure.f DegToRad(Angle.f)
    ProcedureReturn Angle.f*#PI/180
EndProcedure


;Initialize environment
HandleError(InitSprite(), "InitSprite() command failed.")
HandleError(InitKeyboard(), "InitKeyboard() command failed.")
#FLAGS=#PB_Window_SystemMenu | #PB_Window_ScreenCentered


If OpenWindow(#WINDOW_MAIN, 0, 0, ScrW, ScrH, "Windowed Screen", #FLAGS)
    If OpenWindowedScreen(WindowID(#WINDOW_MAIN), 0, 0, ScrW, ScrH, 0, 0, 0)
        SetFrameRate(60)
        ;Create an image
        If CreateImage(#IMAGE_MAIN, 128, 128)
            If StartDrawing(ImageOutput(#IMAGE_MAIN))
                For x.l=255 To 0 Step-1
                    Circle(64, 64, x/4, RGB(255-x, 0, 0))
                Next x
                StopDrawing()
            EndIf
        EndIf
        ;Main loop
        Repeat
            Event.l=WindowEvent()
            ClearScreen(RGB(0, 0, 0))
            Angle.f+2.0
            Radius.f=((ScrH/2)-100)*Sin(DegToRad(Angle))
            StartDrawing(ScreenOutput())
                For x.l=0 To 359 Step 45
                    XPos.f=XOrigin+(Radius*Cos(DegToRad(Angle+x)))
                    YPos.f=YOrigin+(Radius*Sin(DegToRad(Angle+x)))
                    DrawImage(ImageID(#IMAGE_MAIN), XPos, YPos)
                Next x
            StopDrawing()
            FlipBuffers()
            ExamineKeyboard()
            If KeyboardReleased(#PB_Key_Escape)
                Quit=#True
            EndIf
        Until Event=#PB_Event_CloseWindow Or Quit=#True
    EndIf
EndIf
End
 

Этот пример должен быть для вас понятным, потому что большую часть этого кода вы видели раньше. Основным отличием является команда OpenWindowedScreen(), которая принимает восемь параметров! Первым параметром является идентификатор ОС окна, в котором графика должна быть открыта. Второй и третий параметры  Х и У позиция нового экрана на окне. Четвертый и пятый параметры ширина и высота нового экрана. Шестой параметр автоматический размер или auto-stretch. Если этот параметр установлен в 0, то нет автоматического изменения размера, но если он установлен в  1 , то экран автоматически изменяет размер самого себя до максимального размера окна. Это позволит, не обращать внимания на параметры четыре и пять. Это означает, что даже если, мы будем изменять размер родительского окна, экран будет автоматически изменять свой размер, чтобы заполнить всегда всю область окна. Седьмой и восьмой параметры  можно определять, когда auto-stretch включен. Они будут тянуть автоматическую калибровку экрана немного назад, с правой стороны или снизу, соответственно, оставив место для строки состояния или других устройств в окно. Кроме того, очень важно понимать при использовании экрана в окне: нужно правильно вести обработку событий и здесь как раз подойдет команда WindowEvent(). Если вы помните из главы 9, эта команда не ждет пока событие произойдет, а она всегда пытается обнаружить и вернуть любые события, которые требуют обработки. Использование этой команды является обязательным. Если мы будем использовать  команду  WaitWindowEvent(), то это остановит переключения буферов для любого промежутка времени.

Спрайты

Спрайты в PureBasic это образы, которые можно отобразить в любое место на экране. В отличие от изображений, спрайты имеют свой собственный набор команд, оптимизированы по скорости и могут быть использованы для достижения многих специальных эффектов. Все команды обыкновенных спрайтов вы можете почитать и изучить в справке (Helpfile:Reference Manual->2D Games Libraries->Sprite & Screen), но существуют еще так называемые 3D спрайты, о которых можно почитать (Helpfile:Reference Manual->2DGames Libraries->Sprite3D). Для ознакомления со спрайтами , советую изучить оба раздела.

Разница между простыми спрайтами и 3D спрайтами.

В PureBasic есть два разных типов спрайтов. Первый, это обыкновенный спрайт из загруженного изображения, манипулировать которым нужно, используя стандартную библиотеку спрайтов. Второй тип почти тоже самое, за исключением того, что PureBasic использует небольшой 3D движок для отображения 3D спрайтов. Кроме того, команды, используемые для рисования и управления этим типом спрайта, позволяет программисту достигнуть графических эффектов, которые невозможны с простыми типами спрайтов. Эти эффекты включают масштабирование в реальном времени, трехмерное преобразование и плавное сопряжение спрайта. 3D-движок, который выполняет преобразования и отображения 3D-спрайтов, это не движок OGRE, о чем говорится в следующей главе. Это небольшой 3D-движок, специально созданный для манипуляций с данным типом спрайта.

Использование обычных спрайтов

Для создания спрайтов, используемых в вашей программе, вы можете либо загрузить готовый с помощью команды LoadSprite( ) (Helpfile:Reference Manual->2D Games Libraries->Sprite & Screen->LoadSprite), либо создать новый, используя команду CreateSprite() (Helpfile:Reference Manual->2D Games Libraries->Sprite & Screen->CreateSprite).

Чтобы загрузить существующие изображения, которые будут использоваться в качестве спрайтов, надо использовать команду LoadSprite(). Она очень похожа на команду LoadImage()  и так же принимает три параметра. Первый идентификатор(номер PB), который будет закреплен за данным спрайтом. Второй, это имя файла, которое хотите загрузить, помня, конечно, про использование декодеров изображения в случае необходимости. Третий, это режим спрайта, который определяет, как это спрайт будет использоваться, подробнее об этом чуть позже. Для создания своего собственного спрайта, надо использовать 2D команды рисования, но перед этим его надо создать с помощью команды CreateSprite(). Будучи очень похожа на команду CreateImage(), команда CreateSprite() имеет четыре параметра. Первый параметр, это идентификатор, который закрепится за этим спрайтом. Второй и третий параметры это ширина и высота в пикселях нового спрайта, а четвертый параметр это режим спрайта. Эти две команды создают новый спрайт и оба имеют необязательный параметр-режим спрайта. Этот режим определяет формат внутреннего спрайта, для правильного использования других команд, с ним связанных. Этот формат обычно определяет встроенная константа, рисунок ниже показывает эти константы для каждого из режимов, а также описание каждого режима. В зависимости от команд применяемых в последствии для спрайта, вы должны использовать правильный формат спрайтов,  который устанавливается при создании или загрузки спрайта.

Режимы спрайтов

Используемые константы

Описание режима

Нет

Режим по умолчанию. Спрайт загружается в видеобуфер (если возможно).

#PB_Sprite_Memory

Спрайт загружается в нормальную оперативную память, а не в видеобуфер, для использования с  командой StartSpecialFX()

#PB_Sprite_Alpha

У спрайта должна быть 8 битовая градация серого цвета для использования с командами  DisplayAlphaSprite() или DisplayShadowSprite(). При использовании команды StartSpecialFX() в данном режиме, необходимо указать так же константу  #PB_Sprite_Memory

#PB_Sprite_Texture

Спрайт создается с поддержкой 3D, так что вы можете создавать 3D спрайт, используя команду CreateSprite3D()

#PB_Sprite_AlphaBlending

Спрайт создается с поддержкой альфа-канала. Загруженные изображения должны содержать альфа-канал. В настоящее время для PureBasic альфа-канал поддерживается только в форматах Png и Tiff. (Если вы собираетесь преобразовать эти спрайты в 3D-спрайты,нужно будет так же указать константу  PB_Sprite_Texture)

Режимы могут быть объеденены как обычно с помощью побитового оператора |

Вот несколько примеров того, как правильно определить режим спрайта  для каждой команды дисплея. Я так же дал пример того, как создать и загрузить спрайт с правильными настройками режима, поэтому он(спрайт) будет отображаться правильно при использовании команд.

 

DisplaySprite() & DisplayTransparentSprite()

;Default format
CreateSprite(#PB_NUMBER, Width.l, Height.l)
LoadSprite(#PB_NUMBER, "Image.bmp")

 

DisplaySprite3D()

;Without an alpha channel
CreateSprite(#PB_NUMBER, Width.l, Height.l, #PB_Sprite_Texture )
LoadSprite(#PB_NUMBER, "Image.bmp", #PB_Sprite_Texture )
;With an alpha channel
;NOTE: You can’t create sprites with an alpha channel in PureBasic yet.
LoadSprite(#PB_NUMBER,"Image.bmp",#PB_Sprite_Texture|#PB_Sprite_AlphaBlending)

DisplayTranslucentSprite()

;Load in normal RAM for processing by the 'StartSpecialFX()' command
CreateSprite(#PB_NUMBER, Width.l, Height.l, #PB_Sprite_Memory)
LoadSprite(#PB_NUMBER, "Image.bmp", #PB_Sprite_Memory)

 

DisplayAlphaSprite()’, ‘DisplayShadowSprite()’ & ‘DisplaySolidSprite()

;Load in normal RAM for processing by the 'StartSpecialFX()' command
;and specify as an alpha type sprite
CreateSprite(#PB_NUMBER, Width.l, Height.l, #PB_Sprite_Memory|#PB_Sprite_Alpha)
LoadSprite(#PB_NUMBER, "Image.bmp", #PB_Sprite_Memory | #PB_Sprite_Alpha)

 

Эти примеры должны дать вам хорошее представление о том, как загружать и создавать свои собственные спрайты для каждой отображенной команды.

 

Вы можете рисовать на спрайтах тоже.

После того как вы создали или загрузили спрайт, вы можете использовать его. Так же как и с изображениями, это делается с помощью стандартной команды StartDrawing() с параметром  SpriteOutput(). Это позволяет использовать 2D  команды на поверхность спрайта. Вы можете даже нарисовать один спрайт на другой. Для этого вы должны переключать спрайт из заднего буфера на ваш целевой спрайт. Это достигается с помощью команды UseBuffer(). Эта команда имеет один параметр-идентификатор того спрайта, на который вы хотите рисовать. После подключения рисования с помощью UseBuffer(), все команды рисования применяются для рисования на спрайт. Когда вы все нарисовали на спрайте, и вам нужно вернуть возможность рисовать на основном экране, примените опять команду UseBuffer(), только на этот раз с параметром #PB_Default.

Команды спрайта SpecialFX

В таблице с режимами, я уже упоминал о спрайтах SpecialFX. Это обыкновенные спрайты, но работают гораздо быстрее, если вставлять их в блок команд StartSpecialFX().....StopSpecialFX(). Все спрайты, которые используют спецэффекты, способны производить красивую графику, но поскольку все это происходит внутри основной оперативной памяти компьютера, эти спрайты не так быстры, как 3D спрайты. Вот небольшой фрагмент текста, который показывает использование этих команд:

...
StartSpecialFX()
  DisplayAlphaSprite(#SPRITE_NUMBER, 64, 64)
  DisplayRGBFilter(100, 100, 100, 100, 0, 255, 0)
  DisplayTranslucentSprite(#SPRITE_NUMBER, 128, 128, 128)
  ;etc...
StopSpecialFX()
...

Как вы можете видеть, команда StartSpecialFX() начинает блок, а команда StopSpecialFX() заканчивает. Все команды, связанные со спецэффектами должны идти внутрь этого блока. Это сделано для увеличения скорости рендеринга спецэффектов, в противном случае, без  StartSpecialFX()  производительность отображения будет очень низкая. Если вы используете эти команды, очень важно понимать, что все команды графики должны быть в этом блоке. В противном случае, если вы используете другие команды графики до блока спецэффектов, они будут рисовать в заднем буфере. Если вы используете команду ClearScreen() для очистки буфера перед рисованием, вы должны включить ее в блок StartSpecialFX() тоже. Еще один важный момент, желательно использовать только один блок StartSpecialFX() в любом основном цикле, так как это увеличивает производительность.

Команды, которые используют блок StartSpecialFX():

DisplayAlphaSprite()
DisplaySolidSprite()
DisplayShadowSprite()
DisplayRGBFilter()
DisplayTranslucentSprite()

Вы можете прочитать об этих командах более подробно в справке (Helpfile:Reference Manual->2D Games Libraries->Sprite & Screen).

Отображение простых спрайтов

Простые спрайты лежат в основе двумерных игр в PureBasic. Этот тип спрайта был использован снова и снова, раз за разом, производя "холодные" изображения во многих самых популярных играх. Вот простой пример создания новых спрайтов и отображения их на экране с помощью стандартной команды DisplayTransparentSprite():

#SPRITE_MAIN = 1
#NUMBER_OF_BALLS = 500
;Set the width, height and bit depth of the screen
;Abbreviated variables are used here due to page width constraints :(
Global ScrW.l = 1024
Global ScrH.l = 768
Global ScrD.l = 32
Global Quit.b = #False


Structure BALL
    x.f
    y.f
    XOrigin.l
    YOrigin.l
    Radius.l
    Angle.f
    Speed.f
EndStructure


Global Dim Balls.BALL(#NUMBER_OF_BALLS)
;Simple error checking procedure


Procedure HandleError(Result.l, Text.s)
    If Result = 0
        MessageRequester("Error", Text, #PB_MessageRequester_Ok)
        End
    EndIf
EndProcedure


;Convert Degrees to Radians


Procedure.f DegToRad(Angle.f)
    ProcedureReturn Angle.f * #PI / 180
EndProcedure


;Initialize all ball data


Procedure InitialiseBalls()
    For x.l = 0 To #NUMBER_OF_BALLS
        Balls(x)\XOrigin = Random(ScrW) - 32
        Balls(x)\YOrigin = Random(ScrH) - 32
        Balls(x)\Radius = Random(190) + 10
        Balls(x)\Angle = Random(360)
        Balls(x)\Speed = Random(2) + 1
    Next x
EndProcedure


;Initialize environment
HandleError(InitSprite(), "InitSprite() command failed.")
HandleError(InitKeyboard(), "InitKeyboard() command failed.")
HandleError(OpenScreen(ScrW, ScrH, ScrD, "Blobs"), "Could not open screen.")
SetFrameRate(60)
;Create an image
Global Offset.f = 32
If CreateSprite(#SPRITE_MAIN, 64, 64)
    If StartDrawing(SpriteOutput(#SPRITE_MAIN))
        Box(0, 0, 64, 64, RGB(255, 255, 255))
        For x.l = 220 To 1 Step -1
            Offset + 0.025
            Circle(Offset, 64 - Offset, x / 8, RGB(0, 255 - x, 0))
        Next x
        StopDrawing()
    EndIf
EndIf
TransparentSpriteColor(#SPRITE_MAIN, RGB(255, 255, 255))
InitialiseBalls()
;Main loop
Repeat
    ClearScreen(RGB(56, 76, 104))
    For x.l = 0 To #NUMBER_OF_BALLS
        Balls(x)\x=Balls(x)\XOrigin+(Balls(x)\Radius*Cos(DegToRad(Balls(x)\Angle)))
        Balls(x)\y=Balls(x)\YOrigin+(Balls(x)\Radius*Sin(DegToRad(Balls(x)\Angle)))
        Balls(x)\Angle + Balls(x)\Speed
        DisplayTransparentSprite(#SPRITE_MAIN, Balls(x)\x, Balls(x)\y)
    Next x
    FlipBuffers()
    ExamineKeyboard()
    If KeyboardReleased(#PB_Key_Escape)
        Quit = #True
    EndIf
Until Quit = #True
End

Команда DisplayTransparentSprite() позволяет отображать на экране спрайты. Она очень похожа на команду DisplaySprite(), но при выводе спрайтов с помощью DisplayTransparentSprit(), она выбирает один цвет на изображении и относит его к прозрачному цвету. Это позволяет не показывать всю площадь спрайта. В этом примере я создал новый спрайт, а затем тут же заполнил его белым цветом с использованием команды Box(). После этого я нарисовал затененную зеленую область с помощью команды Circle() в цикле. В итоге зеленая область на белом фоне. После команд рисования, я пометил все белые пиксели в новом спрайте как прозрачные, используя  команду TransparentSpriteColor(). Эта команда имеет два параметра, первый идентификатор спрайта, а второй цвет, который мы хотим пометить прозрачным. Как только цвет взят для следующего использования, команда  DisplayTransparentSprite() показывает спрайт, минус прозрачный цвет. После запуска примера, вы должны увидеть экран, заполненный зелеными сферами, без отображения белого фона. Это отличный способ показать спрайты с прозрачностью. Вы также заметили в этом примере, что для того, чтобы отобразить нормальный спрайт не нужны блоки команд: StartSpecialFX() или StartDrawing() и т.д. Вы можете использовать команды отображения обычного спрайта сами по себе. До тех пор, пока движок спрайта инициализируется и экран открыт, вы можете использовать стандартные команды для отображения спрайтов. Стандартные команды показывающие спрайты :

DisplaySprite()
DisplayTransparentSprite()

Использование 3D спрайтов

Каждый 3D спрайт  это 2D поверхность, состоящая из двух многоугольников. Эти многоугольники рисуются с помощью небольшого 3D-движка и могут быть преобразованы в 3D, но каждый 3D спрайт в конечном счете используется на 2D на экране. Непонятно? Хорошо, давайте продолжим. 3D спрайт в PureBasic на самом деле простой спрайт, для которого оказывается поддержка 3D с помощью малого 3D движка, отображающего его. Чтобы использовать любой 3D спрайт в вашей программе, вы должны инициализировать 3D движок перед использованием любых связанных команд. Это делается с помощью команды InitSprite3D(). Эта команда, однако вызывается после обязательной команды InitSprite(). Каждый 3D спрайт начинает "жизнь" как нормальный спрайт. Превращение его в 3D происходит в два этапа. Первый это при загрузке устанавливается режим PB_Sprite_Texture#. Вторым этапом  спрайт с помощью команды CreateSprite3D() как раз и превращается в 3D спрайт. Эта команда имеет два параметра. Первый это идентификатор нового 3D спрайта, который за ним закрепится. Второй параметр собственно тот 2D спрайт, из которого надо его создать. Вот как происходит преобразование простого спрайта в 3D спрайт:

LoadSprite(#NORMAL_SPRITE, "Image.bmp", #PB_Sprite_Texture)
CreateSprite3D(#SPRITE_3D, #NORMAL_SPRITE)

После того как 3D спрайт был создан, мы можем показывать это на экране, используя команду DisplaySprite3D(). Чтобы было все более или менее понятно, покажу на  примере отображения и манипулирования 3D спрайта:

UsePNGImageDecoder()

Enumeration
  #SPRITE_2D
  #SPRITE_3D
EndEnumeration

#NUMBER_OF_FLOWERS = 150
;Set the width, height and bit depth of the screen
;Abbreviated variables are used here due to page width constraints :(
Global ScrW.l = 1024
Global ScrH.l = 768
Global ScrD.l = 32
;Other global variables
Global Quit.b = #False
Global XOrigin.l = ScrW / 2
Global YOrigin.l = ScrH / 2

Structure FLOWER
  XPos.f
  YPos.f
  Width.f
  Height.f
  Angle.f
  Radius.f
  RadiusStep.f
EndStructure

Global Dim Flowers.FLOWER(#NUMBER_OF_FLOWERS)
;Simple error checking procedure

Procedure HandleError(Result.l, Text.s)
  If Result = 0
    MessageRequester("Error", Text, #PB_MessageRequester_Ok)
    End
  EndIf
EndProcedure

;Convert Degrees to Radians

Procedure.f DegToRad(Angle.f)
  ProcedureReturn Angle.f * #PI / 180
EndProcedure

;Initialize all flowers

Procedure InitialiseAllFlowers()
  For x.l = 0 To #NUMBER_OF_FLOWERS
    Flowers(x)\Width = 0
    Flowers(x)\Height = 0
    Flowers(x)\Angle = Random(360)
    Flowers(x)\Radius = 1.0
    Flowers(x)\RadiusStep = (Random(30) / 10) + 1.0
  Next x
EndProcedure

;Reset a flower

Procedure ResetFlower(Index.l)
  Flowers(Index)\Width = 0
  Flowers(Index)\Height = 0
  Flowers(Index)\Angle = Random(360)
  Flowers(Index)\Radius = 1.0
  Flowers(Index)\RadiusStep = (Random(30) / 10) + 1.0
  ProcedureReturn
EndProcedure

;Initialize environment

HandleError(InitSprite(), "InitSprite() command failed.")
HandleError(InitSprite3D(), "InitSprite3D() command failed.")
HandleError(InitKeyboard(), "InitKeyboard() command failed.")
HandleError(OpenScreen(ScrW, ScrH, ScrD, "Flowers"), "Could not open screen.")
SetFrameRate(60)
Sprite3DQuality(1)
;Load sprite
LoadSprite(#SPRITE_2D,"Flower.png",#PB_Sprite_Texture|#PB_Sprite_AlphaBlending)
CreateSprite3D(#SPRITE_3D, #SPRITE_2D)
InitialiseAllFlowers()
;Main loop

Repeat
  ClearScreen(RGB(200, 100, 100))
  HandleError(Start3D(), "Start3D() command failed.")
  For x.l = 0 To #NUMBER_OF_FLOWERS
    Flowers(x)\Width + 1.5
    Flowers(x)\Height + 1.5
    Flowers(x)\Angle + 1.0
    If Flowers(x)\Width > 512.0 Or Flowers(x)\Height > 512.0
        Flowers(x)\Width = 512.0
        Flowers(x)\Height = 512.0
    EndIf
    If Flowers(x)\Radius > ScrW
        ResetFlower(x)
    EndIf
    Flowers(x)\Radius + Flowers(x)\RadiusStep
    Flowers(x)\XPos=XOrigin+(Flowers(x)\Radius*Cos(DegToRad(Flowers(x)\Angle)))
    Flowers(x)\YPos=YOrigin+(Flowers(x)\Radius*Sin(DegToRad(Flowers(x)\Angle)))
    Flowers(x)\XPos - Flowers(x)\Radius / 3.5
    Flowers(x)\YPos - Flowers(x)\Radius / 3.5
    ZoomSprite3D(#SPRITE_3D, Flowers(x)\Width, Flowers(x)\Height)
    RotateSprite3D(#SPRITE_3D, Flowers(x)\Angle, 0)
    DisplaySprite3D(#SPRITE_3D, Flowers(x)\XPos, Flowers(x)\YPos)
  Next x
  Stop3D()
  FlipBuffers()
  ExamineKeyboard()
  If KeyboardReleased(#PB_Key_Escape)
    Quit = #True
  EndIf
Until Quit = #True
End

Чтобы иметь возможность использовать 3D спрайт в моем примере, я инициализировал два движка, один за другим с помощью команд InitSprite() и  InitSprite3D(). Это крайне важно перед использованием любых команд, связанных с 3D спрайтами. После этого, я  использовал команду LoadSprite() для загрузки изображения формата PNG. Это изображение с именем  "Flower.png", используется с альфа-каналом для создания прозрачного фона. Загрузка изображения в формате "Png" с альфа-каналом,  требует определения правильного режима для команды LoadSprite(). Если вы посмотрите на пример кода, я определил режим:  # PB_Sprite_Texture | # PB_Sprite_AlphaBlending. Это сообщает компилятору,что я хочу использовать этот спрайт, как 3D спрайт, содержащий альфа-канал. После того, как он загружен и правильно определен, я могу создать 3D спрайт из него при помощи команды CreatSprite3D(), при этом  альфа-канал сохраняется. После того, как спрайт был создан, настало время обратить его на экране. Это достигается с помощью команды DisplaySprite3D()внутри блока Start3D()...Stop3D() . Это выглядит примерно так:

...
Start3D()
DisplaySprite3D(#SPRITE_3D, x, y, Alpha)
Stop3D()
...

Если вы посмотрите на прошлый пример, вы увидите что блок Start3D()  проверяется с помощью процедуры малых ошибок. Если все правильно инициализировано, мы можем продолжить и сделать спрайты. Если он  запускается неправильно, мы не должны делать никаких 3D спрайтов, во избежание серьезной аварии программы. Команда Stop3D()используется для завершения блока команд 3D спрайта, которые в нем находятся .. Для показа 3D спрайта я использую команду DisplaySprite3D(), которая принимает четыре параметра. Первый идентификатор 3D спрайта. Второй и третий  Х  и  У  координаты. Четвертый параметр это альфа значение спрайта, определяет прозрачность спрайта на экране. Это целое число в диапазоне от 0, которое является полностью прозрачным, до 255, которое полностью непрозрачное. В примере я также использовал команды: ZoomSprite3D() и RotateSprite3D() для изменения размера и поворота 3D спрайта. Эти команды несложно понять, и прочесть о них более подробно, можно в справке (Helpfile:Reference Manual->2D GamesLibraries->Sprite3D).

Качество 3D спрайтов

При использовании 3D спрайтов в вашей программе, есть возможность переключать качество спрайтов. Это делается с помощью команды Sprite3DQuality(). Эта команда имеет один параметр, которым является режим рендеринга всех 3D спрайтов в вашей программе. Параметр представляет собой числовое значение:

0: Нет фильтрации (быстро, но очень неровно при масштабировании и наклоне)

1: Билинейная фильтрация (медленно, но смешивает пиксели для более качественного просмотра при масштабировании и наклоне)

В моем примере я использовал команду Sprite3DQuality(1), которая позволит билинейную фильтрацию и дает спрайтам хороший ровный взгляд, когда я меняю размеры и их ротацию. Когда эта команда не используется (по умолчанию настройки качества для программ 0), получается отсутствие фильтрации, в результате чего 3D спрайты выглядят не так гладко, при манипуляциях с ними.


 
Содержание                  Учебник                Главная
Сайт создан в системе uCoz