Создание простой игры в PICO-8 — крестики‑нолики
PICO-8 — лёгкая виртуальная консоль для быстрой разработки ретро-игр. В этой инструкции вы научитесь запускать PICO-8, написать простую игру «крестики‑нолики», отслеживать состояние игры, обрабатывать ввод мышью и упаковать игру для распространения.

Кратко о терминах:
- PICO-8 — виртуальная консоль и набор инструментов для создания 8‑битных игр.
- Картридж — сохранённый файл игры (.p8 или .p8.png) для PICO-8.
- Lua (подмножество) — язык, используемый в PICO-8 для логики игры.
Введение
PICO-8 отлично подходит для обучения созданию игр. Интерфейс простой, встроены редакторы спрайтов и музыки, а игры легко распространять в виде HTML или нативных бинарников. Начните с небольшой игры, чтобы освоить цикл игры, ввод и отрисовку.
Важно: PICO-8 использует экран 128×128 пикселей и ограниченный набор API — это упрощает разработку, но требует аккуратного планирования графики и логики.
Запуск консоли PICO-8
- Скачайте PICO-8 с itch.io и установите для Windows, macOS или Linux.
- Запустите приложение PICO-8.
Вы увидите стартовый экран командной строки PICO-8. Здесь можно загружать картриджи, запускать команды и экспортировать проекты.
Подсказка: команда FOLDER откроет папку с картриджами в файловом менеджере.
Базовое использование редактора кода
Чтобы понять, как писать код для PICO-8, откройте встроенный редактор и запустите простую программу.
- На стартовом экране нажмите ESC для входа в редактор кода.
- Введите простую программу:
-- простой пример
PRINT("HELLO, WORLD")- Нажмите ESC, чтобы вернуться к командной строке.
- Введите RUN и нажмите Enter — программа выведет сообщение “HELLO, WORLD”.
Примечание: PICO-8 поддерживает подмножество Lua и имеет свои встроенные функции для отрисовки и ввода.
Концепция игрового цикла
Основная идея разработки игр — цикл игры (game loop):
- Получить ввод от игрока.
- Обновить состояние игры.
- Отрисовать экран.
PICO-8 автоматически вызывает специальные функции _init(), _update() и _draw().
- _init() — инициализация, запускается один раз при старте.
- _update() — логика, вызывается каждый кадр (обычно 30 FPS по умолчанию).
- _draw() — отрисовка экрана, вызывается каждый кадр.
Первое взаимодействие с мышью
Если вы хотите использовать мышь, в _init() нужно включить поддержку:
function _init()
-- включить мышь
poke(0x5f2d, 1)
endВ _update() следует получить координаты мыши:
function _update()
mousex = stat(32)
mousey = stat(33)
endstat(n) — встроенная функция, возвращающая разные данные окружения; 32/33 — координаты мыши, 34 — состояние левой кнопки (0 или 1).
В _draw() можно отрисовать простой прицел (крест):
function _draw()
cls()
line(mousex, mousey - 4, mousex, mousey + 4)
line(mousex - 4, mousey, mousex + 4, mousey)
endФункция cls() очищает экран. Попробуйте временно удалить cls(), чтобы увидеть эффект накопления линий.
Рисование игровых элементов
Игровое поле for крестиков‑ноликов — 3×3, экран 128×128, поэтому оптимальный размер клетки ~42 пикселя с одной полосой для линий сетки.
function draw_grid()
-- две вертикальные линии
line(42, 0, 42, 127)
line(85, 0, 85, 127)
-- две горизонтальные линии
line(0, 42, 127, 42)
line(0, 85, 127, 85)
endФункции для рисования символов:
function draw_nought(x, y)
circ(x, y, 10) -- окружность радиусом 10
end
function draw_cross(x, y)
line(x - 10, y - 10, x + 10, y + 10)
line(x + 10, y - 10, x - 10, y + 10)
endЧтобы рисовать символы в конкретной ячейке, вычисляем центр клетки и вызываем draw_cross/draw_nought.
Отражение состояния доски в данных
Для хранения состояния используем одномерный массив из 9 элементов. В PICO-8 индексация начинается с 1.
p = {"", "", "", "", "", "", "", "", ""}
current_player = "x" -- или "0"
finished = false
winner = nilПример записи значения в верхнюю левую ячейку и проверки:
-- записать нолик в верхний левый угол
p[1] = "0"
-- проверить нижний правый угол
if p[9] == "x" then
-- действие
endДля преобразования координат мыши в индекс массива используйте деление и округление вниз (flr):
mousecol = flr(mousex / 42.666)
mouserow = flr((mousey / 42.666) % 3)
-- индекс массива от 1 до 9
cell_index = mousecol + mouserow * 3 + 1Важно: подгоняйте делитель (42.666) под точную формулу, чтобы нечёткие границы отрабатывались корректно.
Обработка кликов мышью
Нужно отслеживать переход кнопки из состояния “не нажата” в “нажата” (детект первого клика). Для этого используем флаг down:
down = false
function _update()
local left = stat(34) -- 0 или 1
if down and left == 0 then
down = false
end
if (not down) and left == 1 then
down = true
-- обработать клик: вычислить cell_index и сделать ход
handle_click()
end
endФункция handle_click() должна:
- проверить, что игра не закончена;
- вычислить индекс клетки;
- если клетка пуста — записать символ текущего игрока;
- переключить current_player;
- вызвать проверку на победу.
Пример handle_click():
function handle_click()
if finished then return end
local col = flr(mousex / 42.666)
local row = flr(mousey / 42.666)
if col < 0 or col > 2 or row < 0 or row > 2 then return end
local idx = col + row * 3 + 1
if p[idx] == "" then
p[idx] = current_player
check_for_win()
if not finished then
if current_player == "x" then current_player = "0" else current_player = "x" end
end
end
endПроверка победы и ничьей
Для крестиков‑ноликов часто удобнее применить прямую (brute-force) проверку всех выигрышных комбинаций. Это просто и понятно для маленького поля.
function check_for_win()
-- проверить колонки
for a = 1, 3 do
if p[a] ~= "" and p[a] == p[a + 3] and p[a] == p[a + 6] then
finished = true
winner = p[a]
return
end
end
-- проверить строки
for r = 0, 2 do
local base = r * 3 + 1
if p[base] ~= "" and p[base] == p[base + 1] and p[base] == p[base + 2] then
finished = true
winner = p[base]
return
end
end
-- диагонали
if p[1] ~= "" and p[1] == p[5] and p[1] == p[9] then
finished = true
winner = p[1]
return
end
if p[3] ~= "" and p[3] == p[5] and p[3] == p[7] then
finished = true
winner = p[3]
return
end
-- ничья — все клетки заполнены
local full = true
for i = 1, 9 do
if p[i] == "" then full = false break end
end
if full then finished = true; winner = nil end
endПосле обнаружения победителя переменные finished и winner можно использовать в _draw() для отображения сообщения.
Полная схема отрисовки экрана
В _draw() объедините очистку экрана, отрисовку сетки, доски, превью символа и финального сообщения:
function _draw()
cls()
draw_grid()
draw_board()
draw_hover_preview()
if finished then
draw_result()
end
endПример draw_board(), которая рисует символы в каждой клетке:
function draw_board()
for i = 1, 9 do
local col = ((i - 1) % 3)
local row = flr((i - 1) / 3)
local cx = col * 42 + 21 -- центр клетки
local cy = row * 42 + 21
if p[i] == "x" then
draw_cross(cx, cy)
elseif p[i] == "0" then
draw_nought(cx, cy)
end
end
endДополнительные проверки и устойчивость
- Защитите от выхода за пределы массива.
- Обрабатывайте неоднозначности на границе клеток.
- Добавьте кнопку перезапуска (например, клавиша R или клик по кнопке на экране).
Пример перезапуска:
function reset_game()
for i = 1, 9 do p[i] = "" end
current_player = "x"
finished = false
winner = nil
end
function _update()
-- пример: нажатие клавиши R
if btnp(19) then -- btnp(19) соответствует клавише R в PICO-8 (проверьте в вашей конфигурации)
reset_game()
end
-- остальная логика (мышь и т. п.)
endПримеры улучшений и альтернативные подходы
- AI оппонент: реализуйте простой алгоритм (выбор случайной пустой клетки) или Minimax для идеального соперника.
- Спрайты: вместо векторных линий используйте спрайты (editor S) для более выразительной графики.
- Управление с клавиатуры: добавьте перемещение фокуса по клеткам стрелками и подтверждение Enter.
- Сохранение результата: экспортируйте строки состояния в текстовый файл или используйте встроенное сохранение картриджа.
Когда эти подходы не подходят:
- Minimax избыточен для простых быстрых прототипов.
- Спрайты усложняют логику, если вы хотите минималистичный ретро‑стиль.
Чек‑лист перед публикацией
- Игра запускается командой RUN без ошибок.
- Скриншот сделан (F2) и корректно отображается.
- Команда EXPORT HTML/BIN проходит без ошибок.
- Кнопка перезапуска работает.
- Обработаны краевые случаи (клики вне поля, быстрые повторные клики).
Упаковка и экспорт
- Запустите игру: введите RUN.
- Во время выполнения нажмите F2, чтобы сделать скриншот — он станет превью.
- На командной строке PICO-8 выполните:
- Для HTML: EXPORT TICTACTOE.HTML
- Для нативных бинарников: EXPORT TICTACTOE.BIN
Файлы будут сохранены в папке картриджей.
Советы по тестированию и критериям приёмки
Тестовые сценарии (приёмка):
- Игрок A делает ход, затем игрок B; символы должны корректно отображаться.
- Попытка поставить символ в занятый слот — отклоняется.
- Обнаружение победы для каждой строки, колонки и диагонали.
- Обнаружение ничьей при заполнении всех клеток.
- Перезапуск игры возвращает всё в исходное состояние.
Ментальные модели и эвристики
- Модель “состояние → обновление → отрисовка”: сначала обновляем все данные, затем рисуем экран.
- Для мелких игровых полей brute-force часто быстрее и безопаснее чем оптимизация алгоритмов.
- Разделяйте представление (рисование) и модель (состояние), чтобы тестировать логику без UI.
Уровни зрелости проекта
- MVP: базовая игра, ходы, победа/ничья, перезапуск.
- v1: простая AI, улучшенная графика, превью хода.
- v2: очки/статистика, меню, музыка и звуки.
- v3: публикация на itch.io, экспорт бинарников и поддержка разных платформ.
Совместимость и миграция
PICO-8 работает на Windows, macOS и Linux. Экспорт HTML даёт максимально широкую совместимость для размещения на веб‑страницах.
Примечание: версии PICO-8 иногда меняют внутренние id статуса — при портировании кода проверяйте актуальность stat() индексов в документации.
Локализация и адаптация под русскоязычную аудиторию
- Переведите текст интерфейса и сообщения о результате (например, “Игрок X победил” или “Ничья”).
- Учитывайте, где размещаете экспорт: itch.io и другие площадки поддерживают описания на русском.
Превью и объявление для соцсетей
OG заголовок: Простая игра в PICO-8 — крестики‑нолики OG описание: Маленький туториал по созданию и экспорту игры крестики‑нолики в PICO-8. Подходит для начинающих.
Короткое объявление (100–200 слов): Создал простую инструкцию по PICO-8 для начинающих. В руководстве — настройка консоли, работа с редактором кода, реализация игрового цикла, обработка мыши, проверка победы и экспорт в HTML/BIN. Примеры кода и чек‑лист для публикации помогут быстро получить рабочий прототип.
Примеры тестов / критерии приёмки
- Тест: нажать в центр пустой клетки — ожидаемый результат: запись символа текущего игрока в массив p.
- Тест: заполнить ряд одинаковых символов — игра завершится, winner установится в соответствующее значение.
- Тест: быстрые повторные клики — не допускается многократная запись в одну цепочку событий.
Итог
Важно: начинать с простого — быстрее получите работающий прототип и сможете постепенно улучшать AI и графику. PICO-8 идеален для обучения, прототипирования и распространения небольших игр.
Ключевые шаги: установить PICO-8, изучить _init/_update/_draw, реализовать логику доски и проверку победы, протестировать, экспортировать HTML/BIN.
Важно: в PICO-8 индексация массивов начинается с 1. Это важное отличие от многих языков.
Примечание: если вы хотите продолжить — добавьте AI, сохранение результатов и пользовательский интерфейс для выбора режима игры.
Похожие материалы
LocalStorage в Vue — To‑Do с сохранением
Как отключить VPN на iPhone — пошагово
Fix Download failed — network error в Chrome
Как обойти блокировку сайтов на Virgin Media
Как исправить проблемы с печатью в Windows 10