
Здравствуйте, уважаемые читатели!
В этой статье я хотел бы поделиться необычным и вдохновляющим проектом — реализацией арканоида в текстовом VGA-режиме, написанного полностью на Rust, без использования стандартной библиотеки и даже без аллокации памяти (#![no_std] + no_alloc).
Проект работает напрямую с VGA-памятью и PS/2 клавиатурой через порт 0x60, создавая абсолютно нативную игру в стиле 80-х, но с современным вниманием к качеству кода. И всё это — с участием милого талисмана Platinum-tan.
Зачем вообще создавать игру в текстовом режиме?
Для нас, разработчиков, работающих с высокоуровневыми фреймворками и богатыми API, подобные проекты становятся отличной возможностью:
Погрузиться в низкоуровневую архитектуру x86
Попрактиковаться в чистой архитектуре и системном программировании
Понять, как можно обойтись без аллокации, без стандартных зависимостей
И просто — почувствовать дух ретро
Архитектура проекта
Проект написан на Rust с использованием #![no_std]
и bootimage
, что позволяет компилировать игру в виде загрузочного ядра.
Основные модули:
Модуль | Назначение |
---|---|
| Прямая работа с VGA-буфером |
| Чтение клавиш напрямую с |
| Игровая логика, отрисовка, физика мячика |
Точка входа, игровой цикл, обработка клавиш |
Особенности реализации
Мячик (
o
) отскакивает от стен, блоков и платформыПлатформа (
=======
) управляется клавишамиA
иD
Цвета блоков зависят от строки (радуга в ASCII)
Поддержка
SPACE
для начала иR
для рестартаВывод очков и милых сообщений от Platinum-tan
Немного магии: как работают цвета
ColorCode::new(Color::Red, Color::Black)
Каждый символ в VGA-буфере имеет не только ASCII-байт, но и байт цвета. Мы изменяем эти цвета на лету — и получаем полноцветный «текстовый» арканоид.
Чтение клавиш без драйвера
pub unsafe fn inb(port: u16) -> u8 {
let value: u8;
core::arch::asm!(\"in al, dx\", out(\"al\") value, in(\"dx\") port);
value
}
Клавиши считываются напрямую из порта 0x60 — без драйверов, без ОС, просто железо и вы.
Вывод информации в виртуальную машину кастомный и реализован через vga_buffer так как мы не можем использовать вывод с использованием no_std
...
impl Writer {
pub fn new() -> Self {
Self {
column_position: 0,
color_code: ColorCode::new(Color::Yellow, Color::Black),
buffer: unsafe { &mut *(VGA_BUFFER_ADDR as *mut Buffer) },
}
}
pub fn write_byte(&mut self, byte: u8) {
match byte {
b'\n' => self.new_line(),
byte => {
if self.column_position >= BUFFER_WIDTH {
self.new_line();
}
let row = BUFFER_HEIGHT - 1;
let col = self.column_position;
self.buffer.chars[row][col].write(ScreenChar {
ascii_character: byte,
color_code: self.color_code,
});
self.column_position += 1;
}
}
}
pub fn write_string(&mut self, s: &str) {
for byte in s.bytes() {
match byte {
0x20..=0x7e | b'\n' => self.write_byte(byte),
_ => self.write_byte(0xfe),
}
}
}
pub fn new_line(&mut self) {
for row in 1..BUFFER_HEIGHT {
for col in 0..BUFFER_WIDTH {
let c = self.buffer.chars[row][col].read();
self.buffer.chars[row - 1][col].write(c);
}
}
self.clear_row(BUFFER_HEIGHT - 1);
self.column_position = 0;
}
fn clear_row(&mut self, row: usize) {
let blank = ScreenChar {
ascii_character: b' ',
color_code: self.color_code,
};
for col in 0..BUFFER_WIDTH {
self.buffer.chars[row][col].write(blank);
}
}
/// Выводит строку по центру последней строки экрана
pub fn write_centered(&mut self, text: &str) {
let len = text.len().min(BUFFER_WIDTH);
let padding = (BUFFER_WIDTH - len) / 2;
self.column_position = padding;
self.write_string(text);
}
...
Как собрать и запустить
Установите Rust nightly и bootimage
:
rustup install nightly
rustup component add rust-src --toolchain nightly
cargo install bootimage
Соберите ядро:
cargo +nightly bootimage -Z build-std=core,compiler_builtins --target x86_64-platinum_os.json -Z build-std-features=compiler-builtins-mem --target-dir target/x86_64-platinum_os
Запустите в QEMU:
qemu-system-x86_64 -drive format=raw,file=target\x86_64-platinum_os\x86_64-platinum_os\debug\bootimage-platinum_os.bin -serial stdio -no-reboot -no-shutdown
Демо: Скриншот

Вдохновение
Это не просто технический эксперимент — это способ выразить любовь к железу, к языку Rust, и к эстетике ASCII-графики. Если вы когда-нибудь мечтали создать свою игру без ОС — сейчас самое время.
Спасибо за внимание!