Raylib в Pharo
Raylib в Pharo
См. также: Morphic · Pharo · SmallShooter · SmallPong · Справочник §16 — FFI · Игры на C++ · Pygame — Ping Pong · Практикум игр
Что такое Raylib?
Raylib — лёгкая C-библиотека для 2D/3D-игр и мультимедиа. Она даёт:
- создание OS-окна;
- отрисовку примитивов, текста, текстур;
- загрузку звуков и музыки;
- опрос клавиатуры и мыши.
Девиз проекта — "just code": минимум настроек, один нативный файл raylib.dll / libraylib.so. Сайт: raylib.com.
Важно для Smalltalk: Raylib не входит в стандартный образ Pharo. Подключение идёт через FFI (Foreign Function Interface) — механизм вызова C-функций из Smalltalk. Pharo вызывает, например, InitWindow, DrawText, CloseWindow из загруженной DLL.
Термины:
- FFI / uFFI — Unified FFI в Pharo; переносимый слой поверх libffi; см. §16 справочника.
- Call-out — вызов из Smalltalk в C (наружу из image).
- Binding (биндинг) — Smalltalk-обёртка с методами для функций C-библиотеки.
- pharo-cig — генератор биндингов из заголовков
.hчерез libclang.
После хотя бы одного Morphic-практикума (крестики-нолики, SmallPong). Иначе сначала непонятна разница между step и C-циклом while.
Зачем Raylib, если есть Morphic?
| Критерий | Morphic | Raylib |
|---|---|---|
| Окно | Внутри среды Pharo (World) | Отдельное OS-окно |
| Графика | drawOn:, цветные прямоугольники | Текстуры, шейдеры, 3D |
| Звук | Ограниченно / сторонние libs | Встроенный audio API |
| Зависимости | Нет | Нативный raylib |
| Учебная цель | ООП, MVC, live UI | FFI, нативный game loop |
| Практикумы раздела | SmallPong, SmallShooter, TTT | Расширение для "настоящего" рендера |
Morphic — лучший первый шаг: весь код в image, Debugger доступен между кадрами, модель игры отделена от UI (SmallPong).
Raylib — когда нужна производительная 2D/3D-графика или осознанное сравнение с:
- Pygame (Python);
- raylib в C++;
- классическим циклом "poll → update → draw" из практикума игр.
uFFI — основа вызовов
Pharo использует Unified FFI (uFFI). Минимальный call-out к Raylib:
Object subclass: #RaylibTutorial
classVariableNames: ''
package: 'RaylibTutorial'
RaylibTutorial class >> initWindow: width height: height title: title
^ self ffiCall: #(void InitWindow(int width, int height, char *title))
library: (self raylibLibrary)
RaylibTutorial class >> raylibLibrary
^ 'raylib'
Разбор:
| Фрагмент | Смысл |
|---|---|
ffiCall: | Сообщение uFFI; аргумент — литерал с сигнатурой C-функции |
#(void InitWindow(...)) | Тип возврата void, имя функции, типы параметров |
char *title | Указатель на C-строку; Smalltalk передаёт ByteString / ExternalString |
library: (self raylibLibrary) | Имя DLL/SO; VM подставит .dll, .so, .dylib |
'raylib' | Базовое имя файла raylib.dll на Windows |
Подробная книга: Calling Foreign Functions from Pharo (uFFI booklet).
На практике сотни ffiCall вручную не пишут — берут готовый пакет или генерируют код через pharo-cig.
Проекты биндингов в Pharo
| Проект | Описание | Ссылка |
|---|---|---|
| pharo-raylib | Биндинги сообщества pharo-cig | github.com/pharo-cig/pharo-raylib |
| pharoRaylib | Ручные обёртки, RaylibConstants | github.com/Zenchess/pharoRaylib |
| pharo-cig | Генератор FFI из C/C++ | github.com/pharo-cig/pharo-cig |
pharo-cig читает raylib.h и создаёт пакет Raylib с тысячами функций. Для графических библиотек включают useMainThread, потому что OpenGL/OS-окно ожидают главный поток процесса.
Пример генерации (упрощённо)
(CigCLibraryGenerator new)
prefix: 'Ray';
packageName: 'Raylib';
libraryName: 'raylib';
import: '/path/to/raylib/src/raylib.h';
cIncludePath: '/path/to/raylib/src';
useMainThread;
generate
После generate в image появляются классы вроде RaylibLibrary с методами для каждой экспортированной C-функции. Поверх них можно писать Smalltalk-обёртки с удобными именами (initWindowWidth:height:title:).
Установка Raylib и DLL
Windows
- Скачайте 64-bit MSVC сборку Raylib 5.x с GitHub releases.
- Положите
raylib.dllрядом с.imagePharo или в каталог изPATH. - Загрузите пакет биндингов через Metacello (скрипт в README репозитория).
Linux
sudo apt install libraylib-dev
Проверьте RaylibLibrary>>unixLibraryName — обычно ^ 'libraylib.so'.
macOS
brew install raylib
Укажите путь к .dylib в finder-классе FFILibrary, если VM не находит библиотеку автоматически.
Биндинги привязаны к версии заголовков (например Raylib 5.0). Несовпадение raylib.dll и сгенерированных сигнатур рушит VM без Smalltalk-исключения — всегда сверяйте README проекта.
Игровой цикл в Pharo и Raylib
Raylib ожидает классический цикл на C:
InitWindow(800, 600, "Pharo Raylib");
while (!WindowShouldClose()) {
BeginDrawing();
ClearBackground(RAYWHITE);
DrawText("Hello", 190, 200, 20, LIGHTGRAY);
EndDrawing();
}
CloseWindow();
Разбор C-цикла:
| Шаг | Назначение |
|---|---|
InitWindow | Создать окно 800×600 |
WindowShouldClose | true, если пользователь закрыл окно |
BeginDrawing / EndDrawing | Пара для кадра |
ClearBackground | Заливка фона цветом RAYWHITE |
DrawText | Текст на экране |
CloseWindow | Освободить ресурсы |
В Smalltalk те же шаги — сообщения к FFI-классу. Константы RAYWHITE, LIGHTGRAY — в shared pool RaylibConstants (пакет pharoRaylib).
Обёртка в Pharo (псевдоструктура)
RayGame class >> run
[ self initWindow.
[ self update.
self draw.
self shouldClose ] whileFalse.
self closeWindow ] ensure: [ self cleanup ]
Сравнение с Morphic:
| Morphic | Raylib |
|---|---|
startStepping + step | while + Draw* |
stepTime = 16 | SetTargetFPS(60) в Raylib |
changed | EndDrawing |
Потоки: UI Pharo исторически однопоточный; Raylib-окно на main thread. Отладка "внутри" DrawText может блокировать морфы Pharo. Логику игры держите в отдельных объектах (как ShooterGame в SmallShooter) — меняется только слой отрисовки.
Сравнение с практикумом SmallShooter
SmallShooter — тот же жанр без Raylib:
| Аспект | SmallShooter (Morphic) | Raylib |
|---|---|---|
| Цикл | ShooterGameMorph>>step | while !WindowShouldClose |
| Спрайты | RectangleMorph, drawOn: | DrawRectangle, текстуры |
| Отладчик | Между кадрами в Pharo | Сложнее при FFI-crash |
| Зависимости | Нет | DLL + биндинги |
Портирование: класс ShooterGame (модель) можно оставить; заменить только морф на FFI-адаптер, который в draw читает координаты из модели и вызывает DrawRectangle.
Raylib даёт больше FPS и эффектов на тяжёлых сценах; Morphic глубже учит Smalltalk. Оба подхода укладываются в игровой практикум как разные слои одной дисциплины.
Загрузка пакета через Metacello
Точный скрипт — в README репозитория. Общий шаблон:
Metacello new
baseline: 'Raylib';
repository: 'github://pharo-cig/pharo-raylib:main';
load
После загрузки:
- Smoke test из документации пакета (открыть окно, нарисовать текст).
- Свой класс
MyRayGameс методамиupdate,draw,run. - Save as копии image перед экспериментами.
Подробнее о Metacello — статья Pharo.
Ограничения и риски
| Риск | Пояснение |
|---|---|
| Краш VM | Неверная сигнатура FFI → падение всего образа, не Error |
| Потоки | Raylib + Morphic UI — согласовать main thread |
| Deploy | VM + image + raylib.dll, не один .exe |
| Документация | Меньше, чем у Morphic-практикумов раздела |
| Отладка | C-level crash не попадает в Smalltalk Debugger |
Рекомендация: чистый образ + копия .image перед FFI; для учёбы достаточно Morphic.
Связь с другими темами
- C++ / raylib — игры на C++: та же библиотека, другой язык.
- FFI — §16 справочника.
- Morphic-игры — SmallPong, SmallShooter.
- Pharo как платформа — статья Pharo.
Что дальше
| Шаг | Действие |
|---|---|
| 1 | Пройти SmallPong на Morphic |
| 2 | Установить Raylib + один пакет биндингов |
| 3 | Запустить demo из репозитория |
| 4 | Портировать модель из SmallShooter на FFI-отрисовку |