Представляю вам образовательный проект — “Змейка”, разработанный в рамках учебно-методического комплекса на базе одноплатного компьютера Repka PI 4.
Проект реализован в двух вариантах. В первом варианте игровой процесс отображается на экране монитора. Игра написана на языке Python с использованием библиотеки Pygame, которая отвечает за визуализацию. Управление осуществляется при помощи двухосевого аналогового джойстика: игрок направляет змейку, собирает еду, увеличивает счёт и избегает столкновений с границами и собственным хвостом.
Во втором варианте проект адаптирован для автономной работы: графика выводится на компактный OLED-дисплей размером 0.96 дюйма, подключенным по интерфейсу I2C. Игра запускается на Repka PI 4, а управление также осуществляется с помощью джойстика. Вся информация о ходе игры отображается в реальном времени на OLED-экране, что делает этот вариант особенно интересным для портативных устройств и встроенных решений.
Проект будет собираться с использованием “Учебно-методический комплекс REPKA”. Схему сборки можно найти в разделе "Примеры готовых проектов" учебного пособия УМК “REPKA”.
Также все необходимые материалы и схемы подключения доступны в репозитории на платформе Gitflic.
Компоненты проекта
1. Дисплей OLED 0.96″ I2C для отображения игрового процесса во втором варианте проекта.
2. Двухосевой джойстик XY модуль (Joystick KY-023) для управления игровым процессом.
3. Потребуется аналогово-цифровой преобразователь (далее АЦП) модели ADS1115 для считывания показаний с джойстика.
Вы можете приобрести все необходимые компоненты отдельно от "Учебно-методический комплекс REPKA". Ссылки на модули приведены в таблице ниже.
Компонент | Ссылка на приобретение |
---|---|
Монтажная/макетная плата | Ссылка |
Шлейф | Ссылка |
Переходник с шлейфа на макетную плату | Ссылка |
Соединительные провода | |
Дисплей OLED 0.96″ I2C | Ссылка |
Двухосевой джойстик XY модуль (Joystick KY-023) | Ссылка |
ADS1115 (АЦП) | Ссылка |
Подготовительный этап
1. Подключим дополнительное питание 5V к макетной плате:
2. После чего выведем дополнительное питание на макетную плату:
3. Подключим переходник с шлейфа на макетную плату:
4. Соединим шлейф с переходником для подключения к макетной плате и Repka Pi 4:
5. Итоговый результат должен выглядеть таким образом:
Сборка проекта (вариант с выводом на монитор)
Во время сборки проекта будем регулярно обращаться к электрической принципиальной схеме и монтажной схеме, представленными в учебном пособии (см. рисунки 4 и 5). Эти схемы будут служить основным ориентиром на всех этапах подключения компонентов, обеспечивая точность и правильность сборки устройства.
Для разработки кода будет использоваться текстовый редактор Geany, который входит в состав стандартного ПО Репка ОС.
Электрическая принципиальная схема #
Монтажная схема #
- Подключение АЦП (ADS1115).
Как видно из рисунков 4 и 5 АЦП подключается через интерфейс I2C и питается от 5V.
1.1. Подключим АЦП (ADS1115) к макетной плате согласно таблице 1:
Макетная плата | АЦП (ADS1115) |
---|---|
5V | V |
GND | G |
SCL1 | SCL |
SDA1 | SDA |
Таблица 1. Подключение АЦП (ADS1115) к макетной плате.
1.2. Результат подключения будет выглядеть следующим образом, см. рисунок 6:
Проверку работоспособности АЦП будем проводить после подключения джойстика, чтобы убедиться в правильности считывания аналогового сигнала и корректности преобразования данных.
2. Подключение двухосевого джойстика XY.
Как видно из рисунков 4 и 5, двухосевой джойстик подключается к аналоговым входам A0 и A1 внешнего АЦП, что позволяет считывать его положение по осям X и Y. Питание модуля осуществляется от линии 5V, обеспечивая стабильную работу устройства. Кроме того, джойстик оснащён функцией нажатия, которая реализуется через цифровой вход GPIO4. Для корректной работы этой функции необходимо подключение подтягивающего резистора номиналом 4.7 кОм к линии 3.3V, обеспечивающего надежное определение состояния кнопки при замыкании.
2.1. Подключаем джойстик к к макетной плате согласно таблице 2.
Макетная плата | Джойстик | АЦП |
---|---|---|
5V | VCC | |
GND | GND | |
URX | A0 | |
URY | A1 | |
GPIO4 | SW |
Таблица 2. Подключение джойстика к макетной плате.
2.2. Результат подключения будет выглядеть следующим образом, см. рисунок 7:
3. Выполним проверку подключения устройств АЦП и джойстика. Для этого будем использовать python скрипт из репозитория repka-pi_iot-examples.
3.1. Клонируем репозиторий:
git clone git@gitflic.ru:repka_pi/repka-pi_iot-examples.git
3.2. Переходим в репозиторий:
cd repka-pi_iot-examples/
3.3. Выполним установку зависимостей.
3.3.1. Если хотите установить зависимости только для джойстика, выполните:
make setup-KY-023
3.3.2. Если хотите установить зависимости для всех датчиков и проектов, выполните:
make setup-all
3.4. Запускаем скрипт для проверки работоспособности прибора:
make KY-023
3.5. Если на этапе 3.4. возникает ошибка, необходимо внести изменения в Python-скрипт, расположенный по пути devices/input-output/KY-023_example/py, корректируя номер – i2c = I2C("/dev/i2c-1") и адрес шины – ADS1115_ADDR. В случае отсутствия ошибок, данный шаг нужно пропустить.
#Адрес по умолчанию для ADS1115 (может быть 0x48, 0x49, 0x4A, 0x4B)
ADS1115_ADDR = 0x48
# Создание I2C интерфейса
i2c = I2C("/dev/i2c-1")
3.6. Из рисунка 8 видно, что скрипт был успешно выполнен, и данные о положении джойстика корректно отображаются в консоли.
Запуск проекта
Теперь, когда все компоненты подключены, можно запустить проект "Змейка". Для этого в репозитории repka-pi_iot-examples выполняем команду:
make snake
Игровой процесс отображается на экране в реальном времени, и пользователь может полноценно взаимодействовать с ним с помощью джойстика. Управление движением змейки осуществляется путём наклона стика в нужном направлении, а для постановки игры на паузу достаточно нажать на стик — встроенная кнопка срабатывает, приостанавливая игру до следующего действия игрока.
Видеообзор проекта (вариант с выводом на монитор)
Для более детального ознакомления с проектом, вы можете посмотреть видеообзор на платформе Rutube:
Пример использования с Python (вариант с выводом на монитор)
Проект полностью реализован на языке Python. Код для работы можно найти в репозитории на платформе Gitflic.
Сборка проекта (вариант с выводом на дисплей OLED 0.96″)
Перед началом сборки проекта обратимся к электрической принципиальной схеме и монтажной схеме, представленной в учебном пособии (см. рисунки 11 и 12). По сравнению со схемами на рисунках 4 и 5, в данной конфигурации добавлен только OLED-дисплей, подключенный по интерфейсу I2C. Остальные компоненты — джойстик, АЦП и их подключения — остались без изменений,
Электрическая принципиальная схема #
Монтажная схема #
4. Выполним подключение OLED дисплея.
Как видно из рисунков 11 и 12 устройство подключается через интерфейс I2C и питается от 5V.
4.1. Подключим дисплей OLED 0.96″ I2C к макетной плате согласно таблице 3.
Макетная плата | Дисплей OLED 0.96″ I2C |
5V | VDD |
GND | GND |
SCL1 | SCK |
SDA1 | SDA |
Таблица 3. Подключение дисплея OLED 0.96″ I2C к макетной плате.
4.2. Результат подключения будет выглядеть следующим образом, см. рисунок 13.
5. Выполним проверку подключения устройства.
5.1. Если ранее не устанавливали все зависимости командой setup-all, то установим зависимости для дисплей модуля, выполнив:
make setup-OLED-SSD1306
5.2. Запустим python скрипт:
make OLED-SSD1306
5.3. Из рисунка 14 видим, что скрипт успешно выполнился, тестовый текст появился на дисплее.
Запуск проекта
Теперь, когда все компоненты подключены, можно запустить проект "Змейка". Для этого в репозитории repka-pi_iot-examples выполняем команду:
make snake-oled
Здесь реализована та же логика, что и в варианте с отображением на мониторе: игровой процесс выводится на OLED-дисплей в реальном времени, а управление осуществляется с помощью двухосевого джойстика. Направление движения змейки определяется наклоном стика, а для постановки игры на паузу достаточно нажатия — встроенная кнопка фиксирует это действие и приостанавливает игру до следующего взаимодействия.
Видеообзор проекта (вариант с выводом на OLED дисплей)
Для более детального ознакомления с проектом, вы можете посмотреть видеообзор на платформе Rutube.
Пример использования с Python (вариант с выводом на OLED дисплей)
Проект полностью реализован на языке Python. Код для работы можно найти в репозитории на платформе Gitflic.
Вы можете собрать более бюджетную версию данного проекта.
Для подключения нам потребуется “Распиновка портов на 40 pin разъёме на Repka Pi 4“, см. изображение ниже:
Поскольку расширительная плата GPIO полностью повторяет конфигурацию распиновки, можно применить те же таблицы и схемы, которые использовались ранее для устройств:
6. Подключим АЦП (ADS1115) к макетной плате согласно таблице 1:
7. Подключаем джойстик к к макетной плате согласно таблице 2:
Проверка подключения джойстика и АЦП осуществляется аналогично пункту 3.
8. Подключим дисплей OLED 0.96″ I2C к макетной плате согласно таблице 3:
Проверка подключения дисплея осуществляется аналогично пункту 5.
Для снижения нагрузки на линию 5 В одноплатного компьютера Repka Pi 4, рекомендуется использовать дополнительное питание 5 В:
А. Подключение с использованием лабораторного блока питания:
Б. Подключение с использованием аккумуляторного блока питания:
Разбор кода проекта.
Проект реализован на языке python. Для того чтобы понять логику работы программы рассмотрите блок схему ниже:
Импортируются библиотеки для работы с I2C, GPIO, OLED-дисплеем, изображениями, случайными числами, временем и системными функциями. Определяется номер GPIO-пина, который будет использоваться для кнопки паузы:
from periphery import I2C, GPIO # Работа с I2C и GPIO
from luma.core.interface.serial import i2c as luma_i2c # Интерфейс I2C для luma.oled
from luma.oled.device import sh1106 # Драйвер OLED-дисплея SH1106
from PIL import Image, ImageDraw # Работа с изображениями
import random # Для генерации случайных чисел (еда)
import time # Для задержек и тайминга
import sys # Для выхода из программы
PIN1 = 362 # Номер GPIO-пина для кнопки паузы
Создается временный GPIO-объект для сброса состояния пина, затем инициализируется I2C для работы с АЦП и OLED. Кнопка паузы настраивается на срабатывание по фронту (нажатие):
temp_gpio = GPIO(PIN1, "out") # Временно открываем пин как выход
temp_gpio.close() # Закрываем, чтобы освободить для входа
# === ИНИЦИАЛИЗАЦИЯ I2C ===
ADS1115_ADDR = 0x48 # Адрес АЦП ADS1115 на шине I2C
i2c = I2C("/dev/i2c-1") # Открываем I2C-интерфейс
# === GPIO для паузы ===
pause_btn = GPIO(PIN1, "in") # Открываем пин как вход (кнопка)
pause_btn.edge = "falling" # Срабатывание на нажатие (переход 1→0)
Создается объект для работы с OLED-дисплеем через библиотеку luma.oled по I2C:
oled_serial = luma_i2c(port=1, address=0x3C) # Интерфейс I2C для дисплея
device = sh1106(oled_serial) # Объект дисплея SH1106
Определяются размеры экрана, размер одного блока, количество столбцов и строк на игровом поле:
WIDTH, HEIGHT = device.width, device.height # Размеры экрана (128x64)
BLOCK_SIZE = 4 # Размер одного блока змейки
COLS = WIDTH // BLOCK_SIZE # Количество столбцов (32)
ROWS = HEIGHT // BLOCK_SIZE # Количество строк (16)
Функция read_adc_channel отправляет команды на АЦП ADS1115 по I2C для выбора канала, затем читает 16-битное значение с выбранного канала:
def read_adc_channel(channel):
if channel == 0:
config = 0xC183 # Конфигурация для канала 0
elif channel == 1:
config = 0xD183 # Конфигурация для канала 1
else:
raise ValueError("Only channels 0 and 1 supported")
msgs = [I2C.Message([0x01, (config >> 8) & 0xFF, config & 0xFF])]
i2c.transfer(ADS1115_ADDR, msgs) # Отправка конфигурации
msgs = [I2C.Message([0x00])]
i2c.transfer(ADS1115_ADDR, msgs) # Установка указателя на регистр данных
read = I2C.Message([0x00, 0x00], read=True)
i2c.transfer(ADS1115_ADDR, [read]) # Чтение двух байт
raw = (read.data[0] << 8) | read.data[1] # Объединение байт в 16-битное число
if raw & 0x8000: # Если число отрицательное (доп. код)
raw -= 1 << 16
return raw # Возвращаем результат
По значениям с джойстика (АЦП) определяется направление движения змейки. Если отклонение незначительное — направление не меняется:
def get_direction(x_val, y_val):
center = 13000 # Центр джойстика
threshold = 4000 # Порог чувствительности
dx = x_val - center
dy = y_val - center
if abs(dx) < threshold and abs(dy) < threshold:
return None # Нет движения
if abs(dx) > abs(dy):
return 'LEFT' if dx > 0 else 'RIGHT' # Движение по X
else:
return 'UP' if dy > 0 else 'DOWN' # Движение по Y
Проверяет, действительно ли кнопка нажата, устраняя дребезг контактов с помощью задержки:
def debounce_check(pin, delay=0.5):
if pin.read() == 0: # Кнопка нажата
time.sleep(delay) # Ждем для устранения дребезга
return pin.read() == 0 # Проверяем еще раз
return False # Кнопка не нажата
Рисует змейку и еду на изображении, затем выводит его на OLED-дисплей:
def draw_game(snake, food):
image = Image.new("1", (WIDTH, HEIGHT)) # Создаем черно-белое изображение
draw = ImageDraw.Draw(image)
for segment in snake: # Рисуем все сегменты змейки
x, y = segment
draw.rectangle([
x * BLOCK_SIZE,
y * BLOCK_SIZE,
x * BLOCK_SIZE + BLOCK_SIZE - 1,
y * BLOCK_SIZE + BLOCK_SIZE - 1
], outline=255, fill=255)
fx, fy = food # Рисуем еду
draw.rectangle([
fx * BLOCK_SIZE,
fy * BLOCK_SIZE,
fx * BLOCK_SIZE + BLOCK_SIZE - 1,
fy * BLOCK_SIZE + BLOCK_SIZE - 1
], outline=255, fill=0)
device.display(image) # Выводим изображение на экран
Генерирует случайную позицию для еды, не совпадающую с телом змейки:
def generate_food(snake):
while True:
food = (random.randint(0, COLS - 1), random.randint(0, ROWS - 1))
if food not in snake: # Проверяем, что еда не на змейке
return food
Основной цикл игры: обработка паузы, чтение управления, движение змейки, проверка столкновений, рост змейки, отрисовка, завершение игры:
def game_loop():
snake = [(5, 5), (4, 5), (3, 5)] # Начальная змейка
direction = 'RIGHT' # Начальное направление
food = generate_food(snake) # Первая еда
last_dir = direction
paused = False
while True:
# --- Проверка паузы ---
if debounce_check(pause_btn):
paused = not paused
print("Пауза:", paused)
time.sleep(0.5)
if paused:
# Показываем надпись "PAUSED"
image = Image.new("1", (WIDTH, HEIGHT))
draw = ImageDraw.Draw(image)
draw.text((20, 25), "PAUSED", fill=255)
device.display(image)
time.sleep(0.1)
continue
# --- Управление направлением ---
x_val = read_adc_channel(0)
y_val = read_adc_channel(1)
new_dir = get_direction(x_val, y_val)
opposites = {'UP': 'DOWN', 'DOWN': 'UP', 'LEFT': 'RIGHT', 'RIGHT': 'LEFT'}
if new_dir and new_dir != opposites.get(last_dir):
direction = new_dir
head_x, head_y = snake[0]
if direction == 'UP':
head_y -= 1
elif direction == 'DOWN':
head_y += 1
elif direction == 'LEFT':
head_x -= 1
elif direction == 'RIGHT':
head_x += 1
new_head = (head_x, head_y)
# Проверка на проигрыш
if (new_head in snake or
head_x < 0 or head_x >= COLS or
head_y < 0 or head_y >= ROWS):
image = Image.new("1", (WIDTH, HEIGHT))
draw = ImageDraw.Draw(image)
draw.text((10, 25), "GAME OVER", fill=255)
draw.text((10, 40), f"Score: {len(snake) - 3}", fill=255)
device.display(image)
time.sleep(3)
return
snake.insert(0, new_head)
if new_head == food:
food = generate_food(snake)
else:
snake.pop()
draw_game(snake, food)
last_dir = direction
time.sleep(0.2)
Запуск игрового цикла, обработка выхода по Ctrl+C, освобождение ресурсов (закрытие I2C, GPIO, очистка экрана):
try:
game_loop()
except KeyboardInterrupt:
print("Выход...")
finally:
i2c.close()
pause_btn.close()
device.clear()
Пример кода выше с использованием ООП:
Импортируются библиотеки для работы с I2C, GPIO, OLED-дисплеем, изображениями, случайными числами, временем и системными функциями. Определяются константы для пинов, адресов и размеров:
from periphery import I2C, GPIO
from luma.core.interface.serial import i2c as luma_i2c
from luma.oled.device import sh1106
from PIL import Image, ImageDraw
import random
import time
import sys
PIN1 = 362
ADS1115_ADDR = 0x48
I2C_DEV = "/dev/i2c-1"
OLED_ADDR = 0x3C
OLED_PORT = 1
BLOCK_SIZE = 4
Класс Display отвечает за работу с OLED-дисплеем: инициализация, отрисовка игрового поля, вывод сообщений, очистка экрана:
class Display:
def __init__(self):
oled_serial = luma_i2c(port=OLED_PORT, address=OLED_ADDR)
self.device = sh1106(oled_serial)
self.width, self.height = self.device.width, self.device.height
self.cols = self.width // BLOCK_SIZE
self.rows = self.height // BLOCK_SIZE
def draw_game(self, snake, food):
image = Image.new("1", (self.width, self.height))
draw = ImageDraw.Draw(image)
for segment in snake.body:
x, y = segment
draw.rectangle([
x * BLOCK_SIZE,
y * BLOCK_SIZE,
x * BLOCK_SIZE + BLOCK_SIZE - 1,
y * BLOCK_SIZE + BLOCK_SIZE - 1
], outline=255, fill=255)
fx, fy = food.position
draw.rectangle([
fx * BLOCK_SIZE,
fy * BLOCK_SIZE,
fx * BLOCK_SIZE + BLOCK_SIZE - 1,
fy * BLOCK_SIZE + BLOCK_SIZE - 1
], outline=255, fill=0)
self.device.display(image)
def show_message(self, text, y=25, score=None):
image = Image.new("1", (self.width, self.height))
draw = ImageDraw.Draw(image)
draw.text((20, y), text, fill=255)
if score is not None:
draw.text((10, y+15), f"Score: {score}", fill=255)
self.device.display(image)
def clear(self):
self.device.clear()
Класс InputHandler обрабатывает ввод: кнопку паузы и джойстик (через АЦП). Содержит методы для устранения дребезга, чтения значений с АЦП, определения направления и освобождения ресурсов:
class InputHandler:
def __init__(self, pin=PIN1, i2c_dev=I2C_DEV, adc_addr=ADS1115_ADDR):
self.pause_btn = GPIO(pin, "in")
self.pause_btn.edge = "falling"
self.i2c = I2C(i2c_dev)
self.adc_addr = adc_addr
def debounce_check(self, delay=0.5):
if self.pause_btn.read() == 0:
time.sleep(delay)
return self.pause_btn.read() == 0
return False
def read_adc_channel(self, channel):
if channel == 0:
config = 0xC183
elif channel == 1:
config = 0xD183
else:
raise ValueError("Only channels 0 and 1 supported")
msgs = [I2C.Message([0x01, (config >> 8) & 0xFF, config & 0xFF])]
self.i2c.transfer(self.adc_addr, msgs)
msgs = [I2C.Message([0x00])]
self.i2c.transfer(self.adc_addr, msgs)
read = I2C.Message([0x00, 0x00], read=True)
self.i2c.transfer(self.adc_addr, [read])
raw = (read.data[0] << 8) | read.data[1]
if raw & 0x8000:
raw -= 1 << 16
return raw
def get_direction(self, x_val, y_val):
center = 13000
threshold = 4000
dx = x_val - center
dy = y_val - center
if abs(dx) < threshold and abs(dy) < threshold:
return None
if abs(dx) > abs(dy):
return 'LEFT' if dx > 0 else 'RIGHT'
else:
return 'UP' if dy > 0 else 'DOWN'
def close(self):
self.i2c.close()
self.pause_btn.close()
Класс Snake инкапсулирует логику змейки: хранит тело, направление, реализует движение, удаление хвоста, проверку столкновений:
class Snake:
def __init__(self):
self.body = [(5, 5), (4, 5), (3, 5)]
self.direction = 'RIGHT'
self.last_dir = self.direction
def move(self, direction):
head_x, head_y = self.body[0]
if direction == 'UP':
head_y -= 1
elif direction == 'DOWN':
head_y += 1
elif direction == 'LEFT':
head_x -= 1
elif direction == 'RIGHT':
head_x += 1
new_head = (head_x, head_y)
self.body.insert(0, new_head)
return new_head
def pop_tail(self):
self.body.pop()
def check_collision(self, new_head, cols, rows):
x, y = new_head
return (
new_head in self.body[1:] or
x < 0 or x >= cols or
y < 0 or y >= rows
)
Класс Food отвечает за генерацию и хранение позиции еды. Может создавать новую еду вне тела змейки:
class Food:
def __init__(self, cols, rows, snake):
self.position = self.generate(cols, rows, snake)
def generate(self, cols, rows, snake):
while True:
food = (random.randint(0, cols - 1), random.randint(0, rows - 1))
if food not in snake.body:
return food
def respawn(self, cols, rows, snake):
self.position = self.generate(cols, rows, snake)
Класс SnakeGame главный управляющий класс. Создаёт все объекты, реализует игровой цикл: обработка паузы, управление, движение, столкновения, рост змейки, отрисовка, завершение игры и освобождение ресурсов:
class SnakeGame:
def __init__(self):
self.display = Display()
self.input = InputHandler()
self.snake = Snake()
self.food = Food(self.display.cols, self.display.rows, self.snake)
self.paused = False
self.running = True
def run(self):
try:
while self.running:
# --- Проверка паузы ---
if self.input.debounce_check():
self.paused = not self.paused
print("Пауза:", self.paused)
time.sleep(0.5)
if self.paused:
self.display.show_message("PAUSED")
time.sleep(0.1)
continue
# --- Управление направлением ---
x_val = self.input.read_adc_channel(0)
y_val = self.input.read_adc_channel(1)
new_dir = self.input.get_direction(x_val, y_val)
opposites = {'UP': 'DOWN', 'DOWN': 'UP', 'LEFT': 'RIGHT', 'RIGHT': 'LEFT'}
if new_dir and new_dir != opposites.get(self.snake.last_dir):
self.snake.direction = new_dir
new_head = self.snake.move(self.snake.direction)
# Проверка на проигрыш
if self.snake.check_collision(new_head, self.display.cols, self.display.rows):
self.display.show_message("GAME OVER", y=25, score=len(self.snake.body) - 3)
time.sleep(3)
self.running = False
break
# Проверка на еду
if new_head == self.food.position:
self.food.respawn(self.display.cols, self.display.rows, self.snake)
else:
self.snake.pop_tail()
self.display.draw_game(self.snake, self.food)
self.snake.last_dir = self.snake.direction
time.sleep(0.2)
except KeyboardInterrupt:
print("Выход...")
finally:
self.input.close()
self.display.clear()
Создаётся объект SnakeGame и запускается игровой цикл:
if __name__ == "__main__":
SnakeGame().run()
Преимущества ООП-подхода:
1. Модульность и повторное использование кода
В ООП каждая функциональная часть системы (например, работа с датчиком, реле, дисплеем) оформляется в виде отдельного класса.
Это позволяет легко переиспользовать эти классы в других проектах или расширять функциональность без переписывания кода.
Например, если потребуется добавить второй датчик или другой тип дисплея, можно просто создать новый класс или унаследовать существующий.
2. Упрощение поддержки и масштабирования
Код, разделённый на классы с чётко определённой ответственностью, проще читать, тестировать и отлаживать.
Если возникает ошибка или требуется доработка, достаточно изменить только соответствующий класс, не затрагивая остальной код.
Это особенно важно для сложных или развивающихся проектов, где часто появляются новые требования.
3. Инкапсуляция и защита данных
ООП позволяет скрыть внутренние детали реализации (например, работу с I2C или обработку ошибок) внутри класса.
Внешний код работает только с публичными методами, не заботясь о низкоуровневых деталях.
Это снижает вероятность ошибок, связанных с неправильным использованием компонентов, и делает интерфейс системы более понятным и безопасным.
Проект “Змейка” на базе одноплатного компьютера Repka Pi 4 имеет высокую образовательную ценность и может быть использован в качестве практического задания в курсах по робототехнике, программированию и системам встраиваемой электроники. Он позволяет учащимся наглядно освоить принципы работы с аналоговыми и цифровыми сигналами, интерфейсом I2C, а также научиться создавать графические интерфейсы и реализовывать интерактивное управление. Использование джойстика, дисплея и АЦП развивает понимание взаимодействия различных компонентов в рамках одного проекта. Благодаря гибкости и открытой архитектуре, данный проект легко масштабируется и может служить основой для создания более сложных игровых или прикладных систем.
Расширение проекта
Проект “Змейка” предоставляет широкие возможности для дальнейшего расширения и развития. Одним из направлений может стать добавление новых игровых механик — препятствий, уровней сложности, счётчиков времени или бонусов. Также возможно интегрировать звуковое сопровождение с использованием зуммера или динамика, подключаемого к выходным GPIO-пинам.
Интересным расширением будет использование гироскопа или акселерометра вместо джойстика для управления движением змейки — это позволит реализовать управление наклоном устройства. Помимо этого, можно подключить RGB-светодиоды для визуальной индикации событий (например, при наборе очков или проигрыше), а также реализовать отображение счёта на отдельном семисегментном индикаторе или дисплее.
Для командной или сетевой игры можно рассмотреть организацию обмена данными между несколькими устройствами Repka Pi 4 по Wi-Fi или Bluetooth, с синхронизацией состояния игры между игроками.