Гид по технологиям

Создание простой игры в PICO-8 — крестики‑нолики

6 min read Разработка игр Обновлено 05 Dec 2025
PICO-8: крестики‑нолики — руководство
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

  1. Скачайте PICO-8 с itch.io и установите для Windows, macOS или Linux.
  2. Запустите приложение PICO-8.

Вы увидите стартовый экран командной строки PICO-8. Здесь можно загружать картриджи, запускать команды и экспортировать проекты.

Экран загрузки PICO-8: чёрный фон, белый пиксельный текст и приглашение командной строки

Подсказка: команда FOLDER откроет папку с картриджами в файловом менеджере.

Базовое использование редактора кода

Чтобы понять, как писать код для PICO-8, откройте встроенный редактор и запустите простую программу.

  1. На стартовом экране нажмите ESC для входа в редактор кода.

Редактор кода PICO-8, пустой файл

  1. Введите простую программу:
-- простой пример
PRINT("HELLO, WORLD")
  1. Нажмите ESC, чтобы вернуться к командной строке.
  2. Введите 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)
end

stat(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

Примеры улучшений и альтернативные подходы

  1. AI оппонент: реализуйте простой алгоритм (выбор случайной пустой клетки) или Minimax для идеального соперника.
  2. Спрайты: вместо векторных линий используйте спрайты (editor S) для более выразительной графики.
  3. Управление с клавиатуры: добавьте перемещение фокуса по клеткам стрелками и подтверждение Enter.
  4. Сохранение результата: экспортируйте строки состояния в текстовый файл или используйте встроенное сохранение картриджа.

Когда эти подходы не подходят:

  • Minimax избыточен для простых быстрых прототипов.
  • Спрайты усложняют логику, если вы хотите минималистичный ретро‑стиль.

Чек‑лист перед публикацией

  • Игра запускается командой RUN без ошибок.
  • Скриншот сделан (F2) и корректно отображается.
  • Команда EXPORT HTML/BIN проходит без ошибок.
  • Кнопка перезапуска работает.
  • Обработаны краевые случаи (клики вне поля, быстрые повторные клики).

Упаковка и экспорт

  1. Запустите игру: введите RUN.
  2. Во время выполнения нажмите F2, чтобы сделать скриншот — он станет превью.
  3. На командной строке 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: итоговая игра крестики‑нолики, показана выигрышная комбинация

Важно: в PICO-8 индексация массивов начинается с 1. Это важное отличие от многих языков.

Примечание: если вы хотите продолжить — добавьте AI, сохранение результатов и пользовательский интерфейс для выбора режима игры.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

LocalStorage в Vue — To‑Do с сохранением
Веб-разработка

LocalStorage в Vue — To‑Do с сохранением

Как отключить VPN на iPhone — пошагово
Безопасность

Как отключить VPN на iPhone — пошагово

Fix Download failed — network error в Chrome
Troubleshooting

Fix Download failed — network error в Chrome

Как обойти блокировку сайтов на Virgin Media
Интернет

Как обойти блокировку сайтов на Virgin Media

Как исправить проблемы с печатью в Windows 10
Windows

Как исправить проблемы с печатью в Windows 10

Как хранить данные автомобиля в Dash
Авто

Как хранить данные автомобиля в Dash